☰
基于SpringBoot+Vue前后端分离的幼儿园儿童信息管理系统设计与实现全解析
2026/10/2 15:00:13 网站建设 项目流程

写毕设项目这几年,我前后帮人看过不少Java方向的课题,其中幼儿园管理系统算是出镜率非常高的一类。今天想借这个机会,把基于SpringBoot+Vue前后端分离的幼儿园儿童信息管理系统的完整实现思路、核心模块、数据库设计、部署细节和踩坑记录做一个系统梳理。如果你正在准备Java毕设,或者刚接触前后端分离项目,这篇文章可以帮你少走很多弯路。

整个项目从业务上看并不复杂,无非就是幼儿信息、班级管理、家长绑定、考勤、健康档案、收费、请假审批这些事。但真正把项目做到“能演示、能答辩、能部署”,还是有一堆细节要注意的:前后端如何联调、权限怎么控制、文件上传怎么处理、打包后怎么部署,每一环都可能卡住人。下面我按照实际开发的顺序,把整个系统的技术原理和操作过程完整拆开来讲。

1. 项目定位与技术选型

1.1 这类毕设项目的核心价值

幼儿园管理系统属于典型的“管理信息系统”,核心是围绕“幼儿”这个主体,把入园、在园、离园全流程的数据管起来。很多同学选这个题目,看中的是业务清楚、功能容易展示、演示效果好。但我个人觉得,这类项目的真正价值在于:它能覆盖一套完整的前后端分离开发流程,从需求拆分、数据库建模、接口设计、权限控制到部署上线,每个环节都是真实项目会用到的。

用Java+SpringBoot做后端,Vue做前端,是目前最主流的技术组合。SpringBoot负责提供RESTful API,处理业务逻辑、数据持久化、权限校验;Vue负责页面渲染、交互操作、状态管理。你把这个项目完整写一遍,等于把Java后端开发的核心知识串了一遍:Spring MVC、MyBatis Plus、Spring Security或JWT、文件上传、定时任务、事务管理,这些全都能用上。

另外我要提醒一点:毕设答辩时,老师问你“为什么前后端分离”,不要只回答“前端拿JSON数据渲染”。你要能说出来分离带来什么好处——比如前端和后端可以独立开发、独立部署,前端只需要调用接口,不需要关心服务端模板;后端只负责提供数据,不掺杂页面逻辑。这样的回答才是有分量的。

1.2 前后端分离到底带来什么

前后端分离在实际开发中,意味着后端工程和前端工程是两套独立的代码库,各自拥有独立的开发、构建、部署流程。

后端通常跑在8080端口,提供形如/api/child/info这样的接口。前端通过Axios发起HTTP请求,拿到JSON数据后在浏览器端渲染页面。开发阶段,前端工程由Node提供服务,默认跑在8080或别的端口,通过代理把接口请求转发到后端;生产阶段,前端代码被打包成静态文件,可以放在Nginx里,也可以直接把dist目录塞进SpringBoot的resources/static目录下,一个端口启动整个系统。

我在这个项目中采用的就是标准的分离结构,项目目录大致如下:

├── backend │ ├── src/main/java │ │ ├── controller │ │ ├── service │ │ ├── mapper │ │ ├── entity │ │ └── config │ └── src/main/resources │ ├── application.yml │ └── mapper └── frontend ├── src │ ├── api │ ├── views │ ├── components │ ├── router │ └── store └── package.json

这种结构的好处很直接:后端写接口,前端写页面,你可以在IDEA里开一个后端服务,在VS Code里写Vue代码,两边互不干扰。调试的时候,浏览器F12看Network面板,请求和响应一目了然,比传统JSP开发图像清爽得多。

2. 业务功能分解与模块实现

2.1 幼儿园业务的特点

幼儿园和中小学的管理系统有很大区别。中小学的核心是“班级、课程、成绩”,幼儿园的核心是“幼儿、家长、健康、安全”。这里的业务主体是一个几岁的孩子,系统里要记录的信息必须围绕孩子的生活和成长展开。

从角色上看,系统至少要有三类用户:园长或管理员、教师、家长。园长关心全园数据统计和收费情况;教师关心班级幼儿信息、考勤和接送管理;家长最关心孩子在园表现、健康状况和缴费记录。不同角色看到的功能完全不同,这也是为什么权限设计在这个项目里特别重要。

