165 lines
6.5 KiB
Markdown
165 lines
6.5 KiB
Markdown
# Bug #757 诸葛亮分析报告
|
||
|
||
> **文档类型**: Bug分析
|
||
> **分析时间**: 2026-06-12 14:58:17
|
||
> **分析模型**: mimo-v2.5 (LLM深度分析)
|
||
|
||
---
|
||
|
||
## 基本信息
|
||
- **Bug #**: 757
|
||
- **标题**: 【门诊医生工作站】中医诊断中没有相同的诊断和症候,但就无法新增中医诊断
|
||
- **模块**: 门诊医生工作站
|
||
- **提出人**: 王栩坤
|
||
|
||
---
|
||
|
||
I have enough information now to produce the analysis. Let me compile the findings.
|
||
|
||
---
|
||
|
||
## 一、Bug 理解
|
||
|
||
用户在门诊医生站打开"中医诊断"对话框,选择中医诊断和中医证候后点击确定,**无法成功保存**。同时,已经保存过的中医诊断也无法正确回显诊断详情。期望:能正常选择诊断和证候、保存成功,并回显诊断详情数据。
|
||
|
||
## 二、根因分析
|
||
|
||
核心问题在 `tcmdiagnosisDialog.vue` 的 `submit()` 函数,它向后端发送的字段名与后端 DTO 完全不匹配:
|
||
|
||
**前端发送的数据结构:**
|
||
```js
|
||
const diagnosisChildList = [{
|
||
conditionCode: condition.value, // ← 字段名错误
|
||
syndromeCode: syndrome.value, // ← 字段名错误
|
||
}];
|
||
```
|
||
|
||
**后端 `SaveDiagnosisChildParam` 期望的数据结构:**
|
||
- `definitionId` (Long) — 诊断定义 ID
|
||
- `ybNo` (String) — 医保编码
|
||
- `syndromeGroupNo` (String) — 中医证候组号(用于关联病和证)
|
||
- `maindiseFlag` (Integer) — 主诊断标记
|
||
- `diagSrtNo` (Integer) — 排序号
|
||
|
||
**具体根因列表:**
|
||
|
||
| # | 问题 | 位置 | 影响 |
|
||
|---|------|------|------|
|
||
| 1 | `submit()` 发送 `conditionCode`/`syndromeCode`,后端接收不到 `definitionId` 和 `ybNo` | `tcmdiagnosisDialog.vue:submit()` | 保存时 Condition 记录的 `definitionId` 为 null,保存失败或数据损坏 |
|
||
| 2 | 没有传 `syndromeGroupNo` 来关联"病"和"证" | `tcmdiagnosisDialog.vue:submit()` | 后端无法将诊断和证候配对成一组 |
|
||
| 3 | `openDialog()` 获取下拉选项时用 `item.ybNo` 作为 value,但没有保存 `definitionId` | `tcmdiagnosisDialog.vue:openDialog()` | 丢失了关键的 `definitionId` |
|
||
| 4 | 没有传 `patientInfo` prop(dialog 用 `defineProps` 声明了但父组件可能未传) | `tcmdiagnosisDialog.vue` | `saveTcmDiagnosis` 请求中 `patientId`/`encounterId` 为 null |
|
||
|
||
**可能涉及的文件:**
|
||
- `healthlink-his-ui/src/views/doctorstation/components/tcm/tcmdiagnosisDialog.vue` — 主要 Bug 所在
|
||
- `healthlink-his-ui/src/views/doctorstation/components/api.js` — API 定义(无误)
|
||
- `healthlink-his-server/.../appservice/impl/DoctorStationChineseMedicalAppServiceImpl.java` — 后端 `saveTcmDiagnosis` 方法
|
||
|
||
## 三、修复方案
|
||
|
||
### 修复 1:`tcmdiagnosisDialog.vue` — `openDialog()` 方法
|
||
|
||
将下拉选项的 value 从 `ybNo` 改为同时保存 `definitionId`:
|
||
|
||
```js
|
||
// 修改前
|
||
conditionOptions.value = res.data.records.map((item) => ({
|
||
value: item.ybNo,
|
||
label: item.name,
|
||
}));
|
||
|
||
// 修改后
|
||
conditionOptions.value = res.data.records.map((item) => ({
|
||
value: item.id, // 用 definition ID 作为 value
|
||
ybNo: item.ybNo, // 保留医保编码
|
||
label: item.name,
|
||
}));
|
||
syndromeOptions.value = res.data.records.map((item) => ({
|
||
value: item.id,
|
||
ybNo: item.ybNo,
|
||
label: item.name,
|
||
}));
|
||
```
|
||
|
||
### 修复 2:`tcmdiagnosisDialog.vue` — `submit()` 方法
|
||
|
||
重写提交逻辑,匹配后端 `SaveDiagnosisChildParam` 的字段名:
|
||
|
||
```js
|
||
function submit() {
|
||
if (!condition.value || !syndrome.value) {
|
||
proxy.$modal.msgWarning('请选择诊断和证候');
|
||
return;
|
||
}
|
||
|
||
// 找到选中的诊断和证候的完整信息
|
||
const selectedCondition = conditionOptions.value.find(item => item.value === condition.value);
|
||
const selectedSyndrome = syndromeOptions.value.find(item => item.value === syndrome.value);
|
||
|
||
// 生成证候组号(时间戳)
|
||
const syndromeGroupNo = 'TCM' + Date.now();
|
||
|
||
const diagnosisChildList = [
|
||
{
|
||
definitionId: condition.value, // 中医诊断 definition ID
|
||
ybNo: selectedCondition?.ybNo, // 中医诊断医保编码
|
||
syndromeGroupNo: syndromeGroupNo,
|
||
maindiseFlag: 1, // 主诊断标记
|
||
diagSrtNo: 1, // 排序号(病)
|
||
},
|
||
{
|
||
definitionId: syndrome.value, // 中医证候 definition ID
|
||
ybNo: selectedSyndrome?.ybNo, // 中医证候医保编码
|
||
syndromeGroupNo: syndromeGroupNo, // 同一组号
|
||
maindiseFlag: 0,
|
||
diagSrtNo: 2, // 排序号(证)
|
||
},
|
||
];
|
||
|
||
saveTcmDiagnosis({
|
||
patientId: props.patientInfo.patientId,
|
||
encounterId: props.patientInfo.encounterId,
|
||
diagnosisChildList: diagnosisChildList,
|
||
}).then((res) => {
|
||
if (res.code === 200) {
|
||
proxy.$modal.msgSuccess('保存成功');
|
||
emit('flush');
|
||
close();
|
||
} else {
|
||
proxy.$modal.msgError(res.msg || '保存失败');
|
||
}
|
||
}).catch((error) => {
|
||
console.error('保存中医诊断失败:', error);
|
||
proxy.$modal.msgError('保存失败,请重试');
|
||
});
|
||
}
|
||
```
|
||
|
||
### 修复 3:确保父组件传递 `patientInfo` prop
|
||
|
||
检查父组件(`tcmAdvice.vue` 或使用 `tcmdiagnosisDialog` 的页面)是否正确传递了 `patientInfo` prop。`tcmAdvice.vue` 已有 `patientInfo` prop 定义,所以如果是从 `tcmAdvice` 中使用该 dialog,需要通过 `:patientInfo="patientInfo"` 传递。
|
||
|
||
### 修复 4(可选):后端防御性处理
|
||
|
||
后端 `saveTcmDiagnosis` 方法可以增加对 `definitionId` 为空的校验,避免写入脏数据:
|
||
|
||
```java
|
||
// 在 saveTcmDiagnosis 方法开头增加
|
||
for (SaveDiagnosisChildParam param : diagnosisChildList) {
|
||
if (param.getDefinitionId() == null) {
|
||
return R.fail("诊断定义ID不能为空,请重新选择诊断");
|
||
}
|
||
}
|
||
```
|
||
|
||
## 四、路由决策
|
||
|
||
**FIXER: zhaoyun**(前端开发)
|
||
**REASON:** Bug 根因在前端对话框组件 `tcmdiagnosisDialog.vue` 的字段映射错误和提交逻辑缺陷,需要修改 Vue 前端代码(openDialog 数据映射 + submit 参数构建 + 父组件 prop 传递),属于前端界面和 API 调用层修复。
|
||
|
||
---
|
||
|
||
## 路由决策
|
||
- **修复 Agent**: zhaoyun
|
||
- **原因**: ** Bug 根因在前端对话框组件 `tcmdiagnosisDialog.vue` 的字段映射错误和提交逻辑缺陷,需要修改 Vue 前端代码(openDialog 数据映射 + submit 参数构建 + 父组件 prop 传递),属于前端界面和 API 调用层修复。
|