SpringBoot+Vue做宿舍卫生管理系统,三个角色怎么拆?我把整套思路和踩坑过程写透了
宿舍卫生检查这件事,我相信每个经历过集体生活的人都有体会。纸质表格打勾、微信群拍照接龙、月底汇总扯皮,负责检查的同学累得够呛,被检查的同学也觉得评分不透明。前阵子有朋友找我帮忙梳理一个“springboot学生宿舍卫生分配奖惩管理系统”的项目,前后端分离,Vue做界面,SpringBoot做服务,三个角色权限。我从需求拆解、表结构设计、权限控制到核心业务代码,完整走了一遍,顺便也把实际编码过程里踩过的坑整理出来。
这篇东西适合什么人看?两类人。一类是正在做类似课设或毕设的同学,SpringBoot+Vue这套组合在高校项目里出现频率极高,这套系统的权限模型和业务闭环可以当模板套用。另一类是刚接触前后端分离开发、想知道一个“带角色权限的管理系统”从头到尾怎么落地的新手,我会把每一层的设计思路讲清楚,不是只给代码片段。如果你已经具备SpringBoot和Vue的基础语法能力,只差一个完整的项目串联经验,这篇文章基本就是为你准备的。
1. 项目背景与核心需求拆解
1.1 宿舍卫生管理的业务痛点在哪
很多同学以为宿舍卫生管理系统就是个“线上打分表”,这其实是没理解到位。拿我实际接触过的宿舍管理场景来说,真正的痛点有三个。
第一个是分配问题。一个宿舍楼几十间宿舍,卫生检查每周一次,怎么排班、谁检查哪一层、检查标准是否统一,全靠管理员脑子记,换个人就乱套。第二个是透明化问题。评分打完了,学生不知道自己为什么被扣分,申诉无门,久而久之对检查结果产生不信任。第三个是奖惩问题。光扣分没激励,学生没有动力整改;光表扬没记录,学期末评优时没有任何数据支撑。
所以这个系统的价值不在于“把纸质表变成网页”,而是把“分配—检查—评分—申诉—奖惩—统计”这一整条链路数字化。你说它复杂吗?不复杂,但这条链路必须闭环,断一环系统就废了。
1.2 为什么选SpringBoot+Vue这套组合
选型这个问题,很多人会纠结要不要用更“新”的技术,比如微服务、Saas化、容器编排之类的。但说实话,针对这种规模的宿舍管理业务,微服务就是拿大炮打蚊子。SpringBoot的优势在于生态成熟、上手快、部署简单,一个Fat Jar扔服务器上就能跑,搭配MyBatis-Plus操作数据库效率极高,完全够用。
前端选Vue同理,组件化开发、响应式数据绑定、生态丰富。特别是Vue 3搭配Element Plus,做管理后台的表格、表单、弹窗、抽屉这些基础交互,几乎是开箱即用。这套组合的另一个隐性优势是学习成本曲线平缓,遇到问题随便一搜就是大量案例,非常适合第一次做完整项目的开发者。
1.3 三个角色的业务边界
这个系统的核心在于“三个角色”,并不是三个用户登录就算完事,而是要梳理清楚:每个角色能看到什么、能操作什么、不能碰什么。
- 学生:查看卫生任务、查看自己的评分记录、查看奖惩记录、提交申诉、查看宿舍排名。
- 宿管员:卫生任务分配与排班、执行检查并打分、处理学生申诉、维护宿舍与床位信息、发布整改通知。
- 管理员:系统的最高权限,管理所有用户账号、配置评分规则与奖惩规则、查看全校维度的统计报表、审计所有操作日志。
这三个角色从数据层面看是天然隔离的:学生只能碰自己的数据,宿管员能碰自己管辖楼栋的数据,管理员能碰全部数据。落到代码层面,就是两个关键点:登录后的身份识别(认证)和各接口的权限校验(授权)。后面第四章我会专门讲权限这块的落地细节。
2. 三个角色的权限体系与功能设计
2.1 RBAC模型在本项目里的落地方式
权限设计我强烈推荐直接走RBAC(基于角色的访问控制)模型,这是目前后台管理系统最成熟、最容易扩展的方案。核心思想就三张表:用户表、角色表、用户角色关联表。需要细化权限点时再加一张菜单/权限表,用角色权限关联表连接。
在这个项目里,我设计了三级菜单结构。顶级菜单是模块,比如“卫生管理”“评分管理”“奖惩管理”“系统管理”。每个模块下面挂具体功能点,比如“卫生管理”下有“我的任务”“任务分配”“任务日历”三个功能。三个角色登录后渲染出来的菜单完全不同,后端接口也做了对应的权限标识。
菜单的差异化渲染在Vue端用路由守卫实现。简单说,登录成功后后端返回该用户拥有的权限标识列表,前端在动态添加路由时做过滤,没有权限的路由直接不注册。这样即使有人手动输入URL,也会被路由守卫拦截,压根进不去。
2.2 学生端:被管理者的体验设计
学生这个角色最容易做成“查分工具”,但实际上这个群体的使用体验决定了整个系统的口碑。我见过不少系统,学生端就一个分数查询,连为什么扣分都看不到,这种设计注定要被人吐槽。
学生端的核心功能我建议拆成四块:
- 任务查看:展示本周或本月自己宿舍的卫生检查安排,明确检查时间和检查人。学生最反感的就是“突然检查”,提前看到安排至少心里有数。
- 评分详情:分数只是结果,扣分点明细才是关键。要展示每个评分维度的得分和扣分原因,比如“地面不洁扣5分,物品摆放混乱扣3分”。
- 申诉入口:学生对评分有异议时提交申诉,附带文字说明和照片证据。申诉提交后状态要清晰:待处理、已处理、申诉通过、申诉驳回。
- 奖惩记录:这个页面是学生的“荣誉墙”也是“警示牌”。奖励类型的记录如“月度优秀宿舍”要醒目展示,惩罚记录如“连续两周不合格”也要如实展示,附带整改要求。
2.3 宿管员端:高频操作者的效率设计
宿管员是这个系统里操作频率最高的角色,所以交互设计上最重要的一原则是“减少操作步骤”。我举个例子:检查打分时,宿管员可能同时面对七八间宿舍,如果系统要求每打一间宿舍就要点三次页面跳转,宿管员大概率会弃用系统回到纸质表。
宿管员端的高频场景集中在三个页面。第一个是任务分配页,按楼栋、按楼层批量给检查人分配宿舍,支持一键按床位号轮转或者随机分配。第二个是评分录入页,这是核心页面,我建议做成卡片流或表格批量编辑模式,一个页面内完成多间宿舍的打分,支持快捷键切换,分数变化实时保存。第三个是申诉处理页,申诉列表按“待处理”优先排序,支持查看申诉证据图片,通过或驳回都在一个抽屉里完成,不跳页面。
2.4 管理员端:规则制定者的配置中心
管理员不直接参与日常检查,但所有规则都由管理员维护,所以管理端本质上是“配置中心”加“监控中心”。
配置中心包括:用户管理(手动创建学生账号或批量导入)、角色分配(给用户设置宿管员/学生身份)、评分规则配置(设置检查项、单项分值、合格线)、奖惩规则配置(月度分数达到多少分自动奖励,低于多少分自动提醒整改)。监控中心包括:全系统操作日志、各楼栋检查覆盖率、评分分布统计分析、申诉处理时效统计。
这里有一个容易被忽略的点:奖惩规则必须是“可配置”的,而不是写死在代码里。因为不同学校的宿舍管理规范不一样,有的学校侧重安全,有的侧重整洁,规则不配置化,每次规则调整都要改代码重新部署,就太蠢了。
3. 数据模型设计与核心表结构
3.1 核心表结构一览
数据模型是这类系统的地基,表结构设计好了,后面写业务代码就是水到渠成的事。我把核心表按业务域划分成四组。
用户域:用户表(user)、角色表(role)、用户角色关联表(user_role)。 宿舍域:楼栋表(building)、宿舍表(dormitory)、床位表(bed)、学生住宿关系表(student_bed)。 业务域:卫生任务表(clean_task)、评分记录表(score_record)、评分明细表(score_detail)、申诉表(appeal)。 规则域:奖惩记录表(reward_punish)、评分规则表(score_rule)、操作日志表(operation_log)。
这里我特别提醒一下:学生和宿舍的关系不建议直接写死在用户表里。因为实际场景中学生是有可能调宿的,如果你在用户表里加一个dormitory_id字段,调宿时就要去更新用户表,逻辑上不清晰。正确的做法是用一张中间表(student_bed)维护学生当前关联的床位,调宿时更新中间表的有效期即可,历史记录还能保留。
3.2 卫生任务表的设计要点
卫生任务表是整个分配逻辑的核心,我贴一下关键字段:
CREATE TABLE clean_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, building_id BIGINT NOT NULL COMMENT '楼栋ID', dormitory_id BIGINT NOT NULL COMMENT '宿舍ID', inspector_id BIGINT NOT NULL COMMENT '检查人ID(宿管员)', task_date DATE NOT NULL COMMENT '任务日期', task_time_slot VARCHAR(20) NOT NULL COMMENT '时间段: MORNING/AFTERNOON', status TINYINT DEFAULT 0 COMMENT '0待检查 1已检查 2已确认', score_summary DECIMAL(5,1) DEFAULT NULL COMMENT '总分汇总', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_dorm_date (dormitory_id, task_date, task_time_slot) );这个表的两个设计要点值得多说几句。第一个是唯一索引,我用宿舍+日期+时间段做了唯一约束,这能从根本上防止重复分配——同一间宿舍同一天不能被分配两次。第二个是状态机设计,任务从“待检查”到“已检查”再到“已确认”,每一步都有明确的事件触发。比如宿管员录入评分后状态变为“已检查”,管理员或系统定时任务确认后变为“已确认”,此时奖惩规则就可以自动触发了。
3.3 评分与奖励记录的关联设计
评分表我拆成了主表和明细表,原因很简单:一张表也能存,但明细数据是变长的(有的检查项5个,有的8个),拆开更规范。主表存“这间宿舍这次检查得了几分”,明细表存“哪一项扣了多少分、原因是什么”。
CREATE TABLE score_detail ( id BIGINT PRIMARY KEY AUTO_INCREMENT, score_id BIGINT NOT NULL COMMENT '主表ID', rule_item_id BIGINT NOT NULL COMMENT '评分规则项ID', item_name VARCHAR(100) NOT NULL COMMENT '检查项名称', deduct_score DECIMAL(5,1) DEFAULT 0 COMMENT '扣分分值', issue_desc VARCHAR(500) COMMENT '问题描述' ); CREATE TABLE reward_punish ( id BIGINT PRIMARY KEY AUTO_INCREMENT, student_id BIGINT NOT NULL COMMENT '学生ID', dormitory_id BIGINT NOT NULL COMMENT '宿舍ID', type TINYINT NOT NULL COMMENT '1奖励 2惩罚', reason_type VARCHAR(50) COMMENT '触发类型: MONTHLY_EXCELLENT/CONTINUOUS_FAIL', description VARCHAR(500), related_score_id BIGINT COMMENT '关联评分记录ID', status TINYINT DEFAULT 0 COMMENT '0待确认 1已生效', create_time DATETIME DEFAULT CURRENT_TIMESTAMP );奖惩记录这里有一个关键点要吃透:奖励和惩罚不应该是人肉录入的,而应该由规则自动触发。我在服务端写了一个定时任务,每天晚上11点扫描当日的评分数据,自动判断有没有宿舍达到奖励线或触犯惩罚线,生成记录后推送给相关学生。这样的设计让奖惩数据有凭有据,每一笔奖惩记录都能追溯到具体的评分记录,学生查看时也更有说服力。
3.4 前端Vue项目结构规划
前端用Vue 3 + Vite + Pinia + Element Plus,这套组合是当前管理后台的主流搭配。项目结构我按业务模块分包,而不是按技术类型分包:
src/ ├── api/ │ ├── auth.js │ ├── task.js │ ├── score.js │ ├── appeal.js │ └── reward.js ├── stores/ │ ├── user.js │ └── permission.js ├── router/ │ └── index.js ├── views/ │ ├── student/ │ ├── inspector/ │ └── admin/ └── components/这段结构里最有讲究的是views目录按角色分包。同一类业务,不同角色进入看到的视图大同小异,但操作权限完全不同。比如“卫生任务”页面,学生端是只读的“我的任务日历”,宿管员端是带分配功能的“任务管理台”。按角色分包后,每个页面文件职责单一,不会出现一个.vue文件里写满几百行if-else判断角色身份的糟糕情况。
4. 核心流程分析与业务代码实现
4.1 登录认证与权限校验的落地
登录模块我用的是Spring Boot + Spring Security + JWT这套组合。JWT(JSON Web Token)的核心理念是“无状态认证”:用户登录成功后,服务端签发一个包含用户信息和角色标识的Token给前端,前端后续每次请求都在Header里带上这个Token,服务端解析校验通过即放行。
这里要特别讲一下为什么不用传统Session方案。Session方案需要在服务端存储会话状态,对单机部署问题不大,但一旦后续要多实例部署做负载均衡,Session共享就非常麻烦。JWT天然无状态,任何一台服务实例都能独立校验Token,扩展性远好于Session。
权限校验我用了一个很优雅的方式:自定义注解加Spring Security的PreAuthorize。在Controller方法上标注@PreAuthorize("hasRole('ADMIN')"),方法执行前Spring Security会自动检查当前用户的角色,不匹配就返回403。核心代码逻辑是这样的:
@RestController @RequestMapping("/api/task") public class TaskController { @PostMapping("/assign") @PreAuthorize("hasRole('INSPECTOR') or hasRole('ADMIN')") public Result<?> assignTask(@RequestBody AssignTaskVO vo) { // 只有宿管员和管理员能调用分配接口 cleanTaskService.assignTask(vo); return Result.success(); } @GetMapping("/my-tasks") @PreAuthorize("hasRole('STUDENT') or hasRole('INSPECTOR')") public Result<?> myTasks(@RequestParam Long userId) { // 学生查看自己的任务,宿管员查看检查任务列表 return Result.success(cleanTaskService.getMyTasks(userId)); } }4.2 卫生任务分配的三种策略实现
任务分配是宿管员每天都要用的功能,我在实现时做了三种策略:自动轮转、手工指定、随机挂载。
自动轮转是使用频率最高的。思路是:宿管员选择楼栋和时间段后,系统扫描该楼栋下所有宿舍,然后根据当前检查人列表做拼接分配。这里我在代码里做了一个很实用的“全局轮转位置”设计——每次分配后记录轮转位置,下次分配从上次位置继续,而不是每次都从第一个检查人开始。
public void autoAssign(Long buildingId, LocalDate taskDate, String timeSlot) { List<Dormitory> dormitoryList = dormitoryMapper.selectByBuilding(buildingId); List<Inspector> inspectorList = inspectorMapper.selectActiveByBuilding(buildingId); if (inspectorList.isEmpty()) { throw new BusinessException("当前楼栋没有可分配的检查人"); } // 从缓存中读取上次轮转位置,初始为0 int rotateIndex = redisTemplate.opsForValue().get("ROTATE:" + buildingId) == null ? 0 : Integer.parseInt(redisTemplate.opsForValue().get("ROTATE:" + buildingId)); for (Dormitory dorm : dormitoryList) { Inspector inspector = inspectorList.get(rotateIndex % inspectorList.size()); saveTask(dorm.getId(), inspector.getId(), taskDate, timeSlot); rotateIndex++; } // 保存本轮结束后的轮转位置 redisTemplate.opsForValue().set("ROTATE:" + buildingId, String.valueOf(rotateIndex)); }为什么要把轮转位置放在Redis而不是数据库里?因为这是个高频读写、且允许丢失的数据——真正重要的是“尽量均匀分配”,而不是分毫不差地记住上次位置。Redis在性能和实现复杂度之间找到了一个很好的平衡点。
4.3 评分业务的防重复提交设计
评分录入看着简单,真正做的时候最容易出问题的是重复提交。宿管员打完分数,手一抖多点了一下保存按钮,同一间宿舍就生成了两条评分记录。所以我特意在服务端做了幂等校验:评分请求进来后,先去查一下该宿舍在该任务下是否已有“已检查”状态的评分主记录,如果有就直接返回提示,不重复插入。
另一个细节是评分总分怎么算。我实现的评分规则是“一票否决制加扣分制”,比如宿舍内发现违规电器,直接判定为“不合格”,单项最高分拉满也不低于合格线。这个逻辑在代码里要单独处理,不能只做简单的累减。
public ScoreSummary calcScore(List<ScoreItemVO> items) { BigDecimal total = BigDecimal.valueOf(100); for (ScoreItemVO item : items) { if (item.isVetoItem() && item.getDeductScore() > 0) { // 一票否决项直接判为0分 return ScoreSummary.fail(item.getItemName()); } total = total.subtract(item.getDeductScore()); } return ScoreSummary.of(total.max(BigDecimal.ZERO)); }4.4 奖惩规则自动触发的闭环逻辑
奖惩自动触发的实现,我放在一个独立的定时任务类里,每天晚上跑一次。为什么不用实时触发?因为评分录入是分散在一天里的,如果实时触发,可能出现“前一秒评完分拿到了奖励,后一秒另外一条扣分数据把平均分拉到奖励线以下”的矛盾情况。定时任务在当天所有评分都录入完毕后执行,基于的是全量数据,天然避免了这个冲突。
任务逻辑分三步。第一步,扫描当天所有已确认的评分记录,按宿舍维度汇总出当日平均分。第二步,读取奖惩规则配置表,把每条规则依次套用,生成符合条件的奖惩记录。第三步,调用消息推送模块,把奖惩结果通过系统通知发送给学生。
我看到网上很多类似项目是把奖惩做成手动操作,宿管员觉得某个宿舍卫生好就手动加个奖励。这不能说错,但手动操作的问题在于:没有可复用性,没有统一标准,容易凭主观印象。系统自动触发虽然前期配置规则要花些时间,但一旦跑起来,每一条奖惩都有数据支撑,学生心服口服,也能反向督促宿管员规范评分。
4.5 Vue端的动态路由与按钮级权限控制
前端权限控制分两层:路由级和按钮级。路由级就是一个人没有某个菜单的权限时,这个菜单压根不显示,输入URL也会被重定向到403页。按钮级更细,比如同一张评分表上,“删除”按钮只有管理员能看到,宿管员只能看到“录入”和“修改”。
按钮级权限我在Vue里用了一个小小的自定义指令实现,非常方便:
// 注册一个权限校验指令 app.directive('permission', { mounted(el, binding) { const requiredPermission = binding.value; const userPermissions = useUserStore().permissions; if (!userPermissions.includes(requiredPermission)) { el.parentNode.removeChild(el); } } });页面里这样用就完事了:<el-button v-permission="'task:delete'">删除</el-button>。没有这个权限的用户,页面渲染时按钮直接会被移除。这种指令式的写法省去了一大堆v-if判断,代码干净很多。
5. 常见问题排查与避坑实录
5.1 前端请求跨域问题
前后端分离项目第一个拦路虎基本就是跨域。浏览器同源策略下,前端在8080端口,后端在9090端口,直接发请求会被浏览器拦截。我试过两种方案:一种是后端配置CORS过滤器,一种是前端通过Vite代理转发。
我的建议是:开发环境用Vite代理,生产环境用Nginx反向代理,后端不要开CORS。为什么?因为后端开了CORS相当于把跨域校验这件事交给了浏览器,对于没有浏览器的客户端调用(比如移动端、服务间调用)就完全失去了控制力。而通过Nginx配置/api路径转发到后端服务,浏览器看到的始终是同源的,最规范。开发环境的Vite配置也很简单,在vite.config.js里加一段server.proxy就行。
5.2 JWT过期与刷新策略
JWT用起来爽,但过期处理很容易被忽略。如果Token有效期设得太短,用户体验极差——用户登录后可能写一条申诉到一半就被踢下线。设得太长又有安全风险,Token一旦泄露,攻击者会获得很长时间的访问权限。
我采用的方案是“短期Token加长期RefreshToken”双Token机制。AccessToken有效期设为30分钟,RefreshToken有效期设为7天。前端封装axios响应拦截器,收到401时自动用RefreshToken去刷新换新Token,用户全程无感知。
axios.interceptors.response.use( response => response, async error => { if (error.response.status === 401 && !error.config._retry) { error.config._retry = true; const newToken = await refreshTokenRequest(); localStorage.setItem('token', newToken); error.config.headers.Authorization = `Bearer ${newToken}`; return axios(error.config); } return Promise.reject(error); } );5.3 数据库时间字段的时区陷阱
这个坑我印象很深。开发时数据库和本地都在东八区,一切正常。部署到云服务器后,学生反馈“查看任务时间总差8个小时”。排查半天才发现,云服务器默认时区是UTC,而MySQL连接串里没有追加时间参数,导致时间字段读出来被当作UTC时间处理,展示时加上了时区偏移。
解决方案是在JDBC连接串上配上时区参数:jdbc:mysql://localhost:3306/dorm_db?serverTimezone=Asia/Shanghai。同时建议后端统一使用LocalDateTime类型,避免使用老旧的Date类型,前者在Jackson序列化和反序列化时对时区更可控。
5.4 图片上传与文件存储方案
宿舍卫生评分申诉这个场景必然涉及图片,比如学生申诉时上传“打扫后”的照片佐证。图片上传如果用后端接收MultipartFile再存本地磁盘,代码两三行就搞定,但这方案只适合单机小规模场景。
实际部署时我建议用对象存储服务,无论是云服务商提供的OSS还是自建的MinIO都行。核心原因是:应用服务和图片文件不应该耦合在一起,否则将来应用做多实例部署时,图片散落在不同机器上,就会出现“明明上传成功了,另一台机器却访问不到”的问题。对象存储天然是中心化的,所有实例读写同一个存储桶,省心太多。
上传功能的接口设计也有讲究。前端先向后端请求一个预签名上传地址,再直传对象存储,整个上传过程根本不过后端应用服务器,后端压力小很多。这个方案的代码量不大,但架构思想上完全不是一回事。
5.5 表格大数据量渲染的优化
卫生任务列表如果按宿舍楼去查,一次可能返回几百条记录,前端表格一次性渲染几百行在Element Plus下基本没问题。但如果再加上自动轮转分配后,宿管员要看的是一个学期的任务日历,数据量就是几千条了,表格会明显卡顿。
我的处理方式是后端接口强制分页,前端表格开启远程排序和远程过滤,而不是把所有数据一把梭拖到前端再本地排序。Element Plus的el-table自带remote-sort属性,配合后端排序参数,用户点表头排序时重新向后端请求数据,体验非常流畅。
如果你确实需要在前端展示大量只读数据,并且不希望频繁请求后端,可以考虑加上虚拟滚动组件。Vue Virtual Scroller这类库只渲染可视区域内的行,几千行数据也能丝滑滚动。但要注意,虚拟滚动和自动行高、展开行这类功能会有兼容性问题,用之前先确认你的表格功能复杂度。
5.6 宿舍调宿场景的数据一致性处理
最后一个坑来自业务逻辑层面:学生在学期中途调宿舍了。如果只更新student_bed表的床位关联,看起来很简单,但历史评分和奖惩记录怎么办?按当时的宿舍归属展示,还是按现在的宿舍归属展示?
我的建议是双轨制。历史评分明细永远归属到当时的宿舍,不做迁移;而统计报表(比如月度宿舍平均分)默认按“当前宿舍”聚合。这样做的理由是:学生调宿后,新宿舍的卫生状态与学生无关,如果把他旧宿舍的历史低分带到新宿舍,会严重打击调宿生的积极性。在代码里实现时,就是在聚合查询时用student_bed表关联到当前宿舍,而明细查询时直接用score_record里的dormitory_id。
6. 项目实施过程与开发节奏建议
6.1 从需求到上线的时间线规划
最后聊聊我做这类项目时的时间安排,给正在规划的同学一个参考。一个完整且质量不错的三角色宿舍卫生管理系统,一个人开发大概是这个节奏:
- 第1-2天:需求梳理和数据库设计。这个阶段最枯燥但也最重要,建议用工具把表结构图画清楚,字段名、类型、注释都标注好,后面写代码时能省大量时间。
- 第3-6天:后端基础框架搭建加核心模块开发。按“认证—用户—楼栋宿舍—任务分配—评分—奖惩—申诉—统计”的依赖顺序来写,前一个模块做完再进入下一个,不要平行推进。
- 第7-10天:前端页面开发。先搭登录页和主框架,再按角色分包开发页面。学生端最简单放最后做,宿管员端最复杂建议先做,因为它的交互逻辑能反过来验证后端接口设计是否顺手。
- 第11天:前后端联调。这一步不要到了这个阶段才做,建议开发后端时每写完一个接口就立刻写一份接口文档,并用在线工具测试过,联调就会快很多。
- 第12-14天:部署上线和测试。至少找三个不同角色身份的同学帮忙做一轮真实业务验证,你会发现很多想不到的问题:权限漏配、时间显示不对、操作流程不顺畅等等。
6.2 数据库初始化数据与演示账号的准备工作
系统做完后,展示效果很重要。很多项目死在演示环节是因为数据库里空空如也,登录进去没有数据可看,评委或老师根本感受不到系统完整功能。我习惯写一个init_data.sql初始化脚本,预置三部分数据。
第一部分是基础数据:两栋楼、每栋楼三层、每层四间宿舍、每间宿舍四张床位,再配二十个学生账号。第二部分是业务数据:过去三周的卫生任务和评分记录,分数要有高有低,申诉记录至少准备一条待处理的和一条已处理的。第三部分是规则数据:评分规则和奖惩规则预先激活。这样直播间演示时,登录进去看到的是一个“活”的系统,而不是空壳。
6.3 关于项目扩展方向的一点思考
这套系统的架构是有扩展空间的。举个例子,如果学校想把检查从“人来人往参观打分”升级为“扫码实时打分”,可以基于现有表结构增加一个二维码标识字段,每间宿舍门口贴一个绑定宿舍ID的二维码,宿管员扫码后手机浏览器打开评分页,数据一样落到score_record表。如果想把奖惩结果接入到学校的综合素质评价体系,只需要在reward_punish表增加一个external_push_status字段,定时任务把新记录推送到外部系统API即可。
个人在实际开发中最大的体会是:这类管理系统功能看似零散,但核心还是“流程闭环”四个字。分配、执行、审核、反馈、奖励,每一步都要有状态流转、有数据留存、有明确负责人。把这条主链路打通,系统就算立住了,剩下的都是加功能而已。