2.2 核心模块划分

我设计的功能模块一共八个,覆盖幼儿园日常管理的方方面面:

  1. 系统管理模块:用户管理、角色管理、菜单管理,用的是一套标准的RBAC权限模型。
  2. 幼儿信息管理:幼儿的入园登记、基本信息维护、离园记录,支持批量导入。
  3. 班级管理:年级、班级的维护,幼儿分班和调班。
  4. 家长管理:家长信息和幼儿的绑定关系,支持一个幼儿绑定多个家长。
  5. 考勤管理:幼儿每日入园、离园打卡记录,教师可代登记。
  6. 健康管理:体检记录、疫苗接种记录、每日晨检情况登记。
  7. 收费管理:按月生成缴费单,记录缴费状态。
  8. 请假审批:家长提交请假申请,教师审批,请假记录关联考勤。

这套模块看起来多,但实现起来并没有想象中困难,因为大多数模块都是标准的增删改查加一个关联查询。真正有看点的只有两个:一个是幼儿分班和调班的数据联动,另一个是收费模块的按月自动生成账单。这两块逻辑写好了,能明显拉开和其他同学的差距。

2.3 典型业务闭环

我举一个具体的业务场景来说明这些模块是如何协作的。

家长用账号登录系统,在“请假申请”页面选择孩子、填写请假时间和事由,提交后数据存入leave表,状态为待审批。教师登录后,在待办列表里看到审批任务,点击通过后,请假状态变为已批准。此时考勤模块里,该孩子对应日期的考勤记录会被标记为“请假”,不再算作缺勤。

再比如收费场景:管理员在收费管理模块配置每个月每个班级的收费标准,系统通过定时任务,在每个月1号自动为所有在园幼儿生成当月缴费账单。家长登录后在缴费记录里看到账单并确认,管理员在后台看到缴费状态统计。整个过程不需要人工一个个去建账单,这就是定时任务的价值所在。

3. 数据库设计与权限模型

3.1 表结构设计思路

数据库是这类项目的灵魂,表设计得好不好,直接决定后期代码好不好写。我用的数据库是MySQL 8.0,核心表一共15张左右。下面挑几张重点表说几个关键设计点。

幼儿信息表child_info是最核心的一张表,存储姓名、性别、出生日期、入园日期、班级ID、家长ID等核心字段。这里有一个设计要点:不要把家长信息直接冗余到幼儿表里,而是建立单独的家长表和绑定关系表,因为一个孩子可能同时绑定爸爸、妈妈、爷爷奶奶多个联系人。

班级表classes和幼儿表是典型的“一对多”关系。幼儿表持有class_id外键。分班操作本质就是更新幼儿表的class_id字段,调班也是同一个逻辑。但要注意:如果幼儿已经有考勤记录或缴费记录,调班后历史数据的归属就变得复杂了。稳妥的做法是,幼儿表记录当前班级,考勤表记录幼儿当时所在班级的快照字段,这样历史统计不会乱。

考勤表attendance记录了幼儿每天的入园离园时间和状态。设计上建议用(attendance_date, child_id)做唯一索引,保证一个孩子一天只能生成一条考勤记录,避免重复数据。

我列出主要表的字段结构供参考:

表名核心字段说明
sys_userid, username, password, role_id, status用户表,保存登录账号
sys_roleid, role_name, role_code角色表,区分管理员/教师/家长
child_infoid, name, gender, birthday, class_id, photo幼儿信息表
parentsid, name, phone, relation, child_id家长表,relation存爸爸/妈妈等
classesid, grade, class_name, head_teacher班级表
attendanceid, child_id, date, status, check_in_time考勤记录表
health_recordid, child_id, record_date, height, weight, note健康档案表
fee_billid, child_id, month, amount, status缴费账单表
leave_requestid, child_id, start_date, end_date, reason, status请假申请表

3.2 角色权限设计

权限模型我采用经典的RBAC设计:用户-角色-菜单三层关系。用户表里存role_id,角色表里存角色编码,菜单表里存前端路由地址和按钮权限标识。

