Browse Source

视频分析统计接口对接

canghailong 5 months ago
parent
commit
ed1fc2efb3

+ 19 - 170
src/api/statisticalAnalysis/videoAnalysis.js

@@ -24,164 +24,6 @@ const generateCourseOptions = () => {
 	})
 	})
 }
 }
 
 
-// 生成视频分析统计数据
-const generateVideoStats = (options) => {
-	console.log('options-', options)
-	const params = new URLSearchParams(options.url.split('?')[1])
-	const courseId = params.get('courseId') || ''
-	const timeRange = params.get('timeRange') || '30'
-
-	// 根据时间范围调整数据规模
-	const timeMultiplier =
-		{
-			7: 0.3,
-			30: 1,
-			90: 2.5,
-			365: 8
-		}[timeRange] || 1
-	console.log('courseId', courseId)
-	// 根据课程选择调整数据规模 - 全部课程数据更多
-	const courseMultiplier = courseId === '' ? 3.5 : 1 // 全部课程是单个课程的3.5倍
-	console.log('courseMultiplier', courseMultiplier)
-	// 基础数据
-	const baseViewers = Math.floor(800 * timeMultiplier * courseMultiplier)
-	const baseCompleted = Math.floor(baseViewers * (0.65 + Math.random() * 0.2)) // 65%-85%完成率
-	const completionRate = Math.round((baseCompleted / baseViewers) * 100)
-
-	const baseDownloads = Math.floor(baseViewers * (0.25 + Math.random() * 0.15)) // 25%-40%下载率
-	const downloadRate = Math.round((baseDownloads / baseViewers) * 100)
-	const avgDownloads = Math.round((baseDownloads / baseViewers) * 100) / 100
-
-	const baseExits = Math.floor(baseViewers * (0.15 + Math.random() * 0.1)) // 15%-25%跳出率
-	const exitRate = Math.round((baseExits / baseViewers) * 100)
-
-	const baseNotes = Math.floor(baseViewers * (0.6 + Math.random() * 0.4)) // 60%-100%笔记率
-	const baseDiscussions = Math.floor(baseViewers * (0.3 + Math.random() * 0.2)) // 30%-50%讨论率
-	const baseReplies = Math.floor(baseDiscussions * (2 + Math.random() * 2)) // 每个讨论2-4个回复
-
-	return Mock.mock({
-		code: 200,
-		data: {
-			totalViewers: baseViewers + Math.floor(Math.random() * 200),
-			completedViewers: baseCompleted,
-			completionRate: completionRate,
-			totalDownloads: baseDownloads,
-			downloadRate: downloadRate,
-			avgDownloads: avgDownloads,
-			totalExits: baseExits,
-			exitRate: exitRate,
-			avgExitTime: '@pick(["08:45", "12:34", "15:23", "18:56", "22:15", "06:30", "14:20", "19:45"])',
-			totalNotes: baseNotes,
-			totalDiscussions: baseDiscussions,
-			totalReplies: baseReplies
-		}
-	})
-}
-
-// 生成学员详细数据
-const generateStudentData = (options) => {
-	const params = new URLSearchParams(options.url.split('?')[1])
-	const current = parseInt(params.get('current')) || 1
-	const pageSize = parseInt(params.get('pageSize')) || 10
-	const courseId = params.get('courseId') || ''
-	const timeRange = params.get('timeRange') || '30'
-
-	// 根据课程和时间范围调整总数
-	const timeMultiplier = { 7: 0.3, 30: 1, 90: 2.5, 365: 8 }[timeRange] || 1
-	const courseMultiplier = courseId === '' ? 3.5 : 1
-	const baseTotal = Math.floor(120 * timeMultiplier * courseMultiplier)
-
-	return Mock.mock({
-		code: 200,
-		[`data|${pageSize}`]: [
-			{
-				'key|+1': (current - 1) * pageSize + 1,
-				id: () => String((current - 1) * pageSize + Mock.Random.increment()).padStart(3, '0'),
-				name: '@cname',
-				totalTime: () => {
-					const minutes = Math.floor(Math.random() * 180) + 30 // 30-210分钟
-					const hours = Math.floor(minutes / 60)
-					const mins = minutes % 60
-					return hours > 0 ? `${hours}小时${mins}分钟` : `${mins}分钟`
-				},
-				'progress|20-100': () => Math.floor(Math.random() * 80) + 20,
-				'viewCount|1-12': () => Math.floor(Math.random() * 12) + 1,
-				'exitPoints|1-5': () => {
-					const count = Math.floor(Math.random() * 5) + 1
-					const points = []
-					for (let i = 0; i < count; i++) {
-						const minutes = Math.floor(Math.random() * 45)
-						const seconds = Math.floor(Math.random() * 60)
-						points.push(`${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`)
-					}
-					return points
-				},
-				'seekCount|2-25': () => Math.floor(Math.random() * 24) + 2,
-				'noteCount|0-15': () => Math.floor(Math.random() * 16),
-				'discussionCount|0-12': () => Math.floor(Math.random() * 13),
-				'replyCount|0-20': () => Math.floor(Math.random() * 21),
-				lastAccess: '@datetime("yyyy-MM-dd HH:mm")'
-			}
-		],
-		total: baseTotal + Math.floor(Math.random() * 50),
-		current,
-		pageSize
-	})
-}
-
-// 生成章节数据
-const generateChapterData = (options) => {
-	const params = new URLSearchParams(options.url.split('?')[1])
-	const courseId = params.get('courseId') || ''
-	const timeRange = params.get('timeRange') || '30'
-
-	// 根据课程和时间范围调整数据规模
-	const timeMultiplier = { 7: 0.3, 30: 1, 90: 2.5, 365: 8 }[timeRange] || 1
-	const courseMultiplier = courseId === '' ? 3.5 : 1
-
-	const chapterCount = Math.floor(Math.random() * 4) + 5 // 5-8章
-	const chapters = []
-
-	for (let i = 1; i <= chapterCount; i++) {
-		const baseViewers = Math.floor((800 - i * 50) * timeMultiplier * courseMultiplier) // 越后面章节观看人数越少
-		const completionRate = Math.max(95 - i * 5 - Math.random() * 10, 60) // 越后面完成率越低
-		const completed = Math.floor(baseViewers * (completionRate / 100))
-
-		// 生成视频时长
-		const totalMinutes = Math.floor(Math.random() * 30) + 15 // 15-45分钟
-		const minutes = totalMinutes % 60
-		const seconds = Math.floor(Math.random() * 60)
-		const duration = `${minutes}:${seconds.toString().padStart(2, '0')}`
-
-		// 平均观看时长应该小于等于视频时长
-		const avgWatchMinutes = Math.floor(totalMinutes * (0.7 + Math.random() * 0.3))
-		const avgWatchSeconds = Math.floor(Math.random() * 60)
-		const avgWatchTime = `${avgWatchMinutes}:${avgWatchSeconds.toString().padStart(2, '0')}`
-
-		chapters.push({
-			key: i,
-			chapter: `第${i}章:${
-				['课程介绍', '基础知识', '核心概念', '实战应用', '高级技巧', '项目实战', '总结回顾', '拓展学习'][i - 1] ||
-				'课程内容'
-			}`,
-			duration: duration,
-			viewers: baseViewers + Math.floor(Math.random() * 100),
-			completed: completed,
-			completionRate: Math.round(completionRate),
-			avgWatchTime: avgWatchTime,
-			exitRate: Math.min(Math.floor(5 + i * 3 + Math.random() * 10), 35), // 越后面跳出率越高
-			downloads: Math.floor(baseViewers * (0.1 + Math.random() * 0.15)), // 10%-25%下载率
-			notes: Math.floor(baseViewers * (0.4 + Math.random() * 0.3)), // 40%-70%笔记率
-			discussions: Math.floor(baseViewers * (0.15 + Math.random() * 0.15)) // 15%-30%讨论率
-		})
-	}
-
-	return {
-		code: 200,
-		data: chapters
-	}
-}
-
 // 生成图表数据
 // 生成图表数据
 const generateChartData = (options) => {
 const generateChartData = (options) => {
 	const params = new URLSearchParams(options.url.split('?')[1])
 	const params = new URLSearchParams(options.url.split('?')[1])
@@ -257,9 +99,6 @@ const generateChartData = (options) => {
 }
 }
 // Mock 接口定义
 // Mock 接口定义
 Mock.mock(/\/api\/webapp\/video-analysis\/course-options/, 'get', generateCourseOptions)
 Mock.mock(/\/api\/webapp\/video-analysis\/course-options/, 'get', generateCourseOptions)
-Mock.mock(/\/api\/webapp\/video-analysis\/stats/, 'get', generateVideoStats)
-Mock.mock(/\/api\/webapp\/video-analysis\/students/, 'get', generateStudentData)
-Mock.mock(/\/api\/webapp\/video-analysis\/chapters/, 'get', generateChapterData)
 Mock.mock(/\/api\/webapp\/video-analysis\/charts/, 'get', generateChartData)
 Mock.mock(/\/api\/webapp\/video-analysis\/charts/, 'get', generateChartData)
 
 
 // 导出的API函数
 // 导出的API函数
@@ -268,21 +107,31 @@ export const videoAnalysisApi = {
 	getCourseOptions() {
 	getCourseOptions() {
 		return request('/video-analysis/course-options', '', 'get')
 		return request('/video-analysis/course-options', '', 'get')
 	},
 	},
-
-	// 获取视频分析统计数据
-	getVideoStats(params = {}) {
-		console.log('params=', params)
-		return request('/video-analysis/stats', params, 'get')
+	// 视频分析-观看人数统计
+	watchUserCountProgress(params = {}) {
+		return request('/disk/videoanalysis/watchUserCountProgress', params, 'get')
+	},
+	// 视频分析-讲义下载次数
+	teachMaterialsDownloadCount(params = {}) {
+		return request('/disk/videoanalysis/teachMaterialsDownloadCount', params, 'get')
+	},
+	// 视频分析-跳出时间分析
+	jumpTimeAnalyse(params = {}) {
+		return request('/disk/videoanalysis/jumpTimeAnalyse', params, 'get')
+	},
+	// 视频分析-互动统计分析
+	interactionDataAnalyse(params = {}) {
+		return request('/disk/videoanalysis/interactionDataAnalyse', params, 'get')
 	},
 	},
 
 
 	// 获取学员详细数据
 	// 获取学员详细数据
-	getStudentData(params = {}) {
-		return request('/video-analysis/students', params, 'get')
+	studyBehaviorDetailData(params = {}) {
+		return request('/disk/videoanalysis/studyBehaviorDetailData', params, 'get')
 	},
 	},
 
 
 	// 获取章节数据
 	// 获取章节数据
-	getChapterData(params = {}) {
-		return request('/video-analysis/chapters', params, 'get')
+	videoDetailDataAnalysis(params = {}) {
+		return request('/disk/videoanalysis/videoDetailDataAnalysis', params, 'get')
 	},
 	},
 
 
 	// 获取图表数据
 	// 获取图表数据

+ 115 - 68
src/views/statisticalAnalysis/videoAnalysis/index.vue

@@ -19,15 +19,17 @@
 						</a-select-option>
 						</a-select-option>
 					</a-select>
 					</a-select>
 				</div>
 				</div>
-				<div class="filter-group">
-					<label>时间范围</label>
-					<a-select v-model:value="filters.timeRange" style="width: 100%">
-						<a-select-option value="7">最近7天</a-select-option>
-						<a-select-option value="30">最近30天</a-select-option>
-						<a-select-option value="90">最近90天</a-select-option>
-						<a-select-option value="365">最近一年</a-select-option>
-					</a-select>
+				<!-- 日期范围选择 -->
+				<div class="flex-1 mr-4">
+					<label class="block text-sm font-medium text-gray-700 mb-1">开始时间</label>
+					<a-date-picker v-model:value="startTime" class="w-full" placeholder="开始时间" />
+				</div>
+
+				<div class="flex-1 mr-4">
+					<label class="block text-sm font-medium text-gray-700 mb-1">结束时间</label>
+					<a-date-picker v-model:value="endTime" class="w-full" placeholder="结束时间" />
 				</div>
 				</div>
+
 				<div class="filter-group">
 				<div class="filter-group">
 					<a-button type="primary" @click="updateStats">查询</a-button>
 					<a-button type="primary" @click="updateStats">查询</a-button>
 				</div>
 				</div>
@@ -36,43 +38,43 @@
 
 
 		<!-- 核心统计数据 -->
 		<!-- 核心统计数据 -->
 		<div class="stats-grid">
 		<div class="stats-grid">
-			<div class="stat-card">
+			<div class="stat-card" v-if="stats.countData">
 				<h3>👥 观看人数统计</h3>
 				<h3>👥 观看人数统计</h3>
-				<div class="stat-number">{{ stats.totalViewers.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.countData.alreadyWatchUserCount }}</div>
 				<div class="stat-label">总观看人数</div>
 				<div class="stat-label">总观看人数</div>
-				<div class="stat-number">{{ stats.completedViewers.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.countData.completeWatchUserCount }}</div>
 				<div class="stat-label">完成观看人数</div>
 				<div class="stat-label">完成观看人数</div>
-				<div class="completion-rate">{{ stats.completionRate }}%</div>
+				<div class="completion-rate">{{ stats.countData.completeRate }}%</div>
 				<div class="stat-label">完成率</div>
 				<div class="stat-label">完成率</div>
 			</div>
 			</div>
 
 
-			<div class="stat-card">
+			<div class="stat-card" v-if="stats.downData">
 				<h3>📥 讲义下载统计</h3>
 				<h3>📥 讲义下载统计</h3>
-				<div class="stat-number">{{ stats.totalDownloads.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.downData.allDownloadCount }}</div>
 				<div class="stat-label">总下载次数</div>
 				<div class="stat-label">总下载次数</div>
-				<div class="stat-number">{{ stats.downloadRate }}%</div>
+				<div class="stat-number">{{ stats.downData.downloadRate }}%</div>
 				<div class="stat-label">下载率</div>
 				<div class="stat-label">下载率</div>
-				<div class="stat-number">{{ stats.avgDownloads }}</div>
+				<div class="stat-number">{{ stats.downData.avgDownloadCount }}</div>
 				<div class="stat-label">人均下载次数</div>
 				<div class="stat-label">人均下载次数</div>
 			</div>
 			</div>
 
 
-			<div class="stat-card">
+			<div class="stat-card" v-if="stats.jumpData">
 				<h3>⏱️ 跳出时间分析</h3>
 				<h3>⏱️ 跳出时间分析</h3>
-				<div class="stat-number">{{ stats.totalExits.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.jumpData.jumpOutCount }}</div>
 				<div class="stat-label">总跳出次数</div>
 				<div class="stat-label">总跳出次数</div>
-				<div class="stat-number">{{ stats.exitRate }}%</div>
+				<div class="stat-number">{{ stats.jumpData.jumpOutRate }}%</div>
 				<div class="stat-label">跳出率</div>
 				<div class="stat-label">跳出率</div>
-				<div class="stat-number">{{ stats.avgExitTime }}</div>
+				<div class="stat-number">{{ stats.jumpData.jumpAvgTime }}</div>
 				<div class="stat-label">平均跳出时间</div>
 				<div class="stat-label">平均跳出时间</div>
 			</div>
 			</div>
 
 
-			<div class="stat-card">
+			<div class="stat-card" v-if="stats.interdata">
 				<h3>📝 互动数据统计</h3>
 				<h3>📝 互动数据统计</h3>
-				<div class="stat-number">{{ stats.totalNotes.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.interdata.noteCount }}</div>
 				<div class="stat-label">笔记总数</div>
 				<div class="stat-label">笔记总数</div>
-				<div class="stat-number">{{ stats.totalDiscussions.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.interdata.postCount }}</div>
 				<div class="stat-label">讨论总数</div>
 				<div class="stat-label">讨论总数</div>
-				<div class="stat-number">{{ stats.totalReplies.toLocaleString() }}</div>
+				<div class="stat-number">{{ stats.interdata.replyCount }}</div>
 				<div class="stat-label">回帖总数</div>
 				<div class="stat-label">回帖总数</div>
 			</div>
 			</div>
 		</div>
 		</div>
@@ -115,14 +117,14 @@
 				:scroll="{ x: 1200 }"
 				:scroll="{ x: 1200 }"
 			>
 			>
 				<template #bodyCell="{ column, record }">
 				<template #bodyCell="{ column, record }">
-					<template v-if="column.key === 'progress'">
+					<template v-if="column.key === 'finishRate'">
 						<div class="progress-container">
 						<div class="progress-container">
-							<a-progress :percent="record.progress" size="small" />
-							<span :class="{ 'low-engagement': record.progress < 50 }"> {{ record.progress }}% </span>
+							<a-progress :percent="record.finishRate * 100" size="small" />
+							<span :class="{ 'low-engagement': record.finishRate * 100 < 50 }"> {{ record.finishRate * 100 }}% </span>
 						</div>
 						</div>
 					</template>
 					</template>
-					<template v-else-if="column.key === 'exitPoints'">
-						<span v-for="point in record.exitPoints" :key="point" class="time-point">
+					<template v-else-if="column.key === 'jumpTimeContact'">
+						<span v-for="point in record.jumpTimeContactArr" :key="point" class="time-point">
 							{{ point }}
 							{{ point }}
 						</span>
 						</span>
 					</template>
 					</template>
@@ -133,17 +135,25 @@
 		<!-- 视频章节详细统计 -->
 		<!-- 视频章节详细统计 -->
 		<div class="data-table">
 		<div class="data-table">
 			<h3>📚 视频章节详细统计</h3>
 			<h3>📚 视频章节详细统计</h3>
-			<a-table :columns="chapterColumns" :data-source="chapterData" :pagination="false" :loading="loading">
+			<a-table
+				:columns="chapterColumns"
+				:data-source="chapterData"
+				:pagination="chapterPagination"
+				:loading="chapterLoading"
+			>
 				<template #bodyCell="{ column, record }">
 				<template #bodyCell="{ column, record }">
-					<template v-if="column.key === 'completionRate'">
+					<template v-if="column.key === 'completeRate'">
 						<span
 						<span
-							:class="{ 'completion-rate': record.completionRate >= 70, 'low-engagement': record.completionRate < 70 }"
+							:class="{
+								'completion-rate': record.completeRate * 100 >= 70,
+								'low-engagement': record.completeRate * 100 < 70
+							}"
 						>
 						>
-							{{ record.completionRate }}%
+							{{ record.completeRate * 100 }}%
 						</span>
 						</span>
 					</template>
 					</template>
-					<template v-else-if="column.key === 'exitRate'">
-						<span :class="{ 'low-engagement': record.exitRate > 25 }"> {{ record.exitRate }}% </span>
+					<template v-else-if="column.key === 'jumpOutRate'">
+						<span :class="{ 'low-engagement': record.jumpOutRate * 100 > 25 }"> {{ record.jumpOutRate * 100 }}% </span>
 					</template>
 					</template>
 				</template>
 				</template>
 			</a-table>
 			</a-table>
@@ -152,15 +162,20 @@
 </template>
 </template>
 
 
 <script setup>
 <script setup>
-	import { ref, reactive, onMounted, nextTick, watch } from 'vue'
+	import { ref, reactive, onMounted, nextTick, watch, computed } from 'vue'
 	import { message } from 'ant-design-vue'
 	import { message } from 'ant-design-vue'
 	import * as echarts from 'echarts'
 	import * as echarts from 'echarts'
+	import { getCourseOptions } from '@/api/statisticalAnalysis/analysisTeachingActivities'
 	import { videoAnalysisApi } from '@/api/statisticalAnalysis/videoAnalysis'
 	import { videoAnalysisApi } from '@/api/statisticalAnalysis/videoAnalysis'
+	import dayjs from 'dayjs'
 
 
 	// 筛选条件
 	// 筛选条件
+	const startTime = ref(dayjs('2025-08-04'))
+	const endTime = ref(dayjs('2025-08-09'))
 	const filters = reactive({
 	const filters = reactive({
 		courseId: '',
 		courseId: '',
-		timeRange: '30'
+		startTime: computed(() => dayjs(startTime.value).format('YYYY-MM-DD')),
+		endTime: computed(() => dayjs(endTime.value).format('YYYY-MM-DD'))
 	})
 	})
 
 
 	// 课程选项
 	// 课程选项
@@ -168,7 +183,7 @@
 
 
 	// 加载状态
 	// 加载状态
 	const loading = ref(false)
 	const loading = ref(false)
-
+	const chapterLoading = ref(false)
 	// 统计数据
 	// 统计数据
 	const stats = reactive({
 	const stats = reactive({
 		totalViewers: 2800,
 		totalViewers: 2800,
@@ -193,17 +208,17 @@
 
 
 	// 学员数据表格列定义
 	// 学员数据表格列定义
 	const studentColumns = [
 	const studentColumns = [
-		{ title: '学员ID', dataIndex: 'id', key: 'id', width: 80 },
-		{ title: '姓名', dataIndex: 'name', key: 'name', width: 100 },
-		{ title: '访问总时长', dataIndex: 'totalTime', key: 'totalTime', width: 120 },
-		{ title: '学习进度', dataIndex: 'progress', key: 'progress', width: 150 },
-		{ title: '观看次数', dataIndex: 'viewCount', key: 'viewCount', width: 100 },
-		{ title: '跳出时间点', dataIndex: 'exitPoints', key: 'exitPoints', width: 200 },
-		{ title: '快进快退次数', dataIndex: 'seekCount', key: 'seekCount', width: 120 },
+		{ title: '学员ID', dataIndex: 'userId', key: 'userId', width: 80 },
+		{ title: '姓名', dataIndex: 'stuName', key: 'stuName', width: 100 },
+		{ title: '访问总时长', dataIndex: 'allStayTime', key: 'allStayTime', width: 120 },
+		{ title: '学习进度', dataIndex: 'finishRate', key: 'finishRate', width: 150 },
+		{ title: '观看次数', dataIndex: 'watchCount', key: 'watchCount', width: 100 },
+		{ title: '跳出时间点', dataIndex: 'jumpTimeContact', key: 'jumpTimeContact', width: 200 },
+		{ title: '快进快退次数', dataIndex: 'quickOperaCount', key: 'quickOperaCount', width: 120 },
 		{ title: '笔记数', dataIndex: 'noteCount', key: 'noteCount', width: 80 },
 		{ title: '笔记数', dataIndex: 'noteCount', key: 'noteCount', width: 80 },
-		{ title: '讨论数', dataIndex: 'discussionCount', key: 'discussionCount', width: 80 },
+		{ title: '讨论数', dataIndex: 'postCount', key: 'postCount', width: 80 },
 		{ title: '回帖数', dataIndex: 'replyCount', key: 'replyCount', width: 80 },
 		{ title: '回帖数', dataIndex: 'replyCount', key: 'replyCount', width: 80 },
-		{ title: '最后访问', dataIndex: 'lastAccess', key: 'lastAccess', width: 150 }
+		{ title: '最后访问', dataIndex: 'lastLoginTime', key: 'lastLoginTime', width: 150 }
 	]
 	]
 
 
 	// 学员数据
 	// 学员数据
@@ -223,19 +238,33 @@
 			fetchStudentData()
 			fetchStudentData()
 		}
 		}
 	})
 	})
