Przeglądaj źródła

feat(课程详情): 添加知识点分析模块和一键催缴功能

- 新增知识点学习情况分析页面,包含统计图表和学生列表
- 在课程详情页添加一键催缴按钮功能
- 统一设置各详情页面的宽度为1200px
- 添加相关API接口用于获取知识点数据
tanshanming 6 miesięcy temu
rodzic
commit
e29052fed8

+ 5 - 0
src/api/course/courseDetail.js

@@ -11,6 +11,9 @@ export const getChapterAllList = (p) => request('disk/chapter/allList', p, 'get'
 export const updateCourseStatus = (p) => request('disk/courseinfo/updateStatus', p, 'post')
 //删除课程
 export const deleteCourse = (p) => request('disk/courseinfo/delete', p, 'post')
+//一键催缴
+export const urgeSubmit = (p) => request('disk/courseinfo/urgeSubmit', p, 'get')
+
 // 部门与成员 mock 数据
 export const mockDepartments = [
 	{
@@ -90,3 +93,5 @@ export const mockStudentDetail = {
 export function getStudentDetail() {
 	return Promise.resolve(mockStudentDetail)
 }
+
+export const selectKnowledgeByCourseId = (p) => request('disk/chapterknowledge/selectKnowledgeByCourseId', p, 'get')

+ 10 - 1
src/views/courseDetails/components/tab/LessonDetails.vue

@@ -14,6 +14,9 @@
 							<span>创建人:{{ lesson.createUserName }}</span>
 						</div>
 					</div>
+					<div class="lesson-actions">
+						<a-button type="primary" size="small" @click="handleUrgeSubmit(lesson)"> 一键催缴 </a-button>
+					</div>
 				</div>
 			</div>
 			<div v-else class="no-lessons">
@@ -51,7 +54,7 @@
 		pageSize: Number,
 		sectionsLength: Number
 	})
-	const emits = defineEmits(['edit-lesson', 'delete-lesson', 'page-change', 'page-size-change'])
+	const emits = defineEmits(['edit-lesson', 'delete-lesson', 'page-change', 'page-size-change', 'urge-submit'])
 
 	const localPageSize = ref(props.pageSize)
 	watch(
@@ -60,6 +63,11 @@
 			localPageSize.value = newVal
 		}
 	)
+
+	// 处理一键催缴
+	const handleUrgeSubmit = (lesson) => {
+		emits('urge-submit', lesson)
+	}
 </script>
 
 <style scoped>
@@ -121,6 +129,7 @@
 	.lesson-actions {
 		display: flex;
 		align-items: center;
+		margin-left: 16px;
 	}
 	.action-icon {
 		font-size: 18px;

+ 665 - 0
src/views/courseDetails/components/tab/knowledgePointAnalysis.vue

@@ -0,0 +1,665 @@
+<template>
+	<div class="container">
+		<header>
+			<h1>知识点学习情况分析</h1>
+			<div class="subtitle">实时监控学员学习进度与参与情况</div>
+		</header>
+
+		<div class="content">
+			<!-- 左侧柱形图 -->
+			<div id="chartContainer">
+				<div class="chart-title">各知识点学习人数统计</div>
+				<div class="chart-wrapper">
+					<div ref="myChart" style="width: 100%; height: 600px"></div>
+				</div>
+			</div>
+
+			<!-- 右侧列表 -->
+			<div id="listContainer">
+				<div class="list-title">学习人员名单</div>
+				<div id="selectedKnowledge" class="selected-knowledge">请选择左侧知识点查看学习人员</div>
+				<div style="flex: 1; overflow-y: auto">
+					<table id="studentTable">
+						<thead>
+							<tr>
+								<th>专业</th>
+								<th>班级</th>
+								<th>学号</th>
+								<th>姓名</th>
+							</tr>
+						</thead>
+						<tbody id="studentList">
+							<tr>
+								<td colspan="4" class="no-data">暂无数据</td>
+							</tr>
+						</tbody>
+					</table>
+				</div>
+
+				<!-- 分页控件 -->
+				<div class="pagination-container">
+					<div class="pagination" id="pagination">
+						<!-- 分页按钮将通过JavaScript动态生成 -->
+					</div>
+					<div class="pagination-info" id="paginationInfo">
+						<!-- 分页信息将通过JavaScript动态生成 -->
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+<script setup>
+	// 示例数据
+	import { ref, reactive, watch, nextTick } from 'vue'
+	import * as echarts from 'echarts'
+	import { selectKnowledgeByCourseId } from '@/api/course/courseDetail.js'
+	const myChart = ref(null)
+	import { useRouter, useRoute } from 'vue-router'
+	import { Modal } from 'ant-design-vue'
+	const router = useRouter()
+	const route = useRoute()
+	const props = defineProps({
+		courseId: {
+			type: Number,
+			default: 0
+		}
+	})
+	let myChartInstance = null
+	// 每页显示的项目数量
+	const ITEMS_PER_PAGE = 10
+
+	// 当前分页信息
+	let currentPage = 1
+	let totalPages = 1
+	let currentDataIndex = 0
+
+	// 示例数据
+	const knowledgeData = {
+		labels: ['电传操纵系统', '飞行控制律', '传感器技术', '故障诊断', '人机交互'],
+		datasets: [
+			{
+				label: '学习人数',
+				data: [32, 25, 41, 18, 29],
+				backgroundColor: [
+					'rgba(255, 99, 132, 0.8)',
+					'rgba(54, 162, 235, 0.8)',
+					'rgba(255, 206, 86, 0.8)',
+					'rgba(75, 192, 192, 0.8)',
+					'rgba(153, 102, 255, 0.8)'
+				],
+				borderColor: [
+					'rgba(255, 99, 132, 1)',
+					'rgba(54, 162, 235, 1)',
+					'rgba(255, 206, 86, 1)',
+					'rgba(75, 192, 192, 1)',
+					'rgba(153, 102, 255, 1)'
+				],
+				borderWidth: 2,
+				borderRadius: 8,
+				borderSkipped: false
+			}
+		]
+	}
+
+	// 学员数据
+	const studentData = [
+		// 电传操纵系统
+		[
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023001', name: '张三' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023002', name: '李四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023003', name: '王五' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023004', name: '赵六' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023005', name: '钱七' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023006', name: '孙八' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023007', name: '周九' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023008', name: '吴十' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023009', name: '郑一' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023010', name: '王二' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023011', name: '冯三' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023012', name: '陈四' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023013', name: '褚五' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023014', name: '卫六' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023015', name: '蒋七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023016', name: '沈八' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023017', name: '韩九' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023018', name: '杨十' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023019', name: '朱一' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023020', name: '秦二' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023021', name: '尤三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023022', name: '许四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023023', name: '何五' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023024', name: '吕六' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023025', name: '施七' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023026', name: '张八' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023027', name: '孔九' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023028', name: '曹十' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023029', name: '严一' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023030', name: '华二' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023031', name: '金三' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023032', name: '魏四' }
+		],
+		// 飞行控制律
+		[
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023033', name: '郑一' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023034', name: '王二' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023035', name: '冯三' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023036', name: '陈四' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023037', name: '褚五' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023038', name: '卫六' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023039', name: '蒋七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023040', name: '沈八' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023041', name: '韩九' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023042', name: '杨十' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023043', name: '朱一' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023044', name: '秦二' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023045', name: '尤三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023046', name: '许四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023047', name: '何五' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023048', name: '吕六' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023049', name: '施七' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023050', name: '张八' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023051', name: '孔九' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023052', name: '曹十' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023053', name: '严一' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023054', name: '华二' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023055', name: '金三' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023056', name: '魏四' }
+		],
+		// 传感器技术
+		[
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023057', name: '蒋七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023058', name: '沈八' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023059', name: '韩九' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023060', name: '杨十' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023061', name: '朱一' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023062', name: '秦二' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023063', name: '尤三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023064', name: '许四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023065', name: '何五' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023066', name: '吕六' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023067', name: '施七' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023068', name: '张八' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023069', name: '孔九' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023070', name: '曹十' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023071', name: '严一' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023072', name: '华二' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023073', name: '金三' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023074', name: '魏四' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023075', name: '张三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023076', name: '李四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023077', name: '王五' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023078', name: '赵六' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023079', name: '钱七' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023080', name: '孙八' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023081', name: '周九' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023082', name: '吴十' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023083', name: '郑一' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023084', name: '王二' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023085', name: '冯三' }
+		],
+		// 故障诊断
+		[
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023086', name: '尤三' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023087', name: '许四' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023088', name: '何五' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023089', name: '吕六' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023090', name: '施七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023091', name: '张八' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023092', name: '孔九' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023093', name: '曹十' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023094', name: '严一' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023095', name: '华二' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023096', name: '金三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023097', name: '魏四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023098', name: '张三' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023099', name: '李四' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023100', name: '王五' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023101', name: '赵六' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023102', name: '钱七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023103', name: '孙八' }
+		],
+		// 人机交互
+		[
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023104', name: '施七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023105', name: '张八' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023106', name: '孔九' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023107', name: '曹十' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023108', name: '严一' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023109', name: '华二' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023110', name: '金三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023111', name: '魏四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023112', name: '张三' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023113', name: '李四' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023114', name: '王五' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023115', name: '赵六' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023116', name: '钱七' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023117', name: '孙八' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023118', name: '周九' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023119', name: '吴十' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023120', name: '郑一' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023121', name: '王二' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023122', name: '冯三' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023123', name: '陈四' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023124', name: '褚五' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023125', name: '卫六' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023126', name: '蒋七' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023127', name: '沈八' },
+			{ major: '航空航天工程', class: '飞控1班', studentId: '2023128', name: '韩九' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023129', name: '杨十' },
+			{ major: '航空航天工程', class: '飞控2班', studentId: '2023130', name: '朱一' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023131', name: '秦二' },
+			{ major: '航空航天工程', class: '飞控3班', studentId: '2023132', name: '尤三' }
+		]
+	]
+
+	const initChart = () => {
+		myChartInstance = echarts.init(myChart.value)
+		let option = {
+			xAxis: {
+				type: 'category',
+				data: knowledgeData.labels
+			},
+			yAxis: {
+				type: 'value'
+			},
+			series: [
+				{
+					data: [],
+					type: 'bar'
+				}
+			]
+			// onClick: (event, elements) => {
+			// 	if (elements.length > 0) {
+			// 		const index = elements[0].index;
+			// 		currentDataIndex = index;
+			// 		currentPage = 1; // 重置为第一页
+			// 		updateStudentList(index, 1);
+			//
+			// 		// 更新选中知识点显示
+			// 		document.getElementById('selectedKnowledge').innerHTML =
+			// 			`<strong>当前查看:</strong> ${knowledgeData.labels[index]}
+			//                      <span style="color: #666; font-weight: normal;">(${knowledgeData.datasets[0].data[index]}人学习)</span>`;
+			// 	}
+			// },
+		}
+
+		option.series[0].data = []
+		let nums = [32, 25, 41, 18, 29]
+		let backgroundColors = [
+			'rgba(255, 99, 132, 0.8)',
+			'rgba(54, 162, 235, 0.8)',
+			'rgba(255, 206, 86, 0.8)',
+			'rgba(75, 192, 192, 0.8)',
+			'rgba(153, 102, 255, 0.8)'
+		]
+
+		let borderColors = [
+			'rgba(255, 99, 132, 1)',
+			'rgba(54, 162, 235, 1)',
+			'rgba(255, 206, 86, 1)',
+			'rgba(75, 192, 192, 1)',
+			'rgba(153, 102, 255, 1)'
+		]
+		for (let i = 0; i < nums.length; i++) {
+			option.series[0].data.push({
+				value: nums[i],
+				itemStyle: {
+					color: backgroundColors[i],
+					borderColor: borderColors[i],
+					barBorderRadius: 5,
+					borderWidth: 2
+				}
+			})
+		}
+
+		myChartInstance.setOption(option)
+
+		myChartInstance.on('click', function (param) {
+			console.log('点击柱状图', param)
+
+			const index = param.dataIndex
+			currentDataIndex = index
+			currentPage = 1 // 重置为第一页
+			updateStudentList(index, 1)
+
+			// 更新选中知识点显示
+			document.getElementById(
+				'selectedKnowledge'
+			).innerHTML = `<strong>当前查看:</strong> ${knowledgeData.labels[index]}
+		                         <span style="color: #666; font-weight: normal;">(${knowledgeData.datasets[0].data[index]}人学习)</span>`
+		})
+
+		window.addEventListener('resize', myChartInstance.resize)
+		console.log('都经过了吗', myChartInstance)
+	}
+
+	// 更新右侧列表(带分页)
+	const updateStudentList = (index, page = 1) => {
+		const listContainer = document.getElementById('studentList')
+		const students = studentData[index]
+		const paginationContainer = document.getElementById('pagination')
+		const paginationInfo = document.getElementById('paginationInfo')
+
+		if (students && students.length > 0) {
+			// 计算分页
+			totalPages = Math.ceil(students.length / ITEMS_PER_PAGE)
+			currentPage = page
+
+			// 计算当前页的数据
+			const startIndex = (page - 1) * ITEMS_PER_PAGE
+			const endIndex = Math.min(startIndex + ITEMS_PER_PAGE, students.length)
+			const currentPageData = students.slice(startIndex, endIndex)
+
+			// 清空列表并添加当前页数据
+			listContainer.innerHTML = ''
+			currentPageData.forEach((student) => {
+				const tr = document.createElement('tr')
+				tr.innerHTML = `
+                        <td>${student.major}</td>
+                        <td>${student.class}</td>
+                        <td>${student.studentId}</td>
+                        <td>${student.name}</td>
+                    `
+				listContainer.appendChild(tr)
+			})
+
+			// 更新分页信息
+			paginationInfo.textContent = `共 ${students.length} 条记录,第 ${page} 页,共 ${totalPages} 页`
+
+			// 生成分页按钮
+			generatePaginationButtons()
+		} else {
+			listContainer.innerHTML = '<tr><td colspan="4" class="no-data">暂无学习人员</td></tr>'
+			paginationContainer.innerHTML = ''
+			paginationInfo.textContent = ''
+		}
+	}
+
+	// 生成分页按钮
+	const generatePaginationButtons = () => {
+		const paginationContainer = document.getElementById('pagination')
+		paginationContainer.innerHTML = ''
+
+		// 上一页按钮
+		const prevButton = document.createElement('button')
+		prevButton.innerHTML = '&laquo;'
+		prevButton.disabled = currentPage === 1
+		prevButton.addEventListener('click', () => {
+			if (currentPage > 1) {
+				updateStudentList(currentDataIndex, currentPage - 1)
+			}
+		})
+		paginationContainer.appendChild(prevButton)
+
+		// 页码按钮(最多显示5个页码)
+		const maxVisiblePages = 5
+		let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2))
+		let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1)
+
+		// 如果接近末尾,调整起始页
+		if (endPage - startPage + 1 < maxVisiblePages) {
+			startPage = Math.max(1, endPage - maxVisiblePages + 1)
+		}
+
+		for (let i = startPage; i <= endPage; i++) {
+			const pageButton = document.createElement('button')
+			pageButton.textContent = i
+			pageButton.classList.toggle('active', i === currentPage)
+			pageButton.addEventListener('click', () => {
+				updateStudentList(currentDataIndex, i)
+			})
+			paginationContainer.appendChild(pageButton)
+		}
+
+		// 下一页按钮
+		const nextButton = document.createElement('button')
+		nextButton.innerHTML = '&raquo;'
+		nextButton.disabled = currentPage === totalPages
+		nextButton.addEventListener('click', () => {
+			if (currentPage < totalPages) {
+				updateStudentList(currentDataIndex, currentPage + 1)
+			}
+		})
+		paginationContainer.appendChild(nextButton)
+	}
+
+	watch(
+		() => props.courseId,
+		() => {
+			nextTick(() => {
+				selectKnowledgeByCourseId({ courseId: props.courseId }).then((res) => {
+					console.log('知识点统计数据返回', res)
+				})
+
+				initChart()
+				setTimeout(() => {
+					// 默认选择第一个知识点
+					const firstIndex = 0
+					currentDataIndex = firstIndex
+					currentPage = 1
+					updateStudentList(firstIndex, 1)
+
+					// 更新选中知识点显示
+					document.getElementById(
+						'selectedKnowledge'
+					).innerHTML = `<strong>当前查看:</strong> ${knowledgeData.labels[firstIndex]}
+                     <span style="color: #666; font-weight: normal;">(${knowledgeData.datasets[0].data[firstIndex]}人学习)</span>`
+				}, 100)
+			})
+		},
+		{ immediate: true }
+	)
+	// 页面加载完成后,默认显示第一个知识点的人员列表
+	// window.addEventListener('load', function() {
+	// 	// 等待Chart.js完全渲染完成
+	// 	setTimeout(() => {
+	// 		// 默认选择第一个知识点
+	// 		const firstIndex = 0;
+	// 		currentDataIndex = firstIndex;
+	// 		currentPage = 1;
+	// 		updateStudentList(firstIndex, 1);
+	//
+	// 		// 更新选中知识点显示
+	// 		document.getElementById('selectedKnowledge').innerHTML =
+	// 			`<strong>当前查看:</strong> ${knowledgeData.labels[firstIndex]}
+	//                      <span style="color: #666; font-weight: normal;">(${knowledgeData.datasets[0].data[firstIndex]}人学习)</span>`;
+	// 	}, 100);
+	// });
+</script>
+<style>
+	.container {
+		max-width: 100%;
+		margin: 0 auto;
+		background: white;
+		border-radius: 15px;
+		box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
+		overflow: hidden;
+	}
+
+	.container header {
+		background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+		color: white;
+		padding: 20px;
+		text-align: center;
+	}
+
+	.container h1 {
+		font-size: 28px;
+		margin-bottom: 10px;
+	}
+
+	.subtitle {
+		font-size: 16px;
+		opacity: 0.9;
+	}
+
+	.content {
+		display: flex;
+	}
+
+	#chartContainer {
+		flex: 1;
+		padding: 30px;
+		border-right: 1px solid #eee;
+	}
+
+	#listContainer {
+		flex: 1;
+		padding: 30px;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.chart-title {
+		font-size: 20px;
+		color: #333;
+		margin-bottom: 20px;
+		text-align: center;
+	}
+
+	.container .list-title {
+		font-size: 20px;
+		color: #333;
+		margin-bottom: 20px;
+		text-align: center;
+	}
+
+	/* 修复柱形图容器,避免变形 */
+	.container .chart-wrapper {
+		position: relative;
+		width: 100%;
+		height: 400px;
+	}
+
+	.container canvas {
+		width: 100% !important;
+		height: 100% !important;
+		max-width: 100%;
+	}
+
+	.container table {
+		width: 100%;
+		border-collapse: collapse;
+		box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
+		border-radius: 10px;
+		overflow: hidden;
+	}
+
+	.container th {
+		background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
+		color: white;
+		text-align: left;
+		padding: 15px;
+		font-weight: 600;
+		font-size: 14px;
+		text-transform: uppercase;
+		letter-spacing: 0.5px;
+	}
+
+	.container td {
+		padding: 12px 15px;
+		border-bottom: 1px solid #eee;
+		color: #555;
+	}
+
+	.container tr:hover {
+		background-color: #f8f9ff;
+		transform: translateY(-1px);
+		transition: all 0.3s ease;
+	}
+
+	.container tbody tr:last-child td {
+		border-bottom: none;
+	}
+
+	.container .no-data {
+		text-align: center;
+		padding: 40px;
+		color: #999;
+		font-style: italic;
+	}
+
+	.container .chartjs-tooltip {
+		background: rgba(0, 0, 0, 0.8) !important;
+		border: none !important;
+		border-radius: 8px !important;
+		padding: 10px !important;
+		color: white !important;
+		font-size: 14px !important;
+	}
+
+	.container .selected-knowledge {
+		background: #f0f8ff;
+		padding: 15px;
+		border-radius: 10px;
+		margin-bottom: 20px;
+		text-align: center;
+		font-weight: 600;
+		color: #4facfe;
+		border: 2px dashed #4facfe;
+	}
+
+	/* 分页样式 */
+	.container .pagination {
+		display: flex;
+		justify-content: center;
+		margin-top: 20px;
+		gap: 5px;
+	}
+
+	.pagination button {
+		background: white;
+		border: 1px solid #ddd;
+		color: #333;
+		padding: 8px 12px;
+		cursor: pointer;
+		border-radius: 4px;
+		font-size: 14px;
+		transition: all 0.3s ease;
+	}
+
+	.pagination button:hover {
+		background: #f0f0f0;
+		border-color: #999;
+	}
+
+	.pagination button.active {
+		background: #4facfe;
+		color: white;
+		border-color: #4facfe;
+	}
+
+	.pagination button:disabled {
+		background: #f5f5f5;
+		color: #ccc;
+		cursor: not-allowed;
+	}
+
+	.pagination-info {
+		text-align: center;
+		margin-top: 10px;
+		color: #666;
+		font-size: 14px;
+	}
+
+	@media (max-width: 768px) {
+		.content {
+			flex-direction: column;
+		}
+
+		#chartContainer {
+			border-right: none;
+			border-bottom: 1px solid #eee;
+		}
+
+		#listContainer {
+			height: 400px;
+		}
+
+		.pagination button {
+			padding: 6px 10px;
+			font-size: 12px;
+		}
+	}
+</style>

