Переглянути джерело

refactor(学习进度统计): 重构学习进度统计模块,移除mock数据并接入真实接口

- 移除原有的mock数据及相关逻辑
- 重构API接口,对接真实后端接口
- 调整页面筛选条件,改为课程ID选择和时间范围选择
- 更新图表和表格数据展示逻辑,适配新接口数据结构
- 添加课程列表获取功能,支持课程选择
tanshanming 6 місяців тому
батько
коміт
3e7f07f76a

+ 161 - 259
src/api/statisticalAnalysis/overviewLearningProgress.js

@@ -1,272 +1,174 @@
-// 文件模块相关接口
+// 学习进度统计分析相关接口
 import { moduleRequest } from '@/utils/request'
-import Mock from 'mockjs'
 
-const request = moduleRequest(`/api/webapp`)
-
-// Mock 数据配置
-Mock.setup({
-	timeout: '200-600'
-})
-
-// 课程名称列表
-const courseNames = [
-	'Python编程入门',
-	'数据结构与算法',
-	'机器学习基础',
-	'Web前端开发',
-	'Java后端开发',
-	'数据库设计',
-	'算法分析',
-	'人工智能导论',
-	'计算机网络',
-	'操作系统原理',
-	'软件工程',
-	'计算机图形学',
-	'编译原理',
-	'分布式系统',
-	'云计算技术'
-]
-
-// 生成完整的课程数据集(用于分页)
-const generateFullCourseData = () => {
-	return courseNames.map((courseName, index) => ({
-		id: index + 1,
-		courseName,
-		studentCount: Mock.Random.integer(80, 150),
-		visitCount: Mock.Random.integer(800, 2000),
-		videoDuration: Mock.Random.pick(['3h25m', '4h12m', '5h30m', '6h45m', '2h58m', '7h20m', '8h15m', '9h30m']),
-		documentVisit: Mock.Random.integer(300, 800),
-		submissionCount: Mock.Random.integer(70, 95),
-		numberStudentsDroppingCourses: Mock.Random.integer(5, 25)
-	}))
-}
-
-// 全局存储完整数据集
-let fullCourseData = generateFullCourseData()
-
-// 根据筛选条件调整数据
-const adjustDataByFilters = (data, courseName, contentType) => {
-	return data.map((item) => {
-		let adjustedItem = { ...item }
-
-		// 根据课程名称筛选调整数据
-		if (courseName && courseName !== '' && item.courseName !== courseName) {
-			// 如果不是选中的课程,数据为0或很小
-			adjustedItem.studentCount = 0
-			adjustedItem.visitCount = 0
-			adjustedItem.documentVisit = 0
-			adjustedItem.submissionCount = 0
-			adjustedItem.numberStudentsDroppingCourses = 0
-			adjustedItem.videoDuration = '0h0m'
-		} else if (courseName && courseName !== '' && item.courseName === courseName) {
-			// 如果是选中的课程,保持原数据或稍微增加
-			adjustedItem.studentCount = item.studentCount
-			adjustedItem.visitCount = item.visitCount
-			adjustedItem.documentVisit = item.documentVisit
-			adjustedItem.submissionCount = item.submissionCount
-		}
-
-		// 根据内容类型调整数据
-		if (contentType && contentType !== 'all') {
-			const reductionFactor = 0.6 // 具体类型的数据是全部的60%
-			switch (contentType) {
-				case 'video':
-					adjustedItem.visitCount = Math.floor(adjustedItem.visitCount * reductionFactor)
-					adjustedItem.documentVisit = Math.floor(adjustedItem.documentVisit * 0.3)
-					break
-				case 'document':
-					adjustedItem.documentVisit = Math.floor(adjustedItem.documentVisit * reductionFactor)
-					adjustedItem.visitCount = Math.floor(adjustedItem.visitCount * 0.4)
-					break
-				case 'exercise':
-					adjustedItem.submissionCount = Math.floor(adjustedItem.submissionCount * reductionFactor)
-					adjustedItem.visitCount = Math.floor(adjustedItem.visitCount * 0.3)
-					adjustedItem.documentVisit = Math.floor(adjustedItem.documentVisit * 0.2)
-					break
-			}
-		}
-
-		return adjustedItem
-	})
-}
-
-// 生成分页的课程列表数据
-const generateCourseList = (options) => {
-	// 解析查询参数
-	const url = new URL('http://localhost' + options.url)
-	const current = parseInt(url.searchParams.get('current')) || 1
-	const pageSize = parseInt(url.searchParams.get('pageSize')) || 6
-	const courseName = url.searchParams.get('courseName') || ''
-	const contentType = url.searchParams.get('contentType') || 'all'
-
-	// 根据筛选条件调整数据
-	let filteredData = adjustDataByFilters(fullCourseData, courseName, contentType)
-
-	// 如果选择了特定课程,只显示该课程
-	if (courseName && courseName !== '') {
-		filteredData = filteredData.filter((item) => item.courseName === courseName)
-	}
-
-	// 计算分页
-	const startIndex = (current - 1) * pageSize
-	const endIndex = startIndex + pageSize
-	const pageData = filteredData.slice(startIndex, endIndex)
-
-	return {
-		code: 200,
-		data: {
-			data: pageData,
-			total: filteredData.length,
-			current: current,
-			pageSize: pageSize
-		}
-	}
-}
-
-// 生成统计概览数据
-const generateOverviewStats = (options) => {
-	// 解析查询参数
-	const url = new URL('http://localhost' + options.url)
-	const courseName = url.searchParams.get('courseName') || ''
-	const contentType = url.searchParams.get('contentType') || 'all'
-
-	// 基础数据
-	let baseStats = {
-		totalStudents: 2846,
-		totalVisits: 12587,
-		totalSubmissions: 1924,
-		totalInteractions: 5362
-	}
-
-	// 根据课程名称调整数据
-	if (courseName && courseName !== '') {
-		// 选择特定课程时,数据减少到20-30%
-		baseStats.totalStudents = Math.floor(baseStats.totalStudents * Mock.Random.float(0.2, 0.3))
-		baseStats.totalVisits = Math.floor(baseStats.totalVisits * Mock.Random.float(0.2, 0.3))
-		baseStats.totalSubmissions = Math.floor(baseStats.totalSubmissions * Mock.Random.float(0.2, 0.3))
-		baseStats.totalInteractions = Math.floor(baseStats.totalInteractions * Mock.Random.float(0.2, 0.3))
-	}
-
-	// 根据内容类型调整数据
-	if (contentType && contentType !== 'all') {
-		const reductionFactor = 0.65 // 具体类型是全部的65%
-		switch (contentType) {
-			case 'video':
-				baseStats.totalVisits = Math.floor(baseStats.totalVisits * reductionFactor)
-				baseStats.totalSubmissions = Math.floor(baseStats.totalSubmissions * 0.3)
-				break
-			case 'document':
-				baseStats.totalVisits = Math.floor(baseStats.totalVisits * 0.4)
-				baseStats.totalSubmissions = Math.floor(baseStats.totalSubmissions * 0.2)
-				break
-			case 'exercise':
-				baseStats.totalSubmissions = Math.floor(baseStats.totalSubmissions * reductionFactor)
-				baseStats.totalVisits = Math.floor(baseStats.totalVisits * 0.3)
-				break
-		}
-	}
-
-	return {
-		code: 200,
-		data: baseStats
-	}
-}
-
-// 生成趋势图数据
-const generateTrendData = (options) => {
-	// 解析查询参数
-	const url = new URL('http://localhost' + options.url)
-	const courseName = url.searchParams.get('courseName') || ''
-	const contentType = url.searchParams.get('contentType') || 'all'
-
-	// 基础趋势数据
-	let baseVisitTrend = [2400, 2100, 2600, 2300, 2800, 2200, 2500]
-	let baseSubmissionTrend = [85, 78, 92, 88, 95, 82, 90]
-
-	// 根据课程名称调整数据
-	if (courseName && courseName !== '') {
-		baseVisitTrend = baseVisitTrend.map((val) => Math.floor(val * Mock.Random.float(0.25, 0.35)))
-		baseSubmissionTrend = baseSubmissionTrend.map((val) => Math.floor(val * Mock.Random.float(0.25, 0.35)))
-	}
-
-	// 根据内容类型调整数据
-	if (contentType && contentType !== 'all') {
-		const reductionFactor = 0.6
-		switch (contentType) {
-			case 'video':
-				baseVisitTrend = baseVisitTrend.map((val) => Math.floor(val * reductionFactor))
-				baseSubmissionTrend = baseSubmissionTrend.map((val) => Math.floor(val * 0.3))
-				break
-			case 'document':
-				baseVisitTrend = baseVisitTrend.map((val) => Math.floor(val * 0.4))
-				baseSubmissionTrend = baseSubmissionTrend.map((val) => Math.floor(val * 0.2))
-				break
-			case 'exercise':
-				baseSubmissionTrend = baseSubmissionTrend.map((val) => Math.floor(val * reductionFactor))
-				baseVisitTrend = baseVisitTrend.map((val) => Math.floor(val * 0.3))
-				break
-		}
-	}
-
-	return {
-		code: 200,
-		data: {
-			dates: ['4日', '5日', '6日', '7日', '8日', '9日', '10日'],
-			visitTrend: baseVisitTrend,
-			submissionTrend: baseSubmissionTrend
-		}
-	}
-}
-
-// 生成课程选项数据
-const generateCourseOptions = () => {
-	const options = courseNames.slice(0, 10).map((courseName, index) => ({
-		id: index + 1,
-		courseName
-	}))
-
-	return {
-		code: 200,
-		data: options
-	}
-}
-// Mock 接口定义 - 使用更宽松的正则表达式匹配
-Mock.mock(/\/api\/webapp\/?\/overview\/stats/, 'get', (options) => {
-	return generateOverviewStats(options)
-})
-
-Mock.mock(/\/api\/webapp\/?\/overview\/trend/, 'get', (options) => {
-	return generateTrendData(options)
-})
-
-Mock.mock(/\/api\/webapp\/?\/overview\/courses/, 'get', (options) => {
-	return generateCourseList(options)
-})
-
-Mock.mock(/\/api\/webapp\/?\/overview\/course-options/, 'get', () => {
-	return generateCourseOptions()
-})
+const request = moduleRequest('/api/webapp')
 
 // 导出的API函数
 export const overviewLearningProgressApi = {
-	// 获取统计概览数据
-	getOverviewStats(params = {}) {
-		return request('/overview/stats', params, 'get')
+	// 获取学习进度顶部基本数据
+	getTopFundamentalDetail(params = {}) {
+		return request('/disk/learningprogress/topFundamentalDetail', params, 'get')
 	},
 
-	// 获取趋势数据
-	getTrendData(params = {}) {
-		return request('/overview/trend', params, 'get')
+	// 获取访问人数趋势
+	getViewTendency(params = {}) {
+		return request('/disk/learningprogress/viewTendency', params, 'get')
 	},
 
-	// 获取课程列表数据
-	getCourseList(params = {}) {
-		return request('/overview/courses', params, 'get')
+	// 获取练习平均提交数趋势
+	getPaperSubmitTendency(params = {}) {
+		return request('/disk/learningprogress/paperSubmeitTendency', params, 'get')
 	},
 
-	// 获取课程选项
-	getCourseOptions() {
-		return request('/overview/course-options', '', 'get')
+	// 获取学习明细数据
+	getStudyDetail(params = {}) {
+		return request('/disk/learningprogress/studyDetail', params, 'get')
 	}
 }
+
+/**
+ * 真是接口文档
+ * 
+	学习进度-顶部基本数据
+	/disk/learningprogress/topFundamentalDetail?courseId=&startTime=&endTime=
+	Query请求参数
+
+参数名	参数值	是否必填	参数类型	描述
+courseId	-	否	string	
+课程id
+startTime	-	否	string	
+开始时间
+endTime	-	否	string	
+结束时间
+
+返回数据:
+courseOpenStuNum开课人数
+courseViewNum课程访问次数
+paperSubmitNum提交数(作业、测验)
+interactionNum互动数(发帖/回帖),这个数据先写假的
+
+
+
+----------------
+学习进度-访问人数趋势
+/disk/learningprogress/viewTendency?courseId=&startTime=&endTime=
+Query请求参数
+
+参数名	参数值	是否必填	参数类型	描述
+courseId	-	否	string	
+课程id
+startTime	-	否	string	
+开始时间
+endTime	-	否	string	
+结束时间
+
+返回数据:
+month月份
+viewTendencyNum访问人数
+
+
+--------------------
+学习进度-练习平均提交数
+/disk/learningprogress/paperSubmeitTendency?courseId=&startTime=&endTime=
+Query请求参数
+
+参数名	参数值	是否必填	参数类型	描述
+courseId	-	否	string	
+课程id
+startTime	-	否	string	
+开始时间
+endTime	-	否	string	
+结束时间
+
+返回数据:
+month月份
+SubmeitTendency提交数
+
+
+
+-------------------
+学习进度-学习明细数据
+/disk/learningprogress/studyDetail?courseId=&startTime=&endTime=
+Query请求参数
+
+参数名	参数值	是否必填	参数类型	描述
+courseId	-	否	string	
+课程id
+startTime	-	否	string	
+开始时间
+endTime	-	否	string	
+结束时间
+
+返回数据:
+courseId课程id
+courseName课程名称
+openStuNum开课人数
+viewCount课程访问量
+stayTime讲义访问量
+teachMaterialsNum练习提交量
+ */
+/**
+
+ * 真实接口文档
+ * 
+ * 学习进度-顶部基本数据
+ * /disk/learningprogress/topFundamentalDetail?courseId=&startTime=&endTime=
+ * Query请求参数
+ * 
+ * 参数名	参数值	是否必填	参数类型	描述
+ * courseId	-	否	string	课程id
+ * startTime	-	否	string	开始时间
+ * endTime	-	否	string	结束时间
+ * 
+ * 返回数据:
+ * courseOpenStuNum 开课人数
+ * courseViewNum 课程访问次数
+ * paperSubmitNum 提交数(作业、测验)
+ * interactionNum 互动数(发帖/回帖),这个数据先写假的
+ * 
+ * ----------------
+ * 学习进度-访问人数趋势
+ * /disk/learningprogress/viewTendency?courseId=&startTime=&endTime=
+ * Query请求参数
+ * 
+ * 参数名	参数值	是否必填	参数类型	描述
+ * courseId	-	否	string	课程id
+ * startTime	-	否	string	开始时间
+ * endTime	-	否	string	结束时间
+ * 
+ * 返回数据:
+ * month 月份
+ * viewTendencyNum 访问人数
+ * 
+ * --------------------
+ * 学习进度-练习平均提交数
+ * /disk/learningprogress/paperSubmeitTendency?courseId=&startTime=&endTime=
+ * Query请求参数
+ * 
+ * 参数名	参数值	是否必填	参数类型	描述
+ * courseId	-	否	string	课程id
+ * startTime	-	否	string	开始时间
+ * endTime	-	否	string	结束时间
+ * 
+ * 返回数据:
+ * month 月份
+ * SubmeitTendency 提交数
+ * 
+ * -------------------
+ * 学习进度-学习明细数据
+ * /disk/learningprogress/studyDetail?courseId=&startTime=&endTime=
+ * Query请求参数
+ * 
+ * 参数名	参数值	是否必填	参数类型	描述
+ * courseId	-	否	string	课程id
+ * startTime	-	否	string	开始时间
+ * endTime	-	否	string	结束时间
+ * 
+ * 返回数据:
+ * courseId 课程id
+ * courseName 课程名称
+ * openStuNum 开课人数
+ * viewCount 课程访问量
+ * stayTime 讲义访问量
+ * teachMaterialsNum 练习提交量
+ */

+ 104 - 178
src/views/statisticalAnalysis/overviewLearningProgress/index.vue

@@ -3,39 +3,25 @@
 		<div class="w-full mx-auto">
 			<!-- 顶部筛选区 -->
 			<div class="bg-white rounded-lg shadow-sm p-6 mb-6 h-25 flex items-center">
-				<!-- 讲座选择 -->
+				<!-- 课程ID输入 -->
 				<div class="flex-1 mr-4">
-					<label class="block text-sm font-medium text-gray-700 mb-1">讲座名称</label>
-					<div class="relative">
-						<a-select v-model:value="filters.courseName" class="w-full" placeholder="全部课程">
-							<a-select-option value="">全部课程</a-select-option>
-							<a-select-option v-for="course in courseOptions" :key="course.id" :value="course.courseName">
-								{{ course.courseName }}
-							</a-select-option>
-						</a-select>
-					</div>
+					<label class="block text-sm font-medium text-gray-700 mb-1">课程ID</label>
+					<a-select class="w-full" v-model:value="filters.courseId" placeholder="请选择课程" allow-clear>
+						<a-select-option v-for="item in courseinfoAllListOptions" :key="item.courseId" :value="item.courseId">
+							{{ item.courseName }}
+						</a-select-option>
+					</a-select>
 				</div>
 
-				<!-- 内容类型 -->
+				<!-- 日期范围选择 -->
 				<div class="flex-1 mr-4">
-					<label class="block text-sm font-medium text-gray-700 mb-1">内容类型</label>
-					<div class="flex space-x-2">
-						<a-button
-							v-for="type in contentTypes"
-							:key="type.value"
-							:type="filters.contentType === type.value ? 'primary' : 'default'"
-							size="small"
-							@click="filters.contentType = type.value"
-						>
-							{{ type.label }}
-						</a-button>
-					</div>
+					<label class="block text-sm font-medium text-gray-700 mb-1">开始时间</label>
+					<a-date-picker v-model:value="startDate" class="w-full" placeholder="开始时间" />
 				</div>
 
-				<!-- 日期范围选择 -->
-				<div class="flex-1">
-					<label class="block text-sm font-medium text-gray-700 mb-1">日期范围(周次)</label>
-					<a-range-picker v-model:value="filters.dateRange" class="w-full" :placeholder="['开始日期', '结束日期']" />
+				<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="endDate" class="w-full" placeholder="结束时间" />
 				</div>
 
 				<!-- 操作按钮 -->
@@ -62,7 +48,7 @@
 						<div class="flex justify-between items-start">
 							<div>
 								<div class="text-gray-500 text-sm">{{ card.title }}</div>
-								<div class="text-4xl font-bold text-gray-800 mt-2">{{ card.value.toLocaleString() }}</div>
+								<div class="font-size-30 font-bold text-gray-800 mt-2">{{ card.value.toLocaleString() }}</div>
 							</div>
 							<div :class="card.iconBgClass" class="p-2 rounded-full">
 								<component :is="card.icon" :class="card.iconClass" class="text-xl" />
@@ -97,25 +83,10 @@
 				<a-table
 					:columns="tableColumns"
 					:data-source="tableData"
-					:pagination="pagination"
+					:pagination="false"
 					:loading="loading"
 					size="small"
-				>
-					<template #bodyCell="{ column, record }">
-						<template v-if="column.key === 'submissionCount'">
-							<span
-								:class="{
-									'text-green-500': record.submissionCount >= 90,
-									'text-orange-500': record.submissionCount >= 70 && record.submissionCount < 90,
-									'text-red-500': record.submissionCount < 70
-								}"
-								class="font-semibold"
-							>
-								{{ record.submissionCount }}
-							</span>
-						</template>
-					</template>
-				</a-table>
+				></a-table>
 			</div>
 		</div>
 	</div>
@@ -127,35 +98,35 @@
 	import * as echarts from 'echarts'
 	import dayjs from 'dayjs'
 	import { overviewLearningProgressApi } from '@/api/statisticalAnalysis/overviewLearningProgress'
+	import { courseinfoAllList } from '@/api/semester/index.js'
+
 	import { message } from 'ant-design-vue'
 
 	// 响应式数据
 	const loading = ref(false)
 	const lineChartRef = ref(null)
 	const barChartRef = ref(null)
+	const courseinfoAllListOptions = ref([])
 	let lineChart = null
 	let barChart = null
 
+	// 日期选择器
+	const startDate = ref(dayjs('2025-08-04'))
+	const endDate = ref(dayjs('2025-08-10'))
+
 	// 筛选条件
 	const filters = reactive({
-		courseName: '',
-		contentType: 'all',
-		dateRange: [dayjs('2025-08-04'), dayjs('2025-08-10')]
+		courseId: '',
+		startTime: '2025-08-04',
+		endTime: '2025-08-10'
 	})
 
-	// 内容类型选项
-	const contentTypes = [
-		{ label: '全部', value: 'all' },
-		{ label: '视频', value: 'video' },
-		{ label: '文档', value: 'document' },
-		{ label: '练习', value: 'exercise' }
-	]
-
 	// 统计卡片数据
 	const statsCards = reactive([
 		{
 			title: '开课人数',
-			value: 2846,
+			value: 0,
+			key: 'courseOpenStuNum',
 			icon: UserOutlined,
 			borderClass: 'border-l-4 !border-blue-500',
 			iconBgClass: 'bg-blue-100',
@@ -163,7 +134,8 @@
 		},
 		{
 			title: '课程访问次数',
-			value: 12587,
+			value: 0,
+			key: 'courseViewNum',
 			icon: EyeOutlined,
 			borderClass: 'border-l-4 !border-green-500',
 			iconBgClass: 'bg-green-100',
@@ -171,7 +143,8 @@
 		},
 		{
 			title: '提交数(作业、测验)',
-			value: 1924,
+			value: 0,
+			key: 'paperSubmitNum',
 			icon: FileTextOutlined,
 			borderClass: 'border-l-4 !border-orange-500',
 			iconBgClass: 'bg-orange-100',
@@ -179,7 +152,8 @@
 		},
 		{
 			title: '互动数(发帖/回帖)',
-			value: 5362,
+			value: 0,
+			key: 'interactionNum',
 			icon: MessageOutlined,
 			borderClass: 'border-l-4 !border-blue-500',
 			iconBgClass: 'bg-blue-100',
@@ -189,81 +163,40 @@
 
 	const tableColumns = [
 		{
-			title: '讲座名称',
+			title: '课程名称',
 			dataIndex: 'courseName',
-			key: 'courseName',
-			sorter: true
+			key: 'courseName'
 		},
 		{
 			title: '开课人数',
-			dataIndex: 'studentCount',
-			key: 'studentCount',
-			sorter: true
+			dataIndex: 'openStuNum',
+			key: 'openStuNum'
 		},
 		{
 			title: '课程访问量',
-			dataIndex: 'visitCount',
-			key: 'visitCount',
-			sorter: true
-		},
-		{
-			title: '学习视频总时长',
-			dataIndex: 'videoDuration',
-			key: 'videoDuration',
-			sorter: true
+			dataIndex: 'viewCount',
+			key: 'viewCount'
 		},
 		{
 			title: '讲义访问量',
-			dataIndex: 'documentVisit',
-			key: 'documentVisit',
-			sorter: true
+			dataIndex: 'stayTime',
+			key: 'stayTime'
 		},
 		{
 			title: '练习提交量',
-			dataIndex: 'submissionCount',
-			key: 'submissionCount',
-			sorter: true
-		},
-		{
-			title: '退课人数',
-			dataIndex: 'numberStudentsDroppingCourses',
-			key: 'numberStudentsDroppingCourses',
-			sorter: true
+			dataIndex: 'teachMaterialsNum',
+			key: 'teachMaterialsNum'
 		}
 	]
 
-	// 表格数据
-	const tableData = ref([])
-
 	// 图表数据
 	const chartData = reactive({
-		dates: [],
 		visitTrend: [],
 		submissionTrend: []
 	})
 
-	// 课程选项
-	const courseOptions = ref([])
-
-	// 分页配置
-	const pagination = reactive({
-		current: 1,
-		pageSize: 6,
-		total: 0,
-		showSizeChanger: true,
-		showQuickJumper: true,
-		showTotal: (total, range) => `显示 ${range[0]}-${range[1]} 条,共 ${total} 条`,
-		onChange: (page, pageSize) => {
-			pagination.current = page
-			pagination.pageSize = pageSize
-			fetchCourseList()
-		},
-		onShowSizeChange: (current, size) => {
-			pagination.current = 1
-			pagination.pageSize = size
-			fetchCourseList()
-		}
-	})
+	// 表格数据
+	const tableData = ref([])
 
 	// 初始化折线图
 	const initLineChart = () => {
@@ -282,17 +215,17 @@
 			tooltip: { trigger: 'axis' },
 			xAxis: {
 				type: 'category',
-				data: chartData.dates
+				data: chartData.visitTrend.map((item) => item.month)
 			},
 			yAxis: { type: 'value', name: '访问人数' },
 			series: [
 				{
-					name: '访问人数',
+					name: '访问人数',
 					type: 'line',
 					smooth: true,
 					symbol: 'circle',
 					symbolSize: 8,
-					data: chartData.visitTrend,
+					data: chartData.visitTrend.map((item) => item.viewTendencyNum),
 					lineStyle: { color: '#3A7BFF', width: 3 },
 					itemStyle: { color: '#3A7BFF' },
 					areaStyle: {
@@ -324,15 +257,15 @@
 			tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
 			xAxis: {
 				type: 'category',
-				data: chartData.dates
+				data: chartData.submissionTrend.map((item) => item.month)
 			},
-			yAxis: { type: 'value', name: '平均提交数' },
+			yAxis: { type: 'value', name: '提交数' },
 			series: [
 				{
-					name: '练习平均提交数',
+					name: '练习提交数',
 					type: 'bar',
 					barWidth: 28,
-					data: chartData.submissionTrend,
+					data: chartData.submissionTrend.map((item) => item.SubmeitTendency),
 					itemStyle: {
 						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
 							{ offset: 0, color: '#5B8EFF' },
@@ -348,11 +281,8 @@
 
 	// 格式化日期范围显示
 	const formatDateRange = () => {
-		if (!filters.dateRange || filters.dateRange.length !== 2) {
-			return '2025/08/04至2025/08/10'
-		}
-		const start = filters.dateRange[0].format('YYYY/MM/DD')
-		const end = filters.dateRange[1].format('YYYY/MM/DD')
+		const start = startDate.value ? startDate.value.format('YYYY/MM/DD') : filters.startTime
+		const end = endDate.value ? endDate.value.format('YYYY/MM/DD') : filters.endTime
 		return `${start}至${end}`
 	}
 
@@ -360,16 +290,15 @@
 	const fetchOverviewStats = async () => {
 		try {
 			const params = {
-				courseName: filters.courseName,
-				contentType: filters.contentType,
-				dateRange: filters.dateRange
+				courseId: filters.courseId,
+				startTime: startDate.value ? startDate.value.format('YYYY-MM-DD') : filters.startTime,
+				endTime: endDate.value ? endDate.value.format('YYYY-MM-DD') : filters.endTime
 			}
-			const data = await overviewLearningProgressApi.getOverviewStats(params)
+			const data = await overviewLearningProgressApi.getTopFundamentalDetail(params)
 			// 更新统计卡片数据
-			statsCards[0].value = data.totalStudents
-			statsCards[1].value = data.totalVisits
-			statsCards[2].value = data.totalSubmissions
-			statsCards[3].value = data.totalInteractions
+			statsCards.forEach((card) => {
+				card.value = data[card.key] || 0
+			})
 		} catch (error) {
 			console.error('获取统计数据失败:', error)
 			message.error('获取统计数据失败')
@@ -380,16 +309,20 @@
 	const fetchTrendData = async () => {
 		try {
 			const params = {
-				courseName: filters.courseName,
-				contentType: filters.contentType,
-				dateRange: filters.dateRange
+				courseId: filters.courseId,
+				startTime: startDate.value ? startDate.value.format('YYYY-MM-DD') : filters.startTime,
+				endTime: endDate.value ? endDate.value.format('YYYY-MM-DD') : filters.endTime
 			}
-			const data = await overviewLearningProgressApi.getTrendData(params)
+
+			// 并行获取访问趋势和提交趋势数据
+			const [visitData, submitData] = await Promise.all([
+				overviewLearningProgressApi.getViewTendency(params),
+				overviewLearningProgressApi.getPaperSubmitTendency(params)
+			])
 
 			// 更新图表数据
-			chartData.dates = data.dates
-			chartData.visitTrend = data.visitTrend
-			chartData.submissionTrend = data.submissionTrend
+			chartData.visitTrend = visitData || []
+			chartData.submissionTrend = submitData || []
 
 			// 更新图表
 			updateLineChart()
@@ -400,38 +333,23 @@
 		}
 	}
 
-	// 获取课程选项
-	const fetchCourseOptions = async () => {
-		try {
-			const data = await overviewLearningProgressApi.getCourseOptions()
-			courseOptions.value = data
-		} catch (error) {
-			console.error('获取课程选项失败:', error)
-		}
-	}
-
-	// 获取课程列表数据
-	const fetchCourseList = async () => {
+	// 获取学习明细数据
+	const fetchStudyDetail = async () => {
 		try {
 			const params = {
-				courseName: filters.courseName,
-				contentType: filters.contentType,
-				dateRange: filters.dateRange,
-				current: pagination.current,
-				pageSize: pagination.pageSize
+				courseId: filters.courseId,
+				startTime: startDate.value ? startDate.value.format('YYYY-MM-DD') : filters.startTime,
+				endTime: endDate.value ? endDate.value.format('YYYY-MM-DD') : filters.endTime
 			}
-			const response = await overviewLearningProgressApi.getCourseList(params)
+			const data = await overviewLearningProgressApi.getStudyDetail(params)
 			// 更新表格数据
-			tableData.value = response.data.map((item, index) => ({
+			tableData.value = (data.records || []).map((item, index) => ({
 				...item,
-				key: item.id || index + 1
+				key: item.courseId || index + 1
 			}))
-
-			// 更新分页信息
-			pagination.total = response.total
 		} catch (error) {
-			console.error('获取课程列表失败:', error)
-			message.error('获取课程列表失败')
+			console.error('获取学习明细数据失败:', error)
+			message.error('获取学习明细数据失败')
 		}
 	}
 
@@ -439,7 +357,11 @@
 	const refreshData = async () => {
 		loading.value = true
 		try {
-			await Promise.all([fetchOverviewStats(), fetchTrendData(), fetchCourseList()])
+			// 更新筛选条件
+			filters.startTime = startDate.value ? startDate.value.format('YYYY-MM-DD') : filters.startTime
+			filters.endTime = endDate.value ? endDate.value.format('YYYY-MM-DD') : filters.endTime
+
+			await Promise.all([fetchOverviewStats(), fetchTrendData(), fetchStudyDetail()])
 		} catch (error) {
 			console.error('刷新数据失败:', error)
 		} finally {
@@ -447,26 +369,26 @@
 		}
 	}
 
-	// 初始化数据
-	const initData = async () => {
-		// 先获取课程选项
-		await fetchCourseOptions()
-		// 再获取其他数据
-		await refreshData()
-	}
-
 	// 窗口大小变化处理
 	const handleResize = () => {
 		if (lineChart) lineChart.resize()
 		if (barChart) barChart.resize()
 	}
 
+	const getCourseinfoAllList = () => {
+		courseinfoAllList()
+			.then((res) => {
+				courseinfoAllListOptions.value = res.data
+			})
+			.catch((err) => {
+				console.log(err)
+			})
+	}
+
 	// 监听筛选条件变化
 	watch(
-		() => [filters.courseName, filters.contentType, filters.dateRange],
+		() => [filters.courseId, startDate.value, endDate.value],
 		() => {
-			// 筛选条件变化时重置到第一页
-			pagination.current = 1
 			refreshData()
 		},
 		{ deep: true }
@@ -480,7 +402,8 @@
 		window.addEventListener('resize', handleResize)
 
 		// 初始化数据
-		await initData()
+		await refreshData()
+		getCourseinfoAllList()
 	})
 
 	onUnmounted(() => {
@@ -506,4 +429,7 @@
 		border: 1px solid #e4e7ed;
 		border-radius: 4px;
 	}
+	.font-size-30 {
+		font-size: 30px;
+	}
 </style>