大家好,我是Java1234_小锋老师,分享一套锋哥原创的SpringBoot4+Vue3运动会管理系统。

项目介绍
随着高校体育事业的不断发展,运动会作为学校体育工作的重要组成部分,其组织规模和参与人数日益扩大。传统的运动会管理大多依赖人工方式完成报名登记、资格审核、成绩统计与名次排定等工作,存在效率低下、数据易错、查询不便、信息孤岛等诸多问题,已经难以满足现代高校精细化、信息化管理的需求。因此,设计并实现一套功能完善、操作便捷的运动会管理系统具有重要的现实意义。
本文针对高校运动会管理的实际业务需求,设计并实现了一套基于 SpringBoot 与 Vue3 的前后端分离运动会管理系统。系统后端采用 SpringBoot 作为核心框架,结合 MyBatis-Plus 持久层框架实现对数据的高效访问,使用 MySQL 作为数据存储,并借助 JWT 实现无状态的登录认证;前端采用 Vue3 框架,配合 Element Plus 组件库与 ECharts 可视化图表库构建美观、响应式的用户交互界面,通过 Axios 完成前后端数据通信。系统按角色划分为管理员与学生两类用户,主要实现了登录认证、用户管理、学院班级管理、比赛项目管理、报名与审核、成绩录入与排名、数据统计与公告管理等功能模块。
本文从系统的需求分析、可行性分析入手,详细阐述了系统的功能模块设计、数据库设计以及核心功能的具体实现过程,并对系统进行了功能测试。测试结果表明,该系统运行稳定、功能完整、操作友好,能够有效提升高校运动会的组织与管理效率,具有较好的实用价值。
源码下载
链接: https://pan.baidu.com/s/1AIHjxMiADWnRgOuoxUZOpQ?pwd=1234
提取码: 1234
系统展示






核心代码
package com.java1234.sports.controller;
import com.java1234.sports.common.Result;
import com.java1234.sports.entity.ClassInfo;
import com.java1234.sports.service.ClassInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 班级管理控制器
*
* @author Java1234_小锋老师
*/
@RestController
@RequestMapping("/api/class")
public class ClassController {
@Autowired
private ClassInfoService classInfoService;
/**
* 查询班级列表
*/
@GetMapping("/list")
public Result<List<ClassInfo>> list() {
return Result.success(classInfoService.listWithCollege());
}
/**
* 根据学院ID查询班级
*/
@GetMapping("/byCollege/{collegeId}")
public Result<List<ClassInfo>> byCollege(@PathVariable Long collegeId) {
return Result.success(classInfoService.listByCollegeId(collegeId));
}
/**
* 新增班级
*/
@PostMapping
public Result<?> add(@RequestBody ClassInfo classInfo) {
classInfoService.save(classInfo);
return Result.success();
}
/**
* 修改班级
*/
@PutMapping
public Result<?> update(@RequestBody ClassInfo classInfo) {
classInfoService.updateById(classInfo);
return Result.success();
}
/**
* 删除班级
*/
@DeleteMapping("/{id}")
public Result<?> delete(@PathVariable Long id) {
classInfoService.removeById(id);
return Result.success();
}
}
<template>
<div class="page-container">
<!-- 统计卡片 -->
<el-row :gutter="16" style="margin-bottom: 16px;">
<el-col :span="6">
<div class="stat-card">
<div class="stat-label">用户总数</div>
<div class="stat-num">{{ stats.userCount || 0 }}</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card green">
<div class="stat-label">运动员数</div>
<div class="stat-num">{{ stats.studentCount || 0 }}</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card orange">
<div class="stat-label">比赛项目</div>
<div class="stat-num">{{ stats.eventCount || 0 }}</div>
</div>
</el-col>
<el-col :span="6">
<div class="stat-card blue">
<div class="stat-label">报名总数</div>
<div class="stat-num">{{ stats.registrationCount || 0 }}</div>
</div>
</el-col>
</el-row>
<!-- 图表区域 -->
<el-row :gutter="16">
<el-col :span="12">
<div class="chart-card">
<div class="chart-title">各项目报名人数</div>
<div ref="barChartRef" style="height: 350px;"></div>
</div>
</el-col>
<el-col :span="12">
<div class="chart-card">
<div class="chart-title">运动员性别分布</div>
<div ref="pieChartRef" style="height: 350px;"></div>
</div>
</el-col>
</el-row>
<el-row :gutter="16" style="margin-top: 16px;">
<el-col :span="12">
<div class="chart-card">
<div class="chart-title">项目类型分布</div>
<div ref="typeChartRef" style="height: 350px;"></div>
</div>
</el-col>
<el-col :span="12">
<div class="chart-card">
<div class="chart-title">班级团体总分排行</div>
<div ref="rankChartRef" style="height: 350px;"></div>
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import * as echarts from 'echarts'
import { getDashboardStats } from '@/api'
const stats = ref({})
const barChartRef = ref()
const pieChartRef = ref()
const typeChartRef = ref()
const rankChartRef = ref()
let charts = []
const initCharts = (data) => {
// 柱状图 - 各项目报名人数
const barChart = echarts.init(barChartRef.value)
barChart.setOption({
tooltip: { trigger: 'axis' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: (data.eventRegStats || []).map(i => i.name), axisLabel: { rotate: 30 } },
yAxis: { type: 'value', minInterval: 1 },
series: [{
type: 'bar',
data: (data.eventRegStats || []).map(i => i.count),
itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#667eea' }, { offset: 1, color: '#764ba2' }
])},
barWidth: '40%',
borderRadius: [6, 6, 0, 0]
}]
})
charts.push(barChart)
// 饼图 - 性别分布
const pieChart = echarts.init(pieChartRef.value)
pieChart.setOption({
tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' },
legend: { bottom: 0 },
color: ['#409eff', '#f56c6c'],
series: [{
type: 'pie', radius: ['40%', '65%'], center: ['50%', '45%'],
data: data.genderStats || [],
label: { formatter: '{b}\n{c}人' },
emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.2)' } }
}]
})
charts.push(pieChart)
// 饼图 - 项目类型
const typeChart = echarts.init(typeChartRef.value)
typeChart.setOption({
tooltip: { trigger: 'item' },
legend: { bottom: 0 },
color: ['#11998e', '#f093fb'],
series: [{
type: 'pie', radius: '60%', center: ['50%', '45%'],
data: data.typeStats || [],
roseType: 'radius',
label: { formatter: '{b}: {c}项' }
}]
})
charts.push(typeChart)
// 柱状图 - 班级排行
const rankChart = echarts.init(rankChartRef.value)
rankChart.setOption({
tooltip: { trigger: 'axis' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'value' },
yAxis: { type: 'category', data: (data.classRankStats || []).map(i => i.name).reverse() },
series: [{
type: 'bar',
data: (data.classRankStats || []).map(i => i.score).reverse(),
itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: '#4facfe' }, { offset: 1, color: '#00f2fe' }
])},
barWidth: '50%',
borderRadius: [0, 6, 6, 0]
}]
})
charts.push(rankChart)
}
const handleResize = () => charts.forEach(c => c.resize())
onMounted(async () => {
const res = await getDashboardStats()
stats.value = res.data
initCharts(res.data)
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
charts.forEach(c => c.dispose())
})
</script>



43万+

被折叠的 条评论
为什么被折叠?



