管理类系统确实是计算机毕业设计里的常青树,但大多数学生的作品都死在同一个问题上:需求是编的。老师一看就明白你这套系统没有任何人真的会用,自然给不了高分。而"高校资产维修管理系统"这个题目,恰好踩中了高校里真实存在的痛点——宿舍灯管坏了、教室投影仪失灵、实验室设备故障,这些报修和维修流程每天都在发生。就冲这"真实"二字,答辩的时候你就已经赢了一半。
这篇博文写给正在准备毕设的计算机专业同学,以及想系统了解"申联网小程序 + Java 全栈开发"项目完整链路的人。我会从业务建模拆到数据表设计、后端接口实现、小程序端交互实现,再穿插我实际开发中踩过的坑和毕设答辩的实战建议。项目本身的技术栈覆盖了 Spring Boot、MySQL、Redis、微信小程序原生框架、微信订阅消息通知这几个核心点,足够支撑一场像样的答辩。
1. 先把业务边界画清楚:三种角色三条核心链路
很多同学拿到"高校资产维修管理系统"这个题目,第一版设计就把自己绕晕了。造成混乱的根本原因是没有先做角色隔离。我建议你仿照真实高校后勤维修服务的流程,把用户拆成三类:普通师生(报修人)、维修师傅、资产管理员,这直接决定了你的菜单结构、接口权限和数据表关联。
每种角色的核心动线不同:
- 普通师生:用微信小程序扫描资产二维码或手动选择所在楼栋/教室,填写故障描述,提交报修单;后续能查看工单进度、与维修师傅进行简单留言沟通、确认完成并评价。
- 维修师傅:小程序端接收平台推送的派单通知;查看待接/待修工单列表;领取工单后更新状态(维修中/待验收/已完成);填写维修记录、配件耗材和完成备注。
- 资产管理员:对报修单进行审核、派单、驳回;对资产台账进行新增、编辑、报废、转移;查看维修统计报表(按部门/楼栋/类别聚合);管理用户和师傅账号。
有人会问:管理员端要不要单独做一套 Web 后台?我的建议是:如果你的毕设时间充裕且想展示前后端分离能力,可以做一个精简的 Vue3 管理后台;如果时间紧张,小程序里内置管理员角色即可,用 condition 条件渲染(在小程序端控制是否显示管理菜单)完全够用。但注意:如果答辩时老师说"管理员在手机上操作 Excel 式的台账很不方便",你要能接住话,所以至少要在代码里预留一套后台管理接口的 Controller(哪怕前端不展示),这个我们在第 3 章展开讲。
核心业务的状态流转是整个系统的灵魂,必须一开始就界定清楚。你不能让前端页面想怎么改状态就怎么改,以后端为准。我把工单状态设计成这样一个流动链路:
待审核 → 已派单 → 维修中 → 待验收 → 已完成 │ │ │ │ └── 驳回 ┘ └── 退回重派 ──┘对应到后端就是一个状态机。我的做法是在RepairOrder实体里加一个status字段,然后用一个工具类统一做状态迁移校验,而不是把判断逻辑散布在各个 Service 方法里。这样答辩时你可以明确说:"我的业务状态流转是有约束的,不是前端想跳就跳。"
1.1 从报名到归档:一条工单的生命周期
拿一个真实场景走一遍。某学生发现 3 号教学楼 201 教室的投影仪无法开机,他打开微信小程序,扫描资产二维码(二维码内容就是资产编号),填报"投影仪不通电"并拍了两张照片。提交后系统自动带上他的 openid、手机号(如有授权)和资产编号,生成一条状态为"待审核"的工单。
管理员在管理端看到新工单。他拉开工单详情,看到报修时间、资产历史维修记录、故障照片,判断派给从事多媒体设备维护的张师傅,填了个备注"投影仪电源键可能损坏,带一个备用电源板"。系统生成一条"已派单"工单,并通过微信订阅消息通知张师傅。张师傅在小程序上点击"接单",工单状态变为"维修中"。修好后张师傅拍照留证、填写维修详情和耗材清单(电源板 1 块),状态更新为"待验收"。管理员抽空点开看维修照片,点击"确认",工单完成,这条资产的在维状态也随之解除。
这个流程是闭环的。做毕设时,哪怕功能简单,也一定要保证流程闭环,有头有尾,有通知有确认,这是和普通课程设计最大的区别。
2. 数据模型设计:把"资产"和"工单"这两张主表设计扎实
数据表设计决定了你系统能走多远。很多毕设项目表数量不少但关系一团浆糊,就是因为没有用"一句话描述业务关系"的方式来建模。你可以用这句话自检:一个资产可以产生多条报修工单,每条工单关联一个报修人、一个维修师傅、一个审核管理员和一组维修记录。
基于这句话,核心表就出来了。我会重点讲三张表,因为它们最容易出问题。
2.1 资产表:码住台账的底子
资产表asset不只存"名称和位置"就完事了,还应该引入分类维度。我采用的方案是asset_category一级分类表 +asset资产表,一级分类(如"电子设备""家具""实验仪器""建筑设施")挂在资产上,这样统计分析时能按分类聚合。
资产表的核心字段如下:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | bigint | 主键 |
| asset_code | varchar(64) | 资产编号,唯一索引。扫码报修全靠它。 |
| asset_name | varchar(128) | 资产名称,如"戴尔 5430 投影仪" |
| category_id | bigint | 分类 ID |
| location_building | varchar(64) | 所在楼栋,如"3号教学楼" |
| location_room | varchar(64) | 所在房间,如"201" |
| status | tinyint | 0=正常,1=维修中,2=报废,3=丢失 |
| purchase_date | date | 购置日期 |
| price | decimal(10,2) | 资产原值 |
| custodian_name | varchar(64) | 保管人姓名 |
| create_time | datetime | 创建时间 |
| deleted | tinyint | 逻辑删除标记 |
这里我踩过一个坑:资产编号千万不要只写"1001"这种序列号。高校资产是"一物一码",我建议用类似ZC-2024-0001的规则,前三位是资产大类缩写,中间是年份,后面是年度序号。毕业设计哪怕不使用真实规则,也建议做成可配置前缀,答辩时能体现出你对"高校资产编码规范"的了解。
2.2 工单表:别把状态只存一个字符串
工单表repair_order是最核心的表,也是状态机的主体。字段上要包含报修人(student_id)、资产 id、故障描述、图片 URL、管理员/审核人、维修师傅、派单备注、维修结果、维修耗材、各时间节点、评分与评价。重点说一下状态字段的设计:
我有一个习惯,状态字段除了存当前状态的status,还会存一个prev_status,用于状态回退和操作审计。举例:管理员误派单给张师傅,想退回重派,只有知道prev_status是"待审核",才能安全回到上一个状态,而不是一通乱改。
工单表还需要一个fault_type字段,比如"硬件损坏""软件问题""耗材缺失""其他"。这个字段不仅是派单的参考,也是后期统计学生报修最多的故障类型的依据。答辩时你就能说:"下一步可以基于故障类型做智能派单。"
2.3 维修记录表与通知记录表
维修记录表repair_log是工单表的子表,记录每一次师傅的操作行为:接手时间、维修描述、配件使用、完成时间、照片反馈。一条工单有多条日志,审计时很有用。我在实际项目中会在该表加一个log_type(如ASSIGN、START、FINISH、REJECT),便于前端时间线展示。
通知记录表同样重要。微信订阅消息是"一次性订阅",用户授权一次只能推送一次,所以必须记录每一张工单对每个用户发送过哪条模板消息、发送时间、是否成功。不记录的话,就会出现"不可预知的通知丢失",排查起来非常痛苦。这个表其实就是一张普通的日志表,但很多做毕设的人会漏掉。
3. 后端接口设计:Spring Boot 三层架构下的业务落地
后端我推荐 Spring Boot 2.7.x + MyBatis-Plus + MySQL,这套组合能让你快速撸出项目,又能在答辩时熟练讲解"依赖注入、数据库映射、事务管理"。用到的核心依赖就这几个:spring-boot-starter-web、mybatis-plus-boot-starter、mysql-connector-java、lombok。
3.1 登录鉴权:微信登录换取 openid,再发 JWT
这大概是整个项目里第一个真正的技术难点。微信小程序端调用wx.login()拿到临时code,后端拿到code去调微信接口换成openid和session_key。关键点:code只能用一次,且有效期短,所以后端必须在上一步就把openid和会话状态管理好。
我的做法是:
前端 wx.login() 拿 code → 后端 GET https://api.weixin.qq.com/sns/jscode2session appid + secret + code → 拿到 openid + session_key → 在后端查用户表,没有则自动注册(角色默认"普通用户") → 生成 JWT token(存 openid + userId + 角色) → 返回前端,后续请求带 Authorization 头这里有一个常见坑:小程序前端内存存的 token 一旦丢失就又得重新登录,所以我会在用户点击"报修"或"查看工单"时主动检查 token 是否存在,不存在则让用户重新走wx.login。但注意,静默登录是体验最好的方案,因为 UI 上不需要用户做任何操作。
JwtUtil我用的是jjwt库,代码也不复杂:
public String generateToken(Long userId, String role) { return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("role", role) .setExpiration(new Date(System.currentTimeMillis() + 7 * 24 * 3600 * 1000)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }拦截器里解析 token 这一段务必自己亲手写一遍,不要在答辩时说自己只是"调别人的工具类"。老师大概率会问:"如果 token 过期了,你的拦截器怎么办?"你要能回答:"我定义了一个自定义异常,由全局异常处理器返回 401 状态码,前端收到后清理本地 token 并跳转登录页。"
3.2 工单提交流程里的"幂等"设计
学生端最容易出现的问题是重复提交。学生手一抖,连点两次"提交",后端就生成了两条一模一样的工单。这个问题的标准解法是前端提交按钮加 loading 状态,同时后端做幂等校验。我的做法是:在提交报修接口的业务逻辑里,先查同一个用户最近 5 分钟内是否存在所含资产编号相同的"待审核"工单,存在则直接返回"请勿重复提交"。
这样一个低成本的逻辑,就能在答辩时解释为"我考虑了用户误操作场景,用后端逻辑保障了数据一致性",这种细节往往比多写一个 CRUD 接口更有亮点。
3.3 维修进度推送:微信订阅消息的实现要点
微信订阅消息是"一次性订阅",调用requestSubscribeMessage授权后,用户同意一次,你只能发一条。所以设计时就要规划好"哪几个关键节点推给谁":
| 触发动作 | 接收人 | 模板内容建议 |
|---|---|---|
| 报修提交成功 | 报修人 | 工单号、资产名、提交时间、当前状态 |
| 管理员派单 | 维修师傅 | 工单号、故障描述、位置、学生电话 |
| 工单完成 | 报修人 | 工单号、完成说明、评价入口 |
模板消息的后端调用逻辑很简单,就是用HttpClient请求微信的subscribeMessage.send接口。核心参数是touser(用户 openid)、template_id、page(点击跳转路径)、data(模板字段),访问令牌access_token建议缓存一份,因为它有 7200 秒的有效期,不要每个请求都重新获取。
这里有一个细节:必须先取得访问令牌再批量发。我踩过的坑是每发一条就重新获取一次access_token,结果在高峰期被微信限流。正确做法是启动时加载一次,然后在服务里加个定时任务每 100 分钟刷新一次。
3.4 文件上传:图片压缩再传,别塞原图
报修图片、维修图片都涉及文件上传。毕设阶段不建议接云存储,直接在服务器本地保存或者用 FastDFS 都行。但有一个很现实的问题:学生随手拍的图动不动就好几 MB,如果不压缩,后端处理慢、前端加载也慢。
我的做法是在前端wx.chooseMedia后用wx.compressImage做一次压缩(质量设为 80),再走上传接口。后端MultipartFile接收后,会限制类型(jpg/png/jpeg)和大小(5MB 以内),然后按日期目录存储,返回一个 URL。注意,小程序生产环境要求所有 HTTP 请求都走 HTTPS 域名,但本地开发调试时,你可以勾选开发者工具里的"不校验合法域名",这在答辩演示时特别重要——服务器如果部署在实验室局域网里的 Windows 电脑上,前端访问 http://192.168.x.x:8080 必须靠这个勾选才能正常加载。
4. 小程序端核心页面与交互实现
小程序原生开发比 uni-app 更稳妥,原因在于:如果用 uni-app,你还要和编辑器、编译链斗智斗勇;原生小程序就三个文件(wxml、wxss、js、json),没有任何中间层直接跑。如果你熟悉 Vue3 且不排斥 HBuilderX,那用 uni-app 也完全可以。我自己更推荐原生,因为针对"高校资产维修管理系统"这个项目,原生小程序已经足够,而且排查问题时定位更快。
我在实现页面时,最重视以下三块:
4.1 首页与"扫码报修"功能
首页不能只放一个"我的报修"按钮。我设计成:顶部是资产快捷入口,按分类排列;中间是"扫码报修"大按钮;下方是最近 5 条报修进度和公告通知。这样用户第一眼就能看到核心功能入口。
扫码报修用的是微信小程序的wx.scanCode接口,扫出来的内容如果是资产编号,就直接跳转到报修表单页并自动填充资产信息。这里需要处理的一个兼容场景是:没带二维码怎么办?我给表单页设计了一个"选择资产"按钮,弹窗里按楼栋→房间→资产名称三级联动选择。这样既完成了真实使用闭环,又实现了兜底方案。
4.2 报修表单页:组件组合与数据校验
报修表单页字段很多,你要学会拆分。我的方案:
- 资产选择(picker 或扫描)
- 楼栋/房间(自动带出,也可手动选择)
- 故障类型(picker 单选)
- 故障描述(textarea,必填,最长 500 字)
- 图片证据(最多 3 张,支持删除重传)
- 联系电话(自动带出微信绑定手机号,可改)
- 提交按钮 + 勾选"同意维修服务须知"
交互上值得注意两个点:一是在用户提交前做一遍字段校验,不要在用户点了提交之后才报错;二是提交后跳转到"报修详情页"而不是返回首页,这样用户能看到提交成功后的工单号,感知到"真的提交成功了"。
4.3 维修师傅端的任务大厅
维修师傅角色登录后,看到的首页应该是"待接单列表"。列表项要展示:工单号、报修人位置、故障类型、提交时间。因为师傅抢单靠的是列表刷新,所以数据要及时。我在这里做了一个比较朴素但有效的方案:下拉刷新 + 定时器每 30 秒自动刷新一次待接单列表。
师傅点进工单详情,可以看到报修人填写的文字和照片,然后有两个动作:接单 / 转单。接单后进入工作台,填写维修记录时,页面做了引导式表单:维修结果(维修完成/需要更换配件/无法维修)、维修说明、上传维修照片。这比一个空白 textarea 好得多,因为师傅文化水平参差不齐,给结构化输入才能拿到高质量数据。这个小细节在答辩时也可以说:"我根据用户的实际使用习惯,将非结构化文本记录改为结构化表单,提高了数据规范度。"
5. 实战踩坑实录:从登录态到生命周期,五个最常见的坑
这一部分全部来自我实际开发中踩过以后找解决办法的问题,至少能帮你省下三天的调试时间。
5.1 wx.login 在真机上偶尔拿不到 code
开发工具里一切正常,真机上一测试就偶尔白屏。原因主要是用户当前微信未登录,或者网络抖动导致wx.login回调里拿到的 res.code 为空。解决办法是增加重试机制:wx.login失败后延时 500ms 再调一次,最多重试三次,并且每次都要在fail回调里做提示和处理,不要只在success里处理逻辑。
5.2 前端上传图片后,后端收不到文件
这个坑特别隐蔽。小程序wx.uploadFile的name参数必须和后端@RequestParam("file")保持一致,如果写成file变量大小写不一致,后端直接报Required request part 'file' is not present。我踩坑时的排查过程:先打开浏览器开发者工具看 FormData 里的字段名,然后又去后端日志里看multipart请求参数名,最后发现是name="uploadFile"和@RequestParam("file")不一致引起的,改一行就通了。
5.3 Token 过期导致的"白屏"不是真的白屏
小程序端如果请求拦截器里统一判断 401,刷新 token 的异步逻辑必须用 Promise 包装好,否则会出现一个请求进入拦截器后,等待刷新 token 的请求还没回来,原来的请求已经被reject了,进而表现为页面加载一半停住。这个并发场景的解法很简单:维护一个refreshTokenPromise单例,所有 401 请求都 await 同一个刷新 Promise。
5.4 列表页返回后不刷新:onShow 生命周期
学生提交报修单后跳转到详情页,再返回列表页,列表还是旧的,没有把新工单加进去。原因是列表页只监听了onLoad,没有监听onShow。正确做法:每次onShow都重新拉取列表数据,或至少监听一个"页面可见"标志来决定是否刷新。项目里凡是"从 A 页面操作后返回 B 页面,B 页面需要更新"的场景,都必须用onShow来处理。
5.5 耗材字段与统计审计的坑
维修工单设计时,很多同学把"耗材"设计成一个字符串字段,比如"电源板 1 块,螺丝 4 颗"。这样写当然能跑,但一旦想按耗材种类做统计,就完全无法拆解。所以我后来升级为part_id + part_name + part_count三字段,单独建一张repair_order_part关联表。这样管理员查询"本月换了多少块电源板"就是一条 join 语句的事。这个设计点前后差别很大,建议从一开始就用关联表,不要偷懒。
6. 答辩前夜:演示数据、讲解思路与节奏控制
最后一部分直接讲最现实的:答辩怎么讲、演示怎么演、老师最常问什么。你的 PPT 可以漂亮,但比 PPT 更重要的是一个真正能跑起来的 demo 和清晰的解题思路。
6.1 演示数据准备
答辩时最尴尬的是现场数据一片空白,或者数据杂乱。建议你在答辩前一天把系统数据清理一下,往库里灌一套高质量演示数据:“资产台账”里放 20 个正常资产,分布在三四个楼栋;“用户表”里造好学生、师傅、管理员三个测试账号(记得把密码/手机号写在你自己的演示备注里,别当场去翻数据库);“工单表”造 8~10 条,状态涵盖了待审核/已派单/维修中/待验收/已完成/已驳回,时间均匀分布在近两周;再往维修记录表里写 3 条带照片附件的记录。这套数据能让老师看到"历史流程"而非"刚开张的店面"。
6.2 讲解节奏建议(15 分钟标准)
答辩时间一般 10~15 分钟,要在这段时间里讲清楚业务背景、技术栈、数据库设计和高亮技术点。我的建议节奏是:先花 2 分钟讲业务背景和角色划分;3 分钟现场演示学生端提交报修流程(扫码或选择资产→填表→提交);3 分钟演示管理员端派单和师傅端接单完成流程;2 分钟讲技术难点——订阅消息推送和登录鉴权;3 分钟总结项目亮点和改进方向。讲到"订阅消息"时,容易紧张,建议提前在订阅管理页面把授权勾选状态准备好,现场演示时直接展示收到的通知。
6.3 老师爱问的三个问题,你要提前有底
- "你这套系统的并发性能怎么样?"——不要慌,如实说:项目定位是维修管理系统,属于轻量级内部工具,我对核心接口做了 Redis 缓存热点数据、数据库连接池默认 20,并采用分页查询减少压力。同时可以根据后续需求引入消息队列进行请求削峰。这样回答既诚实又展示了思考深度。
- "如果某位同学报修了但一直没人接单怎么办?"——你要引出"超时自动提醒"功能:设计一个定时任务,每 30 分钟扫描一次超过 2 小时仍处于'待审核'或'已派单未接单'状态的工单,提醒管理员介入或重新派单。哪怕你时间紧没实现,你能答出这个逻辑也是一个加分项。
- "整体架构里你觉得最有技术含量的地方是什么?"——不推荐答"登录",这个太通用。推荐答"状态机流转"或"订阅消息的 token 管理",因为你在这里引入了约束和设计,而简单的登录接口大家都写过。
7. 写在最后:这个项目还能怎么延伸
如果你做完了核心流程还学有余力,我建议按以下优先级延伸,这些方向都能在答辩时当作"未来展望",也方便你将来扩充成真实上线的作品集:
- 消息通知体系智能化:由"用户主动订阅"改为"用户可以订阅多类通知",并在通知记录表里增加已读/未读状态,进阶成站内信+订阅消息双通道。
- 管理员 Web 管理后台:用 Vue3 + Element Plus 做一版桌面端管理界面,深色统计卡片展示"本月报修总数、平均处理时长、各楼栋报修排行"。
- 数据分析可视化:用 ECharts 展示资产维修频率 Top 10、各分类故障分布、维修工时趋势。这个方向也是目前高校后勤数字化管理中被提及最多的方向之一,做出来就是增量亮点。
- 扫码到资产的 N 种玩法:目前扫码只能报修,实际上可以把二维码升级为"资产身份码",扫码后能看到资产信息、历史维修记录和保修状态,相当于把查询从"管理后台"移到了"终端用户"手里。
我做这类系统最大的个人体会是:好的全栈项目不在于用了多新的技术,而在于你有没有把一个真实场景里的角色、流程和异常路都走通。你在毕设里解决"重复提交""状态不可回退""通知丢失"这类细节问题的经验,会比背再多八股文都值钱。如果这篇博文能让你少熬两个通宵,把精力花在真正能让你成长的地方,那就很值了。最后分享一个小技巧:把演示用的测试账号和流程脚本贴在电脑便签上——我见过太多同学在答辩台上因为打错一个测试密码而乱了阵脚,你永远不会想成为那个在台上翻数据库找密码的人。