源文档: docs/superpowers/specs/2026-08-08-health-data-center-design.md 日期: 2026-08-09 分支: cfclub
| 项 | spec 描述 | 实际现状 | 影响 |
|---|---|---|---|
| 身维度首页路径 | pages/body/index.vue |
不存在;实际为 pages/body-detail/index.vue(pages.json:883-890) |
改造目标文件需修正 |
| 迁移编号 | spec §8.2 写"迁移194" | 当前最高迁移为 迁移203(notices表) | 新迁移编号应为 迁移204 |
| dimension-questionnaire 维度 | spec §6.1 要新增 cognitive/mental/relationship | 现有仅 7 个体质维度(growth/sleep/vision/immunity/nutrition/gut/exercise) | 需新增题目+后端 DIMENSIONS 列表扩展 |
| LangGraph 端点 | spec §7.2 调用 analysis/run |
Python 侧 /api/v1/analysis/run 存在(cfc-langgraph/app/api/adapter.py:124);Java 侧需走 AiGateway |
需补充 AiGateway 方法 |
| health_plans 表 | spec §7.3 建表 | 不存在 | 需新建 |
| RadarChart 复用 | spec 未说明 | components/RadarChart.vue:34-43 已支持 props {dimensions, scores, avgScores} |
无需扩展,直接复用 |
任务 1: 迁移204 — 创建 health_plans 表
文件: cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java(在迁移203后追加)
DDL(与 spec §7.3 一致,补充 deleted 字段支持软删除):
CREATE TABLE IF NOT EXISTS health_plans (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
family_id BIGINT NOT NULL COMMENT '家庭ID',
member_ids VARCHAR(200) NOT NULL COMMENT '目标成员ID列表(逗号分隔)',
dimensions VARCHAR(100) NOT NULL COMMENT '维度列表(逗号分隔)',
goal TEXT NOT NULL COMMENT '用户输入的目标',
plan_content TEXT COMMENT 'LangGraph生成的方案内容(JSON/HTML)',
member_name VARCHAR(50) COMMENT '成员名称摘要',
deleted TINYINT DEFAULT 0 COMMENT '软删标记(0=正常 1=已删)',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_family (family_id),
INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康方案汇总记录';
同步修改 cfc-backend/src/main/resources/schema.sql(文件末尾追加 CREATE TABLE)。
QA 场景:
mvn clean compile 通过DESCRIBE health_plans 确认字段存在任务 2: HealthPlan 实体 + Mapper
新建:
cfc-backend/src/main/java/com/etotem/cfc/entity/HealthPlan.java(字段与 DDL 一一对应)cfc-backend/src/main/java/com/etotem/cfc/mapper/HealthPlanMapper.java(extends BaseMapper)
QA 场景:
mvn clean compile 通过,无编译错误任务 3: HealthPlanService + ServiceImpl
新建:
cfc-backend/src/main/java/com/etotem/cfc/service/HealthPlanService.javacfc-backend/src/main/java/com/etotem/cfc/service/impl/HealthPlanServiceImpl.java接口方法:
Long savePlan(Long familyId, Long adminId, String memberIds, String dimensions, String goal, String planContent, String memberName);
List<HealthPlan> listPlans(Long familyId, Integer page, Integer size);
HealthPlan getPlan(Long id, Long userId); // 校验 familyId 归属
void deletePlan(Long id, Long userId); // 软删除:deleted=1,校验归属
QA 场景:
mvn clean compile 通过任务 4: AiGateway — 新增 generateHealthPlan 方法
文件: cfc-backend/src/main/java/com/etotem/cfc/service/AiGateway.java
新增方法(与现有 generateQuestionnaire 行185-216 模式一致):
public String generateHealthPlan(Map<String, Object> inputs) {
if (!enabled || baseUrl == null) return null;
try {
String url = baseUrl + "/api/v1/analysis/run";
HttpEntity<String> entity = new HttpEntity<>(JSON.toJSONString(inputs), headers());
ResponseEntity<String> resp = restTemplate.postForEntity(url, entity, String.class);
// 解析返回的 content/result 字段
return extractContent(resp.getBody());
} catch (Exception e) {
log.warn("AiGateway generateHealthPlan 失败: {}", e.getMessage());
return null;
}
}
QA 场景:
mvn clean compile 通过任务 5: DimensionScoreService DIMENSIONS 列表扩展
文件: cfc-backend/src/main/java/com/etotem/cfc/service/impl/DimensionScoreServiceImpl.java
在 DIMENSIONS 列表(行39-47)末尾追加:
new String[]{"cognitive", "认知能力"},
new String[]{"mental", "心理健康"},
new String[]{"relationship", "关系质量"},
注意: submitQuestionnaire 方法(行208-237)无维度白名单校验,传入新维度码可直接写入 health_dimension_scores 表。但 getDimensionOverview 和 getDimensionHistory 依赖 DIMENSIONS 列表来展示,扩展后前端可正常获取数据。
QA 场景:
mvn clean compile 通过POST /api/dimension/overview?dimension=cognitive 返回数据结构与现有维度一致任务 6: 前端 API 函数声明(无需等后端编译)
文件: cfc-frontend/utils/api.js
新增:
export const generateHealthPlan = (data) => {
return request('/api/health/plan/generate', 'POST', data)
}
export const getHealthPlanList = (familyId) => {
return request('/api/health/plan/list', 'POST', { familyId })
}
export const saveHealthPlan = (data) => {
return request('/api/health/plan/save', 'POST', data)
}
export const deleteHealthPlan = (id) => {
return request('/api/health/plan/delete', 'POST', { id })
}
QA 场景:
node -e "require('./utils/api.js')" 无 Unexpected token任务 7: pages.json 注册 health-plan-summary 页面
文件: cfc-frontend/pages.json,在 pages/health 分包末尾追加:
{
"path": "health-plan-summary",
"style": {
"navigationBarTitleText": "方案汇总"
}
}
QA 场景:
node -e "JSON.parse(require('fs').readFileSync('pages.json','utf8'))" 无异常任务 8: HealthPlanController(小程序前端接口)
新建: cfc-backend/src/main/java/com/etotem/cfc/controller/health/HealthPlanController.java
端点:
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/health/plan/generate | 调 LangGraph 生成方案并返回结果 |
| POST | /api/health/plan/save | 保存方案到 health_plans 表 |
| POST | /api/health/plan/list | 查询当前用户家庭的历史方案列表 |
| POST | /api/health/plan/detail | 查询方案详情 |
| POST | /api/health/plan/delete | 软删除方案 |
QA 场景:
mvn clean compile 通过/api/health/plan/list 返回 JSON(未登录返回 401)任务 9: AdminHealthPlanController(管理后台接口,可选 MVP)
新建: cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminHealthPlanController.java
端点:
POST /api/admin/health-plans/list — 分页查询全平台方案列表POST /api/admin/health-plans/delete — 管理员强制删除QA 场景:
mvn clean compile 通过任务 10: dimension-questionnaire.vue 扩展
文件: cfc-frontend/pages/body-detail/dimension-questionnaire.vue(546 行)
改动:
dimensions 数组(行95-103)新增 3 项(spec §6.1)questions 对象(行105-221)新增 cognitive/mental/relationship 三组题库(spec §6.2-6.4,每组 8 题)onLoad 增加 dim 参数支持(spec §6.5):
onLoad(options) {
if (options.dim) {
this.selectedDimension = options.dim
this.step = 2 // 跳过选维度,直接进入答题
}
// 原有逻辑保留
}
答题完成结果页新增"返回数据中心"按钮(跳回 body-detail/index.vue)
QA 场景:
/pages/body-detail/dimension-questionnaire?dim=cognitive&memberId=1,直接进入答题页任务 11: body-detail/index.vue 改造为健康数据中心
文件: cfc-frontend/pages/body-detail/index.vue(676 行)
改造要点:
/pages/health/report-upload/pages/health/health-plan-summaryQA 场景:
任务 12: 新建 health-plan-summary.vue
新文件: cfc-frontend/pages/health/health-plan-summary.vue
页面结构(spec §7.1):
QA 场景:
任务1 (迁移204) ──→ 任务2 (实体+Mapper) ──→ 任务3 (Service)
│
任务6 (API函数) ←──────────────────────────────────────┘
任务7 (pages.json) ←───────────────────────────────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
任务4 (AiGateway) 任务5 (DIMENSIONS) 任务8 (Controller)
│ │ │
└────────────────────────┴────────────────────────┘
│
任务9 (AdminController,可选)
│
┌────────────────────────┴────────────────────────┐
▼ ▼
任务10 (问卷扩展) 任务11 (body-detail改造)
│ │
└────────────────────────┬────────────────────────┘
▼
任务12 (方案汇总页)
| 风险 | 影响 | 缓解 |
|---|---|---|
LangGraph Python 服务 /analysis/run 未部署或返回异常 |
方案生成功能不可用 | AiGateway 已有熔断器,返回 null;Controller 层做 mock fallback(返回预置方案文本) |
| body-detail/index.vue 现有样式复杂(676行,含大量残留样式) | 改造时易引入样式冲突 | 保留 RadarChart/FamilyMemberStrip/FamilyEnergyBar 组件引用,仅替换 funcList 下方区块;新样式加 .health-center- 前缀避免冲突 |
| dimension-questionnaire 跳转 URL 参数变化 | 现有链接失效 | dim 参数为可选,不传时走原有选维度流程 |
| 五维雷达图标签数据从哪来 | 智/心/行 Tab 的 radarDimensions 如何填充 | 复用 getDimensionOverview,传 dimension=cognitive/mental/relationship;后端 DIMENSIONS 列表扩展后,返回对应五维分值 |
| 迁移204 幂等性 | 重复部署不报错 | 使用 CREATE TABLE IF NOT EXISTS(与现有迁移203一致) |
mvn clean compile 通过;数据库有 health_plans 表,含 deleted 字段POST /api/health/plan/save 写入一条记录;调 POST /api/health/plan/list 返回该记录POST /api/dimension/overview?dimension=cognitive 返回正常数据结构(即使分值为0)?dim=cognitive&memberId=1 直接进入答题页,8题完整可作答mvn clean compile);无 Vue/JS 语法错误(HBuilderX 打包无 Unexpected token)