+ 12 - 0
src/views/courseDetails/components/tab/statice.vue

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<template>
+	<div style="display: flex; justify-content: center; align-items: center; ">
+		<iframe src="../../../../../public/html/knowledgePointAnalysis.html" style="width: 88%; height: 950px;"></iframe>
+	</div>
+</template>
+<script setup>
+
+
+</script>
+<style scoped>
+</style>

+ 43 - 7
src/views/courseDetails/index.vue

@@ -46,10 +46,11 @@
 		<!-- tab 导航 -->
 		<a-tabs v-model:activeKey="activeTab" class="course-tabs">
 			<a-tab-pane key="detail" tab="课程详情" />
-			<!-- <a-tab-pane key="homework" tab="批改作业" /> -->
-			<!-- <a-tab-pane key="test" tab="批改测试" /> -->
-			<!-- <a-tab-pane key="student" tab="学员详情" />
-			<a-tab-pane key="stat" tab="学习统计" /> -->
+			<a-tab-pane key="statice" tab="学习统计" />
+			<!--			<a-tab-pane key="homework" tab="批改作业" />-->
+			<!--			<a-tab-pane key="test" tab="批改测试" />-->
+			<!--			<a-tab-pane key="student" tab="学员详情" />-->
+			<!--			<a-tab-pane key="stat" tab="学习统计" />-->
 		</a-tabs>
 
 		<LessonDetails