前端路由的动态注册依赖菜单表:用户登录后,后端根据用户角色返回对应的菜单列表,前端拿到菜单列表后,通过Vue Router的addRoute方法动态添加路由。这样做的好处是,家长登录后根本看不到系统管理菜单,也不会因为路由缺失跳到404页面,体验和安全性都好很多。

后端接口层用Spring Security加JWT做认证。登录成功后签发JWT令牌,后续请求在请求头里携带token,后端通过拦截器校验。接口的权限控制用注解方式实现,比如只有管理员能调用收费管理接口时,在Controller方法上加@PreAuthorize("hasRole('ADMIN')"),没有权限就直接返回403。

这里有一个我实践下来的心得:毕设项目不要为了追求复杂而引入太多框架。JWT+拦截器完全够用,加上Spring Security完全可以,但不要再去搞OAuth2、网关之类的。项目规模就那么大,做多了反而显得主次不分。

4. 后端SpringBoot核心实现

4.1 项目结构与安全认证

我在后端用的是SpringBoot 2.7版本,为什么不用3.x?这里有个很现实的坑:SpringBoot 3.x要求JDK 17,很多同学本机还是JDK 8,换过来以后会引发一堆兼容性问题。另外3.x里不少依赖的命名空间和配置方式都变了,增删改查的代码倒是影响不大,但安全框架的写法差异很大。毕设稳定压倒一切,用2.7版本配JDK 8最稳妥。

项目包结构按职责划分:

com.example.kindergarten ├── config ├── controller ├── service ├── mapper ├── entity ├── common └── utils

统一返回结果类Result是必须的,里面包含code、message、data三个字段。所有接口都返回这个结构,前端Axios根据code字段判断请求是否成功,这样处理错误逻辑只需要写一次。查询时的分页参数统一用pageNum和pageSize,返回分页对象PageResult。

登录认证这块,我用的方案是JWT+拦截器。用户登录成功后在服务端生成token,token里携带用户ID和角色。拦截器里解析token并放入ThreadLocal,业务代码中可以随时取出当前登录用户。这个方案实现简单,逻辑也容易讲清楚。如果你使用Spring Security,核心是重写UserDetailsService和JwtAuthenticationFilter,思路是一样的。

4.2 接口设计与统一返回

接口设计遵循Restful风格,接口路径统一以/api开头。前后端分离项目里,接口路径加/api前缀是约定俗成的做法,好处是一方面方便Nginx做路径转发,另一方面在开发环境也容易区分静态资源和接口请求。

幼儿信息相关的接口设计如下:

接口方法说明
/api/child/listGET分页查询幼儿列表
/api/child/{id}GET查询幼儿详情
/api/childPOST新增幼儿
/api/child/{id}PUT修改幼儿信息
/api/child/{id}DELETE删除幼儿
/api/child/importPOSTExcel批量导入
/api/child/exportGET导出幼儿名单

写接口时大家容易忽略参数校验。用注解方式给实体类的关键字段加上校验规则,比如@NotBlank、@NotNull,在Controller参数上加上@Validated注解,非法参数会被统一拦截并返回友好提示。这属于加分项,代码里体现出来,答辩时就能说“我考虑了接口的健壮性”。

4.3 文件上传与MinIO接入

幼儿园系统里有一类功能必不可少,就是图片上传。幼儿照片、体检报告、活动图片都属于文件上传场景。很多毕设项目把文件放在本地磁盘,然后在代码里配置一个虚拟路径映射。这个方案够用,但不够专业。

我的做法是引入MinIO做对象存储。MinIO是开源的兼容S3协议的对象存储服务,部署非常轻量,一个二进制文件就能跑起来。SpringBoot集成MinIO的流程很固定:先在pom.xml引入minio依赖,配置文件里加入endpoint、accessKey、secretKey、bucketName,然后封装一个FileStorageUtil工具类,提供上传、下载、删除三个方法即可。

MinIO接入SpringBoot的关键代码如下:

import io.minio.MinioClient; import io.minio.PutObjectArgs; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class MinioUtil { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.access-key}") private String accessKey; @Value("${minio.secret-key}") private String secretKey; private MinioClient client; @PostConstruct public void init() { client = MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } public String upload(MultipartFile file, String bucketName) { String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); // 具体上传逻辑... return endpoint + "/" + bucketName + "/" + fileName; } }

