Files
his/MD/bugs/BUG_743_ANALYSIS.md

7.0 KiB
Raw Blame History

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_idPostgreSQL 的 NOT NULL 约束拒绝插入,系统将底层数据库报错直接暴露给用户。正确行为应该是:后端校验 patient_id 必填或从分诊记录自动关联患者ID前端也应加必填校验。


二、根因分析

根因:addRescue 方法零校验 + 缺少患者ID自动关联逻辑

调用链路:前端 submitForm() → POST /emergency/rescue/addEmergencyController.addRescue()rescueService.save(rescue) → DB INSERT

问题层 具体问题
后端 Controller addRescue() 方法第167行直接 rescueService.save(rescue)无任何参数校验patientId 为 null 时仍然保存
后端 Controller 虽然有 triageIdEmergencyTriage 的联动逻辑第172行但这段逻辑在 save 之后,且只更新分诊状态,没有从 triage 反填 patientId
前端 Form el-form:rules 校验规则,el-form-itemrequired 标记患者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.javapatientId 字段(用于反填)

三、修复方案

修复1后端 Controller — 增加校验 + 从分诊记录自动关联 patientId

文件: EmergencyController.java 第165-180行

修改内容:在 save 前增加校验和自动填充逻辑:

@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. 确保 patientIdsave 前必定有值

修复2前端表单 — 增加必填校验规则

文件: healthlink-his-ui/src/views/emergency/rescue/index.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">
// 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 分析决策

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