@@ -62,10 +63,11 @@
 			@delete-lesson="onDeleteLesson"
 			@page-change="onPageChange"
 			@page-size-change="onPageSizeChange"
+			@urge-submit="onUrgeSubmit"
 		/>
-		<StudentDetails :courseInfoId="courseInfoId" v-if="activeTab === 'student'" />
+		<StudentDetails :courseInfoId="courseId" v-if="activeTab === 'student'" />
 		<LearningStatistics v-if="activeTab === 'stat'" />
-
+		<KnowledgePointAnalysis v-if="activeTab === 'statice'" :courseId="courseId" />
 		<!-- 编辑课程弹窗 -->
 		<a-modal v-model:visible="editVisible" title="新建工单" :footer="null" width="700px" @cancel="editVisible = false">
 			<CourseAdd />
@@ -81,11 +83,19 @@
 	import { message, Modal } from 'ant-design-vue'
 	import AddClassHours from './components/AddClassHours.vue'
 	import LessonDetails from './components/tab/LessonDetails.vue'
+	import KnowledgePointAnalysis from './components/tab/knowledgePointAnalysis.vue'
+	// import Statice from './components/tab/statice.vue'
 	// import StudentDetails from './components/tab/StudentDetails.vue'
 	import StudentDetails from '@/views/courseAdd/components/StudentDetails.vue'
 	import LearningStatistics from './components/tab/LearningStatistics.vue'
 	import CourseAdd from '../courseAdd/index.vue'