+	// 分页配置
+	const chapterPagination = reactive({
+		current: 1,
+		pageSize: 10,
+		total: 0,
+		showTotal: (total, range) => `显示 ${range[0]}-${range[1]} 条,共 ${total} 条`,
+		onChange: (page, pageSize) => {
+			chapterPagination.current = page
+			chapterPagination.pageSize = pageSize
+			fetchChapterData()
+		}
+	})
 
 
 	// 章节数据表格列定义
 	// 章节数据表格列定义
 	const chapterColumns = [
 	const chapterColumns = [
-		{ title: '章节', dataIndex: 'chapter', key: 'chapter', width: 200 },
-		{ title: '视频时长', dataIndex: 'duration', key: 'duration', width: 100 },
-		{ title: '观看人数', dataIndex: 'viewers', key: 'viewers', width: 100 },
-		{ title: '完成人数', dataIndex: 'completed', key: 'completed', width: 100 },
-		{ title: '完成率', dataIndex: 'completionRate', key: 'completionRate', width: 100 },
-		{ title: '平均观看时长', dataIndex: 'avgWatchTime', key: 'avgWatchTime', width: 120 },
-		{ title: '跳出率', dataIndex: 'exitRate', key: 'exitRate', width: 100 },
-		{ title: '下载次数', dataIndex: 'downloads', key: 'downloads', width: 100 },
-		{ title: '笔记数', dataIndex: 'notes', key: 'notes', width: 80 },
-		{ title: '讨论数', dataIndex: 'discussions', key: 'discussions', width: 80 }
+		{ title: '课程名称', dataIndex: 'courseIdName', key: 'courseIdName', width: 200 },
+		{ title: '章节名称', dataIndex: 'chapterIdName', key: 'chapterIdName', width: 200 },
+		{ title: '课时名称', dataIndex: 'hourIdName', key: 'hourIdName', width: 200 },
+		{ title: '视频时长', dataIndex: 'allStayTime', key: 'allStayTime', width: 100 },
+		{ title: '观看人数', dataIndex: 'watchUserCount', key: 'watchUserCount', width: 100 },
+		{ title: '完成人数', dataIndex: 'completeWatchUserCount', key: 'completeWatchUserCount', width: 100 },
+		{ title: '完成率', dataIndex: 'completeRate', key: 'completeRate', width: 100 },
+		{ title: '平均观看时长', dataIndex: 'avgStayTime', key: 'avgStayTime', width: 120 },
+		{ title: '跳出率', dataIndex: 'jumpOutRate', key: 'jumpOutRate', width: 100 },
+		{ title: '下载次数', dataIndex: 'downloadCount', key: 'downloadCount', width: 100 },
+		{ title: '笔记数', dataIndex: 'noteCount', key: 'noteCount', width: 80 },
+		{ title: '讨论数', dataIndex: 'postCount', key: 'postCount', width: 80 }
 	]
 	]
 
 
 	// 章节数据
 	// 章节数据
