Files
his/BUG_472_ANALYSIS.md
2026-05-16 14:55:05 +08:00

3.0 KiB
Raw Blame History

Bug #472 深度分析报告

标题

住院医生工作站-手术申请单:勾选手术项目无效,导致无法正常开立医嘱

根因分析

问题链路

  1. 当前分支将手术项目数据源从 getApplicationList 改为专用接口 getSurgeryPage
  2. getSurgeryPage 的 SQL 查询使用 LEFT JOIN adm_charge_item_definition t2 关联价格表
  3. 关键问题SQL 中缺少 DISTINCT ON (t1.ID) 去重逻辑
  4. 如果某个手术项目在 adm_charge_item_definition 表中有多条匹配的价格记录如不同状态、不同时间点LEFT JOIN 会产生多行重复记录,具有相同的 advice_definition_id
  5. 前端 mapToTransferItem 将这些重复记录映射为 el-transfer 数据项,所有重复项的 key 相同
  6. el-transfer 组件内部使用 key 进行 Vue 的列表渲染追踪。当多个 item 拥有相同的 key 时Vue 的 diff 算法无法正确追踪哪些 item 被选中/取消选中,导致点击复选框无响应

对比工作正常的代码

旧版 getAdviceBaseInfo SQL仍在工作中明确使用了 DISTINCT ON (T1.ID) 去重:

SELECT DISTINCT ON (T1.ID) ...

新版 getSurgeryPage SQL 遗漏了这个去重逻辑。

影响范围

  • 前端surgery.vue — el-transfer 复选框交互异常
  • 后端 SQLDoctorStationAdviceAppMapper.xml — getSurgeryPage 查询缺少去重
  • 数据库表wor_activity_definition(手术项目定义)、adm_charge_item_definition(价格定义)
  • 同类问题getExaminationPage 查询也存在相同缺陷

修复方案

1. 后端 SQL 修复(根因修复)

DoctorStationAdviceAppMapper.xmlgetSurgeryPagegetExaminationPage 查询中添加 DISTINCT ON (t1.ID)

  • DISTINCT ON (t1.ID) 确保每个手术/检查项目只返回一行
  • PostgreSQL 的 DISTINCT ON 按 t1.ID 去重,保留每个组的第一行

2. 前端防御性修复(加固)

  • applicationList 初始化为 ref([]) 而非 ref()(避免 undefined
  • mapToTransferItem 添加 adviceDefinitionId 空值保护

验证计划

  1. 修改 SQL 后,进入住院医生工作站 → 手术申请单
  2. 确认"未选择"列表中每个手术项目只显示一次(无重复)
  3. 点击复选框,项目应被正确选中并移入"已选择"列表
  4. 点击确认按钮,应成功开立手术申请

修复结果

修复策略策略A直接修复代码逻辑

根因修复

  • SQL getSurgeryPagegetExaminationPage 添加 DISTINCT ON (t1.ID) 去重
  • ORDER BY 调整为 t1.ID, t1.name ASC, t2.ID ASCDISTINCT ON 要求 ORDER BY 首列必须与 DISTINCT ON 一致)

前端加固

  • applicationList 初始化为 ref([]) 而非 ref()
  • 数据映射前过滤 adviceDefinitionId != null 的脏数据

改动量2文件8行增6行删

  • DoctorStationAdviceAppMapper.xml+4/-4DISTINCT ON + ORDER BY 调整)
  • surgery.vue+4/-2初始化空数组 + 空值过滤)

修复结果: 成功8行改动