docs(bug): 诸葛亮分析报告 Bug #750
This commit is contained in:
129
MD/bugs/BUG_750_ANALYSIS.md
Normal file
129
MD/bugs/BUG_750_ANALYSIS.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# 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 分析决策
|
||||
|
||||
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。
|
||||
Reference in New Issue
Block a user