|
|
@@ -1699,6 +1699,66 @@ interactionType 取值:`PHONE` / `WECHAT` / `MEETING` / `OTHER`。
|
|
|
|
|
|
*文档更新:2026-10-09(指标统一层新增,见 `specs/2026-10-09-indicator-change-curve-design.md`)*
|
|
|
|
|
|
+> **⚠️ `/api/health/indicator/list` 已被取代**:老接口返回裸 `List<HealthIndicator>`(无上一期对照、无 summary)。新接口 `/api/health/report/indicators` 返回同一批指标 + `previous` / `change` / `summary` 五档形态数据。`/api/health/indicator/list` **保留不动**(cfc-web `views/nutritionist/HealthIndicators.vue` 仍在调),新接入一律走 `/api/health/report/indicators`。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### 4.48.1 指标多期展示 · 后端接口(`/api/health/report/indicators`、`/api/indicator/periods`、`/api/admin/indicator/backfill`)
|
|
|
+
|
|
|
+> 本节为 §4.48 指标统一层的多期展示增量。**所有 `change` 计算统一由 `IndicatorChangeService.computeChange` 单点产出**(trendCode 五档:`improved` / `worsened` / `flat` / `first_record` / `pending_backfill`),读路径一律过滤 `indicator_definitions.status=1`,拿不到 active definition 的观测**直接剔除,不降级为「指标」+id 假名称**(QP17)。
|
|
|
+
|
|
|
+**① `POST /api/health/report/indicators`** — 报告指标明细(含上一期对照,D12 报告详情页接入点)
|
|
|
+
|
|
|
+| 端点 | 权限 | 请求 | 返回 |
|
|
|
+|---|---|---|---|
|
|
|
+| `POST /api/health/report/indicators` | 登录(JWT;管理员/本人/被授权成员,校验逻辑同 `/api/health/report/detail`) | `{reportId, withPrevious?}` | `{reportId, reportType, subjectId, reportDate, dateSource, olderReportCount, summary, items}` |
|
|
|
+
|
|
|
+- **入参**:`reportId`(必填);`withPrevious`(选填,默认 `true`,`false` 时跳过 previous/change 计算,供编辑模式快速返回单期)。
|
|
|
+- **权限**:无 `subjectId` 的报告(历史未绑定成员)仅**本人上传者或家庭管理员**可见;有 `subjectId` 时走 `ReportMemberPermissionService.canViewMemberReports`。
|
|
|
+- **items[]** 每项含:指标原字段(`indicatorId`/`definitionId`/`category`/`indicatorName`/`indicatorValue`/`numericValue`/`unit`/`refRange`/`status`)+ 字典字段(`goodDirection`/`valueType`)+ `previous`(上一期观测,无则 null)+ `change`(`{delta, deltaPct, movement, trendLabel, trendCode, skipGaps, unitMismatch, comparable}`,首期时为 `first_record`,报告日期未知时为 `pending_backfill`)。
|
|
|
+- **summary**:`totalCount` / `abnormalCount`(`status` 非「正常」)/ `abnormalDelta`(预留字段,当前固定 `0`,单报告视角无法直接算)/ `changedCount`(`trendCode` 为 improved/worsened 的条数)/ `comparableCount` / `firstRecordCount` / `pendingCount` / `dataIncomplete`(存在 pending_backfill 时为 true,驱动残缺横幅组件)。
|
|
|
+- **与 `withPrevious=false`**:返回单期 items(每项含 `indicatorId/category/indicatorName/indicatorValue/unit/refRange/status`,**不含** `definitionId/previous/change/goodDirection/valueType`)。
|
|
|
+- **`olderReportCount`**:该成员在本报告之前(同 sourceType)的历史报告数,用于 `first_record` 档区分「真的首期」与「更早报告未回填」。
|
|
|
+- **N+1 约束**:42 项指标一次请求的 SQL ≤ 5 次(指标行 1 + 上期批量解析 1 + 字典/定义 1 + 报告 1);`IndicatorMappingService.resolveBatch` 用 `indicator_mapping_rules` JOIN `indicator_definitions` 单查询批量解析,**严禁逐指标查库**。
|
|
|
+
|
|
|
+**② `POST /api/indicator/periods`** — 期次列表(双期对比页 picker 数据源)
|
|
|
+
|
|
|
+| 端点 | 权限 | 请求 | 返回 |
|
|
|
+|---|---|---|---|
|
|
|
+| `POST /api/indicator/periods` | 登录(JWT;`subjectId` 须属于当前家庭) | `{subjectId, sourceType?}` | `{subjectId, sourceType, items}` |
|
|
|
+
|
|
|
+- **items[]**:`{reportDate, reportId, dateSource, indicatorCount}`,按 `reportDate` 倒序;`reportDate=null`(日期未知期)**恒定排最后**,picker 显示「日期未知」。
|
|
|
+- **dateSource**:该期所有观测中**最差**的一个(`unknown < confirm < upload < real`),诚实口径——只要有一项来源是上传推断,整期就标 `upload`。
|
|
|
+- **indicatorCount**:该期有有效值(`value` 非空)的指标数,picker 显示「2026-10-08(42 项)」。
|
|
|
+- **不分页**(单人单类型期次数实测 < 30);只读幂等。
|
|
|
+
|
|
|
+**③ `POST /api/admin/indicator/backfill`** — 存量时序回填(admin)
|
|
|
+
|
|
|
+| 端点 | 权限 | 请求 | 返回 |
|
|
|
+|---|---|---|---|
|
|
|
+| `POST /api/admin/indicator/backfill` | admin(`@RequestAttribute("role")` 校验,非 admin 返回「权限不足」) | `{subjectId?, reportId?, limit?, dryRun?, fixReportDates?}` | `{scanned, eligible, written, skippedNoSubject, skippedNoPayload, failed, dryRun, fixReportDates, dateFixable, dateFixed, details[]}` |
|
|
|
+
|
|
|
+- **用途**:把 confirm 链路补写之前的历史报告补进 `indicator_values`(P0-3 数据面补全),并可顺带用 `ReportDateExtractor` 修复被 `new Date()` 污染的历史报告日期。
|
|
|
+- **入参**:`subjectId`(选填,指定成员;不传扫全部 `status=active` 报告);`reportId`(选填,只回填指定报告,灰度验证用);`limit`(选填,默认 200,上限 500);`dryRun`(默认 `true`);`fixReportDates`(默认 `false`)。
|
|
|
+- **`dryRun=true`**:预演只统计不写入,返回 `eligible`/`dateFixable` 计数,且**不触发 `mappingService.resolve`**(避免惰性建定义这类副作用);**首次执行必须 dryRun,核对无误后传 `false`**。
|
|
|
+- **顺序红线**:先修日期、再补时序(污染日期若固化进 `indicator_values` 再修就晚了)。日期修复判定条件:能提取到真实日期 且 `report_date != extracted` 且 `report_date >= created_at` 当天(`new Date()` 污染特征签名);修后需连带 `refreshMemberIndicatorCurrent`。
|
|
|
+- **幂等**:`NormalizeIndicatorPipeline` 按唯一键 `source_type + source_id + definition_id` upsert,已覆盖报告返回 `already_covered`,重复执行不产生重复时序。
|
|
|
+
|
|
|
+**④ 升级改造的既有端点(`IndicatorController`)**
|
|
|
+
|
|
|
+| 端点 | 变更 |
|
|
|
+|---|---|
|
|
|
+| `POST /api/indicator/trend` | 新增可选入参 `{sourceType, fromDate, toDate, granularity: raw\|month, sourceKind: all\|report\|device}`;出参新增 `refLow/refHigh/goodDirection/valueType/pointsCount/totalReportCount/olderReportCount/chartMode/unitMismatch/latest/change/points/missingPeriods`。**破坏性:无** |
|
|
|
+| `POST /api/indicator/change-ranking` | 新增可选入参 `{scope: pair, fromReportDate, toReportDate, filter: improved\|worsened\|flat\|incomparable\|all, page, pageSize}`;`scope=pair` 缺 `fromReportDate`/`toReportDate` 返回明确错误;**`magnitude` 排序口径从 `\|Δ\|` 改为 `\|Δ%\|` 降序**(视觉有变化,属预期修正,见 §4.48 变更汇总);`deltaPct=null` 的项恒定排最后且不参与 improved/worsened 筛选(Q14)。**破坏性:无** |
|
|
|
+| `POST /api/indicator/quick-lookup` | 新增可选入参 `{withSparkline, sparkLimit}`;出参每项新增 `previous`/`change`/`latestDateSource`/`latestReportId`/`goodDirection`/`valueType`/`sparkline`;**修复 `reportDate=null` 观测被当作最新值的 bug**。**破坏性:无** |
|
|
|
+| `POST /api/indicator/source-types` | 出参新增 `periodCount` / `latestReportDate`(曲线页类型筛选用,原只返回类型名)。**破坏性:无** |
|
|
|
+
|
|
|
+> **`chartMode` 判定表**(后端单点定义,`IndicatorChangeService.chartModeOf`):`pointsCount=0 → empty`;`=1 → single`;`=2 → pair`;`<20 → line`;`≥20 → line_aggregated`(`granularity=month` 时强制 `line_aggregated`)。
|
|
|
+> **`IndicatorService.listDefinitions`**:`status` 传 null 时**默认按 `status=1` 过滤**(防止 P1-6 自动创建的 `status=0` definition 冒进管理端字典列表,QP17)。
|
|
|
+> **老接口兼容矩阵**见 `specs/2026-10-25-indicator-timeline-display-design.md` §4.7。
|
|
|
+
|
|
|
+*文档更新:2026-10-27(指标多期展示 T02 后端接口,见 `specs/2026-10-25-indicator-timeline-display-design.md`)*
|
|
|
+
|
|
|
---
|
|
|
|
|
|
### 4.49 健康方案删除(`/api/health/plan/delete`、`/api/admin/health-plan/delete`)
|