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

4.4 KiB
Raw Blame History

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)

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 中:

String dictLabel = queryDictLabel(...);
if (dictLabel != null) {  // ← 空字符串 "" 不等于 null条件为 true
    textField.set(dto, dictLabel);  // ← 设置为空字符串
}

空字符串 "" 不是 null,所以 _dictText 被设为空字符串,而不是保持 null(未翻译)。前端收到 activityDefinitionId_dictText: "",当作有效值处理,显示为空或回退到 ID。

前端 fallback 的不足

前端代码在 getList() 中尝试用 activityDefinitionId_dictText 补充选项,但:

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 层直接填充字典翻译值,确保前端能接收到正确的项目名称。