56 lines
2.7 KiB
Markdown
56 lines
2.7 KiB
Markdown
# Bug #443 分析报告
|
||
|
||
## Bug 描述
|
||
手术计费:点击"签发"耗材时异常报错
|
||
|
||
## 复现步骤
|
||
1. 以"手术室护士"角色登录
|
||
2. 进入【门诊手术安排】→ 点击【计费】
|
||
3. 勾选一条状态为"待签发"的耗材项目
|
||
4. 点击【签发】按钮
|
||
|
||
## 预期 vs 实际
|
||
- 预期:提示"签发成功",状态变为"已签发"
|
||
- 实际:弹出"后端程序异常"报错
|
||
|
||
## 代码分析
|
||
|
||
### 前端流程
|
||
1. `surgicalschedule/index.vue` → `handleChargeCharge()` 打开计费弹窗
|
||
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)
|
||
|
||
### 可能根因
|
||
|
||
**根因1:dbOpType 语义错误**
|
||
- 前端 `handleSave()` 对已存在的耗材发送 `dbOpType: '1'` (INSERT)
|
||
- 后端 `handDevice` 中 `insertOrUpdateList` 通过 `requestId != null` 过滤包含这些项
|
||
- 但对于 INSERT 操作,如果 DeviceRequest 已存在,`saveOrUpdate` 走 UPDATE 路径
|
||
- 问题在于:INSERT 语义下某些字段(如 `bus_no`)仅在 `is_save=true` 时设置
|
||
|
||
**根因2:contentJson 数据一致性**
|
||
- 前端将 `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)从顶层补充
|