☰
微信小程序病历复印申请系统:前端设计与状态机实现
2026/10/14 23:14:28 网站建设 项目流程

病历复印这件事,听起来好像没什么技术含量,真做起来你会发现它比想象中复杂得多:涉及身份核验、病历调取、复印、收费、自提或邮寄,中间还夹着一个患者可能完全不懂流程的“情绪敏感期”。我去年接到某医院信息科的一个需求,要把门诊和住院的病历复印申请搬到微信小程序上,前后花了一个多月做了个完整可跑的流程,这篇文章先分享上半部分,重点说说前端页面、系统设计、状态机流转和那些容易被忽略的坑。适合小程序开发者、医院信息科同事,以及接医疗外包项目但没做过医疗场景的团队参考。

1. 需求拆解与整体方案设计

1.1 病历复印业务的真实痛点

先聊一个容易被低估的问题:线下的病历复印有多麻烦?我实地在某三甲医院病案室蹲了半天,看到很多真实场景。早上八点半,窗口前就排起了长队,有人拿身份证、有人拿户口本、有人代办但代理手续不全,窗口工作人员一边翻纸质申请单一边解释“缺这个材料”“要填那个编号”,患者家属急得直冒火。复印量大、人工登记慢、审核靠肉眼、付款靠跑收费处、取件靠再跑一趟,整个链路全是断点。

其实病案室的工作人员也很委屈,他们要做的不只是复印,还得按制度核验申请资格、登记用途、统计份数、编号归档。这是一个典型的“低频刚需”场景——对单个用户来说几年才办一次,但对医院来说每天都在发生。低频刚需意味着用户不会愿意专门下载一个App,也不想登录复杂的官网系统,打开微信就能办是最低门槛的路径。这也是我一开始就认定必须用微信小程序而不是H5或者原生App的原因。

1.2 为什么选微信小程序而不是H5或App

选型这件事我们内部也争论过一轮。H5基本被我否掉,原因很现实:H5在微信里虽然也能打开,但关键能力被限制得很死。支付体验差、无法订阅消息、用户没有“留存”入口,最关键的是,H5页面一旦分享给别人,链路的可追溯性极差。病历这东西涉及隐私,审计要求每一笔申请都能对应到一个明确的微信身份,H5很难扛住这种合规压力。

原生App也不合适,开发周期长、分发成本高,医院也不会让患者为了复印一份病历专门去应用商店下载一个几MB的App。小程序是那个折中最优解:微信生态内的免安装使用、用户授权后可以稳定拿到unionid或openid、配合订阅消息能做到关键节点通知,支付走微信支付商户号,全程都在一个闭环里。

1.3 核心功能模块拆解

完整系统我拆成了六个核心模块:微信登录与实名信息绑定、病历复印申请(含病历类型选择、用途、份数、领取方式)、后台审核管理、在线支付、进度查询与通知、物流/自提状态跟踪。第一期没有做电子病历下载,因为电子病历涉及更敏感的授权逻辑,医院也担心数据泄露,所以第一期只做纸质病历的复印申请,但系统设计的数据模型要预留电子签章的扩展位。

申请流程的状态机很重要,我一开始就把它定义清楚:草稿 -> 待审核 -> 审核通过(待支付) -> 已支付(待处理) -> 复印中 -> 待邮寄/待自提 -> 已完成;另外还有两个终止态:审核驳回、用户取消。这里要强调,很多人做类似系统时会忽略“用户取消”和“驳回”状态,导致用户在等待时无法在界面上确认当前卡在哪个环节,投诉率会直线上升。

2. 小程序前端页面设计与交互实现

2.1 页面架构与导航设计

这个小程序不用tabBar,主路径是一个向导式流程,从首页进入申请,申请完成后跳转订单详情页。原因很直接:业务场景是“用户来办事”,不像内容类产品需要沉淀在多个页面来回逛。tabBar里放“首页”和“我的”显得多余,反而把简单的流程变复杂了。导航结构我最终定了三段:小程序整体首页、申请向导页(分三步)、订单中心页。