-	import { getCourseDetail, getChapterAllList, updateCourseStatus, deleteCourse } from '@/api/course/courseDetail.js'
+	import {
+		getCourseDetail,
+		getChapterAllList,
+		updateCourseStatus,
+		deleteCourse,
+		urgeSubmit
+	} from '@/api/course/courseDetail.js'
 	import sysConfig from '@/config/index'
 	import EventBus from '@/utils/EventBus'
 	const props = defineProps({
@@ -278,6 +288,32 @@
 			}
 		})
 	}
+	// 处理一键催缴
+	function onUrgeSubmit(lesson) {
+		Modal.confirm({
+			title: '确认催缴',
+			content: `确定要对课时"${lesson.name}"进行催缴吗?`,
+			okText: '确认',
+			cancelText: '取消',
+			onOk: async () => {
+				try {
+					const params = {
+						hourId: lesson.id
+					}
+					const res = await urgeSubmit(params)
+					if (res.code === 200) {
+						message.success('催缴成功')
+					} else {
+						message.error(res.msg || '催缴失败')
+					}
+				} catch (error) {
+					console.error('催缴失败:', error)
+					message.error('催缴失败,请稍后重试')
+				}
+			}
+		})
+	}
+
 	watch(
 		() => props.courseId,
 		(newVal, oldVal) => {