|
|
@@ -0,0 +1,452 @@
|
|
|
+# 指标变化曲线 · 指标速查 · 指标关联 设计规范
|
|
|
+
|
|
|
+**版本:** v1.0
|
|
|
+**日期:** 2026-10-09
|
|
|
+**状态:** 已确认(头脑风暴 + Oracle 架构评审通过)
|
|
|
+**作者:** Sisyphus
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1. 背景与目标
|
|
|
+
|
|
|
+### 1.1 现状问题
|
|
|
+
|
|
|
+- 同一类报告(如肠道菌群报告)多次上传后,页面只展示**单份报告**的详情,无法看到各项指标**随时间的变化**(哪项菌群升了、哪项降了)
|
|
|
+- 食材推荐指数虽有 `food_recommend_idx_log` 变化日志和 `getTrend()` 接口,但**没有按变化幅度排序**的能力
|
|
|
+- 指标名散落在各报告的 `health_indicators`(文本名),**没有统一的指标身份**,无法跨报告类型对比、无法做指标间的关联
|
|
|
+- 报告与报告之间、指标与指标之间的**关联关系**(如「记忆力 ↔ 影响睡眠的菌群含量」正/负相关、强度)完全没有数据模型支撑
|
|
|
+- `health_reports.report_date` 目前存的是**上传时间**而非报告真实日期,曲线横轴必然错位
|
|
|
+- 用户与规划师无法快速回答:「这个孩子最近 3 次菌群报告,哪些指标在好转、哪些在恶化?」
|
|
|
+
|
|
|
+### 1.2 设计目标
|
|
|
+
|
|
|
+1. **指标变化曲线**:同一类报告、不同报告日期 → 展示各指标数值随报告日期的变化(菌群增减、食材推荐升降),支持**按变化幅度排名**
|
|
|
+2. **指标速查**:查询某一成员当前所有指标的数值 + 变化趋势(分类分页)
|
|
|
+3. **指标关联关系**:定义指标之间的关联(正/负相关、强度、说明),管理端人工定义 + 真实数据校准(混合模式)
|
|
|
+
|
|
|
+### 1.3 用户故事
|
|
|
+
|
|
|
+- 作为家长,我想看孩子两次菌群报告之间哪些菌群/营养指标上升了、哪些下降了,好判断调理方向
|
|
|
+- 作为家长,我想知道「记忆力」这类认知指标和菌群报告里「影响睡眠的菌群」是否相关、相关性多强
|
|
|
+- 作为规划师/运营,我想在管理端维护指标关联关系和归一化映射规则,校准数据
|
|
|
+
|
|
|
+### 1.4 不在本文档范围(二期)
|
|
|
+
|
|
|
+- DAN / 体检等其余报告详情页的「变化」区块(一期只做菌群报告详情页)
|
|
|
+- 跨报告类型的同曲线叠加对比(如菌群乳杆菌 vs 体检某项)
|
|
|
+- `good_direction` 自动推断(一期管理端手配)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 2. 现状调研结论
|
|
|
+
|
|
|
+| 现有资产 | 内容 | 对本次的可用性 |
|
|
|
+|---|---|---|
|
|
|
+| `health_reports` | 报告主表(report_type/report_date/subject_id/payload_json) | 曲线原数据;`report_date` 需修正为真实日期 |
|
|
|
+| `health_indicators` | 解析后的指标明细(report_id/category/indicator_name/indicator_value/status) | 报告指标原数据;保持为单一写者目标,**不删除** |
|
|
|
+| `report_type_registry` | 报告类型登记 + expected_indicators | 「同一类报告」分组依据;定义/映射种子来源 |
|
|
|
+| `food_recommend_idx` / `_log` | 食材推荐指数 + 变更日志(previous/new/report_id/changed_at) | 食材曲线几乎现成;缺变化幅度排名;保留语义 |
|
|
|
+| `indicator_definitions` / `indicator_values` | 通用指标字典 + 泛用指标值(sourceType/sourceId/definitionId/numericValue/recordedAt) | **升级为全平台统一指标层**(当前仅舌诊在用) |
|
|
|
+| `five_dimension_scores` / `health_dimension_scores` | 五维 / 七维评分(含 assessedAt) | 维度评分趋势现成;**不写入统一时序**,API 层单独合入 |
|
|
|
+| 指标关联表 | **不存在** | 新建 `indicator_correlations` |
|
|
|
+
|
|
|
+**关键缺口**:统一指标身份、归一化映射层、指标关联表、真实报告日期、变化幅度排名接口。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3. 设计决策
|
|
|
+
|
|
|
+| 决策项 | 选择 | 理由 |
|
|
|
+|--------|------|------|
|
|
|
+| 指标统一身份 | **方案 A**:复用 `indicator_definitions` + `indicator_values` 升级为统一指标层 | 项目本就有意的通用结构;跨类型统一;关联可跨类型;速查一处查全 |
|
|
|
+| 指标范围 | 报告解析指标(含菌属、营养、维生素等)+ 食材推荐指数 + 五维/七维评分 | 用户确认「全报告类型统一」+「上述 + 五维/七维评分」 |
|
|
|
+| 五维/七维存储 | **不进** `indicator_values`,保留原表,API 层单独合入「维度评分」小节 | 维度评分是聚合值,与原始测量混在一个时序中层级混乱 |
|
|
|
+| 关联关系 | 人工定义(候选对+方向+人工强度)+ 真实数据校准(computed_strength + sample_size),混合模式 | 用户确认 |
|
|
|
+| 报告日期 | 从 PDF 提取真实报告/采样日期;历史回填 | 曲线横轴准确性前提,用户确认纳入 |
|
|
|
+| 归一化映射 | 独立表 `indicator_mapping_rules`(source_type+raw_name→definition_id),exact→fuzzy→AI兜底→惰性注册 | Oracle 评审:比在 definitions 上加 aliases 列更可运营、可支撑 fuzzy/AI 兜底 |
|
|
|
+| 食材推荐 | 保留 `food_recommend_idx`+`log`(变化日志语义),同时**增写** `indicator_values`(source_type=food_recommend) | 不破坏现有变化日志接口 |
|
|
|
+| 双写一致性 | 单一写者模式:解析照旧写 `health_indicators`,`NormalizeIndicatorPipeline` 同流程写 `indicator_values`,幂等覆盖 | Oracle 评审:避免两表分叉 |
|
|
|
+| 校准算法 | Spearman 秩相关;单对象 ≥3 配对、聚合有效样本 ≥30 才用 computed 覆盖 manual;非数值型对跳过 | 菌群丰度偏态分布,Spearman 稳健;样本不足不误导 |
|
|
|
+| 图表实现 | 沿用小程序手写 canvas 模式,新增 `TrendChart.vue`,不引入图表库 | 小程序包体积 + HBuilderX 打包约束 |
|
|
|
+| 变化着色 | `good_direction`(越高越好/越低越好/区间内越好)驱动箭头与颜色 | Oracle 评审:没有它无法判断变化是改善还是恶化 |
|
|
|
+| 关联对排序 | `definition_id_a < definition_id_b`(按 code 字典序),应用层强制 | 唯一键对称,避免 A-B / B-A 重复 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4. 数据模型
|
|
|
+
|
|
|
+### 4.1 报告日期修正
|
|
|
+
|
|
|
+- PDF 解析阶段(`PdfParseService` / LangGraph `report_parse_agent.py`)新增提取「报告日期 / 采样日期」→ `payload.reportDate`
|
|
|
+- 入库时 `health_reports.report_date` 优先使用真实日期,缺失回退上传时间
|
|
|
+- 历史回填任务:扫描 `report_date` 缺失或为上传时间的旧报告,从其 `payload_json` / 存储 PDF 中重新提取真实日期并回填;**幂等可重跑**;无法提取的置 NULL(不伪装成上传时间)
|
|
|
+- ⚠️ 实现前先确认 `health_indicators.collection_date` 列在数据库真实存在(实体注释标注「DB列不存在」),若确实缺失先补迁移
|
|
|
+
|
|
|
+### 4.2 `indicator_definitions` 扩展
|
|
|
+
|
|
|
+新增列:
|
|
|
+
|
|
|
+| 列 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `source_kind` | VARCHAR(32) | `report_indicator` / `bacteria` / `food_index` / `dimension_score` |
|
|
|
+| `report_type_scope` | VARCHAR(32) | 适用报告类型(空=通用),支撑「同一类报告」分组 |
|
|
|
+| `value_type` | VARCHAR(16) | `numeric` / `categorical` / `level`(语义类型,与 dataType 区分) |
|
|
|
+| `good_direction` | VARCHAR(16) | `higher_is_better` / `lower_is_better` / `in_range_is_better` / `neutral` |
|
|
|
+| `dimension_code` | VARCHAR(16) | 关联五维(body/mind/wisdom/action/wealth,可空) |
|
|
|
+
|
|
|
+保留现有:`domain` / `category` / `code` / `name` / `dataType` / `options` / `unit` / `refRange` / `sortOrder` / `status`。
|
|
|
+
|
|
|
+**目录来源**:
|
|
|
+- `report_type_registry.expected_indicators` → 预生成每类报告的指标定义
|
|
|
+- 菌属 200+ / 食材 224 → **惰性注册**(首次出现即 upsert,不预埋),code 使用 `bacteria.<name>` / `food.<foodId>` / `indicator.<category>.<name>` 风格
|
|
|
+- 五维/七维 → 预置少量定义(`dim.body` 等,仅作展示标签,不写 indicator_values)
|
|
|
+
|
|
|
+### 4.3 `indicator_values` 扩展(统一观测时序)
|
|
|
+
|
|
|
+新增列:
|
|
|
+
|
|
|
+| 列 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `subject_id` | BIGINT | 观测对象(对齐 `health_reports.subject_id` / family_members.id) |
|
|
|
+| `family_id` | BIGINT | 所属家庭 |
|
|
|
+| `report_id` | BIGINT | 来源报告(可空:食物指数 / 维度评分类) |
|
|
|
+| `report_date` | DATE | 冗余报告日期,供时序查询 |
|
|
|
+| `unit` | VARCHAR(32) | 观测单位(若与定义不一致,写入时告警) |
|
|
|
+| `status` | VARCHAR(32) | 观测时状态快照(正常/偏高/偏低…) |
|
|
|
+
|
|
|
+保留现有:`source_type` / `source_id` / `definition_id` / `value` / `numeric_value` / `remark` / `recorded_at`。
|
|
|
+
|
|
|
+**索引与约束**:
|
|
|
+```sql
|
|
|
+ALTER TABLE indicator_values
|
|
|
+ ADD COLUMN subject_id BIGINT NULL,
|
|
|
+ ADD COLUMN family_id BIGINT NULL,
|
|
|
+ ADD COLUMN report_id BIGINT NULL,
|
|
|
+ ADD COLUMN report_date DATE NULL,
|
|
|
+ ADD COLUMN unit VARCHAR(32) NULL,
|
|
|
+ ADD COLUMN status VARCHAR(32) NULL,
|
|
|
+ ADD UNIQUE KEY uk_source_definition (source_type, source_id, definition_id),
|
|
|
+ ADD INDEX idx_subject_def_date (subject_id, definition_id, report_date),
|
|
|
+ ADD INDEX idx_def (definition_id);
|
|
|
+```
|
|
|
+
|
|
|
+- 唯一约束保证**幂等**:同一 (source_type, source_id, definition_id) 重解析只覆盖更新
|
|
|
+- `source_type` 取值:报告类型(`gut_flora` 等)/ `food_recommend` / `dimension_score`
|
|
|
+
|
|
|
+### 4.4 `indicator_mapping_rules`(新建)
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS indicator_mapping_rules (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ source_type VARCHAR(32) NOT NULL COMMENT 'gut_flora|physical_exam|dan_a2|food_recommend|five_dimension|health_dimension',
|
|
|
+ raw_name VARCHAR(200) NOT NULL COMMENT '报告中的原始名称(指标名/菌名/食材名)',
|
|
|
+ alias_text TEXT COMMENT '别名 JSON 数组,用于模糊匹配',
|
|
|
+ definition_id BIGINT NOT NULL COMMENT 'FK → indicator_definitions.id',
|
|
|
+ match_type VARCHAR(20) DEFAULT 'exact' COMMENT 'exact|fuzzy|ai_fallback|auto_created',
|
|
|
+ priority INT DEFAULT 0 COMMENT '多规则冲突时取最高',
|
|
|
+ status TINYINT DEFAULT 1,
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ UNIQUE KEY uk_source_raw (source_type, raw_name),
|
|
|
+ INDEX idx_def (definition_id)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标归一化映射规则';
|
|
|
+```
|
|
|
+
|
|
|
+### 4.5 `indicator_correlations`(新建)
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS indicator_correlations (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ definition_id_a BIGINT NOT NULL COMMENT 'code 字典序较小的指标',
|
|
|
+ definition_id_b BIGINT NOT NULL COMMENT 'code 字典序较大的指标',
|
|
|
+ relation_type VARCHAR(20) DEFAULT 'correlation' COMMENT 'correlation(相关)|influence(影响)|same_source(同源)',
|
|
|
+ direction VARCHAR(10) NOT NULL COMMENT 'positive|negative',
|
|
|
+ manual_strength DECIMAL(3,2) NOT NULL COMMENT '人工标定强度 0~1,样本不足时使用',
|
|
|
+ computed_strength DECIMAL(4,3) NULL COMMENT '统计计算相关系数(Spearman rho)',
|
|
|
+ method VARCHAR(20) DEFAULT 'spearman' COMMENT 'pearson|spearman',
|
|
|
+ sample_size INT DEFAULT 0 COMMENT '参与计算的聚合有效样本数',
|
|
|
+ confidence VARCHAR(10) COMMENT 'high(>=30)|medium(10~29)|low(<10)',
|
|
|
+ effective_strength DECIMAL(4,3) NOT NULL COMMENT '展示值:有效样本>=30 时取 computed,否则取 manual',
|
|
|
+ manual_locked TINYINT DEFAULT 0 COMMENT '1=人工锁定,数据校准不覆盖 direction/manual_strength/effective_strength',
|
|
|
+ cohort_scope VARCHAR(20) DEFAULT 'subject' COMMENT 'subject|family|population',
|
|
|
+ status VARCHAR(20) DEFAULT 'active' COMMENT 'active|inactive|pending',
|
|
|
+ computed_at DATETIME NULL COMMENT '最后校准时间',
|
|
|
+ created_by BIGINT NULL COMMENT '创建者(人工定义时)',
|
|
|
+ description VARCHAR(500) NULL COMMENT '给用户看的解释',
|
|
|
+ source_note VARCHAR(255) NULL COMMENT '依据/出处',
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ UNIQUE KEY uk_pair (definition_id_a, definition_id_b),
|
|
|
+ INDEX idx_def_a (definition_id_a),
|
|
|
+ INDEX idx_def_b (definition_id_b)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='指标关联关系(人工定义 + 数据校准)';
|
|
|
+```
|
|
|
+
|
|
|
+**对序规则**:写入前按 `definition.code` 字典序比较,小的存 `a`、大的存 `b`,应用层强制,保证唯一键对称。
|
|
|
+
|
|
|
+### 4.6 数据校准(Spearman 任务)
|
|
|
+
|
|
|
+- 定时任务(Spring `@Scheduled`,每日凌晨)+ 管理端手动触发(`/api/admin/indicator/correlation/calibrate`)
|
|
|
+- 范围:`status='active'` 且 `manual_locked=0` 的关联对
|
|
|
+- 算法:
|
|
|
+ 1. 仅计算两端指标均为数值型/有序等级型的配对(`value_type IN ('numeric','level')`)
|
|
|
+ 2. 按 `subject_id` 分组,对每个对象取该指标对的**配对测量序列**(按 report_date 对齐,≥3 个配对点才参与)
|
|
|
+ 3. 每对象算 Spearman rho → Fisher z 变换 → 全对象 z 均值 → 还原为平均 rho
|
|
|
+ 4. 有效样本量 = 参与聚合的对象配对点总数;`confidence`:≥30 → high,10~29 → medium,<10 → low
|
|
|
+ 5. 更新 `computed_strength` / `sample_size` / `method` / `confidence` / `computed_at`
|
|
|
+ 6. `effective_strength = 有效样本>=30 ? computed_strength : manual_strength`(方向若与人工矛盾且锁定时,保持人工)
|
|
|
+- Java 8 无内置相关函数:新增约 20 行工具方法(排序后计算秩差平方),不引外部依赖
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 5. 归一化映射管道(单一写者)
|
|
|
+
|
|
|
+```
|
|
|
+报告解析/采集确认(或重解析)
|
|
|
+ ├─ 原有逻辑照旧写 health_indicators(不动现有消费者:HealthAnalysisService 等)
|
|
|
+ └─ NormalizeIndicatorPipeline(同流程/同事务内)
|
|
|
+ 1. 收集该报告全部:health_indicators 明细 + 菌属(payload/gut_flora)+ 食物(payload/食材)
|
|
|
+ 2. 每条 (source_type=报告类型, raw_name) 解析 definition_id:
|
|
|
+ exact 命中 indicator_mapping_rules → definition_id
|
|
|
+ fuzzy 命中(CJK 二元组 / 拼音归一化)→ definition_id
|
|
|
+ AI 兜底(AiGateway → LangGraph 归类)→ 建议 definition_id(登记 pending 规则,管理端确认)
|
|
|
+ 新发现 → 惰性注册新 definition + 自动登记 exact 规则(match_type=auto_created)
|
|
|
+ 3. 幂等写入 indicator_values
|
|
|
+ INSERT ... ON DUPLICATE KEY UPDATE (source_type, source_id, definition_id)
|
|
|
+ 4. 记录 subject_id / family_id / report_id / report_date(真实报告日期)
|
|
|
+```
|
|
|
+
|
|
|
+**食物推荐指数钩子**:`FoodRecommendService.recalculateForUser()` 完成后,把该用户最新 `food_recommend_idx` 全量快照写入 `indicator_values`(`source_type=food_recommend`,`source_id=food_recommend_idx.id`,`definition_id` 经 `food.<foodId>` 映射)。
|
|
|
+
|
|
|
+**批量种子**:管理端 `/api/admin/indicator/mapping/import` 一次性导入菌属 200+ / 食材 224 / expected_indicators 的映射种子。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 6. 后端 API 契约
|
|
|
+
|
|
|
+> 统一 `@PostMapping`、`Result<T>`、JWT;`subject_id` 服务端校验归属(当前用户家庭内成员)。
|
|
|
+
|
|
|
+### 6.1 指标曲线
|
|
|
+
|
|
|
+```
|
|
|
+POST /api/indicator/trend
|
|
|
+body: { subjectId, definitionIds: [1,2,3] }
|
|
|
+→ data: {
|
|
|
+ "items": [{
|
|
|
+ "definitionId": 1, "name": "双歧杆菌属",
|
|
|
+ "points": [ { "reportDate":"2026-08-15", "value":"12.8", "unit":"%", "status":"偏高" }, ... ]
|
|
|
+ }]
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+横轴 `reportDate` = 真实报告日期,升序。
|
|
|
+
|
|
|
+### 6.2 变化幅度排名
|
|
|
+
|
|
|
+```
|
|
|
+POST /api/indicator/change-ranking
|
|
|
+body: { subjectId, reportType?, category?, scope: "adjacent"|"first-vs-latest", orderBy: "up"|"down"|"magnitude", limit: 50 }
|
|
|
+→ data: {
|
|
|
+ "items": [{
|
|
|
+ "definitionId": 5, "name": "维生素B1", "category": "维生素",
|
|
|
+ "sourceKind": "report_indicator", "unit": "mg",
|
|
|
+ "before": { "reportDate":"2026-08-15", "value":"2" },
|
|
|
+ "after": { "reportDate":"2026-10-01", "value":"4" },
|
|
|
+ "delta": 2, "deltaPct": 100,
|
|
|
+ "movement": "up"|"down"|"flat",
|
|
|
+ "trendLabel": "改善"|"恶化"|"中性" // 按 good_direction 判定
|
|
|
+ }],
|
|
|
+ "overall": { "improvedCount": 12, "worsenedCount": 3, "flatCount": 5 }
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+- `scope=adjacent`:相邻两次报告之差(默认);`first-vs-latest`:首尾对比
|
|
|
+- 排序:`magnitude` 按 Δ 绝对值降序(默认);`up`/`down` 按 Δ 正/负降序
|
|
|
+- 食材指数单独过滤(`sourceKind=food_index`)或混合(按 category 过滤)
|
|
|
+
|
|
|
+### 6.3 指标速查
|
|
|
+
|
|
|
+```
|
|
|
+POST /api/indicator/quick-lookup
|
|
|
+body: { subjectId, category?, page: 1, pageSize: 30 }
|
|
|
+→ data: {
|
|
|
+ "categories": [ { "name":"核心菌属", "total": 32 }, ... ],
|
|
|
+ "items": [{
|
|
|
+ "definitionId": 1, "name": "双歧杆菌属", "category": "核心菌属",
|
|
|
+ "value": "12.8", "unit": "%", "refRange": "0.19-14.59", "status": "偏高",
|
|
|
+ "trend": "up"|"down"|"flat", "trendLabel": "改善",
|
|
|
+ "latestReportDate": "2026-10-01", "pointsCount": 3
|
|
|
+ }],
|
|
|
+ "dimensionScores": [ // 五维/七维评分小节(不写 indicator_values,API 层 join 原表)
|
|
|
+ { "dimensionCode":"body", "name":"身", "score": 82, "assessedAt":"2026-09-30", "trend": "up" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+分类分页(每类 ≤30 项),避免一次拉取 200+ 菌属。
|
|
|
+
|
|
|
+### 6.4 指标关联查询
|
|
|
+
|
|
|
+```
|
|
|
+POST /api/indicator/correlation/list
|
|
|
+body: { subjectId, definitionId }
|
|
|
+→ data: {
|
|
|
+ "relations": [{
|
|
|
+ "relation": { "pairId": 1, "indicatorA": {"definitionId":1,"name":"记忆力"}, "indicatorB": {...},
|
|
|
+ "direction":"positive", "effectiveStrength": 0.72,
|
|
|
+ "strengthSource":"computed"|"manual", "sampleSize": 45,
|
|
|
+ "confidence":"high", "manualLocked": false,
|
|
|
+ "description":"记忆力与睡眠相关菌群含量正相关……" },
|
|
|
+ "subjectEvidence": { // 该成员自己的配对数据支撑(如有)
|
|
|
+ "points": 4, "personalRho": 0.68, "hasEnough": true
|
|
|
+ }
|
|
|
+ }]
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+### 6.5 管理端(cfc-web)
|
|
|
+
|
|
|
+| 接口 | 用途 |
|
|
|
+|---|---|
|
|
|
+| `POST /api/admin/indicator/correlation/save` | 人工定义/编辑关联对(A/B/方向/人工强度/说明/locked/来源) |
|
|
|
+| `POST /api/admin/indicator/correlation/list` | 关联对分页列表(含校准状态) |
|
|
|
+| `POST /api/admin/indicator/correlation/calibrate` | 手动触发全校准或单对校准 |
|
|
|
+| `POST /api/admin/indicator/mapping/import` | 批量导入映射种子(JSON/CSV) |
|
|
|
+| `POST /api/admin/indicator/mapping/list` | 映射规则分页 + 未匹配 raw 的 review 列表 |
|
|
|
+
|
|
|
+### 6.6 复用既有接口
|
|
|
+
|
|
|
+- `POST /api/food/recommendation/trend`(食材单指标趋势)继续用于菌群食物详情页
|
|
|
+- `POST /api/health/knowledge/query` 知识库弹出框继续用于速查/曲线页指标名称点击
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 7. 前端页面
|
|
|
+
|
|
|
+### 7.1 小程序(家长端双角色视图)
|
|
|
+
|
|
|
+**指标变化曲线页** `pages/health/indicator-curve.vue`(新增)
|
|
|
+- 入口:菌群报告详情页顶部「变化」入口、`pages/health/report-list` 顶部、身维度页
|
|
|
+- 布局:
|
|
|
+ - 顶部筛选:成员切换 + 报告类型 + 时间范围
|
|
|
+ - 曲线区:指标选择器 → `TrendChart` 折线(横轴=真实报告日期,多报告点,数据点标注数值)
|
|
|
+ - 变化排名区:Tab(菌群变化 / 食材变化 / 指标变化)+ 排序(升幅↑ / 降幅↓ / 绝对幅度);相邻两次报告 Δ;按 `good_direction` 着色
|
|
|
+- 图表:新增通用 `components/TrendChart.vue`(多序列折线 + 数据点 + 箭头),沿用**手写 canvas** 模式(参考 `RadarChart.vue` 的 type=2d + DPR 适配 + 重试初始化),不引入图表库
|
|
|
+
|
|
|
+**指标速查页** `pages/health/indicator-quicklook.vue`(新增)
|
|
|
+- 分类 Tab + 分页(每类 ≤30 项/页)
|
|
|
+- 每项一行:名称(可点弹知识库,复用 `health-knowledge-popup`)| 最新值 | 参考区间 | ↑↓→ 趋势 | 最近报告日期
|
|
|
+- 独立小节:五维/七维评分趋势
|
|
|
+- 点击单项 → 跳转该指标曲线页(携带 definitionId)
|
|
|
+
|
|
|
+**菌群报告详情页** `pages/health/gut-flora-detail.vue`(改)
|
|
|
+- 增加「变化」区块:最近两次同类型报告的菌属 Δ,红/绿标注(一期仅此报告详情页;DAN/体检详情页变化区块留到二期)
|
|
|
+
|
|
|
+**pages.json**:注册 2 个新页面路径;**utils/api.js**:新增 trend / change-ranking / quick-lookup / correlation/list 封装(遵守 API 去重规范,同 URL 单一规范入口)
|
|
|
+
|
|
|
+### 7.2 Web 管理端(cfc-web)
|
|
|
+
|
|
|
+**`views/admin/IndicatorCorrelations.vue`**(新增)
|
|
|
+- 关联对配置:选 A/B 指标(定义搜索框)、方向、人工强度、说明、`manual_locked` 开关
|
|
|
+- 列表:computed_strength / sample_size / confidence / last_calibrated_at;一键触发校准
|
|
|
+
|
|
|
+**`views/admin/IndicatorMappings.vue`**(新增)
|
|
|
+- 归一化规则管理(source_type + raw_name → definition_id)+ 批量导入 + 未匹配 raw review(AI 建议确认)
|
|
|
+
|
|
|
+**router**:注册对应管理端路由(admin 权限)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 8. 变化颜色与箭头规则
|
|
|
+
|
|
|
+由 `good_direction` × 变化方向判定,全局统一:
|
|
|
+
|
|
|
+| good_direction | 数值↑ | 数值↓ | 备注 |
|
|
|
+|---|---|---|---|
|
|
|
+| `higher_is_better` | 🟢 绿 ↑(改善) | 🔴 红 ↓(恶化) | 如双歧杆菌属 |
|
|
|
+| `lower_is_better` | 🔴 红 ↑(恶化) | 🟢 绿 ↓(改善) | 如炎症水平 |
|
|
|
+| `in_range_is_better` | 向参考区间内移动 → 🟢 绿 ↑/↓;远离 → 🔴 红 | 结合 refRange 判定 | 如维生素 |
|
|
|
+| `neutral` | ⚪ 灰 ↑ | ⚪ 灰 ↓ | 无优劣方向 |
|
|
|
+| 无变化 | ⚪ 灰 → | | |
|
|
|
+
|
|
|
+实现遵循小程序限制:`:class="'mb-' + item._cssClass"` 内联表达式(禁方法调用、禁中文类名),`_cssClass` 由后端或前端 computed 映射为英文(`impr-up`/`worst-down`/`flat` 等)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 9. 验收标准
|
|
|
+
|
|
|
+| # | 验收项 | 验证方式 |
|
|
|
+|---|---|---|
|
|
|
+| 1 | 上传第二份同类型报告后,曲线页显示完整前后对比;变化排名按幅度排序正确 | 手工 + e2e |
|
|
|
+| 2 | 变化箭头颜色符合 good_direction(如炎症下降=绿、双歧杆菌上升=绿) | 手工 |
|
|
|
+| 3 | 速查按分类分页正常,含五维/七维小节;点击单项跳转曲线 | 手工 |
|
|
|
+| 4 | 管理端配置关联对 → 小程序立即可见;有真实配对数据显示校准强度+样本量;样本<30 显示人工值 | 手工 |
|
|
|
+| 5 | 新报告 report_date = PDF 真实日期;历史回填任务幂等可重跑(连跑两次结果一致) | 脚本 + 手工 |
|
|
|
+| 6 | 归一化幂等:同一报告重解析不产生重复 observation(唯一键生效) | 脚本断言 |
|
|
|
+| 7 | `report_type_registry.expected_indicators` 与默认映射种子导入后,解析出的常见指标 100% 命中映射(无 AI 兜底) | 脚本统计 |
|
|
|
+| 8 | `mvn clean compile` 通过;前端 script 语法校验(node --check)通过;API 去重审计通过 | CI 命令 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 10. 文件变更清单
|
|
|
+
|
|
|
+| 层 | 文件 | 操作 | 内容 |
|
|
|
+|---|---|---|---|
|
|
|
+| 后端 | `config/DatabaseInitializer.java` | 改 | 迁移:definitions/values 加列 + 索引 + 唯一键;新建 mapping_rules/correlations 两表;report_date 真实日期回填;确认/修复 health_indicators.collection_date;种子映射导入(迁移编号递增查找) |
|
|
|
+| 后端 | `resources/schema.sql` | 改 | 同步 4 处 DDL |
|
|
|
+| 后端 | `entity/IndicatorDefinition.java` / `IndicatorValue.java` | 改 | 新字段 |
|
|
|
+| 后端 | `entity/IndicatorMappingRule.java` / `entity/IndicatorCorrelation.java` | 新建 | 新实体 |
|
|
|
+| 后端 | `mapper/IndicatorMappingRuleMapper.java` / `mapper/IndicatorCorrelationMapper.java` | 新建 | BaseMapper |
|
|
|
+| 后端 | `service/IndicatorMappingService.java` | 新建 | resolve(raw)→definitionId;register;import 种子 |
|
|
|
+| 后端 | `service/NormalizeIndicatorPipeline.java` | 新建 | 解析后钩子,幂等写 indicator_values |
|
|
|
+| 后端 | `service/IndicatorTrendService.java` | 新建 | trend / change-ranking / quick-lookup |
|
|
|
+| 后端 | `service/IndicatorCorrelationService.java` | 新建 | 关联 CRUD + effective_strength + Spearman 校准 |
|
|
|
+| 后端 | `service/ReportDateExtractor.java` | 新建 | PDF/payload 真实日期提取 + 回填 |
|
|
|
+| 后端 | `controller/IndicatorController.java` | 新建 | /api/indicator/*(4 个视图接口) |
|
|
|
+| 后端 | `controller/admin/IndicatorCorrelationAdminController.java` / `IndicatorMappingAdminController.java` | 新建 | 管理端接口 |
|
|
|
+| 后端 | `service/FoodRecommendService.java` | 改 | recalculateForUser 后增写 indicator_values |
|
|
|
+| 后端 | `service/AiGateway.java`(及 LangGraph) | 改 | 新增指标归类兜底方法/endpoint |
|
|
|
+| 后端 | 新增 `job/IndicatorCalibrationJob.java` | 新建 | @Scheduled 每日校准 |
|
|
|
+| 小程序 | `components/TrendChart.vue` | 新建 | 通用折线组件(手写 canvas) |
|
|
|
+| 小程序 | `pages/health/indicator-curve.vue` / `indicator-quicklook.vue` | 新建 | 曲线页 / 速查页 |
|
|
|
+| 小程序 | `pages/health/gut-flora-detail.vue` | 改 | 增加「变化」区块 |
|
|
|
+| 小程序 | `pages.json` | 改 | 注册 2 页 |
|
|
|
+| 小程序 | `utils/api.js` | 改 | 新增 4 个接口封装 |
|
|
|
+| Web 端 | `views/admin/IndicatorCorrelations.vue` / `IndicatorMappings.vue` | 新建 | 关联配置 / 映射管理 |
|
|
|
+| Web 端 | `router/index.js` | 改 | 注册管理端路由 |
|
|
|
+| 测试 | `tests/e2e/indicator-curve-flow.spec.js` 等 | 新建 | 曲线/速查/关联冒烟 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 11. 风险与权衡
|
|
|
+
|
|
|
+| 风险 | 缓解 |
|
|
|
+|---|---|
|
|
|
+| 归一化映射质量(AI 兜底可能错配) | 映射规则管理端可 review;AI 建议先登记 pending,人工确认后生效 |
|
|
|
+| 双写一致性(health_indicators vs indicator_values) | 单一写者;同事务;唯一键幂等覆盖 |
|
|
|
+| 速查性能(200+ 菌属 × 多次报告) | subject_id + 复合索引;分类分页;每类 30 项 |
|
|
|
+| 历史报告回填工作量大 | 分批、幂等、可中断续跑;取不出日期的置 NULL |
|
|
|
+| 方向/颜色误判 | good_direction 管理端可维护;一期手配,二期自动推断 |
|
|
|
+| 关联校准样本不足 | effective_strength 逻辑:样本 ≥30 才用计算值,否则人工值;confidence 分级展示 |
|
|
|
+| 指标名变化(同一菌不同报告写法不同) | fuzzy 匹配 + alias_text + AI 兜底多级回落 |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 12. 实现顺序(分期)
|
|
|
+
|
|
|
+1. **P1 后端数据层**:迁移(4 处 DDL + report_date 回填 + collection_date 确认)→ 实体/Mapper/Service → `mvn clean compile`
|
|
|
+2. **P2 归一化管道**:`IndicatorMappingService` + `NormalizeIndicatorPipeline` + 食物钩子 + 种子导入 → 幂等验证
|
|
|
+3. **P3 视图 API**:trend / change-ranking / quick-lookup(含五维七维小节)+ correlation/list → `mvn clean compile`
|
|
|
+4. **P4 小程序页面**:`TrendChart` → 曲线页 → 速查页 → 菌群详情「变化」区块 → pages.json / api.js → HBuilderX 打包人工验证
|
|
|
+5. **P5 管理端**:`IndicatorCorrelations.vue` + `IndicatorMappings.vue` + admin API + 路由
|
|
|
+6. **P6 校准任务**:Spearman 工具 + `IndicatorCalibrationJob` + 管理端手动触发 + 验收清单逐项过
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 13. 二期展望
|
|
|
+
|
|
|
+- DAN / 体检等其余报告详情页「变化」区块
|
|
|
+- 跨报告类型同曲线叠加对比(菌群乳杆菌 vs 体检某项)
|
|
|
+- 关联关系的知识库弹出框内展示(点击关联项弹出说明)
|
|
|
+- `good_direction` 从参考区间/历史数据自动推断
|
|
|
+- 关联方向与人工矛盾时的冲突提醒与运营工作流
|