Files
his/MD/bugs/BUG_750_ANALYSIS.md

5.6 KiB
Raw Permalink Blame History

Bug #750 诸葛亮分析报告

文档类型: Bug分析 分析时间: 2026-06-12 22:27:51 分析模型: mimo-v2.5 (LLM深度分析)


基本信息

  • Bug #: 750
  • 标题: 【收费工作站-住院登记】修改患者登记信息(如费用性质)并保存后,系统未更新原记录而是新增了一条重复记录
  • 模块: 住院登记管理
  • 提出人: 陈显精

Now I have enough information to provide the analysis. Let me compile the full diagnosis.


一、Bug 理解

禅道 Bug 标题:【收费工作站-住院登记】修改患者登记信息(如费用性质)并保存后,系统未更新原记录而是新增了一条重复记录

重现步骤

  1. 登录系统,进入 [收费工作站] → [住院登记]
  2. 切换到 [已登记入院] 页签找到一条已存在的登记记录序号9测试患者戊费用性质为"全自费"
  3. 点击操作列下的 [修改] 按钮,打开"修改登记"弹窗
  4. 将"费用性质"从"全自费"修改为"职工基本医疗保险"
  5. 点击 [保存],系统提示"住院登记操作成功"

期望结果:修改保存后,系统只保留一行该患者的记录,且费用性质成功更新。

附图关键信息

  • 弹窗中"费用性质"被红框标注为"职工基本医疗保险"(修改后值),"保存"按钮被红框圈出
  • 列表中序号8旧数据"全自费"和序号9新数据"职工基本医疗保险")同时存在,红字标注"生成了两条重复的数据"
  • 两条记录的登记时间完全相同(2026-06-07 21:42:13),说明不是两次独立操作

综合总结:用户在"已登记入院"列表点击修改并保存后,系统本应在原记录上更新费用性质,但实际行为是保留了原记录并新增了一条相同记录,导致同一患者出现两条住院登记。保存操作被错误地执行为"新增"而非"更新"。


二、根因分析

核心问题InHospitalRegisterAppServiceImpl.updateRegistration() 方法中,使用 iEncounterService.saveOrUpdate(encounter) 保存修改后的 encounter 时MyBatis-Plus 将其执行为 INSERT 而非 UPDATE,导致生成新记录。

技术根因链路

  1. 配置冲突HisBaseEntity.deleteFlag 字段标注了 @TableLogic(value = "0", delval = "1"),但全局配置 application.yml 中设置 logic-delete-value: 0应为1logic-not-delete-value: 1应为0二者矛盾。虽然注解优先于全局配置但这种不一致可能导致 saveOrUpdate 内部的存在性检查逻辑产生非预期行为。

  2. saveOrUpdate 的二义性:该方法依赖 entity 的 id 是否为 null 来判断 INSERT/UPDATE。虽然 getById 理论上返回了正确的 entity含 idsaveOrUpdate 在多租户拦截器(TenantLineInnerInterceptor+ 逻辑删除注解(@TableLogic)的叠加作用下,其内部的 selectById 查询可能返回 null例如 tenant_id 过滤条件不匹配),从而触发 INSERT 分支。

  3. @TableLogic 与全局配置冲突application.yml

    mybatis-plus:
      global-config:
        db-config:
          logic-delete-field: validFlag   # 全局指定 validFlag但实体用的是 deleteFlag
          logic-delete-value: 0           # 0=已删除(注解是 0=未删除)
          logic-not-delete-value: 1       # 1=未删除(注解是 1=已删除)
    

涉及文件

文件 角色
InHospitalRegisterAppServiceImpl.java:377-475 updateRegistration() 方法 — 问题入口
HisBaseEntity.java @TableLogic(value="0", delval="1") 注解 — 配置冲突
MybatisPlusConfig.java 多租户 + 乐观锁 + 逻辑删除拦截器链
application.yml:93-100 MyBatis-Plus 全局配置 — 与注解矛盾
accomplishList.vue:286-302 / patientRegister.vue:455-475 前端调用链

三、修复方案

方案:将 saveOrUpdate 改为显式 updateById

最安全、最精确的修复是:在 updateRegistration 中已通过 getById 确认记录存在并获取了完整 entity含 id因此无需使用具有二义性的 saveOrUpdate,直接使用 updateById 确保执行 UPDATE。

修改文件InHospitalRegisterAppServiceImpl.java

// 第406行附近修改前
iEncounterService.saveOrUpdate(encounter);

// 修改为:
iEncounterService.updateById(encounter);

同样,病区信息和账户信息的 saveOrUpdate 也应替换为显式更新:

病区更新约第419行

// 修改前:
iEncounterLocationService.saveOrUpdate(encounterLocationReg);

// 修改为:
iEncounterLocationService.updateById(encounterLocationReg);

账户更新约第429-470行中所有 saveOrUpdate 调用):

// 修改前:
iAccountService.saveOrUpdate(cashAccount);
// 修改为:
iAccountService.updateById(cashAccount);

// 同理修改所有 iAccountService.saveOrUpdate(...) 调用

注意:账户的"else"分支(账户不存在时创建新账户)保持使用 iAccountService.save(newAccount) 不变。


四、路由决策

FIXER: guanyu

REASON: 根因在后端 InHospitalRegisterAppServiceImpl.updateRegistration() 的 MyBatis-Plus saveOrUpdate 调用需改为 updateById,纯后端 Java 修复,属于 guanyu后端开发的职责范围。


路由决策

  • FIXER_ID: guanyu
  • 修复 Agent: guanyu后端
  • 原因: LLM 分析决策

⚠️ 修复人员请先验证以上分析是否正确,再执行修复。