首页重点不是花哨的视觉,而是把业务规则讲清楚。我在首页放了四个核心入口卡片:开始申请、我的申请、邮寄说明、收费说明。这看起来简单,但实际转化率比想象中高。很多第一次使用的人并不知道复印病历要收费,也不知道要等多久,提前把“费用标准”“办理时限”“是否支持邮寄”放在显眼位置,能有效减少后续客服压力。

2.2 申请页三步向导的核心交互

申请页是整个前端最复杂的部分,我把它拆成了三步:第一步选择病历类型和用途,第二步填写身份信息和领取方式,第三步预览确认并提交。三步之间数据要能够持久化保存,因为很多人填到一半会退出小程序,下次进来应该能继续填,而不是从头开始。

第一步的病历类型字段,区分门诊病历和住院病历。这个区分不只是文案差异,会直接影响后续的附件上传规则:住院病历往往多页,需要确认复印范围(入院记录、出院记录、医嘱单、检验单等);门诊病历相对简单,一份即可。用途字段用枚举下拉框固定:复诊、医保报销、保险理赔、司法鉴定、单位存档等。设计师问我要不要做关键词搜索,我拒绝了,枚举值就够了,因为用途选项太散会导致后台审核人员工作量大到崩溃。

第二步会开启用户隐私设置里的手机号授权,同时让用户填写住院号/就诊卡号。这里有个前端的细节,要用 input 的 type="idcard" 来适配身份证号键盘,并且要设置 maxlength="18";另外,证件号码输入完成后要做一个格式第一次校验,前端校验不通过就直接拦截,别传给后端。我见过不少系统前端不校验,严重依赖后端,结果用户填错了身份证号,直到审核环节才被驳回了,白白等了几天。

第三步的预览页,我把用户信息、病历范围、份数、费用预估放在同一屏。这里有一个很关键的交互:如果用户选择“邮寄领取”且此前未填写过收货地址,要主动拉起一个地址表单,并提供“微信自带的收货地址读取”能力。很多用户习惯微信的收货地址,能一键填充的体验真的能提高完成率。我第一次做的时候忽略了这一点,测试时发现很多用户卡在地址填写的步骤,后来加上一键导入后,流失率降了不少。

2.3 登录流程与登录态管理

微信小程序的登录流程,看起来是“经典三行”:wx.login 拿 code,传给后端,后端调微信接口换取 openid,再返回自定义 token。实际做医疗类小程序时还要多一层:绑定就诊人信息。用户首次进来,光拿到 openid 还不够,需要引导他输入与病历关联的身份信息,通过后端校验后,才算完成“可用状态”。

登录态过期这个坑很隐蔽。小程序有个特殊行为:token 过期后,前端几乎不会感知到,除非接口返回 401。所以我在 request 封装里做了统一拦截:所有非登录接口返回 401 时,自动清除本地登录态并跳转到首页的“重新登录”页,同时用 wx.showToast 提示“登录已过期,请重新操作”。这样做的好处是完全不用在每个业务接口里重复写登录态判断。

提一个前端实现上很多人会忽略的点:用户信息里如果包含身份证号,本地缓存里绝对不允许明文存储。小程序本地缓存是可以被用户手动清理、甚至在某些调试工具下看到的,敏感字段要么不落本地,要么做脱敏处理。我在本地保存的UserInfo对象只保留姓名、医院编号;身份证号只在上传时用,后端返回给前端的永远是脱敏后的数据,比如"320****1234"。

3. 后端接口设计与数据模型

3.1 数据表设计与状态机流转

后端我用的是Java Spring Boot,数据库用MySQL,关系不算复杂,但每张表设计时都想着后续业务的扩展性。核心表我有五张:t_user、t_patient(就诊人绑定)、t_apply(病历复印申请)、t_order(支付订单)、t_express(物流),加一张t_audit_log记录每次状态变更的操作人和时间,这张日志表非常重要,医疗业务必须能回答“谁在什么时候改了什么状态”。

状态机流转我用代码强制约束,而不是让运维手动改。具体做法是在 t_apply 表中维护 status 字段,同时用 Spring StateMachine 做状态流转规则校验。很多普通业务可以灵活状态,但病历申请不行,因为它涉及财务和法律凭证,状态一跳错了,后面对账就会有麻烦。状态跳转规则我画了一张清晰的流转表,每次代码评审时都要过一遍,至少保证渠道不会从“待审核”直接跳到“已完成”。

