分享一套锋哥原创的SpringBoot4+Vue3运动会管理系统

大家好,我是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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值