Files
his/MD/bugs/BUG_750_ANALYSIS.md

130 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`应为1`logic-not-delete-value: 1`应为0二者矛盾。虽然注解优先于全局配置但这种不一致可能导致 `saveOrUpdate` 内部的存在性检查逻辑产生非预期行为。
2. **`saveOrUpdate` 的二义性**:该方法依赖 entity 的 `id` 是否为 null 来判断 INSERT/UPDATE。虽然 `getById` 理论上返回了正确的 entity含 id`saveOrUpdate` 在多租户拦截器(`TenantLineInnerInterceptor`+ 逻辑删除注解(`@TableLogic`)的叠加作用下,其内部的 `selectById` 查询可能返回 null例如 `tenant_id` 过滤条件不匹配),从而触发 INSERT 分支。
3. **`@TableLogic` 与全局配置冲突**`application.yml`
```yaml
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`
```java
// 第406行附近修改前
iEncounterService.saveOrUpdate(encounter);
// 修改为:
iEncounterService.updateById(encounter);
```
同样,病区信息和账户信息的 `saveOrUpdate` 也应替换为显式更新:
**病区更新**约第419行
```java
// 修改前:
iEncounterLocationService.saveOrUpdate(encounterLocationReg);
// 修改为:
iEncounterLocationService.updateById(encounterLocationReg);
```
**账户更新**约第429-470行中所有 `saveOrUpdate` 调用):
```java
// 修改前:
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 分析决策
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。