流程表大概是这样:

当前状态允许动作下一状态
草稿提交申请待审核
待审核审核通过待支付
待审核审核驳回驳回结束
待支付用户支付已支付
已支付开始复印复印中
复印中打印完成邮寄/自提待领取/待发货
待发货上传物流单号已发货
已发货/待领取确认收货/确认自提已完成

这张表建议贴在项目文档首页,前后端联调时都按这张表来,不然很容易出现前端期望状态和后端实际状态不一致,导致同一份申请在前端页面上重复渲染两个状态。

3.2 核心接口与业务流程设计

后端主要接口我用 RESTful 风格:POST /api/apply 创建申请,GET /api/apply/{id} 查询详情,PUT /api/apply/{id}/cancel 取消申请,POST /api/pay/createOrder 创建支付单,POST /api/pay/callback 接收微信支付回调。创建申请接口是我花时间最多的接口,因为它的入参校验要细到每个字段:姓名不能为空、身份证号要校验合法、病历类型必须枚举内、用途必须枚举内、份数要大于等于1小于等于10、领取方式如果邮寄则收货地址必填。

身份证号的输入校验,我用了一个双层策略。第一层前端做格式校验,第二层后端不仅要格式校验,还要调用一个内部算法校验身份证号的校验位。这里有个小经验,别只判断18位数字就放行,要算最后一位校验码,很多错号会在这一步被拦截,避免用户填错一个数字,白白浪费了审核的人力。

后端还要注意一个点,微信支付回调接口必须单独做验签,不能信任任何外部传来的“支付成功”消息。验签逻辑是用微信支付商户平台配置的API密钥对通知报文计算签名,比对微信传过来的签名。我在回调处理里还做了一个幂等控制:同一个订单号重复收到回调时,不能重复修改订单状态,直接查一下当前状态,如果是已支付就直接返回success。

3.3 权限、隐私与数据安全设计

医疗类的数据,权限控制是最高优先级。我采用RBAC模型配合数据隔离。普通用户通过openid只能查询到自己名下的申请记录;后台审核员只能看到分配给自己的待审核任务;管理员可以看到全部数据并可以按日期、科室、状态筛选。这里我踩过一个坑:最开始的设计是审核员能搜索所有申请单,结果临床科室反馈太危险,别人看到员工住院记录会有严重伦理问题。后来改成“强制任务分配模式”,每个待审核申请在提交时就根据病历所属科室自动分配给对应科室的审核员。

数据加密我用了两个层次。传输层直接依赖HTTPS,这个不做任何妥协;存储层,身份证号字段采用AES-256加密后落库,查询时再解密。对于小团队来说,可能觉得“内网环境不用加密也还好”,但一旦涉及等级保护测评或医院信息科的安全审计,这个加密是硬性要求,早点加上能省很多事后整改的功夫。另外,日志中绝对不能打印身份证号、手机号、就诊卡号等敏感字段,我用日志过滤切面统一处理,日志输出时会自动替换成星号。

4. 支付功能与消息通知的实现细节

4.1 微信支付的接入与参数校验

医疗类小程序要接入微信支付,先需要确认一个前提:小程序主体必须是企业或个体工商户。个人主体是没办法开通微信支付的,这是硬性要求。另外,医院这类机构通常需要上传《医疗机构执业许可证》,类目审核会比较严。我第一次申请时填的类目被驳回了一次,原因是“医疗服务”类目下面必须同时上传机构资质和相关的执业许可,缺一不可,这个要在立项阶段就准备好资料,别拖到开发完才去申请,会成为项目延期的主要卡点。

支付流程设计上,我在后端创建支付订单后,需要调用微信支付统一下单API,拿到prepay_id,再按照官方文档要求生成前端 wx.requestPayment 所需的 paySign。这里有五个参数容易搞错:timeStamp、nonceStr、package、signType、paySign。其中 package 参数必须是prepay_id=xxx格式,少了prepay_id=前缀,前端所有版本能调起支付都会失败,这个坑我帮同事排查过至少三次。