文件上传后,返回给前端的是一串可访问的URL。前端拿到URL,直接放到img标签里即可显示。用MinIO的好处是,文件不占用应用服务器磁盘,而且后期如果要扩展分布式部署,存储层天然独立,不用改业务代码。

这里有一个很多人不知道的点:MinIO也可以用来存视频。如果项目里涉及活动视频回放,前端用Vue播放mp4视频,直接使用video标签就可以;如果涉及m3u8切片流,那就需要引入hls.js这类播放器来做适配。这个可以根据自己项目的演示需求决定要不要加。

4.4 定时任务与提醒

收费模块的按月自动生成账单功能,依赖的是SpringBoot的定时任务。在启动类上加@EnableScheduling注解,然后在方法上加@Scheduled(cron = "0 0 0 1 * ?"),意思是每月1号零点执行。

自动生成账单的实现逻辑:查当月所有在园幼儿,根据班级的收费标准生成月度账单,调用批量插入方法写入fee_bill表。这里要注意事务控制,生成过程中如果有一条数据插入失败,整个批量插入都应该回滚,否则会出现部分幼儿有账单、部分没有的情况。在方法上加Spring的@Transactional注解即可。

定时任务在实际系统中是很常见的需求,比如每天生成考勤汇总、每月自动生成收费账单、定期清理过期日志。毕设里出现定时任务,属于典型的“功能亮点”,建议至少做一个。

5. 前端Vue核心实现

5.1 环境准备与工程搭建

前端我使用的是Vue2版本搭配Element-UI组件库。Vue2虽然已经不是最新的选择,但对于毕设项目,生态成熟、资料多、遇到问题容易搜到答案,这是我推荐它的核心理由。如果你对Vue3的Composition API比较熟悉,用Vue3加Element-Plus也可以,核心思路一样。

前端开发环境的搭建要注意几个关键点:

  1. Node.js版本不宜太高,Vue2项目建议使用Node 14或16,版本太高可能安装依赖时报错。
  2. 安装依赖用npm install,如果遇到网络问题,配置淘宝镜像源。
  3. 工程创建推荐用Vue CLI,命令是vue create frontend,选择Router和Vuex基础模板即可。

项目创建完成后,第一步先装Axios,然后在src目录下新建api文件夹,封装一个统一的request.js。我在request.js里做了三件事:设置请求超时时间、在请求头里自动加token、统一处理返回结果。整个过程是:

