2026-10-09-indicator-change-curve-design.md 27 KB

指标变化曲线 · 指标速查 · 指标关联 设计规范

版本: 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(不伪装成上传时间)
  • 复用既有入口:HealthReportService 已有 reportDate 修正逻辑(约 1749 行,读 payload.reportDate → yyyy-MM-dd 解析 → setReportDate),新提取只负责把真实日期写入 payload.reportDate,入库逻辑复用
  • health_indicators.collection_date 已存在于 schema.sql(1868 行),无需补列;实施时仅需确认生产库同样存在(用 ensureColumn 兜底)

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。

索引与约束:

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(五维/七维评分不入本表,见 4.2)

4.4 indicator_mapping_rules(新建)

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(新建)

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 真实日期回填;collection_date 已存在(schema.sql 1868 行)用 ensureColumn 兜底生产库;种子映射导入(当前最新迁移编号 355,从 356 起递增)
后端 docs/superpowers/api/API_REFERENCE.md 改 新增接口前查重、新增后同步记录(trend/change-ranking/quick-lookup/correlation + 管理端 5 接口)
后端 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 真实日期提取(写入 payload.reportDate 后复用 HealthReportService 既有入库逻辑)+ 历史回填
后端 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 从参考区间/历史数据自动推断
  • 关联方向与人工矛盾时的冲突提醒与运营工作流