我建议在开发环境用微信支付的沙箱密钥,这个能做完整的支付流程模拟,但不会产生真实扣款。沙箱环境下要特别注意,请求支付接口的签名密钥也要换成沙箱密钥,很多人一开始用正式密钥调到怀疑人生。

4.2 订阅消息推送的时机设计

进度通知这个功能,一开始我想用微信订阅消息,用着用着发现现实很骨感。微信订阅消息现在对用户必须完成主动订阅动作后才能发送,而且一次性订阅消息只能发送一次,发送完就失效。这意味着用户给你授权了一次通知,你只能发一条消息。所以通知的内容和时机要设计得非常谨慎,要把最有用的一条发给用户。

我的设计是:用户在提交申请后,立即弹订阅授权框,申请“审核结果通知”那种一次性订阅消息;等审核通过后,再在用户点击“立即支付”的时候弹第二次订阅,订阅“进度更新通知”。这两次订阅的时机把握很重要。不要在用户一进入页面就疯狂弹订阅授权,会被用户一律拒绝。最好的时机是有明确下一步动作需要他关注的时候,比如提交后和支付前。

有人会问,那后续的物流状态、送达提醒怎么通知?这就是一次性订阅消息的局限了。我的补位方案是:短信通知。因为医疗业务涉及用户隐私比较多,短信的到达率高,而且不受订阅次数的限制。虽然短信是付费的,但相比客服接电话的人力成本,这个投入是完全值得的。

4.3 微信回调里的幂等与对账

支付回调的防重、防篡改、防丢单逻辑,我是严格按微信官方规范做的。核心代码可以给大家一个参考:

// 微信支付回调处理伪代码 public String wxPayCallback(@RequestBody String requestBody) { // 1. 验签 boolean signValid = wxPayService.verifySign(requestBody); if (!signValid) { return WxPayNotifyResponse.fail("签名错误"); } // 2. 解析报文 WxPayNotifyResult result = WxPayNotifyResult.fromXML(requestBody); String orderNo = result.getOutTradeNo(); // 3. 幂等判断 PayOrder payOrder = payOrderMapper.findByOrderNo(orderNo); if (payOrder == null) { return WxPayNotifyResponse.fail("订单不存在"); } if ("PAY_SUCCESS".equals(payOrder.getStatus())) { // 重复回调,直接返回成功 return WxPayNotifyResponse.success(); } // 4. 更新业务状态 payOrder.setStatus("PAY_SUCCESS"); payOrderMapper.update(payOrder); applyMapper.updateStatusByOrderNo(orderNo, "PAID"); // 5. 触发打印/复印流程 printTaskService.createTask(orderNo); return WxPayNotifyResponse.success(); }

幂等判断这块,很多人会忽略第三步的前置查询。假设微信重试三次回调,而你没有幂等处理,用户支付成功后订单状态被反复修改,轻则日志混乱,重则后续流程被重复触发,复印任务会创建好几份。数据状态变更前,一定要先查一次当前状态。

5. 联调过程中的坑与优化

5.1 文件上传与图片压缩

病历申请时,用户经常需要拍照上传身份证正反面、病历封面等,这就涉及图片上传这个小程序里的经典痛点。微信小程序的 chooseMedia 拿到的临时文件,如果直接上传原图,在大几MB的情况下,传到服务器相当慢,而且容易失败。所以我会用 canvas 做一次压缩再上传。

具体做法是,把临时文件路径画到一张离屏canvas上,设置好 width、height 和 jpeg 压缩质量。压到多低合适?我试下来身份证这种证件照片,quality 设为 60,宽度设为 1000px,基本可读性没问题,尺寸也能控制在100KB以内。再小会有辨识度问题,再大传输又慢,这个参数是实测出来的平衡点。

图片上传还有一个容易踩的坑:身份证照片的 EXIF 旋转信息。iPhone 拍出来的照片往往带旋转方向信息,如果不做处理,前端上传后后端查看时头像方向是歪的。解决方案是在前端 canvas 绘制时读取图片的 orientation 信息,绘制时旋转角度。或者后端用组件库自动纠正旋转方向,两者选一个。我的建议是后端做一次同时兼容所有设备,因为前端仍然会漏掉一些特殊场景。

