# 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)` 去重: ```sql SELECT DISTINCT ON (T1.ID) ... ``` 新版 `getSurgeryPage` SQL 遗漏了这个去重逻辑。 ## 影响范围 - **前端**:`surgery.vue` — el-transfer 复选框交互异常 - **后端 SQL**:`DoctorStationAdviceAppMapper.xml` — getSurgeryPage 查询缺少去重 - **数据库表**:`wor_activity_definition`(手术项目定义)、`adm_charge_item_definition`(价格定义) - **同类问题**:`getExaminationPage` 查询也存在相同缺陷 ## 修复方案 ### 1. 后端 SQL 修复(根因修复) 在 `DoctorStationAdviceAppMapper.xml` 的 `getSurgeryPage` 和 `getExaminationPage` 查询中添加 `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 `getSurgeryPage` 和 `getExaminationPage` 添加 `DISTINCT ON (t1.ID)` 去重 - ORDER BY 调整为 `t1.ID, t1.name ASC, t2.ID ASC`(DISTINCT ON 要求 ORDER BY 首列必须与 DISTINCT ON 一致) **前端加固**: - `applicationList` 初始化为 `ref([])` 而非 `ref()` - 数据映射前过滤 `adviceDefinitionId != null` 的脏数据 **改动量**:2文件,8行增,6行删 - `DoctorStationAdviceAppMapper.xml`:+4/-4(DISTINCT ON + ORDER BY 调整) - `surgery.vue`:+4/-2(初始化空数组 + 空值过滤) **修复结果:✅ 成功,8行改动**