Files
his/bug443_analysis.md

2.7 KiB
Raw Blame History

Bug #443 分析报告

Bug 描述

手术计费:点击"签发"耗材时异常报错

复现步骤

  1. 以"手术室护士"角色登录
  2. 进入【门诊手术安排】→ 点击【计费】
  3. 勾选一条状态为"待签发"的耗材项目
  4. 点击【签发】按钮

预期 vs 实际

  • 预期:提示"签发成功",状态变为"已签发"
  • 实际:弹出"后端程序异常"报错

代码分析

前端流程

  1. surgicalschedule/index.vuehandleChargeCharge() 打开计费弹窗
  2. 弹窗中使用 prescriptionlist.vue 组件,传入 generateSourceEnum=6, sourceBillNo=operCode
  3. 用户勾选"待签发"项目 → 点击"签发" → 触发 handleSave()
  4. handleSave() 过滤 item.check && item.statusEnum == 1 && (Number(item.bizRequestFlag)==1||!item.bizRequestFlag)
  5. 构造请求体:解析 contentJson + 补充顶层字段encounterId, patientId, adviceType 等)
  6. 调用 savePrescriptionSign() → POST /doctor-station/advice/sign-advice

后端流程

  1. DoctorStationAdviceController.signAdvice()saveAdvice(param, SIGN_ADVICE)
  2. saveAdvice() 校验 encounterId/patientId 非空
  3. 按 adviceType 分类:药品(1)、耗材(2)、诊疗(3)
  4. 耗材走 handDevice(deviceList, curDate, adviceOpType) 处理
  5. 签发后更新 DeviceRequest 状态为 ACTIVE(2)
  6. 更新 ChargeItem 状态DRAFT(0)→PLANNED(1) 或 BILLABLE(2)→PLANNED(1)

可能根因

根因1dbOpType 语义错误

  • 前端 handleSave() 对已存在的耗材发送 dbOpType: '1' (INSERT)
  • 后端 handDeviceinsertOrUpdateList 通过 requestId != null 过滤包含这些项
  • 但对于 INSERT 操作,如果 DeviceRequest 已存在,saveOrUpdate 走 UPDATE 路径
  • 问题在于INSERT 语义下某些字段(如 bus_no)仅在 is_save=true 时设置

根因2contentJson 数据一致性

  • 前端将 contentJson 解析后 spread 回对象,再序列化为新的 JSON 发送
  • 后端 handDevice 直接将该 JSON 存入 content_json 字段
  • 如果原始 content_json 中的字段名与 AdviceSaveDto 不匹配(如 snake_case vs camelCase可能导致数据丢失

根因3缺少空列表校验

  • handleSave() 未校验 saveList.length == 0 的情况
  • 如果过滤后列表为空,后端会返回"医嘱列表为空"错误
  • 虽然 watch 逻辑应在列表为空时禁用按钮,但存在竞态条件可能

修复方案

  1. 前端 handleSave() 添加 saveList.length == 0 校验(防御性编程)
  2. 前端 handleSave() 对已存在记录requestId 不为空)使用 dbOpType: '2' (UPDATE) 而非 '1' (INSERT)
  3. 前端 handleSave() 确保关键字段quantity, unitCode从顶层补充