5.2 小程序包体积与首屏加载优化

这个小程序整体包体积,微信限制主包不能超过2MB。我第一次把页面、图片、组件全部塞进主包,结果直接超过限制,导致开发者工具一直报警。后来我把三个核心页面拆分到分包,主包只留首页和公共逻辑,包体积降到1.2MB左右。分包加载还有额外的好处,用户首屏只需要下载主包,启动速度会明显更快。

图片资源也要优化。项目里的图标,我全部改成了线上地址,或者用iconfont字体图标,而不是本地PNG。本地图片打几个背景装饰,每个都有几十KB,积少成多。压缩后加载速度提升肉眼可见。

5.3 状态同步与并发问题

这个项目实际运行中还遇到一个很典型的并发问题:用户连续点了两次“提交申请”按钮,导致同一条申请被提交了两遍。常规做法是给按钮加 loading 状态,但如果你开发时没注意,后端也可能用防重幂等兜底。我在后端创建申请接口里,用“用户ID + 身份证号 + 状态不为待审核”唯一约束来判断,已有未完成申请就不允许再创建新申请。这个约束加到数据库唯一索引上,才能彻底防住并发。

还有一个“复制订单”的坑:用户提交一次申请后,如果订单还停留在“待支付”状态,他退出再进入时能看到自己的未支付订单,但如果他误操作又提交了一份新申请,后台就会出现重复的待审核任务。我在前端做了提示拦截:存在未完成待支付的申请时,要先把上一次申请取消或继续支付,才允许发起新申请。这个小逻辑看似简单,但对审核人员的工作效率影响是巨大的。

5.4 打印任务的自动/手动处理边界

病历复印不能像普通电商订单那样直接打印,因为医院的病历系统往往是老旧的C/S架构,不可能直接对接互联网小程序做实时数据读取。我的做法是:小程序端提交申请后,后台自动生成一个“打印工作台”中的待处理任务,审核人员在PC端打开打印工作台,点击“生成打印清单”后,系统调取病历系统的检索结果并输出PDF归档,再由工作人员线下复印、核对装袋。这个半自动化的设计比较务实,全程自动化反而会引入不可控的误差。

打印工作台的几个按钮,我在实现时要特别设置高亮与操作确认弹窗:比如“标记完成”按钮,点击前要二次确认,防止误操作把未打印的申请改成已完成。这种“反悔代价高”的操作,UI上一定要做保护,宁可让操作者多点一次,也不能让他点错。

6. 实操经验汇总与常见问题速查

6.1 从开发到上线的时间线参考

这里给一个基于我个人经验的开发排期估算,供大家做项目计划参考。第一周做需求确认和原型评审,第二周做小程序前端页面,第三周做后端接口与数据库,第四周联调与测试,预留一周缓冲处理医院内部审批流程。如果团队是两个人分工,大概率周期会在五到六周。很多团队会低估资质审批的时间,其实小程序的类目审批和支付商户号申请最长可能要两周,建议立项当天就启动资质提交流程,不要等开发完了再去申请。

阶段主要内容预估工期
需求确认现场调研、流程梳理、原型评审3-5工作日
前端开发首页、申请向导、订单中心5-7工作日
后端开发接口、数据模型、状态机、权限5-7工作日
支付与通知微信支付回调、订阅消息2-3工作日
联调测试全流程走通、兼容性调试3-5工作日
上线准备资质核验、体验版测试、发布2-3工作日

6.2 上线前必做的10个关键检查项

即将发布正式版前的检查,我列了一份自查清单,每一条都是血泪教训换来的:

  1. 用户真实手机号与就诊人身份是否已完成医学校验
  2. 微信支付商户号资质是否已通过“医疗服务”类目
  3. 身份证号加密存储是否生效,日志中脱敏规则是否覆盖全部出口
  4. 隐私保护指引是否在微信公众平台正确配置,是否声明了收集的信息字段
  5. 订阅消息模板内容是否通过审核,模板标题不能包含“复印病历”之外的无关词
  6. 所有异步通知(支付回调、审核结果同步)是否做了幂等处理
  7. 数据库索引是否覆盖高频查询字段(用户ID、身份证号、状态)
  8. 订单超时自动关闭逻辑是否实现,用户支付超时后不许再继续支付
  9. 操作日志是否已归档,并支持按单号、时间、操作人筛选
  10. 线上环境日志级别是否设置为INFO,避免DEBUG日志泄露敏感参数

