|
|
@@ -4,6 +4,150 @@
|
|
|
|
|
|
---
|
|
|
|
|
|
+## v1.0.1803 (2026-10-27)
|
|
|
+
|
|
|
+### 新功能
|
|
|
+- 指标多期展示第一段收尾(报告详情对照/趋势入口/bugfix/降级)
|
|
|
+- 新增报告指标对照接口 + 期次列表接口,字典列表默认过滤停用项
|
|
|
+- IndicatorTrendService 接入时序服务 + 变化计算单点化
|
|
|
+- 新增 IndicatorTimelineService 指标时序服务(timeline/listPeriods/pairCompare)
|
|
|
+
|
|
|
+### 其他
|
|
|
+- (新时间轴页属第二段,须过 L1/L2/L3 gate 后才可上线)
|
|
|
+- 前端(§6.6 红线:只消费后端 trendCode,禁止按 delta 正负自判改善/恶化):
|
|
|
+- - report-detail:合并键改 definitionId(definitionId→item + name→definitionId 双索引)、
|
|
|
+- 徽标由 trendCode+movement 推导、pending 文案调整、分组「较上次 ±N」、指标行「N 期 ›」趋势入口
|
|
|
+- - IndicatorChangeRow:comparable===false 独立分支(恒灰无箭头)、change==null 中性兜底、
|
|
|
+- displayLine 为空时隐藏对照行
|
|
|
+- - IndicatorIncompleteBanner:visible 判定顺序修正(pc===0&&tc===0 提到 pc===tc 之前)
|
|
|
+- - indicator-curve:补 IndicatorIncompleteBanner 注册/数据字段/赋值,空态改「暂无该指标数据」
|
|
|
+- - indicator-timeline:补 getPeriodKey(模板引用但缺失)、headChange 空值防护
|
|
|
+- - indicator-quicklook:change 缺失时中性兜底「暂无对比」
|
|
|
+- - body-detail:/api/health/indicators 未下发 trendCode → 颜色恒中性灰、箭头仅表方向;
|
|
|
+- 缺 definitionId 时 toast 明示原因
|
|
|
+- - TrendChart(pages/health/components):_buildLayout 布局复用、缺失期/NaN 断线、pointTap 点选
|
|
|
+- - utils/api.js:getIndicatorTimeline 委托 getIndicatorTrend(同 URL 唯一 request 入口)
|
|
|
+- - components/TrendChart.vue:孤立「暂无趋势数据」→「暂无该指标数据」(P0 红线)
|
|
|
+- 后端:
|
|
|
+- - IndicatorChangeService.batchResolveHistory:上一期 + 历史期数一次查询,严禁 N+1
|
|
|
+- - IndicatorTimelineService.timeline():totalReportCount/olderReportCount 提到观测为空判断之前;
|
|
|
+- 每个请求 definitionId 都返回 item,无观测 → chartMode='empty'(Q17 保留)
|
|
|
+- 验证:mvn clean compile BUILD SUCCESS;
|
|
|
+- IndicatorTimelineServiceTest 9 / HealthReportServiceIndicatorsTest 3 /
|
|
|
+- IndicatorChangeServiceSemanticTest 20 / IndicatorControllerTest 2 / IndicatorTrendServiceTest 9 全通过;
|
|
|
+- verify-vue-compile 390/390 PASS;audit-mp-antipatterns ERROR 0;audit-duplicate-api-calls 0 error。
|
|
|
+-
|
|
|
+- - 在 §4.48.1 脚注区增加 SQL 预算小节(报告指标 ≤5、quickLookup/sourceTypes 恒 1 次查询),
|
|
|
+- 并说明上一期与 periodCount 全部内存计算,避免后续维护者再写成逐指标回查。
|
|
|
+- - 注明 missingPeriods 固定 2 次查询的优化结果(原先 1+缺失期数会 N+1)。
|
|
|
+-
|
|
|
+- - quickLookup:每个 definitionId 调一次 changeService.resolvePrevious(1 次 SQL),
|
|
|
+- 40 个指标 = 40 次查询。改为复用开头已加载的 rows 内存求解上一期
|
|
|
+- (新增 resolvePreviousInMemory,语义与 resolvePrevious 严格一致:
|
|
|
+- 同来源 + 数值非空 + reportDate 严格早于本期,取最晚一条),
|
|
|
+- 查询数从 1+N 降为 1。
|
|
|
+- - listSourceTypes:每个 sourceType 再查 2 次(periodCount / latestReportDate),
|
|
|
+- 即 1+2N。改为一次取回 (sourceType, reportDate) 后内存计算,
|
|
|
+- 查询数从 1+2N 降为 1;同日去重后得 periodCount,取最大值得 latestReportDate。
|
|
|
+- 单测补充:quickLookup 内存求解上一期(多期数据取到正确的上一期而非最早一期)、
|
|
|
+- 本期日期未知时不猜上一期、listSourceTypes 单查询算准 periodCount/latestReportDate,
|
|
|
+- 并断言 valueMapper.selectList 只被调用 1 次(锁死无 N+1)。
|
|
|
+-
|
|
|
+- 返回 Result.error(400, ...) 而非默认 500,与 GlobalExceptionHandler 对
|
|
|
+- IllegalArgumentException 的映射(400)保持一致,避免同类错误两套码。
|
|
|
+- - IndicatorTrendService.changeRanking:scope=pair 分支捕获 IllegalArgumentException
|
|
|
+- 时回填 code=400(参数/期次非法属客户端错误),与控制器口径统一。
|
|
|
+- - 新增 IndicatorControllerTest:API 边界契约单测,覆盖 scope=pair 缺参 400
|
|
|
+- 且不触达 service、参数齐全时正确透传 12 个入参。
|
|
|
+-
|
|
|
+- "命中字典之后" 提到之前 —— 未命中字典的指标同样可能带异常状态,
|
|
|
+- 原实现会让 summary.abnormalCount 少于实际异常项数(残缺横幅与异常徽标口径失真)。
|
|
|
+- - HealthReportServiceIndicatorsTest:
|
|
|
+- ① 三档形态用例补齐"命中字典但无上一期且有更早报告 → pending_backfill"这一档
|
|
|
+- (此前该档因 definitionId=null 被短路,未真正走到 pending_backfill 分支),
|
|
|
+- 并新增"未命中字典 → previous/change 恒 null"用例;
|
|
|
+- ② summary 断言改用实际契约字段 changedCount(原误写 improvedCount);
|
|
|
+- ③ spy 桩改用 doReturn(...).when(...),避免打桩时真实调用 batchResolve 被计入调用次数;
|
|
|
+- ④ SQL 预算用例断言服务层恒 3 次协作调用且绝不直接访问 indicator_values,
|
|
|
+- 验证查询数与指标条数无关(无 N+1)。
|
|
|
+-
|
|
|
+- - §4.48 后新增 4.48.1 小节:/api/health/report/indicators、/api/indicator/periods、
|
|
|
+- /api/admin/indicator/backfill 三个新增端点,以及 trend/change-ranking/
|
|
|
+- quick-lookup/source-types 四个改造端点的入参出参变更说明。
|
|
|
+- - 标注 /api/health/indicator/list 已被 /api/health/report/indicators 取代
|
|
|
+- (老接口保留不动,cfc-web 仍在调用)。
|
|
|
+- - 记录 SQL ≤ 5 次无 N+1 约束、chartMode 判定表、magnitude 排序口径变更(|Δ| → |Δ%|)、
|
|
|
+- QP17 status=0 剔除规则。
|
|
|
+-
|
|
|
+- - IndicatorChangeServiceSemanticTest(新增):20 条语义用例 semantic01..semantic20,
|
|
|
+- 覆盖全部 5 个 trendCode 分支 + in_range_is_better 四分支 + 微小基数护栏 +
|
|
|
+- 基数为 0 + 单位不一致 + 非数值 + 跨期跳比。
|
|
|
+- - IndicatorTimelineServiceTest(新增):chartMode 在 n=0/1/2/5/25 下的
|
|
|
+- empty/single/pair/line/line_aggregated;pairCompare 参数校验与排序;
|
|
|
+- status=0 剔除;deltaPct=null 恒定排最后。
|
|
|
+- - HealthReportServiceIndicatorsTest(新增):报告指标三档形态(有上期/首次记录/跨期跳比)
|
|
|
+- + 42 项指标 SQL ≤ 5 次(无 N+1)。
|
|
|
+- - IndicatorTrendServiceTest(改):适配新签名,覆盖 reportDate=null 不被当作最新值、
|
|
|
+- status=0 剔除、magnitude 按 |Δ%| 排序且 null 排最后。
|
|
|
+-
|
|
|
+- - HealthReportController 新增 POST /api/health/report/indicators:
|
|
|
+- 返回报告指标 + previous(上一期观测)+ change(五档形态)+ summary 汇总,
|
|
|
+- 权限校验沿用 getReportDetail(管理员 / 本人 / 被授权成员),无 subjectId 的历史报告
|
|
|
+- 仅本人上传者或家庭管理员可见。
|
|
|
+- - IndicatorController 新增 POST /api/indicator/periods(期次列表);
|
|
|
+- /trend、/change-ranking、/quick-lookup 透传新参数并补 scope=pair 的缺参校验。
|
|
|
+- - HealthReportService 新增 getReportIndicatorsWithPrevious:
|
|
|
+- 批量解析 definition + 批量取上一期,严禁 N+1,SQL 恒定 ≤ 5 次。
|
|
|
+- - IndicatorMappingService.resolveBatch + IndicatorMappingRuleMapper.selectRulesWithDefinitions:
|
|
|
+- 改为 indicator_mapping_rules JOIN indicator_definitions 单次联合查询,
|
|
|
+- raw_name → definition_id 解析与 definition 字段一次带出(省掉 selectBatchIds)。
|
|
|
+- - IndicatorService.listDefinitions:status 传 null 时默认按 status=1 过滤,
|
|
|
+- 防止自动创建的停用 definition 冒进管理端字典列表(QP17)。
|
|
|
+-
|
|
|
+- - trend():签名扩展为 8 参(sourceType/fromDate/toDate/granularity/sourceKind),
|
|
|
+- 委托 IndicatorTimelineService.timeline(),老 3 参调用保留(转发)。
|
|
|
+- - changeRanking():新增 scope=pair + fromReportDate/toReportDate + filter + page/pageSize;
|
|
|
+- scope=pair 路由到 IndicatorTimelineService.pairCompare;
|
|
|
+- 老路径(scope=adjacent|first-vs-latest,或只传 limit 不传 page/pageSize)保持兼容。
|
|
|
+- magnitude 排序口径由 |Δ| 改为 |Δ%| 降序,deltaPct=null 恒定排最后(Q14)。
|
|
|
+- - quickLookup():修复 reportDate=null 的观测被当作最新值的 bug;
|
|
|
+- 新增 previous/change/latestDateSource/latestReportId/goodDirection/valueType/sparkline。
|
|
|
+- - listSourceTypes():出参新增 periodCount / latestReportDate。
|
|
|
+- - trend/changeRanking/quickLookup 三个方法统一经 IndicatorChangeService.loadActiveDefinitions()
|
|
|
+- 取 definition(内部 status=1 过滤),拿不到的观测直接剔除,不降级为"指标"+id 假名称(QP17)。
|
|
|
+- - IndicatorChangeService.normUnit 由 private 提升为 public,供 IndicatorTimelineService 复用
|
|
|
+- 单位一致性判定,避免重复实现归一化规则。
|
|
|
+-
|
|
|
+- - timeline():按 definitionId 分组输出 points / latest / change / missingPeriods,
|
|
|
+- refLow/refHigh(definition.refRange + indicator_values.refRange_snapshot 快照优先),
|
|
|
+- pointsCount / totalReportCount / olderReportCount / chartMode / unitMismatch。
|
|
|
+- 支持 sourceType / fromDate / toDate / granularity(raw|month) / sourceKind(all|report|device)。
|
|
|
+- - listPeriods():期次列表(dateSource 取该期最差来源,reportDate=null 恒定排最后),
|
|
|
+- 供双期对比页 picker 使用;2 次查询完成,不分页。
|
|
|
+- - pairCompare():双期对比(scope=pair),含 sameDateWarning / from / to 元信息、
|
|
|
+- skipGaps(内存计算,零额外查询)、improved/worsened/flat/incomparable 汇总、
|
|
|
+- filter + orderBy + 分页。
|
|
|
+- - computeMissingPeriods 重写为 2 次查询(原来 1+缺失期数,N+1),
|
|
|
+- 并用 Map<Date, row> 修掉 Date 与 String 比较恒不相等导致行内容丢失的问题。
|
|
|
+- - 读路径全部经 IndicatorChangeService.loadActiveDefinitions()(status=1 过滤),
|
|
|
+- 拿不到 definition 的观测直接剔除,不降级为"指标"+id(QP17)。
|
|
|
+-
|
|
|
+
|
|
|
+### 文档
|
|
|
+- 补充 N+1 约束与缺失期计算说明到 API_REFERENCE §4.48.1
|
|
|
+- 同步指标多期展示 T02 后端接口到 API_REFERENCE
|
|
|
+
|
|
|
+### 性能优化
|
|
|
+- 消除 quickLookup / listSourceTypes 的 N+1 查询
|
|
|
+
|
|
|
+### Bug 修复
|
|
|
+- scope=pair 缺参返回 400 明确错误码 + 补控制器契约单测
|
|
|
+- 修正报告指标 summary 异常计数漏算 + 强化三档形态与 SQL 预算单测
|
|
|
+
|
|
|
+### 测试
|
|
|
+- 固化 20 条语义用例 + 时序/对照接口单测
|
|
|
+
|
|
|
+
|
|
|
## v1.0.1802 (2026-10-27)
|
|
|
|
|
|
### 文档
|