You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
318 lines
11 KiB
318 lines
11 KiB
<!DOCTYPE html>
|
|
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>湖南大学选课系统分析</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
|
<style>
|
|
body {
|
|
font-family: 'Microsoft YaHei', sans-serif;
|
|
background-color: #f8f9fa;
|
|
}
|
|
.hero {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 60px 0;
|
|
margin-bottom: 30px;
|
|
}
|
|
.card {
|
|
border-radius: 10px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
transition: transform 0.3s ease;
|
|
}
|
|
.card:hover {
|
|
transform: translateY(-5px);
|
|
}
|
|
.stat-card {
|
|
text-align: center;
|
|
padding: 20px;
|
|
}
|
|
.stat-value {
|
|
font-size: 2rem;
|
|
font-weight: bold;
|
|
color: #667eea;
|
|
}
|
|
.stat-label {
|
|
font-size: 1rem;
|
|
color: #6c757d;
|
|
}
|
|
.btn-primary {
|
|
background-color: #667eea;
|
|
border-color: #667eea;
|
|
}
|
|
.btn-primary:hover {
|
|
background-color: #5a6fd8;
|
|
border-color: #5a6fd8;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- 导航栏 -->
|
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
<div class="container">
|
|
<a class="navbar-brand" href="/">湖南大学选课系统分析</a>
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
|
<span class="navbar-toggler-icon"></span>
|
|
</button>
|
|
<div class="collapse navbar-collapse" id="navbarNav">
|
|
<ul class="navbar-nav ms-auto">
|
|
<li class="nav-item">
|
|
<a class="nav-link active" href="/">首页</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="/courses">课程列表</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link" href="/analysis">数据分析</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- 英雄区 -->
|
|
<div class="hero">
|
|
<div class="container">
|
|
<h1 class="display-4">湖南大学选课系统数据分析平台</h1>
|
|
<p class="lead">实时爬取、分析和可视化展示选课系统数据</p>
|
|
<button class="btn btn-light btn-lg" onclick="crawlData()">
|
|
<i class="bi bi-download"></i> 爬取最新数据
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 统计卡片 -->
|
|
<div class="container mb-5">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="card stat-card">
|
|
<div class="card-body">
|
|
<div class="stat-value" th:text="${overallStats.totalCourses}"></div>
|
|
<div class="stat-label">总课程数</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card stat-card">
|
|
<div class="card-body">
|
|
<div class="stat-value" th:text="${overallStats.totalCredits}"></div>
|
|
<div class="stat-label">总学分</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card stat-card">
|
|
<div class="card-body">
|
|
<div class="stat-value" th:text="${overallStats.totalEnrolled}"></div>
|
|
<div class="stat-label">总已选人数</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card stat-card">
|
|
<div class="card-body">
|
|
<div class="stat-value" th:text="${#numbers.formatDecimal(overallStats.overallUsageRate, 0, 1)}%">
|
|
使用率
|
|
</div>
|
|
<div class="stat-label">总体使用率</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 热门课程 -->
|
|
<div class="container mb-5">
|
|
<h2 class="text-center mb-4">热门课程排行</h2>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="topCoursesChart" style="width: 100%; height: 400px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 课程类型分布 -->
|
|
<div class="container mb-5">
|
|
<h2 class="text-center mb-4">课程类型分布</h2>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="courseTypeChart" style="width: 100%; height: 400px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 院系分布 -->
|
|
<div class="container mb-5">
|
|
<h2 class="text-center mb-4">院系课程分布</h2>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div id="departmentChart" style="width: 100%; height: 400px;"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 页脚 -->
|
|
<footer class="bg-dark text-white py-4">
|
|
<div class="container text-center">
|
|
<p>© 2024 湖南大学选课系统分析平台</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
// 爬取数据
|
|
function crawlData() {
|
|
fetch('/crawl', {
|
|
method: 'POST'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert(data.message);
|
|
window.location.reload();
|
|
} else {
|
|
alert('爬取失败');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('爬取失败');
|
|
});
|
|
}
|
|
|
|
// 初始化热门课程图表
|
|
fetch('/api/top-courses')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const courseNames = data.map(item => item.course_name);
|
|
const enrolledCounts = data.map(item => item.enrolled);
|
|
|
|
const chart = echarts.init(document.getElementById('topCoursesChart'));
|
|
chart.setOption({
|
|
title: {
|
|
text: '热门课程排行',
|
|
left: 'center'
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
axisPointer: {
|
|
type: 'shadow'
|
|
}
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: courseNames,
|
|
axisLabel: {
|
|
rotate: 45
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
name: '已选人数'
|
|
},
|
|
series: [{
|
|
data: enrolledCounts,
|
|
type: 'bar',
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{offset: 0, color: '#667eea'},
|
|
{offset: 1, color: '#764ba2'}
|
|
])
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
// 初始化课程类型分布图表
|
|
fetch('/api/course-type-distribution')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const types = Object.keys(data);
|
|
const counts = Object.values(data);
|
|
|
|
const chart = echarts.init(document.getElementById('courseTypeChart'));
|
|
chart.setOption({
|
|
title: {
|
|
text: '课程类型分布',
|
|
left: 'center'
|
|
},
|
|
tooltip: {
|
|
trigger: 'item'
|
|
},
|
|
legend: {
|
|
orient: 'vertical',
|
|
left: 'left'
|
|
},
|
|
series: [{
|
|
name: '课程类型',
|
|
type: 'pie',
|
|
radius: '60%',
|
|
data: types.map((type, index) => ({
|
|
name: type,
|
|
value: counts[index]
|
|
})),
|
|
emphasis: {
|
|
itemStyle: {
|
|
shadowBlur: 10,
|
|
shadowOffsetX: 0,
|
|
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
}
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
// 初始化院系分布图表
|
|
fetch('/api/department-distribution')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
const departments = Object.keys(data);
|
|
const counts = Object.values(data);
|
|
|
|
const chart = echarts.init(document.getElementById('departmentChart'));
|
|
chart.setOption({
|
|
title: {
|
|
text: '院系课程分布',
|
|
left: 'center'
|
|
},
|
|
tooltip: {
|
|
trigger: 'item'
|
|
},
|
|
legend: {
|
|
orient: 'vertical',
|
|
left: 'left'
|
|
},
|
|
series: [{
|
|
name: '院系',
|
|
type: 'pie',
|
|
radius: '60%',
|
|
data: departments.map((dept, index) => ({
|
|
name: dept,
|
|
value: counts[index]
|
|
})),
|
|
emphasis: {
|
|
itemStyle: {
|
|
shadowBlur: 10,
|
|
shadowOffsetX: 0,
|
|
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
}
|
|
}
|
|
}]
|
|
});
|
|
});
|
|
|
|
// 响应式调整
|
|
window.addEventListener('resize', function() {
|
|
const charts = ['topCoursesChart', 'courseTypeChart', 'departmentChart'];
|
|
charts.forEach(id => {
|
|
const chart = echarts.getInstanceByDom(document.getElementById(id));
|
|
if (chart) {
|
|
chart.resize();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|