6.3 常见问题排查速查表

我在整个开发和灰度测试阶段遇到了不少问题,整理了一下高频的几类,给各位少走弯路的参考:

问题现象可能原因排查思路
微信支付调不起缺少prepay_id前缀或签名错检查package参数格式,用后端日志打印签名串逐一比对
订阅消息发送失败43101用户未订阅或模板ID过期检查订阅状态和触发时机,确认是否使用一次性模板
用户上传图片后旋转90度未处理EXIF信息后端图像处理库开启自动旋转,或者前端canvas转换
接口返回401但页面无提示登录态未统一拦截request封装里加401全局拦截并触发重新登录
多个重复申请单产生未做幂等或唯一约束库里加唯一索引,后端申请接口加防重逻辑
审核通过后订单状态未变状态机流转未触发检查状态变更方法是否同时更新了apply与order表
快递单号查询失败物流公司编码不对对照快递鸟/微信物流查询接口的编码表核对

7. 开发中的安全与合规自查

做医疗类小程序,技术只是一半,合规审查是另一半。我强烈建议,在正式上线前,找医院的信息安全负责人和法务一起过一遍全流程,而不是只依赖微信后台的审核反馈。微信侧重点在于用户隐私政策有没有写清楚、敏感信息在页面上有没有明文展示;但医院侧更关心数据存储是否满足区域医疗信息平台的要求、有没有备份和恢复机制。两边要求叠起来,才是完整的安全标准。

在隐私保护指引中,需要如实声明收集哪些用户信息以及用途。我最终收集的信息包括:昵称、头像(用于页面展示)、手机号(用于联系用户)、身份证号(用于身份校验)、住院号/就诊卡号(用于病历关联)、收货地址(用于邮寄)。每一项在后面都写了使用目的。用户协议中也要单独注明“病历复印申请一经审核通过,不支持在线取消”,避免误解。

还有一点容易被忽视:小程序体验版和正式版的数据环境必须隔离。我在开发阶段用过测试环境,正式上线后,开发账号和后端接口指向必须严格分离。曾经见过一个团队因为体验版误连了生产数据库,测试用户直接在线上创建订单,最终导致财务对账差异和隐私泄露隐患。我的做法是环境变量统一放在后端配置中心,小程序端从环境标识接口获取当前环境,一旦识别isProd=true,前端页面上会常驻隐藏的水印标识,方便截图追溯环境。

关于日志文件,保留时长建议至少180天。因为医疗投诉或者纠纷发生后,可能半年后才有人找过来需要追溯到当时的申请单。日志要支持按申请单号全链路检索,将操作日志、支付日志、审核日志与状态变更日志通过同一订单号串联起来。我用的是ELK链路,在小项目里用 Spring Boot + AOP 打印关键日志,同样可以达到这个目的。

我个人在实际操作中最大的体会是,做医疗信息相关的项目,千万不要埋头写代码,第一步就要把业务流程里每个角色的职责边界和审批权限梳理清楚。代码里的状态机可以帮你防止数据混乱,但业务上的制度流程如果没走通,再完善的系统也只是个原型。多跟病案室的工作人员聊,多观察线下业务里真正的痛点,比多写几十行代码有用得多。

另外再分享一个小技巧:在开发的时候顺便把后台审核页面的“驳回原因”做成了可复用的枚举加备注框。审核员选择驳回一级原因后,系统自动生成标准话术,同时预留自定义补充。这个设计让用户的被打回体验好了很多,审核员的工作量也小了不少,边际收益很大。下半篇如果你感兴趣,我会重点拆解后台审核端的设计、与医院现有系统的对接思路,以及如何做数据对账与统计报表。

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

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

立即咨询