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

<!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>&copy; 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>