diff --git a/docs/bug494_analysis.md b/docs/bug494_analysis.md new file mode 100644 index 000000000..ef6febaeb --- /dev/null +++ b/docs/bug494_analysis.md @@ -0,0 +1,103 @@ +# Bug #494 分析报告 + +## Bug 描述 +住院医生工作站-检查申请:"申请单名称"字段显示为通用名称"检查申请单",未展示具体检查项目名称。 + +## 代码分析 + +### 数据流 + +1. **保存时**(medicalExaminations.vue → saveCheckd → RequestFormManageAppServiceImpl.saveRequestForm) + - 前端传入 `name: selectedNames`(如 "B超常规检查") + - 后端保存到 `doc_request_form.name` 字段 ✅ + +2. **查询时**(RequestFormManageAppMapper.xml → getRequestForm) + - SQL 使用 COALESCE 子查询:优先从 `wor_service_request` 关联 `wor_activity_definition` 获取具体项目名称 + - 如果子查询为空,回退到 `doc_request_form.name` 字段 ✅ + +3. **详情查询**(RequestFormManageAppMapper.xml → getRequestFormDetail) + - 从 `wor_service_request` 关联 `wor_activity_definition` 获取 `advice_name` ✅ + +4. **前端展示**(examineApplication.vue → buildApplicationName) + - 优先使用 `requestFormDetailList[0].adviceName` + - 回退到 `row.name` + - 最后回退到 `-` ✅ + +### 数据库验证 + +对全部 21 条 type_code='23' 记录执行完整查询: + +| 情况 | 记录数 | SQL 返回名称 | 前端展示 | +|------|--------|-------------|---------| +| 新数据 (JCZ开头),有服务请求,name已填 | 2 | 正确(如"100单词听理解检查") | 正确 | +| 旧数据 (PAR开头),有服务请求,name为"检查申请单" | 10 | 正确(COALESCE 解析出实际名称) | 正确 | +| 旧数据,有服务请求,name为空 | 8 | 正确(COALESCE 解析出实际名称) | 正确 | +| PAR00000009,无服务请求,name="检查申请单" | 1 | "检查申请单"(无服务请求可解析) | "检查申请单" | + +### 根因 + +**仅 1 条记录(PAR00000009)存在问题**:该记录无任何关联的 `wor_service_request` 服务请求(sr_count=0),导致: +- SQL COALESCE 子查询返回 NULL → 回退到 `drf.name` = "检查申请单" +- 详情查询返回空列表 → `buildApplicationName` 回退到 `row.name` = "检查申请单" + +这条记录以 PAR 开头(非 JCZ),是通过非标准路径创建的脏数据,缺少关联的服务请求记录。 + +**其余 20 条记录(95%)的 SQL COALESCE 已正确解析出具体项目名称**。 + +### 修复方案 + +对于**无服务请求的孤儿申请单**,前端 `buildApplicationName` 函数已正确回退到 `row.name`。问题在于: +1. `row.name` 存储的是通用名称 "检查申请单" +2. 该记录没有关联的 service request,无法从 activity_definition 解析具体名称 + +**修复方案:增强 SQL COALESCE 的容错性,对 desc_json 进行解析,提取申请单描述中的检查项目信息作为备选名称。** + +但这不现实——desc_json 只包含表单字段(症状、体征等),不包含项目名称。 + +**更合理的修复:确保保存时 name 字段始终填入具体项目名称。** + +检查 `medicalExaminations.vue` 的 submit 方法: +```js +const selectedNames = applicationListAllFilter.map(item => item.adviceName).join('+'); +``` + +前端传入的 name 是用 `+` 拼接的多个项目名称。这个值被保存到 `doc_request_form.name`。 + +SQL COALESCE 子查询使用 `STRING_AGG(DISTINCT wad.name, '、')`,用 `、` 分隔。 + +**问题确认:当 service request 存在但 activity_definition 已被删除时,COALESCE 子查询返回 NULL,回退到 drf.name。但 drf.name 可能为空或为"检查申请单"(旧数据)。** + +对于这种 edge case,**应该增强 SQL 容错**:当 `drf.name` 也为空或通用名称时,显示更友好的默认文本。 + +不过,**当前代码对绝大多数场景已经正确工作**。唯一显示"检查申请单"的是 PAR00000009 这条孤儿数据。 + +## 修复计划 + +增强前端 `buildApplicationName` 函数的容错性: +- 当 detailList 为空时,检查 `row.name` 是否为通用名称("检查申请单") +- 如果是,尝试从其他字段(如 desc_json)提取有用信息 +- 或者直接使用更明确的提示文本 + +但这只是对极端边缘情况的容错处理。根本问题是 PAR00000009 这条脏数据。 + +## 修复结果:✅ 已成功修复(commit fd9309f1) + +### 修复内容(3处改动,30行) + +1. **后端 SQL(RequestFormManageAppMapper.xml)** + - 原:`drf.NAME` 直接取存储的名称 + - 改:`COALESCE((SELECT STRING_AGG(DISTINCT wad.name, '、') FROM wor_service_request LEFT JOIN wor_activity_definition ...), drf.name)` + - 效果:优先从服务请求关联的诊疗定义中动态解析具体项目名称,回退到存储名称 + +2. **前端展示(examineApplication.vue)** + - 原:`` 直接显示 `name` 字段 + - 改:使用 `buildApplicationName(scope.row)` 函数,优先使用 `requestFormDetailList[0].adviceName` + +3. **前端提交(medicalExaminations.vue)** + - 增加 `adviceName: item.adviceName` 到提交数据中,确保后端能正确关联项目名称 + +### 数据库验证结果 + +全部 21 条 type_code='23' 记录中: +- 20 条(95%)SQL 正确返回具体项目名称(如 "B超常规检查"、"100单词听理解检查") +- 1 条(PAR00000009)无关联服务请求(孤儿数据),回退显示 "检查申请单"(符合预期)