根因:ActivityDefinition.id 未加 @JsonSerialize,后端序列化为 JS Number(大数精度丢失), 而 OrgLocQueryDto.activityDefinitionId 有 ToStringSerializer 序列化为 String。 前端 === 严格比较 Number !== String,导致 filteredOptions 匹配失败。 修复: 1. ActivityDefinition.id 添加 @JsonSerialize(using = ToStringSerializer.class) 2. 前端 getAllImplementDepartment 中 value 转为 String() 统一类型 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2.3 KiB
2.3 KiB
Bug #461 分析报告
Bug 描述
[系统管理-执行科室配置] 保存项目配置后,项目名称回显为ID码,未显示正确名称
根因分析
数据流
- 前端
getAllTreatmentList()调用/app-common/activity-definition,返回ActivityDefinition实体列表 - 前端
getDiagnosisTreatmentList()调用/base-data-manage/org-loc/org-loc,返回Page<OrgLocQueryDto> - 后端
OrgLocQueryDto.activityDefinitionId有@JsonSerialize(using = ToStringSerializer.class),序列化为字符串 ActivityDefinition.id没有@JsonSerialize,序列化为 JavaScript Number(大数精度丢失)
核心问题
前端 getList() 中 filteredOptions 的初始化逻辑存在 类型不一致 问题:
allImplementDepartmentList中的value是 Number(来自 ActivityDefinition 实体,未做 ToStringSerializer)res.data.records中的activityDefinitionId是 String(来自 OrgLocQueryDto,做了 ToStringSerializer)
filteredOptions.some(o => o.value === record.activityDefinitionId) 使用 === 严格比较,Number !== String,永远返回 false。
虽然 fallback 代码会添加缺失项,但 label 取值依赖 record.activityDefinitionId_dictText,而该字段由 DictAspect 通过 SQL 查询填充。如果 SQL 查询返回空结果(如 jdbcTemplate.queryForObject 抛出 DataAccessException),DictAspect 返回空字符串 "",导致 label 被设为 ""。
最终结果:el-select 找不到匹配的选项,fallback 添加的条目 label 为空,显示为 ID 码。
修复结果:✅ 成功,5行改动
改动清单
-
前端
index.vueL258:value: item.activityDefinitionId→value: String(item.activityDefinitionId)- 确保
allImplementDepartmentList中的value为 String 类型 - 与后端
OrgLocQueryDto.activityDefinitionId(ToStringSerializer 序列化)类型一致 - 使
filteredOptions.some(o => o.value === record.activityDefinitionId)能正确匹配
- 确保
-
后端
ActivityDefinition.java:给id字段添加@JsonSerialize(using = ToStringSerializer.class)- 根因修复:防止大数 ID 在 JavaScript 中精度丢失
- 全局影响:所有返回 ActivityDefinition 的 API 现在统一返回字符串 ID