@@ -480,7 +509,7 @@
 	// 获取课程选项
 	// 获取课程选项
 	const fetchCourseOptions = async () => {
 	const fetchCourseOptions = async () => {
 		try {
 		try {
-			const response = await videoAnalysisApi.getCourseOptions()
+			const response = await getCourseOptions()
 			courseOptions.value = response || []
 			courseOptions.value = response || []
 		} catch (error) {
 		} catch (error) {
 			console.error('获取课程选项失败:', error)
 			console.error('获取课程选项失败:', error)
@@ -490,11 +519,18 @@
 	// 获取统计数据
 	// 获取统计数据
 	const fetchVideoStats = async () => {
 	const fetchVideoStats = async () => {
 		try {
 		try {
-			const response = await videoAnalysisApi.getVideoStats(filters)
-			const data = response || {}
+			const countData = await videoAnalysisApi.watchUserCountProgress(filters)
+			const downData = await videoAnalysisApi.teachMaterialsDownloadCount(filters)
+			const jumpData = await videoAnalysisApi.jumpTimeAnalyse(filters)
+			const interdata = await videoAnalysisApi.interactionDataAnalyse(filters)
 
 
 			// 更新统计数据
 			// 更新统计数据
-			Object.assign(stats, data)
+			Object.assign(stats, {
+				countData,
+				downData,
+				jumpData,
+				interdata
+			})
 		} catch (error) {
 		} catch (error) {
 			console.error('获取统计数据失败:', error)
 			console.error('获取统计数据失败:', error)
 			message.error('获取统计数据失败')
 			message.error('获取统计数据失败')
@@ -504,14 +540,18 @@
 	// 获取学员数据
 	// 获取学员数据
 	const fetchStudentData = async () => {
 	const fetchStudentData = async () => {
 		try {
 		try {
-			const response = await videoAnalysisApi.getStudentData({
+			const response = await videoAnalysisApi.studyBehaviorDetailData({
 				...filters,
 				...filters,
 				current: pagination.current,
 				current: pagination.current,
 				pageSize: pagination.pageSize
 				pageSize: pagination.pageSize
 			})
 			})
-			const data = response || []
-
-			studentData.value = data
+			const data = response.records || []
+			studentData.value = data.map((r) => {
+				return {
+					...r,
+					jumpTimeContactArr: r.jumpTimeContact?.split(',')
+				}
+			})
 			pagination.total = response.total || 0
 			pagination.total = response.total || 0
 		} catch (error) {
 		} catch (error) {
 			console.error('获取学员数据失败:', error)
 			console.error('获取学员数据失败:', error)
@@ -522,8 +562,13 @@
 	// 获取章节数据
 	// 获取章节数据
 	const fetchChapterData = async () => {
 	const fetchChapterData = async () => {
 		try {
 		try {
-			const response = await videoAnalysisApi.getChapterData(filters)
-			chapterData.value = response || []
+			const response = await videoAnalysisApi.videoDetailDataAnalysis({
+				...filters,
+				current: chapterPagination.current,
+				pageSize: chapterPagination.pageSize
+			})
+			chapterData.value = response.records || []
+			chapterPagination.total = response.total || 0
 		} catch (error) {
 		} catch (error) {
 			console.error('获取章节数据失败:', error)
 			console.error('获取章节数据失败:', error)
 			message.error('获取章节数据失败')
 			message.error('获取章节数据失败')
@@ -552,6 +597,7 @@
 	// 更新统计数据
 	// 更新统计数据
 	const updateStats = async () => {
 	const updateStats = async () => {
 		loading.value = true
 		loading.value = true
+		chapterLoading.value = true
 		try {
 		try {
 			await Promise.all([fetchVideoStats(), fetchStudentData(), fetchChapterData(), fetchChartData()])
 			await Promise.all([fetchVideoStats(), fetchStudentData(), fetchChapterData(), fetchChartData()])
 			message.success('数据已更新!')
 			message.success('数据已更新!')
@@ -559,6 +605,7 @@
 			console.error('更新数据失败:', error)
 			console.error('更新数据失败:', error)
 		} finally {
 		} finally {
 			loading.value = false
 			loading.value = false
+			chapterLoading.value = false
 		}
 		}
 	}
 	}
 
 
@@ -577,7 +624,7 @@
 
 
 	// 监听筛选条件变化
 	// 监听筛选条件变化
 	watch(
 	watch(
-		() => [filters.courseId, filters.timeRange],
+		() => [filters.courseId],
 		() => {
 		() => {
 			updateStats()
 			updateStats()
 		},
 		},