在医院场景里,设备报修这件事,远没有想象中那么简单。一台心电监护仪坏了,护士要先找设备科电话,报完型号、故障现象,再等工程师下来判断,中间还得手填一张纸质报修单,后续进度基本靠问。这样的情况多了,设备科自己也很头疼,台账要补、记录要查、维修响应快慢全凭印象。我做了一套基于SpringBoot+微信小程序的医院医疗设备管理系统,把报修、接单、维修、验收、台账归档全部搬到线上,科室人员扫设备上的二维码就能发起报修,工程师在微信小程序里直接接单和填写维修记录,设备科后台查看统计。这套系统面向两类人:一是真正想解决医护设备管理繁琐问题的医院内部信息化场景,二是正在忙计算机毕设、需要一个完整前后端项目做参考和二次开发的同学。如果你正好拿到类似题目,这篇内容能帮你少踩很多坑,把项目从“能跑”做成“能答辩、能演示、能讲清楚”。
1. 项目的起点:医院设备管理到底在管什么
1.1 从医院现场梳理出的三个核心痛点
做任何系统前,我最讨厌一上来就画表建库。这次我先去医院设备科待了大半天,看他们日常怎么处理报修,核心痛点其实就三条。
第一,报修入口分散。科室护士遇到设备故障,有人打电话,有人发微信群,有人干脆把设备推到走廊等人发现。电话报修最大的问题是没有留痕,过了三个月再追问“这台机器到底修没修过”,没人说得清。微信群报修信息会被聊天刷掉,设备科要自己翻聊天记录维护Excel,活生生多出很多重复劳动。
第二,状态不透明。报修单交上去之后,护士不知道工程师什么时候来,工程师不知道设备在哪个楼层哪个房间,设备科不知道现在有多少单子积压、哪些超时了。整个流程像个黑盒,所有人都只能靠催。
第三,设备台账和维修记录脱节。设备买了多少年、使用科室在哪、上次保养是什么时候、换过什么配件,这些问题平时没人关心,等设备科要申报采购、做资产盘点时,才发现资料根本对不上。维修如果没记录,设备的全生命周期管理就是一句空话。
所以这套系统在设计时,我没有按常规思路先把“设备信息管理”做成堆增删改查的模块,而是把所有功能都围绕“报修单”这个核心流转对象来展开。设备信息、科室信息、用户信息都是报修单的上下文,修好之后自然沉淀成维修记录,维修记录反过来更新设备状态,这样就形成了完整闭环。
1.2 参与系统的三类角色与核心链路
这套微信医院医疗设备管理系统里,一共设计了三个端。
科室报修人员,通常是护士长或科室设备管理员,他们负责扫码发起报修,上传故障照片,查看维修进度,最后参与验收。维修工程师,负责查看待接单列表、抢单或由设备科派单,维修时填写故障原因、维修措施,结束后上传维修照片提交验收。设备科管理员,拥有最高权限,可以管理设备台账、维护科室体系、指派工程师、关闭异常工单,并查看各类统计报表。
三类角色在微信小程序里面对的功能界面不同,对应后端接口的权限控制也不同,具体后面会讲。这里先把最核心的一条链路画出来:扫码或者手工选择设备,填写故障描述和图片,生成一张报修单;工程师接单后状态变成维修中,等工程师提交“维修完成”,系统生成待验收状态;科室人员确认没问题,点击验收通过,整张工单结束并归档。管理员随时可以把流程反向操作,比如发现工单信息填错了,或者设备已经报废不能再修,直接强制关闭。
1.3 需求边界:先想清楚不做什么
毕设项目最怕什么?最怕“需求失控”。我见过太多同学一上来就想做设备定位、温湿度监控、配件库存预警、AR眼镜维修指导,结果三个月做出来一个半成品。这里我给自己定了一条规矩:一个报修单从发起到归档的闭环,必须完整体验流畅;闭环之外的功能,统统往后排。
基于这个原则,我做了三处取舍。
第一,不做微信支付。有人觉得可以做一个维修费用结算模块,但小程序的医疗类目本身对支付场景审核很严格,而且医院设备的维修费用通常是科室间内部结算,走的是线下流程。为了一个毕设去撞支付审核的墙,不值。
第二,不做过于复杂的审批流。报修单走的是状态机,不是完整的工作流引擎。SpringBoot整合Flowable确实可以做复杂流程,但引入引擎意味着额外的表、模型和资源文件,对一个报修场景来说属于杀鸡用牛刀。后面我会专门说状态机的设计。
第三,不做设备的实时联网监控。医疗设备本身有通信协议,但不同厂商协议差异巨大,统一采集需要硬件网关和大量适配,这超出了信息管理系统的范畴。系统里有“保养周期”字段,定时生成保养提醒就够了,这已经能覆盖设备科对“预防性维护”的核心诉求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体方案架构与技术选型,为什么这样搭
2.1 SpringBoot版本选择一个容易被忽略的大坑
项目后端采用SpringBoot,这个基本没什么悬念,Java技术栈稳定、生态成熟,答辩时老师也熟悉。但在版本选择上,我强烈建议不要追新,我当时用的是SpringBoot 2.7.18,配合JDK 1.8。
为什么不用SpringBoot 3.x?很多同学搜索时看到“springboot版本太高”这个话题,以为只要换版本就行,其实背后的坑非常实际:SpringBoot 3.0开始强制要求JDK 17,包名从javax.servlet迁移到了jakarta.servlet,相当一部分老教程、旧版本的第三方starter都会出现兼容问题。毕设阶段时间紧张,没有必要为“用最新版本”这个执念多花精力调兼容性。
具体版本搭配如下:
| 组件 | 版本 | 说明 |
|---|---|---|
| JDK | 1.8 | 稳定、兼容性好,几乎所有云服务器都能跑 |
| SpringBoot | 2.7.18 | 2.x系列最后一个维护版本 |
| MyBatis-Plus | 3.5.3 | 简化CRUD,分页和逻辑删除好用 |
| MySQL | 5.7或8.0 | 建议8.0,字符集直接utf8mb4 |
| Sa-Token或JWT | jjwt 0.9.1 | 小程序登录token签发校验 |
| Swagger | knife4j 3.0.3 | 生成接口文档,答辩演示加分 |
顺带提一个让项目显得很精致的小操作:SpringBoot启动时那行默认的Spring Banner很单调,网上有banner生成器,把想要的项目名生成字符画粘到resources/banner.txt里。这个虽然不影响功能,但演示时大屏幕上整屏打印一个“MedicalDevice System”的自定义Banner,老师会觉得你做项目确实用心了。
2.2 单体分层架构与统一返回封装的必要性
这套系统没有拆微服务,也不需要拆。我心里很清楚,一个医院内部科室规模的管理系统,单体能抗住的并发量远超演示环境的需求。与其引入Nacos、Feign一堆组件让人手忙脚乱,不如把单体分层写清楚,代码结构本身就是答辩素材。
后端项目结构我按这个分包:controller负责接收小程序请求,service写业务逻辑,mapper对应MyBatis-Plus的数据访问,entity与数据库表映射,dto承载前端入参,vo承载返回数据。模块上按业务划分成auth、user、device、repair、statistics、message等几个包,不同模块之间通过service方法互相调用,不直接跨层访问mapper。
有一个细节值得强调:前端小程序和后端交互,最好统一返回结构。我自定义了一个Result类,包含code、message、data三个字段,然后所有controller方法都返回Result类型。成功是Result.success(data),失败是Result.error("xxx")。不要小看这个规范,它让后续小程序端处理响应变得非常省心。前端拿到res.data.code等于200就取data,否则弹message,不需要针对每个接口单独判断success字段到底叫什么。
2.3 数据库设计:设备表与报修单表到底要哪些字段
数据库是这次项目设计中的重点,我先后改了三版才定下来。核心原则是:报修单足够轻,设备台账足够完整。
先看设备表(device)的核心字段:device_code设备编号、device_name设备名称、model型号、manufacturer厂商、device_status状态、department_id所属科室、purchase_date购置日期、maintenance_cycle保养周期、last_maintenance_date上次保养日期、qrcode_url二维码地址。这里device_code我设计成医院内部自定义编码,比如ICU-ECG-001这种格式,通过代码校验唯一性,扫码内容也是这个编号。设备状态字段使用字典值存储,1表示正常,2表示维修中,3表示已报废。这个状态不是用户手动改的,而是根据报修单流程自动更新:报修单进入维修中,设备状态自动改成维修中;工单验收完成,设备状态恢复为正常。
报修单表(repair_order)需要重点设计的是状态字段和业务辅助字段。
| 字段 | 类型 | 含义 |
|---|---|---|
| order_no | varchar | 报修单号,规则建议RR+yyyyMMdd+四位流水 |
| device_code | varchar | 冗余存储设备编号 |
| device_name | varchar | 冗余存设备名称,方便列表展示 |
| report_department_id | bigint | 报修科室ID |
| report_user_id | bigint | 报修人ID |
| description | text | 故障描述 |
| images | varchar | 图片URL,多个用逗号分隔 |
| problem_type | varchar | 故障类型,区分电气、机械、软件等 |
| status | tinyint | 工单状态,10-待接单,20-待维修,30-维修中,40-待验收,50-已完成,60-已关闭 |
| assignee_id | bigint | 指派的工程师ID |
| repair_result | varchar | 维修措施说明 |
| finish_time | datetime | 完成时间 |
冗余字段这件事很多人不理解,觉得设备名可以join查出来,为什么还要存在报修单里?原因在于报修单列表页要展示历史数据,而设备表里的名称和科室可能因为重复操作变动。报修单一旦生成,就应该记录当时设备归属的“快照”,这样半年后统计报表才准确。这个细节在答辩时主动讲出来,老师会认为你真的想过数据一致性。
3. SpringBoot后端核心模块拆解:从登录到报修状态机
3.1 微信小程序登录:wx.login如何与后端JWT对接
很多初学小程序的同学还在沿用老的调整方式,页面放一个“获取用户信息”按钮,点击后拿头像昵称发后端。这个思路在现在完全跑不通,微信早已修改规则,getUserInfo接口返回的只是一套默认灰色头像和“微信用户”昵称,真正的用户信息必须配合“头像昵称填写能力”让用户手动选头像、手动输入昵称。
医院设备管理系统并不需要真实的微信昵称和头像,所以推荐的做法是静默登录加openid识别。前端wx.login获取临时code,传给后端接口,后端拿code去微信的jscode2session接口换取openid和session_key,再用openid去用户表匹配,如果查不到就自动注册一个新用户,最后签发一个JWT返回给前端。
对应的后端登录接口核心代码大致长这样:
java复制@PostMapping("/auth/login")
public Result login(@RequestBody LoginRequest req) {
String code = req.getCode();
// 请求微信接口,实际开发中建议用OkHttp或RestTemplate封装
WxSession session = wxService.code2Session(code);
String openid = session.getOpenid();
SystemUser user = userService.findByOpenid(openid);
if (user == null) {
user = userService.registerByOpenid(openid, req.getRole());
}
String token = JwtUtil.createToken(user.getId(), user.getRole());
return Result.success(new LoginVO(token, user));
}
JWT里我塞了userId和role两个声明,后续拦截器解析token时可以直接判断角色权限,省去每次查数据库。token有效期我设置为7天,因为小程序用户不会频繁退出,七天过期后前端拦截到401再引导用户重新登录就行。在需要身份的接口上,后端通过@RequestHeader("Authorization")取出token并解析。同时要注意,Swagger的接口文档路径属于放行范围,不然配置了JWT拦截器之后,连knife4j的页面都打不开。
3.2 报修工单状态机:防止业务状态乱跳的关键实现
报修单状态是整个系统的灵魂。我的做法不是写一堆if else判断,而是在service层把所有状态流转方法收敛起来。
系统中的状态一共六个:待接单、待维修、维修中、待验收、已完成、已关闭。待接单指向的是刚刚创建;待维修指的是工程师已接,但还没有到场;维修中是工程师正在检修,这个状态是为了让护士端能看到“维修进行中”的直观提示;待验收表示维修完成,等待科室确认;已完成是科室点验收通过;已关闭是管理员主动终止。
状态流转表如下:
| 当前状态 | 操作 | 目标状态 | 操作角色 |
|---|---|---|---|
| 待接单 | 接单 | 待维修 | 工程师 |
| 待维修 | 到场维修 | 维修中 | 工程师 |
| 维修中 | 提交完成 | 待验收 | 工程师 |
| 待验收 | 验收通过 | 已完成 | 报修人/管理员 |
| 任意状态 | 关闭工单 | 已关闭 | 管理员 |
在acceptOrder方法中,我先校验工单状态必须等于待接单,再校验当前登录用户的角色是工程师,然后判断是否已经指派给自己或自己主动点击接单。这些校验全部通过才执行update语句。关键点在于把状态校验和业务操作放在同一个事务方法里,并且给数据库repair_order表的状态字段加上乐观锁机制,防止管理员和工程师同时操作时覆盖数据。
为什么要费这么多功夫设计状态机而不是让前端随便改状态?因为如果状态字段能被随意赋值,报修单就会变成一张“谁都能改的纸条”,统计报表全是脏数据。我在代码里严格控制每个状态转移的原子性,顺带也给验收加了一个兜底:如果报修人超过三天未验收,系统自动发订阅消息催一次,仍然不处理则设备科可以代验收。这些边缘情况在答辩追问时是很加分的,说明你考虑到了真实业务中的异常流程。
3.3 设备二维码与图片上传提交:两个容易翻车的接口
设备二维码生成逻辑很简单:后端根据设备编号生成QR码图片,格式约定为MEDIC-DEVICE:CODE=ICU-ECG-001。小程序端使用相机扫码后截取CODE的值,调设备详情接口直接把报修单的设备信息带出来,不用人工搜索。
图片上传是另一个容易翻车的点。科室报修时通常要拍故障设备的照片,照片大小两三MB很常见。SpringBoot里文件上传必须先做配置:
yaml复制spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
不配这个限制,图片稍微大一点就直接报MaxUploadSizeExceededException。上传成功后,我统一把文件保存到服务器本地的/usr/local/medical/upload目录,同时增加一个WebMvcConfigurer实现静态资源映射,把/upload/**路径映射到磁盘目录。因为不同的SpringBoot版本对WebMvc配置方式略有差异,这个资源映射在Spring Boot 2.7里用addResourceHandlers即可。很多同学图片上传成功后返回的是本地路径,但在小程序里无法通过URL加载,多半就是少了这步映射。
3.4 为什么不引入Flowable:两个方案的真实对比
SpringBoot整合Flowable这次没有用到,但我在技术选型时确实做了对比。医院报修不是一条需要会签、分支、条件网关的长流程,它更像一个“接力棒”:报修人传给工程师,工程师传给验收人,每个人只需要做一件事,然后交给下一个角色。用状态机就够,而且状态机代码量少、逻辑直观,出问题好排查。
Flowable的价值在于流程可以动态配置、支持BPMN图形化建模、可以处理复杂的会签或一票否决。但代价是需要初始化几十张ACT_开头的流程引擎表,还要维护流程定义文件,对服务器资源的占用和开发调试的心智负担都更高。如果老师追问“为什么不引入工作流引擎”,你可以回答:报修流程是固定链路,无分支会签,状态机的性能和可维护性更好;后续如果扩展到设备申购审批、报废审批这些需要多人会签的场景,再引入Flowable做引擎也不迟。这个说法既体现了你有全局认知,又说明了技术选型的合理性。
3.5 定时任务驱动:保养提醒与超时工单统计
设备科的日常工作中,保养管理和报修是平行的两条线。系统里我用Spring自带的@Scheduled注解做了两个定时任务:一个是每天早上八点扫描设备表,凡是next_maintenance_date小于当前日期且设备状态正常的,自动生成一条保养提醒,并调用订阅消息给指定工程师发送提醒;另一个是扫描报修单,超过48小时没有工程师接单的工单,自动把order等级标记为“超时”,同时给设备科管理员的待办列表里推一条记录。
Scheduled的cron配置很简单,例如@Scheduled(cron = "0 0 8 * * ?")表示每天早上八点执行。生产环境要注意把定时任务的开关做成配置项,避免多人联调时误触发大批消息。我是加了一个application.yml里的custom.scheduler-enabled开关,本地调试时关掉。
4. 微信小程序端怎么把“报修”做顺手
4.1 页面结构规划与自定义TabBar
小程序前端我用的是微信原生开发,没有引入uni-app。原因很直接:原生调试最省心,不存在HBuilderX中转导致的小程序ID不对、开发者工具提示不是开发者等问题。如果你是想做一套通用的源码发布到多端,那么uni-app有价值;但医院设备管理是典型的内部工具,用户就是医院的医生护士工程师,原生足够。
小程序端页面主体包括:登录页、首页、扫码页、报修提交页、工单列表页、工单详情页、设备列表页、我的页面、管理员后台里的统计页。
原生小程序默认的tabBar只能配置两到五个固定页面。但在这套系统里,科室人员登录应该看到“首页、报修、我的”,工程师登录应该看到“工单、我的”,管理员还要额外看到“数据看板”。如果角色不同却指向同一个固定tabBar,功能入口会非常混乱。我采用自定义tabBar的方式:在app.json里配置“custom:true”,再自定义tabBar组件,渲染时根据全局变量里的role动态决定显示哪几个tab。这里要注意,自定义tabBar要求组件的list至少包含两个tab,并且每个页面的window配置里也需要同步配置对应项,否则真机上会出现页面底部空白。
4.2 科室快速报修:表单填写与图片处理的最佳顺序
报修提交页是使用频率最高的页面。字段不用多,核心几个:设备名称、设备编号、故障类型、详细描述、图片。设备信息通过扫码自动带出,用户只需要填写故障类型和描述。
图片部分踩过一个很实在的坑:如果先选择图片、上传到服务器拿到URL,再和其他表单字段一起提交,万一用户在填写描述时退出页面,服务器上就多了一张没有任何业务记录的僵尸图片。我当时采用的方案是先让用户选择图片,本地保存临时路径,在点击“提交报修”时,把图片和表单信息同时提交到后端。后端先接收上传图片,拿到持久化URL后再创建报修单,保证数据和图片要么都成功,要么都失败,基本不会产生脏数据。
图片组件用wx.chooseMedia,支持拍照和从相册选,设置count为3,最多上传三张。上传时用wx.uploadFile循环上传,注意uploadFile的formData不要放中文对象,需要单独把参数拼成字符串,否则偶尔会出现中文乱码的情况。
4.3 订阅消息:报修进度主动触达的三种状态
医院里没有人会闲到一直打开小程序刷新工单状态,所以状态变更的通知非常重要。微信小程序提供的是订阅消息能力,和公众号模板消息不是一回事。简单理解:订阅消息是一次性授权,用户每点一次允许,小程序才能给他发一条模板消息,而且不同的模板ID要分别授权。
这套系统里我申请了三个模板:报修提交成功、工程师接单提醒、维修完成待验收。用户在提交报修后,会弹窗请求授权“报修进度通知”;工程师接单后,给报修人推送接单提醒;工程师提交完成后,再次推送提醒报修人验收。
实现时最容易出错的是在小程序端还没授权时就调用订阅消息的发送接口,后端必定报43101错误。正确的逻辑顺序是:前端先调用wx.requestSubscribeMessage选中模板,拿到“accept”的授权结果后,再调后端的“提交报修”接口,后端在同一事务里保存工单并调用订阅消息推送。因为微信的订单策略是用户点击一次授权对应一条消息,如果用户连续提交两单但只授权一次,那第二单推送会失败,这属于正常现象,后端要捕获异常避免主流程报错。
4.4 工程师工作台:接单、到场、完工的现场操作
工程师角色的工作台讲究“快”。列表页按状态筛选出待接单的工单,每张卡片显示设备名称、报修科室、故障描述、故障类型、等待时长。等待时长超过2小时的卡片在界面上做特殊高亮,这样工程师不需要管理员催促就知道应该优先处理积压单。
真正的接单操作要防误触。工程师点击“接单”按钮后,弹窗展示设备具体所在地点和报修科室,再次确认后才真正调用接单接口。维修过程中工程师需要维护两个关键动作:到场维修和提交完工。到场操作是指工程师到达现场开始检修,状态从待维修变为维修中,这样护士端能看到“工程师在路上”的确定性信息。完工时工程师需要填写维修措施并上传成片照片,后端会自动记录操作人ID和时间,生成维修记录。
4.5 普通列表页提高人效的几个细节
除了核心报修流程,小程序里还有不少使用细节,总结下来比较有价值的有三项。
第一,报修历史列表必须支持下拉刷新和触底分页。原生小程序的onReachBottom触发条件是滚动到底部,分页参数传pageNum和pageSize,后端返回总条数和当前页数据,前端用总条数判断还有没有下一页。第二,故障类型用单选按钮组还是做放射性标签?我的建议是使用固定枚举值的单选按钮组,故障类型控制在“电源故障、按键失灵、屏幕显示异常、信号连接异常、机械结构问题、其他”这六类里,方便后续统计。第三,状态筛选栏要固定在页面顶部,医院里使用场景多在移动中,单手操作时吸顶的筛选栏比下拉找筛选入口顺手很多。
5. 联调部署与微信公众平台上线细节
5.1 本机联调时快速解决域名校验和网络访问
小程序开发阶段最常见的问题是“不在以下request合法域名列表中”。这是因为微信默认要求所有网络请求的域名是HTTPS且在小程序后台配置过。处理思路分两层。
如果是对接本地后端,只需在微信开发者工具右上角“详情-本地设置”里勾选“不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书”,就能直接访问http://localhost:8080。但如果要用真机预览,问题就来了,真机不能访问你电脑的localhost,必须把接口地址改成后端服务器的局域网IP,比如http://192.168.1.101:8080。手机和电脑连同一个Wi-Fi后能通。需要注意,开发工具的“不校验合法域名”选项只对模拟器生效,真机上还是要靠把地址加入后台的request合法域名列表,或者临时使用“真机调试2.0”配合本机代理。
后端本机调试时也要把服务的监听地址配成0.0.0.0,否则即使局域网IP是对的也连不上。这个小问题排查了我一个下午,后来才发现SpringBoot默认只监听localhost,加了server.address=0.0.0.0之后手机立刻能访问了。
5.2 从体验版到正式发布:小程序类目审核的认知准备
如果这个项目只是用于毕业设计或医院内部试用,一般只需要在微信公众平台把成员添加为体验成员,扫体验版二维码即可使用,不需要提审发布。如果真要上架正式版,需要面对现实问题:医疗相关的小程序在微信公众平台的类目划分里通常属于“医疗-医疗器械信息展示”等范围,个人主体无法申请,需要企业主体并且提供对应的资质文件,比如医疗器械经营许可证等。医院内部系统一般以企业内部工具的方式申请,但流程依然比普通工具类严格。
毕设答辩阶段,切到体验版演示是足够专业的操作,入口在微信公众平台“管理-版本管理”,提交代码后生成体验版二维码,扫码即可打开。现场演示开始前,务必确认已经用体验者微信号登录过一次,否则临时扫码会卡在登录页。
5.3 服务器部署:systemd守护与Nginx反向代理
生产环境我选择了一台轻量云服务器部署,配置不需要高,2核4G跑SpringBoot和MySQL完全没有压力。部署时的几个要点这里直接列出来。
后端打成jar包后,不要直接java -jar放后台裸跑,要注册成systemd服务,这样进程崩溃后能自动重启。具体的service文件是:ExecStart那一行指向java -jar /opt/medical/medical-system.jar,Restart=always,WantedBy=multi-user.target。启动脚本准备好后,systemctl daemon-reload,再systemctl start medical-system即可。
微信小程序正式环境强制要求HTTPS,所以域名必须有备案,并且在前端服务器用Nginx做反向代理,把443端口的HTTPS证书流量代理到本机8080端口。Nginx的配置核心代码就三行:ssl_certificate配置证书文件,ssl_certificate_key配置私钥,proxy_pass http://127.0.0.1:8080。配置好后用nginx -t检查语法,重启后通过https访问测试。
前端的request baseUrl要区分开发环境和线上环境,我习惯在app.js里根据环境判断,开发时用局域网IP,发布体验版时手动改成正式域名。后端上传的文件路径和Nginx的静态资源配置也要对应,我直接在Nginx里把/upload路径映射到服务器磁盘目录,避免后端自己又做一层资源映射造成路径混乱。
6. 常见报错与排查经验实录:真机调试最容易踩的坑
6.1 高频问题速查
开发这套系统的过程中,各种异常基本都是网上能搜到的经典问题,但它们往往集合在一起出现。下面这些内容是按我实际排查经验总结的一个实用速查表,很多问题不是代码逻辑写错了,而是环境或配置层面的坑。
| 现象 | 直接原因 | 解决办法 |
|---|---|---|
| 小程序请求后端返回401 | token失效或没有把token放进header | 后端接口统一在拦截器检查header里的Authorization字段,前端wx.request封装时统一加上token |
| 上传图片后返回路径无法访问 | 没有配置静态资源映射或Nginx未代理upload目录 | 后端增加addResourceHandlers映射系统磁盘路径,Nginx中把/upload/路径单独location代理到同一目录 |
| 真机上无法请求本地后端 | 手机访问localhost指向手机自身 | 改成局域网IP,后端绑定server.address=0.0.0.0,关闭电脑防火墙 |
| 订阅消息推送报43101 | 用户未授权或授权次数不足 | 先调用wx.requestSubscribeMessage获取授权,再调后端接口发送,用一个授权对应一条消息 |
| iOS上时间显示NaN | iOS的Date不支持“2024-01-01 10:00:00”格式 | 把字符串中的“-”替换成“/”,即new Date(“2024/01/01 10:00:00”) |
| 软键盘弹出遮挡表单输入 | 页面没有调整位置 | 页面配置adjust-position,同时根节点加一个scroll-into-view绑定当前输入框的id |
| swiper里嵌套video出现全屏错位 | 原生组件层级关系问题 | 不要让video直接放在swiper-item中,改用页面轮播跳转,或使用同层渲染后的cover-view处理 |
| 小程序选择图片后报错临时路径不存在 | 临时文件被微信回收 | 图片选择完成后立即调用wx.uploadFile,或者把selected临时路径先存到全局变量,不跨页面保存 |
6.2 小程序跳转小程序:公众平台上的两步操作
系统里我预留了一个跳转入口,从设备管理小程序跳到一个通用的素材库小程序。这个功能在需求描述里容易忽略,但一旦涉及,要注意微信要求跳转前必须报备。如果你在公众平台上的操作没做完,运行时就会报“跳转目标应用未配置”之类的错误。
处理动作分两步进行:第一步,在发起跳转的小程序后台“设置-第三方设置-小程序跳转”中添加目标小程序的AppID;第二步,在目标小程序后台也要进行反向配置,双方配置生效后,才能使用wx.navigateToMiniProgram。这个配置往往要等几分钟缓存生效,测试跳转时如果失败,不要怀疑代码,先去检查两边后台配置是否都成功。
6.3 蓝牙打印拓展:为现场打印设备标识加分
不是核心功能但如果想演示时多一点亮点,可以加蓝牙打印。医院设备需要打印带二维码的铭牌或巡检标签,工程师可以连接蓝牙热敏打印机,把设备编号和二维码打印出来贴到设备上。
小程序端连接蓝牙打印机的流程大致是wx.openBluetoothAdapter,wx.startBluetoothDevicesDiscovery发现设备,wx.createBLEConnection连接目标打印机,然后通过writeBLECharacteristicValue写入需要打印的字节内容。蓝牙打印最麻烦的是打印内容的排版协议,不同品牌打印机的ESC/POS指令略有差异,但在毕设演示中可以选用市面常见的58mm热敏打印机,文档和示例都比较容易被找到。
如果只是做功能演示,我建议准备一台已经配好打印机的测试设备,不要临时现场搜蓝牙设备,医院里无线干扰很强,蓝牙搜索经常超时。
6.4 几个保底下的小习惯与复盘心得
从项目交付的角度,我再分享几个我自己习惯用的“保命”操作。
接口文档一定要用knife4j自动生成,后端定义好实体注解,页面直接进入/swagger-ui/index.html查看每个接口的参数和响应结构。小程序联调时如果某个接口异常,先到Swagger页面把该接口单独执行一遍,能立刻区分是后端问题还是前端问题。代码提交时把application-dev.yml和application-prod.yml分开,dev里可以打印SQL日志,prod里关闭。数据库初始化脚本务必用sql文件管理,不能只在本地库手动改字段,否则换一台电脑部署就乱套。
答辩演示最怕现场出意外,网络不好、临时会话过期、图片上传变慢,任何一个都可能导致冷场。我习惯提前用同一台手机在同一个Wi-Fi环境下完整跑一遍报修闭环,然后把关键流程录屏存到手机相册。真到现场如果接口抽风,直接切换到录屏继续讲,反而显得准备充分。
回看这套基于SpringBoot和微信小程序的医院设备管理系统,技术上没有特别高深的内容,真正有价值的部分是把状态、权限、数据一致性这些底层逻辑理清楚了。所谓“能跑的毕设”一抓一大把,但能在答辩时把每一张表为什么这么设计、每个状态为什么这么流转、每个接口为什么这么封装讲清楚的,才是真正能从项目中收获能力的人。如果你正在做类似的设备报修小程序,建议先别着急写登录注册,拿一张纸把“报修单从发起到归档”的完整生命周期画出来,这张图画清楚了,你的系统就成功了一半。
