Forráskód Böngészése

添加后台管理中平台运行状态总览统计

tanshanming 6 hónapja
szülő
commit
ce8a3c5632

+ 497 - 0
src/views/statisticalAnalysis/platformStatusOverview/index.vue

@@ -0,0 +1,497 @@
+<template>
+	<div class="platform-status">
+		<div class="header">
+			<h1>平台运行状态总览</h1>
+			<p>实时掌握全院课程与人员信息、热门课程、开课动态与访问分析</p>
+		</div>
+
+		<!-- 统计卡片 -->
+		<div class="stats-grid">
+			<div class="stat-card">
+				<div class="stat-title">当前创建课程总数</div>
+				<div class="stat-value">{{ platformStats.totalCourses }}</div>
+			</div>
+			<div class="stat-card">
+				<div class="stat-title">开课总数</div>
+				<div class="stat-value">{{ platformStats.openedCourses }}</div>
+			</div>
+			<div class="stat-card">
+				<div class="stat-title">教员总数</div>
+				<div class="stat-value">{{ platformStats.totalTeachers }}</div>
+			</div>
+			<div class="stat-card">
+				<div class="stat-title">学员总数</div>
+				<div class="stat-value">{{ platformStats.totalStudents.toLocaleString() }}</div>
+			</div>
+		</div>
+
+		<!-- 热门课程分析 -->
+		<div class="section">
+			<h2>受欢迎课程 & 引用最受欢迎的课程统计</h2>
+			<a-table :columns="hotCoursesColumns" :data-source="hotCoursesData" :pagination="false" row-key="id" />
+		</div>
+
+		<!-- 开课信息列表 -->
+		<div class="section">
+			<h2>全院开课信息</h2>
+			<a-table :columns="courseInfoColumns" :data-source="courseInfoData" :pagination="{ pageSize: 10 }" row-key="id" />
+		</div>
+
+		<!-- 访问统计弹窗 -->
+		<a-modal
+			v-model:visible="visitModalVisible"
+			:title="modalTitle"
+			width="500px"
+			:footer="null"
+			@cancel="closeVisitModal"
+		>
+			<p style="color: #7f8c8d; margin: 10px 0; text-align: center">显示近7天的访问数据趋势</p>
+			<div ref="visitChart" style="width: 100%; height: 320px; margin-top: 20px"></div>
+		</a-modal>
+	</div>
+</template>
+
+<script setup>
+	import { ref, reactive, nextTick } from 'vue'
+	import * as echarts from 'echarts'
+
+	// 平台统计数据
+	const platformStats = reactive({
+		totalCourses: 128,
+		openedCourses: 97,
+		totalTeachers: 34,
+		totalStudents: 1256
+	})
+
+	// 热门课程表格列定义
+	const hotCoursesColumns = [
+		{
+			title: '排名',
+			dataIndex: 'rank',
+			key: 'rank',
+			width: 80,
+			align: 'center'
+		},
+		{
+			title: '课程名称',
+			dataIndex: 'name',
+			key: 'name'
+		},
+		{
+			title: '主讲教员',
+			dataIndex: 'teacher',
+			key: 'teacher'
+		},
+		{
+			title: '访问量',
+			dataIndex: 'visits',
+			key: 'visits',
+			align: 'center'
+		},
+		{
+			title: '被引用次数',
+			dataIndex: 'references',
+			key: 'references',
+			align: 'center'
+		}
+	]
+
+	// 热门课程数据
+	const hotCoursesData = ref([
+		{
+			id: 1,
+			rank: 1,
+			name: 'Python数据分析',
+			teacher: '王老师',
+			visits: '2,345',
+			references: 56
+		},
+		{
+			id: 2,
+			rank: 2,
+			name: 'JavaScript前端开发',
+			teacher: '李老师',
+			visits: '2,123',
+			references: 48
+		},
+		{
+			id: 3,
+			rank: 3,
+			name: '机器学习基础',
+			teacher: '张老师',
+			visits: '1,987',
+			references: 41
+		},
+		{
+			id: 4,
+			rank: 4,
+			name: '管理学原理',
+			teacher: '赵老师',
+			visits: '1,876',
+			references: 39
+		},
+		{
+			id: 5,
+			rank: 5,
+			name: '大学英语',
+			teacher: '钱老师',
+			visits: '1,765',
+			references: 35
+		}
+	])
+
+	// 开课信息表格列定义
+	const courseInfoColumns = [
+		{
+			title: '课程名称',
+			dataIndex: 'name',
+			key: 'name'
+		},
+		{
+			title: '主讲教员',
+			dataIndex: 'teacher',
+			key: 'teacher'
+		},
+		{
+			title: '开课时间',
+			dataIndex: 'startDate',
+			key: 'startDate'
+		},
+		{
+			title: '学员数',
+			dataIndex: 'studentCount',
+			key: 'studentCount',
+			align: 'center'
+		},
+		{
+			title: '访问量',
+			dataIndex: 'visits',
+			key: 'visits',
+			align: 'center'
+		},
+		{
+			title: '统计分析',
+			key: 'action',
+			align: 'center',
+			customRender: ({ record }) => {
+				return h('button', { class: 'btn-view', onClick: () => showVisitModal(record.name) }, '查看')
+			}
+		}
+	]
+
+	// 开课信息数据
+	const courseInfoData = ref([
+		{
+			id: 1,
+			name: 'Python数据分析',
+			teacher: '王老师',
+			startDate: '2024-03-01',
+			studentCount: 320,
+			visits: '2,345'
+		},
+		{
+			id: 2,
+			name: 'JavaScript前端开发',
+			teacher: '李老师',
+			startDate: '2024-03-10',
+			studentCount: 280,
+			visits: '2,123'
+		},
+		{
+			id: 3,
+			name: '机器学习基础',
+			teacher: '张老师',
+			startDate: '2024-03-15',
+			studentCount: 210,
+			visits: '1,987'
+		},
+		{
+			id: 4,
+			name: '管理学原理',
+			teacher: '赵老师',
+			startDate: '2024-03-20',
+			studentCount: 180,
+			visits: '1,876'
+		},
+		{
+			id: 5,
+			name: '大学英语',
+			teacher: '钱老师',
+			startDate: '2024-03-25',
+			studentCount: 266,
+			visits: '1,765'
+		}
+	])
+
+	// 弹窗相关
+	const visitModalVisible = ref(false)
+	const modalTitle = ref('')
+	const visitChart = ref(null)
+	let chartInstance = null
+
+	// 模拟课程每日访问数据
+	const courseVisitData = {
+		Python数据分析: [120, 156, 178, 210, 234, 245, 267, 289, 312, 234, 198, 156, 145, 134],
+		JavaScript前端开发: [98, 123, 145, 167, 189, 201, 223, 245, 267, 189, 156, 134, 123, 112],
+		机器学习基础: [67, 89, 112, 134, 156, 178, 189, 201, 223, 156, 134, 123, 112, 101],
+		管理学原理: [56, 78, 98, 123, 145, 167, 189, 201, 223, 145, 123, 112, 101, 89],
+		大学英语: [45, 67, 89, 112, 134, 156, 178, 189, 201, 134, 112, 101, 89, 78]
+	}
+
+	// 获取近7天的访问数据
+	const getLast7DaysData = (courseName) => {
+		const baseData = courseVisitData[courseName] || [100, 120, 140, 160, 180, 200, 220]
+		const last7Days = []
+
+		for (let i = 0; i < 7; i++) {
+			const baseValue = baseData[i] || 150
+			const randomFactor = 0.8 + Math.random() * 0.4 // 0.8-1.2的随机因子
+			const dailyVisits = Math.round(baseValue * randomFactor)
+			last7Days.push(dailyVisits)
+		}
+
+		return last7Days
+	}
+
+	// 显示访问统计弹窗
+	const showVisitModal = (courseName) => {
+		modalTitle.value = `${courseName} - 近7天访问统计`
+		visitModalVisible.value = true
+
+		nextTick(() => {
+			initVisitChart(courseName)
+		})
+	}
+
+	// 初始化访问统计图表
+	const initVisitChart = (courseName) => {
+		if (!visitChart.value) return
+
+		if (chartInstance) {
+			chartInstance.dispose()
+		}
+
+		chartInstance = echarts.init(visitChart.value)
+
+		// 构造近7天的日期
+		const days = []
+		const today = new Date()
+		for (let i = 6; i >= 0; i--) {
+			const date = new Date(today)
+			date.setDate(date.getDate() - i)
+			const month = (date.getMonth() + 1).toString().padStart(2, '0')
+			const day = date.getDate().toString().padStart(2, '0')
+			days.push(`${month}-${day}`)
+		}
+
+		// 获取近7天的访问数据
+		const visits = getLast7DaysData(courseName)
+
+		const option = {
+			title: {
+				text: '近7天访问趋势',
+				left: 'center',
+				textStyle: {
+					fontSize: 14,
+					color: '#2c3e50'
+				}
+			},
+			tooltip: {
+				trigger: 'axis',
+				formatter: function (params) {
+					return params[0].name + '<br/>' + params[0].marker + '访问量: ' + params[0].value + ' 次'
+				}
+			},
+			xAxis: {
+				type: 'category',
+				data: days,
+				axisLabel: {
+					color: '#2c3e50'
+				}
+			},
+			yAxis: {
+				type: 'value',
+				name: '访问量',
+				nameTextStyle: {
+					color: '#2c3e50'
+				},
+				axisLabel: {
+					color: '#2c3e50'
+				}
+			},
+			series: [
+				{
+					name: '访问量',
+					type: 'line',
+					data: visits,
+					smooth: true,
+					itemStyle: { color: '#3498db' },
+					areaStyle: {
+						color: {
+							type: 'linear',
+							x: 0,
+							y: 0,
+							x2: 0,
+							y2: 1,
+							colorStops: [
+								{ offset: 0, color: 'rgba(52,152,219,0.3)' },
+								{ offset: 1, color: 'rgba(52,152,219,0.1)' }
+							]
+						}
+					},
+					lineStyle: {
+						width: 3
+					},
+					symbol: 'circle',
+					symbolSize: 8
+				}
+			]
+		}
+
+		chartInstance.setOption(option)
+
+		// 响应式处理
+		window.addEventListener('resize', () => {
+			chartInstance?.resize()
+		})
+	}
+
+	// 关闭访问统计弹窗
+	const closeVisitModal = () => {
+		visitModalVisible.value = false
+		if (chartInstance) {
+			chartInstance.dispose()
+			chartInstance = null
+		}
+	}
+
+	// 将showVisitModal方法暴露到全局,供表格按钮调用
+	window.showVisitModal = showVisitModal
+</script>
+
+<style scoped>
+	.platform-status {
+		background: linear-gradient(135deg, #e0eafc 0%, #cfdef3 100%);
+		min-height: 100vh;
+		padding: 30px 20px;
+	}
+
+	.header {
+		background: #fff;
+		border-radius: 16px;
+		padding: 30px 0 20px 0;
+		margin-bottom: 30px;
+		box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
+		text-align: center;
+		max-width: 1300px;
+		margin-left: auto;
+		margin-right: auto;
+		margin-bottom: 30px;
+	}
+
+	.header h1 {
+		font-size: 2.2em;
+		color: #2c3e50;
+		margin-bottom: 10px;
+	}
+
+	.header p {
+		color: #7f8c8d;
+		font-size: 1.1em;
+	}
+
+	.stats-grid {
+		display: grid;
+		grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+		gap: 25px;
+		margin-bottom: 30px;
+		max-width: 1300px;
+		margin-left: auto;
+		margin-right: auto;
+		margin-bottom: 30px;
+	}
+
+	.stat-card {
+		background: #fff;
+		border-radius: 14px;
+		padding: 28px 20px;
+		box-shadow: 0 4px 16px rgba(44, 62, 80, 0.07);
+		text-align: center;
+		transition: box-shadow 0.2s;
+	}
+
+	.stat-card:hover {
+		box-shadow: 0 8px 32px rgba(44, 62, 80, 0.13);
+	}
+
+	.stat-title {
+		color: #7f8c8d;
+		font-size: 1em;
+		margin-bottom: 10px;
+	}
+
+	.stat-value {
+		font-size: 2.3em;
+		font-weight: bold;
+		color: #3498db;
+		margin-bottom: 5px;
+	}
+
+	.section {
+		background: #fff;
+		border-radius: 14px;
+		padding: 25px 20px;
+		margin-bottom: 30px;
+		box-shadow: 0 4px 16px rgba(44, 62, 80, 0.07);
+		max-width: 1300px;
+		margin-left: auto;
+		margin-right: auto;
+		margin-bottom: 30px;
+	}
+
+	.section h2 {
+		font-size: 1.3em;
+		color: #2c3e50;
+		margin-bottom: 18px;
+	}
+
+	:deep(.ant-table-thead > tr > th) {
+		background: #3498db;
+		color: #fff;
+		font-weight: 600;
+	}
+
+	:deep(.ant-table-tbody > tr:hover > td) {
+		background: #f6faff;
+	}
+
+	:deep(.btn-view) {
+		background: linear-gradient(135deg, #27ae60, #229954);
+		color: #fff;
+		border: none;
+		border-radius: 8px;
+		padding: 7px 18px;
+		cursor: pointer;
+		font-size: 0.95em;
+		transition: background 0.2s;
+	}
+
+	:deep(.btn-view:hover) {
+		background: linear-gradient(135deg, #229954, #27ae60);
+	}
+
+	@media (max-width: 900px) {
+		.stats-grid {
+			grid-template-columns: 1fr 1fr;
+		}
+	}
+
+	@media (max-width: 600px) {
+		.stats-grid {
+			grid-template-columns: 1fr;
+		}
+		.platform-status {
+			padding: 10px;
+		}
+	}
+</style>