Files
his/BUG461_ANALYSIS.md
2026-05-16 14:20:53 +08:00

90 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bug #461 分析报告
## Bug描述
[系统管理-执行科室配置] 保存项目配置后项目名称回显为ID码未显示正确名称
## 根因分析
### 数据流
1. 前端调用 `getDiagnosisTreatmentList()` → GET `/base-data-manage/org-loc/org-loc`
2. 后端 `OrganizationLocationController.getOrgLocPage()` 返回 `Page<OrgLocQueryDto>`
3. `OrgLocQueryDto.activityDefinitionId` 标注了 `@Dict(dictTable="wor_activity_definition", dictCode="id", dictText="name")`
4. `DictAspect` AOP 拦截 GET/POST 请求,对带 `@Dict` 注解的字段执行 SQL 翻译:`SELECT name FROM wor_activity_definition WHERE id::varchar = ? LIMIT 1`
5. 翻译结果写入 `activityDefinitionId_dictText` 字段
6. 前端使用 `record.activityDefinitionId_dictText` 作为项目名称显示
### 根本原因
**`DictAspect.queryDictLabel` 方法在 SQL 查询失败时返回空字符串 `""`,导致 `_dictText` 字段被设置为空值。**
具体代码 (`DictAspect.java:123-149`)
```java
private String queryDictLabel(String dictTable, String dictCode, String dictText, String deleteFlag, String dictValue) {
if (!StringUtils.hasText(dictTable)) {
return DictUtils.getDictLabel(dictCode, dictValue);
} else {
if (!StringUtils.hasText(dictText)) {
return DictUtils.getDictLabel(dictCode, dictValue);
}
String sql = String.format("SELECT %s FROM %s WHERE %s::varchar = ?", dictText, dictTable, dictCode);
// ...
try {
return jdbcTemplate.queryForObject(sql, String.class, dictValue);
} catch (DataAccessException e) {
return ""; // ← 关键问题:查询失败返回空字符串
}
}
}
```
`jdbcTemplate.queryForObject` 查询失败(无结果或异常)时,返回空字符串 `""`。而在 `processDict` 中:
```java
String dictLabel = queryDictLabel(...);
if (dictLabel != null) { // ← 空字符串 "" 不等于 null条件为 true
textField.set(dto, dictLabel); // ← 设置为空字符串
}
```
空字符串 `""` 不是 `null`,所以 `_dictText` 被设为空字符串,而不是保持 `null`(未翻译)。前端收到 `activityDefinitionId_dictText: ""`,当作有效值处理,显示为空或回退到 ID。
### 前端 fallback 的不足
前端代码在 `getList()` 中尝试用 `activityDefinitionId_dictText` 补充选项,但:
```javascript
if (record.activityDefinitionId && !filteredOptions.some(o => o.value === record.activityDefinitionId)) {
filteredOptions.push({
value: record.activityDefinitionId,
label: record.activityDefinitionId_dictText || record.activityDefinitionId // ← 空字符串时显示ID
});
}
```
空字符串是 falsy 值,所以 `"" || record.activityDefinitionId` 回退到 ID仍然显示 ID。
## 影响范围
- **前端**: `openhis-ui-vue3/src/views/basicmanage/implementDepartment/index.vue`
- **后端**: `openhis-server-new/.../basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java`
- **AOP**: `openhis-server-new/.../common/aspectj/DictAspect.java`
- **DTO**: `openhis-server-new/.../basedatamanage/dto/OrgLocQueryDto.java`
- **数据库表**: `adm_organization_location`, `wor_activity_definition`
## 修复方案
### 方案:在 service 层直接 JOIN 查询项目名称
修改 `OrganizationLocationAppServiceImpl.getOrgLocPage()` 方法,在返回结果前手动填充 `activityDefinitionId_dictText`,不依赖 DictAspect 的行为。这样更可靠,避免了 AOP 执行顺序、SQL异常处理等不确定因素。
具体改动:在 `OrganizationLocationAppServiceImpl` 中,利用已有的 `activityDefinitionMapper` 对每条记录补充 `activityDefinitionId_dictText`
## 验证计划
1. 修改代码后编译通过
2. 验证 `activityDefinitionId_dictText` 在 API 响应中正确填充
3. 前端 el-select 能正确显示项目名称而非 ID
---
## 修复结果:✅ 成功12行改动
**修改文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationLocationAppServiceImpl.java`
**改动内容**: 在 `getOrgLocPage()` 方法中,对分页返回的每条记录,使用已注入的 `activityDefinitionMapper` 查询对应的 `ActivityDefinition` 实体,手动填充 `activityDefinitionId_dictText` 字段。
**策略**: 不依赖 DictAspect 的 AOP 翻译机制,在 service 层直接填充字典翻译值,确保前端能接收到正确的项目名称。