import axios from 'axios' const request = axios.create({ baseURL: '/api', timeout: 10000 }) request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config }) request.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { return Promise.reject(new Error(res.message)) } return res }, error => { // 统一处理401等错误 return Promise.reject(error) } ) export default request

这样封装之后,每个接口文件只需要几行代码。比如child.js文件的写法:

import request from '@/utils/request' export function getChildList(params) { return request({ url: '/child/list', method: 'get', params }) }

5.2 动态路由与权限控制

前端权限控制的核心是动态路由。登录成功时,后端除了返回token,还会返回当前用户的角色编码和菜单列表。前端拿到菜单列表后,在主布局的beforeEach路由守卫里判断:如果已经登录但路由未注册,就调用addRoute方法动态添加路由。

动态路由的写法在Vue2里稍微有点绕,但很值得掌握。核心步骤是:

  1. 定义一份静态路由表,包含登录页、404页、主布局。
  2. 在路由守卫中判断当前用户是否有权限访问目标路由。
  3. 如果没有动态注册过任何路由,就根据菜单列表生成动态路由数组并注册。

按钮级别的权限用自定义指令实现。比如删除幼儿按钮,只有管理员能看到,在按钮上写v-permission="'sys:child:delete'",指令内部判断当前用户是否有这个权限标识,没有就从DOM中移除该按钮。这个设计比单纯隐藏菜单更进一步,答辩时可以讲一讲。

5.3 页面与组件封装

Element-UI里最常用的组件是表格、表单、弹窗、日期选择器、树形控件。这里我有一个比较实用的建议:把列表页的翻页逻辑统一封装成混入对象,能减少大量重复代码。

幼儿园系统的页面结构比较固定:一个搜索区、一个操作按钮区、一个表格区、一个分页区。把这段逻辑抽出来,每个列表页只需要维护查询条件和列配置。我带的学生项目中,用这种方式之后,新增一个管理页面的工作量从半天压缩到了半小时。

表单校验是前端的一个重点。添加幼儿时,姓名、出生日期、性别是必填项,手机号要符合格式。Element-UI的form表单自带校验规则,配置rules属性即可。提交前调用validate方法,校验通过才允许提交。这一步不能省,如果前端不拦截非法数据,后端就算有参数校验,也会返回一堆不明所以的错误提示,体验非常差。

5.4 视频播放等扩展能力

如果项目里要展示幼儿活动视频,前端播放mp4格式比较简单,直接用HTML5的video标签。但有的演示场景要求播放m3u8视频流,这就涉及HLS流的客户端播放问题。

Vue播放m3u8的主流方案有两个:一个是vue-video-player组件,另一个是hls.js库。我一般用hls.js,因为体积小、配置灵活。实现方式很简单:下载m3u8地址后,通过Hls实例加载,然后挂载到video元素上。

这段代码可以作为一个扩展功能点到系统里,比如在“班级风采”模块展示活动视频。这类功能对毕设来说属于“加分项”,做好了对技术面的帮助不小。不过要注意,如果只是演示视频,需要先把视频文件传到MinIO或服务器上,拿到可访问的URL后再配置播放地址。

6. 环境配置与部署全流程

6.1 本机开发环境

在开始编码前,先把环境准备妥当。我的建议配置清单如下:

工具版本建议说明
JDK1.8与SpringBoot 2.7配套
Maven3.6+后端依赖管理
Node.js14或16前端开发环境
MySQL5.7或8.0数据库
Redis5.x+按需使用
MinIO最新稳定版对象存储
IDEA2022+后端开发IDE
VS Code最新前端开发IDE

6.2 后端运行步骤

后端工程的运行其实就三步:导入项目、改配置、启动。

第一步,用IDEA打开backend目录,等待Maven下载依赖。第一次加载比较慢,建议配置阿里云Maven镜像,否则下载依赖能等上半小时。在maven的settings.xml里加上镜像配置,速度会有质的提升。

第二步,修改application.yml里的数据库连接、Redis、MinIO配置。数据库连接要注意时区参数,serverTimezone=Asia/Shanghai不能漏掉。数据库需要先手动创建,执行sql脚本生成表结构和初始化数据。

第三步,启动主启动类。如果端口被占用,在application.yml里修改server.port。启动成功后在浏览器访问登录接口,返回正常JSON说明后端已经跑起来了。

6.3 前端运行与打包

前端开发模式下运行命令是npm run serve。这里有一个必须配置的点:开发环境的代理。在vue.config.js里配置:

module.exports = { devServer: { port: 8080, proxy: { '/api': { target: 'http://localhost:8081', changeOrigin: true } } } }

配置代理后,前端请求/api/user/login,开发服务器会把请求转发到后端的http://localhost:8081/api/user/login,这样就不会有跨域问题。有的同学不加代理,在Axios里写死完整地址,虽然能用,但一旦换环境就要改代码,代理的方式明显更优雅。

打包命令:npm run build。打包完成后,dist目录里是纯静态文件。验证打包是否成功,只需要在dist目录下启动一个本地静态服务器,访问index.html即可。

6.4 生产部署方案

部署方式我推荐两种方案。

方式一是前端Nginx部署、后端独立运行。将dist目录拷贝到Nginx的html目录,Nginx配置里把/api开头的请求反向代理到后端接口地址。后端的SpringBoot工程打成jar包,用nohup java -jar xxx.jar命令后台运行。这种方式完全符合前后端分离的生产实践,而且Nginx可以配置负载均衡和HTTPS。

方式二是前端打进SpringBoot,统一端口访问。把dist目录复制到后端工程的resources/static目录,重新打包。启动后直接访问8081端口,即能看到前端页面。这种方式的优点是不需要额外装Nginx,演示环境里非常省事。缺点是前后端耦合在一起,失去了独立扩展的能力。

如果是毕设答辩,我建议学会方式一,因为被问到部署问题时,Nginx反向代理是一个很成熟的回答方向,说清楚以后老师会觉得你对生产环境是有概念的。同时把方式二作为备用方案,现场演示更稳定可靠。

7. 常见问题与排查实录

7.1 高频问题速查表

我在调试这个项目时,遇到和解决的问题不少,整理成一张速查表,方便你在卡住时对照排查:

问题现象根本原因解决办法
前端请求接口跨域前端端口和后端端口不一致配置devServer代理,或后端添加跨域过滤器
登录成功后页面不跳转token未写入localStorage或路由跳转逻辑有误检查登录后的代码是否保存token并跳转
前端访问后端404后端接口路径和前端请求路径不一致统一接口前缀,用Postman先测通后端接口
时间字段显示为UTC后端时区配置错误在配置文件中设置timezone
文件上传报错文件不存在MinIO的bucket未创建写一个初始化方法,启动时自动创建bucket
Vue打包后图片不显示静态资源路径配置错误vue.config.js中配置publicPath为./
Node启动报错Digital EnvelopeNode版本过高导致降低Node版本到16,或设置环境变量
Maven下载依赖太慢默认中央仓库网络不稳配置阿里云镜像

这些坑看着不大,但每个都能卡住人好几个小时。尤其是跨域问题和Node版本问题,几乎每个项目都会遇到。排查的时候要沉着一点,按“网络请求是否发出、后端是否收到、返回数据是什么”的顺序逐步排除,不要瞎猜。

7.2 我踩过的三个最深的坑

第一个坑是SpringBoot版本选择。一开始有人图新用了SpringBoot 3.0,结果JDK从8升到17,MyBatis Plus的兼容版本也得跟着换,Spring Security的写法更是全部重来。最后我全部迁移回2.7才消停。所以给毕设项目定技术栈时,不要盲目追新,稳定、资料多、你熟悉,这三点比版本新更重要。

第二个坑是前端动态路由死循环。Vue路由守卫里注册路由时,没有加一个标志位判断“是否已经注册过”,结果每次路由跳转都重新调addRoute,导致跳转死循环。算是Vue动态路由的经典陷阱,建议动态路由只注册一次,用一个布尔变量或者判断当前路由是否存在于路由表里来控制。

第三个坑是文件上传的虚拟路径。最初我把幼儿照片传到本地磁盘的upload目录,然后通过WebMvcConfigurer配置映射,本地测试一切正常。但部署到服务器后,同样的代码路径却访问不到图片了,因为生产环境的工作目录和开发环境不一致。这个问题的根源在于路径写死了。引入MinIO之后,彻底摆脱了对本地文件系统的依赖,问题才真正解决。做项目时,凡是涉及路径的配置,都要养成“可配置、不写死”的习惯。

7.3 一个实用的规范习惯

这个项目写到最后,我建议大家建立一个习惯:每一张数据表都要有create_time和update_time字段,每一次删除都尽量用逻辑删除(加一个deleted标志位)。这个习惯来源很简单:毕业设计不是一次性代码,导师可能会要求你加功能、改逻辑。如果表里没有时间字段,日志审计和数据追溯都做不了;如果删数据是物理删除,出问题想恢复数据都没机会。

具体到代码层面,MyBatis Plus的MetaObjectHandler可以实现字段自动填充:新增时自动填create_time,更新时自动填update_time。逻辑删除更简单,在实体类deleted字段上加@TableLogic注解即可。这两件事写起来不难,但带来的维护体验完全不同,属于花小钱办大事的典型操作。

回到这个幼儿园管理系统本身。我自己的体会是,这类项目能不能做出彩,技术栈只是基础,真正拉开差距的是你有没有把业务细节想清楚。比如幼儿调班时历史考勤归属的问题,收费账单自动生成的边界条件,家长端和教师端各自的操作习惯差异,这些东西才是答辩时最有话聊的内容。

最后再分享一个小技巧:前端表格里展示幼儿照片时,如果还没有传头像,不要显示裂图。可以在封装的Image组件里监听error事件,图片加载失败时自动替换成本地默认头像。这个细节很多项目都忽略了,你做了,演示效果就会明显比别人的精致。

如果这个项目你已经做完了,想更进一步,可以试试把考勤数据做成每日统计图表,用Echarts在首页展示各班级的出勤率趋势。技术上并不复杂,但能让整个系统的数据价值感提升一个台阶。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询