于添 před 3 měsíci
rodič
revize
60872829cc

+ 503 - 0
src/views/statisticalAnalysis/overviewLearningProgress/index.vue

@@ -0,0 +1,503 @@
+<template>
+	<div class="p-6 flex justify-center">
+		<div class="w-full mx-auto min-h-screen">
+			<!-- 顶部筛选区 -->
+			<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">课程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>-->
+<!--					<a-date-picker v-model:value="startDate" 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="endDate" class="w-full" placeholder="结束时间" />-->
+<!--				</div>-->
+
+				<!-- 操作按钮 -->
+				<div class="flex space-x-2 ml-4 mt-6">
+					<a-button @click="refreshData" :loading="loading">
+						<template #icon>
+							<ReloadOutlined />
+						</template>
+						刷新
+					</a-button>
+				</div>
+			</div>
+
+			<!-- 核心数据看板 -->
+			<div class="mb-6">
+				<!-- 数据卡片 -->
+				<div class="grid grid-cols-4 gap-6 mb-6">
+					<div
+						v-for="(card, index) in statsCards"
+						:key="index"
+						class="card-header bg-white p-5 rounded-lg shadow-sm"
+						:class="card.borderClass"
+					>
+						<div class="flex justify-between items-start">
+							<div>
+								<div class="text-gray-500 text-sm">{{ card.title }}</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" />
+							</div>
+						</div>
+					</div>
+				</div>
+
+				<!-- 图表区 -->
+				<div class="grid grid-cols-2 gap-6">
+					<!-- 折线图 -->
+					<div class="chart-container p-4 bg-white border border-gray-200 rounded">
+						<h3 class="font-bold text-gray-800 mb-4">访问人数趋势</h3>
+						<div ref="lineChartRef" class="h-48"></div>
+					</div>
+
+					<!-- 柱状图 -->
+					<div class="chart-container p-4 bg-white border border-gray-200 rounded">
+						<h3 class="font-bold text-gray-800 mb-4">练习平均提交数</h3>
+						<div ref="barChartRef" class="h-48"></div>
+					</div>
+				</div>
+			</div>
+
+			<!-- 明细表格区 -->
+			<div class="bg-white rounded-lg shadow-sm p-6">
+				<div class="flex justify-between items-center mb-4">
+					<h2 class="text-xl font-bold text-gray-800">学习明细数据</h2>
+<!--					<div class="text-sm text-gray-500">({{ formatDateRange() }})注:从查询条件时间范围落下来的</div>-->
+				</div>
+
+				<a-table
+					:columns="tableColumns"
+					:data-source="tableData"
+					:pagination="pagination"
+					:loading="loading"
+					size="small"
+				>
+					<template #bodyCell="{ column, text, record }">
+						<!-- 状态列 -->
+						<template v-if="column.key === 'viewCount'" >
+							<span @click="onItemStudyDetailCourseView(record)">
+								{{text}}
+							</span>
+						</template>
+						<template v-if="column.key === 'paperSubmitNum'" >
+							<span @click="onItemStudyDetailPracticeResult(record)">
+								{{text}}
+							</span>
+						</template>
+					</template>
+				</a-table>
+			</div>
+		</div>
+	</div>
+
+	<ListViewlistViewStudyDetailCourseView ref="listViewListViewlistViewStudyDetailCourseViewRef"></ListViewlistViewStudyDetailCourseView>
+	<ListViewStudyDetailPracticeResult ref="listViewStudyDetailPracticeResultRef"></ListViewStudyDetailPracticeResult>
+</template>
+
+<script setup>
+
+import { ref, reactive, onMounted, onUnmounted, nextTick, watch } from 'vue'
+	import { ReloadOutlined, UserOutlined, EyeOutlined, FileTextOutlined, MessageOutlined } from '@ant-design/icons-vue'
+	import * as echarts from 'echarts'
+	import dayjs from 'dayjs'
+	import { overviewLearningProgressApi } from '@/api/statisticalAnalysis/overviewLearningProgress'
+	import { courseinfoAllList } from '@/api/semester/index.js'
+	import ListViewlistViewStudyDetailCourseView from './listViewStudyDetailCourseView.vue'
+	import ListViewStudyDetailPracticeResult from './listViewStudyDetailPracticeResult.vue'
+
+	import { message } from 'ant-design-vue'
+
+	// 响应式数据
+	const loading = ref(false)
+	const lineChartRef = ref(null)
+	const listViewListViewlistViewStudyDetailCourseViewRef = ref(null)
+	const listViewStudyDetailPracticeResultRef = 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 startDate = ref(undefined)
+	const endDate = ref(undefined)
+
+	// 筛选条件
+	const filters = reactive({
+		courseId: '',
+		startTime: undefined,
+		endTime: undefined,
+
+	})
+	// 分页配置
+	const pagination = reactive({
+		current: 1,
+		size: 10,
+		total: 0,
+		showSizeChanger: true,
+		showQuickJumper: true,
+		showTotal: (total, range) => `显示 ${range[0]}-${range[1]} 条,共 ${total} 条`,
+		onChange: (page, pageSize) => {
+			pagination.current = page
+			pagination.size = pageSize
+			fetchStudyDetail()
+		}
+	})
+
+
+
+	// 统计卡片数据
+	const statsCards = reactive([
+		{
+			title: '开课人数',
+			value: 0,
+			key: 'courseOpenStuNum',
+			icon: UserOutlined,
+			borderClass: 'border-l-4 !border-blue-500',
+			iconBgClass: 'bg-blue-100',
+			iconClass: 'text-blue-600'
+		},
+		{
+			title: '课程访问次数',
+			value: 0,
+			key: 'courseViewNum',
+			icon: EyeOutlined,
+			borderClass: 'border-l-4 !border-green-500',
+			iconBgClass: 'bg-green-100',
+			iconClass: 'text-green-600'
+		},
+		{
+			title: '提交数(作业、测验)',
+			value: 0,
+			key: 'paperSubmitNum',
+			icon: FileTextOutlined,
+			borderClass: 'border-l-4 !border-orange-500',
+			iconBgClass: 'bg-orange-100',
+			iconClass: 'text-orange-500'
+		},
+		{
+			title: '互动数(发帖/回帖)',
+			value: 0,
+			key: 'interactionNum',
+			icon: MessageOutlined,
+			borderClass: 'border-l-4 !border-blue-500',
+			iconBgClass: 'bg-blue-100',
+			iconClass: 'text-blue-600'
+		}
+	])
+
+	const tableColumns = [
+		{
+			title: '课程名称',
+			dataIndex: 'courseName',
+			key: 'courseName'
+		},
+		{
+			title: '开课人数',
+			dataIndex: 'openStuNum',
+			key: 'openStuNum'
+		},
+		{
+			title: '课程访问量',
+			dataIndex: 'viewCount',
+			key: 'viewCount'
+		},
+		{
+			title: '讲义访问量',
+			dataIndex: 'teachMaterialsNum',
+			key: 'teachMaterialsNum'
+		},
+		{
+			title: '练习提交量',
+			dataIndex: 'paperSubmitNum',
+			key: 'paperSubmitNum'
+		}
+	]
+
+	// 图表数据
+	const chartData = reactive({
+		visitTrend: [],
+		submissionTrend: []
+	})
+
+	// 表格数据
+	const tableData = ref([])
+
+
+
+		const onItemStudyDetailCourseView = (record) => {
+			// console.log('123123点了什么123123',record,' listViewRef ',listViewRef)
+			listViewListViewlistViewStudyDetailCourseViewRef.value.open(record.courseId)
+		}
+		const onItemStudyDetailPracticeResult = (record) => {
+
+			listViewStudyDetailPracticeResultRef.value.open(record.courseId)
+			// console.log('点了什么',record)
+			// const params = {
+			// 	courseId: record.courseId,
+			// 	startTime: undefined,
+			// 	endTime: undefined,
+			// 	size : 99999,
+			// 	current : 1
+			// }
+			// overviewLearningProgressApi.getStudyDetailPracticeResult(params).then((res)=>{
+			//
+			// })
+		}
+	// 初始化折线图
+	const initLineChart = () => {
+		if (!lineChartRef.value) return
+
+		lineChart = echarts.init(lineChartRef.value)
+		updateLineChart()
+	}
+
+	// 更新折线图数据
+	const updateLineChart = () => {
+		if (!lineChart) return
+
+		const option = {
+			grid: { top: 30, right: 20, bottom: 20, left: 40 },
+			tooltip: { trigger: 'axis' },
+			xAxis: {
+				type: 'category',
+				data: chartData.visitTrend.map((item) => item.month)
+			},
+			yAxis: { type: 'value', name: '访问人数' },
+			series: [
+				{
+					name: '访问人数',
+					type: 'line',
+					smooth: true,
+					symbol: 'circle',
+					symbolSize: 8,
+					data: chartData.visitTrend.map((item) => item.viewTendencyNum),
+					lineStyle: { color: '#3A7BFF', width: 3 },
+					itemStyle: { color: '#3A7BFF' },
+					areaStyle: {
+						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+							{ offset: 0, color: 'rgba(58, 123, 255, 0.3)' },
+							{ offset: 1, color: 'rgba(58, 123, 255, 0.05)' }
+						])
+					}
+				}
+			]
+		}
+		lineChart.setOption(option)
+	}
+
+	// 初始化柱状图
+	const initBarChart = () => {
+		if (!barChartRef.value) return
+
+		barChart = echarts.init(barChartRef.value)
+		updateBarChart()
+	}
+
+	// 更新柱状图数据
+	const updateBarChart = () => {
+		if (!barChart) return
+
+		const option = {
+			grid: { top: 30, right: 20, bottom: 20, left: 40 },
+			tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
+			xAxis: {
+				type: 'category',
+				data: chartData.submissionTrend.map((item) => item.month)
+			},
+			yAxis: { type: 'value', name: '提交数' },
+			series: [
+				{
+					name: '练习提交数',
+					type: 'bar',
+					barWidth: 28,
+					data: chartData.submissionTrend.map((item) => item.SubmeitTendency),
+					itemStyle: {
+						color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+							{ offset: 0, color: '#5B8EFF' },
+							{ offset: 1, color: '#3A7BFF' }
+						]),
+						borderRadius: [4, 4, 0, 0]
+					}
+				}
+			]
+		}
+		barChart.setOption(option)
+	}
+
+	// 格式化日期范围显示
+	const formatDateRange = () => {
+		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}`
+	}
+
+	// 获取统计概览数据
+	const fetchOverviewStats = async () => {
+		try {
+			const params = {
+				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.getTopFundamentalDetail(params)
+			// 更新统计卡片数据
+			statsCards.forEach((card) => {
+				card.value = data[card.key] || 0
+			})
+		} catch (error) {
+			console.error('获取统计数据失败:', error)
+			message.error('获取统计数据失败')
+		}
+	}
+
+	// 获取趋势数据
+	const fetchTrendData = async () => {
+		try {
+			const params = {
+				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 [visitData, submitData] = await Promise.all([
+				overviewLearningProgressApi.getViewTendency(params),
+				overviewLearningProgressApi.getPaperSubmitTendency(params)
+			])
+
+			// 更新图表数据
+			chartData.visitTrend = visitData || []
+			chartData.submissionTrend = submitData || []
+
+			// 更新图表
+			updateLineChart()
+			updateBarChart()
+		} catch (error) {
+			console.error('获取趋势数据失败:', error)
+			message.error('获取趋势数据失败')
+		}
+	}
+
+	// 获取学习明细数据
+	const fetchStudyDetail = async () => {
+		try {
+			const params = {
+				courseId: filters.courseId,
+				current : pagination.current,
+				size : pagination.size,
+				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.getStudyDetail(params)
+
+			pagination.current = data.current
+			pagination.total = data.total
+
+			// 更新表格数据
+			tableData.value = (data.records || []).map((item, index) => ({
+				...item,
+				key: item.courseId || index + 1
+			}))
+		} catch (error) {
+			console.error('获取学习明细数据失败:', error)
+			message.error('获取学习明细数据失败')
+		}
+	}
+
+	// 刷新所有数据
+	const refreshData = async () => {
+		loading.value = true
+		try {
+			// 更新筛选条件
+			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 {
+			loading.value = false
+		}
+	}
+
+	// 窗口大小变化处理
+	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.courseId, startDate.value, endDate.value],
+		() => {
+			refreshData()
+		},
+		{ deep: true }
+	)
+
+	// 生命周期
+	onMounted(async () => {
+		await nextTick()
+		initLineChart()
+		initBarChart()
+		window.addEventListener('resize', handleResize)
+
+		// 初始化数据
+		await refreshData()
+		getCourseinfoAllList()
+	})
+
+	onUnmounted(() => {
+		if (lineChart) {
+			lineChart.dispose()
+			lineChart = null
+		}
+		if (barChart) {
+			barChart.dispose()
+			barChart = null
+		}
+		window.removeEventListener('resize', handleResize)
+	})
+</script>
+
+<style scoped>
+	.card-header {
+		border-left: 4px solid;
+	}
+
+	.chart-container {
+		background-color: white;
+		border: 1px solid #e4e7ed;
+		border-radius: 4px;
+	}
+	.font-size-30 {
+		font-size: 30px;
+	}
+</style>

+ 237 - 0
src/views/statisticalAnalysis/overviewLearningProgress/listViewStudyDetailCourseView.vue

@@ -0,0 +1,237 @@
+<template>
+	<a-modal v-model:visible="visible" width="600" @ok="handleOk" title="视频访问" :footer="null">
+		<a-table
+			ref="table"
+			:columns="columns"
+			:data-source="dataSources"
+			:row-key="(record) => record.courseId"
+			bordered
+			:expand-row-by-click="true"
+			:pagination="false"
+			size="small"
+		>
+			<template #bodyCell="{ column, text, record }">
+<!--				<template v-if="column.dataIndex === 'createTime'">-->
+<!--					<span>{{ formatDateTime(record.createTime) }}</span>-->
+<!--				</template>-->
+
+<!--				<template v-if="column.dataIndex === 'action'">-->
+<!--	&lt;!&ndash;				<a-button size="small" @click="handleDetail(record)" style="margin-right: 5px">详情</a-button>&ndash;&gt;-->
+<!--	&lt;!&ndash;				<a-button size="small" @click="handleEdit(record)" style="margin-right: 5px">编辑</a-button>&ndash;&gt;-->
+<!--					<a-popover v-model:visible="popoverVisibles[record.collegeId]" title="确定删除?" trigger="click">-->
+<!--						<template #content>-->
+<!--							<a-button style="margin-right: 10px" type="primary" @click="handleShelf(record,1)">确定-->
+<!--							</a-button>-->
+<!--							<a-button @click="()=>{	popoverVisibles[record.collegeId] = false}">取消</a-button>-->
+<!--						</template>-->
+<!--						&lt;!&ndash;					<a-button size="small" style="margin-right: 5px">选择</a-button>&ndash;&gt;-->
+<!--						<a-button size="small" @click="handleDelete(record)" style="margin-right: 5px">删除</a-button>-->
+<!--					</a-popover>-->
+<!--				</template>-->
+			</template>
+		</a-table>
+		<div style="display: flex; width: 100%; justify-content: flex-end; margin-top: 10px">
+			<a-pagination
+				v-model:current="pagination.current"
+				v-model:pageSize="pagination.size"
+				:total="total"
+				show-less-items
+				@change="handlerChange"
+			/>
+		</div>
+	</a-modal>
+</template>
+
+<script setup>
+import tool from '@/utils/tool'
+import {ref, onMounted} from 'vue'
+import {useRouter} from 'vue-router'
+import {parseTime} from "@/utils/exam";
+
+const router = useRouter()
+import { overviewLearningProgressApi } from '@/api/statisticalAnalysis/overviewLearningProgress'
+const emit = defineEmits(['handleEdit'])
+//发布按钮状态
+const releaseVisible = ref(false)
+const loading = ref(false) // 列表loading
+const dataSources = ref([])
+const popoverVisible = ref({})
+const popoverVisibles = ref({})
+const courseId = ref(null)
+const visible = ref(false)
+const formState = ref({
+	name: '',
+	loacl: ''
+}) // 列表loading
+const columns = [
+	{
+		title: '课程课时名称',
+		dataIndex: 'courseHourName',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '学生名称',
+		dataIndex: 'userName',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '观看次数',
+		dataIndex: 'viewCount',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '课时id',
+		dataIndex: 'hourId',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '学生id',
+		dataIndex: 'userId',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '创建日期',
+		dataIndex: 'createDate',
+		// sorter: true,
+		width: '12%'
+	},
+]
+// tool.formatTimestamp()
+const formatDateTime = (val) => {
+	if (!val) return ''
+	return parseTime(val, '{y}-{m}-{d} {h}:{i}:{s}')
+}
+const formatTimestamp = (time) => {
+	return tool.formatTimestamp(time)
+}
+const total = ref(0)
+const pagination = ref({
+	size: 10,
+	current: 1,
+})
+// const onChangeCurrent = (current) => {
+// 	router.push({
+// 		path: '/' + current
+// 	})
+// }
+const handlerChange = (page, pageSize) => {
+	console.log('分页参数', page, pageSize)
+	// pagination.value.size = pageSize
+	// pagination.value.current = page
+
+	getList()
+}
+const handleOk = () => {
+	visible.value = false
+}
+const open = (id) => {
+	visible.value = true
+	pagination.value.size = 10
+	pagination.value.current = 1
+	courseId.value = id
+	getList()
+}
+const handleDetail = (record) => {
+	console.log('查看详情', record)
+	router.push({
+		path: '/portal/courseDetails',
+		query: {
+			id: record.courseId
+		}
+	})
+	// 在这里添加查看详情的逻辑
+}
+
+// 编辑按钮点击事件
+const handleEdit = (record) => {
+	console.log('编辑记录', record)
+	// 在这里添加编辑记录的逻辑
+
+	emit('handleEdit', record)
+}
+
+// 上架按钮点击事件
+const handleShelf = (record,num) => {
+	console.log('上架记录', record)
+	popoverVisible.value[record.collegeId] = false
+	// 在这里添加上架记录的逻辑
+	// {
+	// 	"courseId": "1948183431150227458",
+	// 	"putawayStatus": 1
+	// }
+	// updateCourseStatus({courseId : record.courseId,putawayStatus : num}).then((res)=>{
+	// 	getList()
+	// })
+
+}
+
+// 删除按钮点击事件
+const handleDelete = (record) => {
+	console.log('删除记录', record)
+	// 在这里添加删除记录的逻辑
+}
+const getList = () => {
+	const params = {
+		courseId: courseId.value,
+		startTime: undefined,
+		endTime: undefined,
+		size : pagination.value.size,
+		current : pagination.value.current
+	}
+	overviewLearningProgressApi.getStudyDetailCourseView(params).then((data)=>{
+		console.log('获取列表', data)
+		dataSources.value = data.records
+		pagination.value.current = data.current
+		pagination.value.size = data.size
+		total.value = data.total
+	})
+}
+const setList = (search) => {
+	console.log('获取列表 setList',search)
+	// courseName: '',
+	// 	collegeId: '',
+	// 	majorId: '',
+	// 	courseType: '',
+	// 	loacl: []
+	formState.value = search
+	pagination.value.current = 1
+	list({...pagination.value, ...formState.value}).then((data) => {
+		if (data.code == 200) {
+			dataSources.value = data.data.records
+			pagination.value.current = data.data.current
+			pagination.value.size = data.data.size
+			total.value = data.data.total
+		}
+		// data.records
+	})
+}
+
+// 重置按钮点击事件
+onMounted(() => {
+	// getListData()
+	// getList()
+})
+
+
+// watch(
+// 	() => dataSources.value,
+// 	(newVal, oldVal) => {
+// 		console.log('数据源变化了 ', ' 新的 ',newVal, '  旧的 ',oldVal)
+// 	},
+// 	{ deep: true, immediate: true }
+// )
+defineExpose({
+	open
+})
+</script>
+
+<style scoped>
+.desc p {
+	margin-bottom: 1em;
+}
+</style>

+ 231 - 0
src/views/statisticalAnalysis/overviewLearningProgress/listViewStudyDetailPracticeResult.vue

@@ -0,0 +1,231 @@
+<template>
+	<a-modal v-model:visible="visible" width="600" @ok="handleOk" title="练习提交" :footer="null">
+		<a-table
+			ref="table"
+			:columns="columns"
+			:data-source="dataSources"
+			:row-key="(record) => record.courseId"
+			bordered
+			:expand-row-by-click="true"
+			:pagination="false"
+			size="small"
+		>
+			<template #bodyCell="{ column, text, record }">
+<!--				<template v-if="column.dataIndex === 'createTime'">-->
+<!--					<span>{{ formatDateTime(record.createTime) }}</span>-->
+<!--				</template>-->
+
+<!--				<template v-if="column.dataIndex === 'action'">-->
+<!--	&lt;!&ndash;				<a-button size="small" @click="handleDetail(record)" style="margin-right: 5px">详情</a-button>&ndash;&gt;-->
+<!--	&lt;!&ndash;				<a-button size="small" @click="handleEdit(record)" style="margin-right: 5px">编辑</a-button>&ndash;&gt;-->
+<!--					<a-popover v-model:visible="popoverVisibles[record.collegeId]" title="确定删除?" trigger="click">-->
+<!--						<template #content>-->
+<!--							<a-button style="margin-right: 10px" type="primary" @click="handleShelf(record,1)">确定-->
+<!--							</a-button>-->
+<!--							<a-button @click="()=>{	popoverVisibles[record.collegeId] = false}">取消</a-button>-->
+<!--						</template>-->
+<!--						&lt;!&ndash;					<a-button size="small" style="margin-right: 5px">选择</a-button>&ndash;&gt;-->
+<!--						<a-button size="small" @click="handleDelete(record)" style="margin-right: 5px">删除</a-button>-->
+<!--					</a-popover>-->
+<!--				</template>-->
+			</template>
+		</a-table>
+		<div style="display: flex; width: 100%; justify-content: flex-end; margin-top: 10px">
+			<a-pagination
+				v-model:current="pagination.current"
+				v-model:pageSize="pagination.size"
+				:total="total"
+				show-less-items
+				@change="handlerChange"
+			/>
+		</div>
+	</a-modal>
+</template>
+
+<script setup>
+import tool from '@/utils/tool'
+import {ref, onMounted} from 'vue'
+import {useRouter} from 'vue-router'
+import {parseTime} from "@/utils/exam";
+
+const router = useRouter()
+import { overviewLearningProgressApi } from '@/api/statisticalAnalysis/overviewLearningProgress'
+const emit = defineEmits(['handleEdit'])
+//发布按钮状态
+const releaseVisible = ref(false)
+const loading = ref(false) // 列表loading
+const dataSources = ref([])
+const popoverVisible = ref({})
+const popoverVisibles = ref({})
+const visible = ref(false)
+const courseId = ref(null)
+const formState = ref({
+	name: '',
+	loacl: ''
+}) // 列表loading
+const columns = [
+	{
+		title: '课程课时名称',
+		dataIndex: 'courseHourName',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '作业分数',
+		dataIndex: 'userScore',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '学生名称',
+		dataIndex: 'userName',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '学生id',
+		dataIndex: 'userId',
+		// sorter: true,
+		width: '15%'
+	},
+	{
+		title: '创建日期',
+		dataIndex: 'createDate',
+		// sorter: true,
+		width: '12%'
+	},
+]
+// tool.formatTimestamp()
+const formatDateTime = (val) => {
+	if (!val) return ''
+	return parseTime(val, '{y}-{m}-{d} {h}:{i}:{s}')
+}
+const formatTimestamp = (time) => {
+	return tool.formatTimestamp(time)
+}
+const total = ref(0)
+const pagination = ref({
+	size: 10,
+	current: 1,
+})
+// const onChangeCurrent = (current) => {
+// 	router.push({
+// 		path: '/' + current
+// 	})
+// }
+const handlerChange = (page, pageSize) => {
+	console.log('分页参数', page, pageSize)
+	// pagination.value.size = pageSize
+	// pagination.value.current = page
+
+	getList()
+}
+const handleOk = () => {
+	visible.value = false
+}
+const open = (id) => {
+	visible.value = true
+	pagination.value.size = 10
+	pagination.value.current = 1
+	courseId.value = id
+	getList()
+}
+const handleDetail = (record) => {
+	console.log('查看详情', record)
+	router.push({
+		path: '/portal/courseDetails',
+		query: {
+			id: record.courseId
+		}
+	})
+	// 在这里添加查看详情的逻辑
+}
+
+// 编辑按钮点击事件
+const handleEdit = (record) => {
+	console.log('编辑记录', record)
+	// 在这里添加编辑记录的逻辑
+
+	emit('handleEdit', record)
+}
+
+// 上架按钮点击事件
+const handleShelf = (record,num) => {
+	console.log('上架记录', record)
+	popoverVisible.value[record.collegeId] = false
+	// 在这里添加上架记录的逻辑
+	// {
+	// 	"courseId": "1948183431150227458",
+	// 	"putawayStatus": 1
+	// }
+	// updateCourseStatus({courseId : record.courseId,putawayStatus : num}).then((res)=>{
+	// 	getList()
+	// })
+
+}
+
+// 删除按钮点击事件
+const handleDelete = (record) => {
+	console.log('删除记录', record)
+	// 在这里添加删除记录的逻辑
+}
+const getList = () => {
+	const params = {
+		courseId: courseId.value,
+		startTime: undefined,
+		endTime: undefined,
+		size : pagination.value.size,
+		current : pagination.value.current
+	}
+	overviewLearningProgressApi.getStudyDetailPracticeResult(params).then((data)=>{
+		console.log('获取列表', data)
+		dataSources.value = data.records
+		pagination.value.current = data.current
+		pagination.value.size = data.size
+		total.value = data.total
+	})
+}
+const setList = (search) => {
+	console.log('获取列表 setList',search)
+	// courseName: '',
+	// 	collegeId: '',
+	// 	majorId: '',
+	// 	courseType: '',
+	// 	loacl: []
+	formState.value = search
+	pagination.value.current = 1
+	list({...pagination.value, ...formState.value}).then((data) => {
+		if (data.code == 200) {
+			dataSources.value = data.data.records
+			pagination.value.current = data.data.current
+			pagination.value.size = data.data.size
+			total.value = data.data.total
+		}
+		// data.records
+	})
+}
+
+// 重置按钮点击事件
+onMounted(() => {
+	// getListData()
+	// getList()
+})
+
+
+// watch(
+// 	() => dataSources.value,
+// 	(newVal, oldVal) => {
+// 		console.log('数据源变化了 ', ' 新的 ',newVal, '  旧的 ',oldVal)
+// 	},
+// 	{ deep: true, immediate: true }
+// )
+defineExpose({
+	open
+})
+</script>
+
+<style scoped>
+.desc p {
+	margin-bottom: 1em;
+}
+</style>