docs(bug): 诸葛亮分析报告 Bug #743
This commit is contained in:
162
MD/bugs/BUG_743_ANALYSIS.md
Normal file
162
MD/bugs/BUG_743_ANALYSIS.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Bug #743 诸葛亮分析报告
|
||||
|
||||
> **文档类型**: Bug分析
|
||||
> **分析时间**: 2026-06-12 23:02:08
|
||||
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||||
|
||||
---
|
||||
|
||||
## 基本信息
|
||||
- **Bug #**: 743
|
||||
- **标题**: 【急诊管理】急诊抢救模块下的开始抢救只填分诊id会出现报错null value in column "patient_id" of relation "emergency_rescue" violates not-null constraint
|
||||
- **模块**: 会诊管理
|
||||
- **提出人**: 王栩坤
|
||||
|
||||
---
|
||||
|
||||
Now I have a complete picture. Let me produce the analysis.
|
||||
|
||||
---
|
||||
|
||||
### 一、Bug 理解
|
||||
|
||||
**禅道 Bug #743 原文:**
|
||||
> **标题**:【急诊管理】急诊抢救模块下的开始抢救只填分诊id会出现报错 null value in column "patient_id" of relation "emergency_rescue" violates not-null constraint
|
||||
>
|
||||
> **重现步骤**:登录内科医生1的账号 doctor1/123456 → 进入急诊管理 → 急诊抢救 → 点击开始抢救 → 只填写分诊ID → 点击确认
|
||||
>
|
||||
> **结果**:报错 `PSQLException: ERROR: null value in column "patient_id" of relation "emergency_rescue" violates not-null constraint`
|
||||
>
|
||||
> **期望**:不会出现报错,能够正常实现,或者显示"患者ID的字段未填入,请填入患者ID"
|
||||
|
||||
**附图分析**:截图中表单显示"患者ID"输入框为空(无值),"分诊ID"填入了 `1`,点击确定后页面顶部弹出红色数据库报错横幅。INSERT SQL 为 `INSERT INTO emergency_rescue (id, triage_id, rescue_start, chief_doctor, rescue_team, procedures, medications, create_by, create_time, tenant_id)` —— 完全缺少 `patient_id` 字段。
|
||||
|
||||
**综合总结**:用户在"开始抢救"弹窗中只填写了分诊ID、未填患者ID就提交,后端没有做参数校验就直接调用 `rescueService.save()`,导致 MyBatis-Plus 生成的 INSERT 语句不含 `patient_id`,PostgreSQL 的 NOT NULL 约束拒绝插入,系统将底层数据库报错直接暴露给用户。正确行为应该是:后端校验 `patient_id` 必填(或从分诊记录自动关联患者ID),前端也应加必填校验。
|
||||
|
||||
---
|
||||
|
||||
### 二、根因分析
|
||||
|
||||
**根因:`addRescue` 方法零校验 + 缺少患者ID自动关联逻辑**
|
||||
|
||||
调用链路:前端 `submitForm()` → POST `/emergency/rescue/add` → `EmergencyController.addRescue()` → `rescueService.save(rescue)` → DB INSERT
|
||||
|
||||
| 问题层 | 具体问题 |
|
||||
|--------|---------|
|
||||
| **后端 Controller** | `addRescue()` 方法(第167行)直接 `rescueService.save(rescue)`,**无任何参数校验**,`patientId` 为 null 时仍然保存 |
|
||||
| **后端 Controller** | 虽然有 `triageId` → `EmergencyTriage` 的联动逻辑(第172行),但这段逻辑在 `save` **之后**,且只更新分诊状态,**没有从 triage 反填 patientId** |
|
||||
| **前端 Form** | `el-form` 无 `:rules` 校验规则,`el-form-item` 无 `required` 标记,患者ID可为空直接提交 |
|
||||
| **数据库** | `emergency_rescue.patient_id` 有 NOT NULL 约束,MyBatis-Plus 对 null 字段不生成 INSERT 列,导致约束违反 |
|
||||
|
||||
**涉及文件**:
|
||||
- `healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emergency/controller/EmergencyController.java` — 第165-180行 `addRescue` 方法
|
||||
- `healthlink-his-ui/src/views/emergency/rescue/index.vue` — 表单模板 + `submitForm` 函数
|
||||
- `healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emergency/domain/EmergencyTriage.java` — `patientId` 字段(用于反填)
|
||||
|
||||
---
|
||||
|
||||
### 三、修复方案
|
||||
|
||||
#### 修复1:后端 Controller — 增加校验 + 从分诊记录自动关联 patientId
|
||||
|
||||
**文件**: `EmergencyController.java` 第165-180行
|
||||
|
||||
**修改内容**:在 `save` 前增加校验和自动填充逻辑:
|
||||
|
||||
```java
|
||||
@PostMapping("/rescue/add")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> addRescue(@RequestBody EmergencyRescue rescue) {
|
||||
// 从分诊记录自动关联患者ID(如果前端未传 patientId)
|
||||
if (rescue.getPatientId() == null && rescue.getTriageId() != null) {
|
||||
EmergencyTriage triage = triageService.getById(rescue.getTriageId());
|
||||
if (triage == null) {
|
||||
return R.fail("分诊记录不存在,请检查分诊ID");
|
||||
}
|
||||
if (triage.getPatientId() == null) {
|
||||
return R.fail("关联的分诊记录中患者ID为空,无法创建抢救记录");
|
||||
}
|
||||
rescue.setPatientId(triage.getPatientId());
|
||||
}
|
||||
// 最终校验 patientId 必填
|
||||
if (rescue.getPatientId() == null) {
|
||||
return R.fail("患者ID不能为空,请填写患者ID或提供有效的分诊ID");
|
||||
}
|
||||
rescue.setRescueStart(new Date());
|
||||
rescue.setCreateTime(new Date());
|
||||
rescueService.save(rescue);
|
||||
// 联动更新分诊状态
|
||||
if (rescue.getTriageId() != null) {
|
||||
EmergencyTriage triage = triageService.getById(rescue.getTriageId());
|
||||
if (triage != null) {
|
||||
triage.setStatus("IN_TREATMENT");
|
||||
triageService.updateById(triage);
|
||||
}
|
||||
}
|
||||
return R.ok(rescue);
|
||||
}
|
||||
```
|
||||
|
||||
**核心逻辑**:
|
||||
1. 如果前端没传 `patientId` 但传了 `triageId`,从 `EmergencyTriage` 记录中自动取 `patientId` 填入
|
||||
2. 如果两个都没有 → 返回友好错误信息 `R.fail("患者ID不能为空...")`
|
||||
3. 确保 `patientId` 在 `save` 前必定有值
|
||||
|
||||
#### 修复2:前端表单 — 增加必填校验规则
|
||||
|
||||
**文件**: `healthlink-his-ui/src/views/emergency/rescue/index.vue`
|
||||
|
||||
**修改内容**:
|
||||
|
||||
```vue
|
||||
<!-- 1. el-form 加 :rules -->
|
||||
<el-form :model="form" label-width="100px" :rules="formRules" ref="formRef">
|
||||
|
||||
<!-- 2. 患者ID 加 prop -->
|
||||
<el-form-item label="患者ID" prop="patientId">
|
||||
|
||||
<!-- 3. 分诊ID 加 prop -->
|
||||
<el-form-item label="分诊ID" prop="triageId">
|
||||
```
|
||||
|
||||
```js
|
||||
// 4. 在 script setup 中添加:
|
||||
import {ref, reactive, onMounted} from 'vue'
|
||||
const formRef = ref(null)
|
||||
const formRules = reactive({
|
||||
patientId: [{ required: true, message: '请输入患者ID', trigger: 'blur' }],
|
||||
triageId: [{ required: true, message: '请输入分诊ID', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
// 5. 修改 submitForm 加表单校验:
|
||||
const submitForm = async () => {
|
||||
await formRef.value.validate()
|
||||
if (isEdit.value) {
|
||||
await (await import('./api')).update(form.value || {})
|
||||
} else {
|
||||
await add(form.value)
|
||||
}
|
||||
ElMessage.success('操作成功')
|
||||
dlgVisible.value = false
|
||||
loadData()
|
||||
}
|
||||
```
|
||||
|
||||
**注意**:由于后端已做了"只填分诊ID自动反填患者ID"的逻辑,前端可以将 `patientId` 改为非必填(允许用户只填分诊ID即可),但建议至少保留 `triageId` 必填。如果希望更严格,则两个都必填。
|
||||
|
||||
---
|
||||
|
||||
### 四、路由决策
|
||||
|
||||
**FIXER**: `guanyu`(后端)+ `zhaoyun`(前端)
|
||||
|
||||
**REASON**: 核心修复在后端 `EmergencyController.addRescue()` 方法——增加参数校验和从分诊记录自动关联 `patientId`,这是 bug 的根因所在,由 **guanyu** 负责。前端 `rescue/index.vue` 的表单校验规则增强为辅助防御层,由 **zhaoyun** 负责。两个修改互相独立,可并行进行。
|
||||
|
||||
---
|
||||
|
||||
## 路由决策
|
||||
- **FIXER_ID**: guanyu
|
||||
- **修复 Agent**: guanyu(后端)
|
||||
- **原因**: LLM 分析决策
|
||||
|
||||
> ⚠️ 修复人员请先验证以上分析是否正确,再执行修复。
|
||||
Reference in New Issue
Block a user