# 五维 TabBar 页面统一改造设计
> **Designer:** 系统分析员 (System Analyst)
> **Status:** 设计稿第一版
> **Scope:** 小程序端 3 个 TabBar 页(身体/心智/行动)+ 相关子页面 + 后端补充接口
---
## 1. 总体设计原则
根据用户要求的 6 条设计原则:
| # | 原则 | 实现方式 |
|:-:|------|----------|
| 1 | 三个页面都包含商品、活动、任务 | 每页底部固定「推荐商品」「热门活动」「今日任务」三个通用区块,按当前维度筛选 |
| 2 | 文章都在心智里 | 只有「心智」页展示文章列表及阅读统计;身体页和行动页不出现文章板块 |
| 3 | 身体包含各种体检数据 | 利用已有 `health_reports` + `health_indicators` 展示健康报告摘要、指标解读 |
| 4 | 心智包括 DAN 成长测评+认知6个维度 | 保留原有心 · 智双 Tab 结构,融合 DAN 结果展示 + 六维雷达图 |
| 5 | 每页显示当前登录用户信息+任务/活动快捷入口 | 在能量柱状图下方统一展示用户身份 + 三个快捷按钮 |
| 6 | 每页顶部横放柱状图:家庭总能量 + 各成员能量值,可点击跳转 | 利用 `/api/energy/sandbox` 数据渲染,成员条可点击跳转到对应维度详情 |
### 统一页面布局
```
┌───────────────────────────────────────────────────────────┐
│ PageBanner (dimension 主题) │
├───────────────────────────────────────────────────────────┤
│ ① 家庭能量柱状图(横放) │
│ 「全家」 ████████████████████ 85 │
│ 「妈妈」 ████████████████ 72 ← 可点击跳转 │
│ 「爸爸」 ████████████████████ 80 ← 可点击跳转 │
│ 「小宝」 ██████████████ 65 ← 可点击跳转 │
├───────────────────────────────────────────────────────────┤
│ ② 当前用户信息 + 快捷入口 │
│ 👤 当前:妈妈(家长) │
│ [📋 今日任务] [🔥 相关活动] [🛍️ 推荐商品] │
├───────────────────────────────────────────────────────────┤
│ ③ 维度专属内容 (见各页详述) │
├───────────────────────────────────────────────────────────┤
│ ④ 推荐商品(按维度筛选) ← 通用区块,3页皆有 │
│ 4个商品卡片,2×2 网格 │
├───────────────────────────────────────────────────────────┤
│ ⑤ 热门活动(按维度筛选) ← 通用区块,3页皆有 │
│ 横向滚动活动卡片 │
├───────────────────────────────────────────────────────────┤
│ ⑥ 功能入口 Grid (4个) ← 通用区块,3页各自不同 │
│ body: 运动/饮食/作息/菌群 │
│ mind: 阅读/小游戏/测评报告/训练中心 │
│ action: 任务/活动/商城/课程 │
└───────────────────────────────────────────────────────────┘
```
---
## 2. 数据流
```
┌──────────────┐
│ Page onShow │
└──────┬───────┘
│
▼
┌──────────────────────────────────────┐
│ POST /api/energy/sandbox │ ← 家庭能量全景
│ → bodyScore/mindScore/wisdomScore/ │
│ actionScore/wealthScore │
│ → members[].{bodyScore,mindScore, │
│ wisdomScore,actionScore,wealthScore}│
└──────────────────┬───────────────────┘
│
├── 提取当前维度评分 → 渲染柱状图
├── 成员列表 → 每成员柱状图 + 跳转
│
▼ 并行加载(根据页面不同)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 健康报告数据 │ │ DAN测评数据 │ │ 任务数据 │
│ POST /api/ │ │ POST /api/ │ │ POST /api/ │
│ health/... │ │ cognitive/.. │ │ tasks/... │
└──────────────┘ └──────────────┘ └──────────────┘
│
▼ 并行加载(3页通用)
┌──────────────┐ ┌──────────────┐
│ 商品(按维度) │ │ 活动(按维度) │
│ POST /api/ │ │ POST /api/ │
│ product/list │ │ activity/list│
└──────────────┘ └──────────────┘
```
### 2.1 按维度筛选
商品用 `energy_dimension_id` 筛选(需给 Product 新增该字段,若尚无)
任务用 `category` 或 `dimension` 字段筛选
活动用新建的 `dimension` 字段筛选
文章用 `relatedDimensions` 字段筛选(已存在)
---
## 3. 身体页面 `pages/body/index.vue`
### 3.1 维度专属内容
```
┌─ ③ 维度专属内容 ──────────────────────────────────────┐
│ ┌─ 家庭健康概况(有数据时) ─────────────────────────┐ │
│ │ 最新体检报告: 2026-05-15 综合评分: 82/100 │ │
│ │ 最新菌群检测: 2026-04-20 菌群健康: 76/100 │ │
│ │ [查看完整报告 →] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 无报告时 ────────────────────────────────────────┐ │
│ │ 还没有健康检测报告 │ │
│ │ [上传体检报告] [菌群检测] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 健康指标解读(有报告时) ─────────────────────────┐ │
│ │ 营养状况: 🟢 正常 疾病风险: 🟢 低 │ │
│ │ 肠道屏障: 🟡 注意 神经递质: 🟢 正常 │ │
│ │ [查看全部指标 →] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 今日身体数据 ────────────────────────────────────┐ │
│ │ 🚶 6,582步 💧 1.2L 😴 8.5h │ │
│ │ (对接智能设备后自动同步) │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 健康打卡 ────────────────────────────────────────┐ │
│ │ 今日: 运动✔ 喝水✔ 早睡✔ 冥想□ +⚡15能量 │ │
│ │ [去打卡 →] │ │
│ └──────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
```
### 3.2 功能入口
| 入口 | 图标 | 跳转 |
|:----:|:----:|------|
| 运动 | 🏃 | `pages/body/sports` (已有或新增) |
| 饮食 | 🍎 | `pages/body/diet` |
| 作息 | 😴 | `pages/body/sleep` |
| 菌群 | 🔬 | `pages/body/gut-flora` (已有或跳转报告) |
### 3.3 调用接口
| 数据 | 接口 | 状态 |
|:----:|------|:----:|
| 家庭能量柱状图 | `POST /api/energy/sandbox` → bodyScore, members[].bodyScore | ✅ 已有 |
| 最新健康报告 | `POST /api/health/report/latest` | ✅ 已有 |
| 报告列表 | `POST /api/health/report/list` | ✅ 已有 |
| 指标明细 | `POST /api/health/indicator/list` | ✅ 已有 |
| 身体维度详情 | `POST /api/health/body/detail` | ✅ 已有 |
| 健康打卡 | `POST /api/checkin/today` | ✨ 新增 |
| 按维度商品 | `POST /api/product/list` + 参数 dimensionCode | ✅ 已有改造 |
| 按维度活动 | `POST /api/activity/list` + 参数 dimensionCode | ✨ 新增 |
---
## 4. 心智页面 `pages/mind/index.vue`
### 4.1 维度专属内容
保留原有的 **心(心理)/ 智(认知)双 Tab** 结构,合并为统一心智页面:
**【心】心理 Tab (emotion):**
```
┌─ 心理能量概况 ─────────────────────────────────────────┐
│ ❤ 心能量: 82 | 💪 韧性: 78 | 😊 情绪: 85 │
└────────────────────────────────────────────────────────┘
┌─ EMI 心理四维 ─────────────────────────────────────────┐
│ 情绪商数 ████████████████░░ 82 优秀 │
│ 心理韧性 ██████████████░░░░ 76 良好 │
│ 压力应对 █████████████████░░ 80 良好 │
│ 自我认知 ██████████████████░ 85 优秀 │
│ [查看完整报告 →] 综合 EQ 分: 81 │
└────────────────────────────────────────────────────────┘
┌─ 无评估数据占位引导 ────────────────────────────────┐
│ 「完成 EMI 心理测评后查看详细分析报告」 │
│ [预约测评] │
└────────────────────────────────────────────────────────┘
```
**【智】认知 Tab (cognitive):**
```
┌─ 综合认知评分 ─────────────────────────────────────────┐
│ 综合得分: 88 | 上次: 2026-05-20 │
│ [查看完整报告 →] [预约测评] │
└────────────────────────────────────────────────────────┘
┌─ 认知六维雷达图 ───────────────────────────────────────┐
│ 家庭成员切换: [小宝 78] [大宝 85] [自己 92] ←横向滚动 │
│ ┌────────────────────────────────────────────────┐ │
│ │ 六维雷达图 (RadarChart) │ │
│ │ 感知 │ │
│ │ 专注 记忆 │ │
│ │ 逻辑 空间 │ │
│ │ 加工速度 │ │
│ └────────────────────────────────────────────────┘ │
│ (点击维度标签进入对应能力训练) │
└────────────────────────────────────────────────────────┘
┌─ 认知训练 ─────────────────────────────────────────────┐
│ [🎯 舒尔特方格] [🔢 猜数字] [🧩 数独] │
└────────────────────────────────────────────────────────┘
┌─ 本月阅读统计 ─────────────────────────────────────────┐
│ 已读: 12篇 / 阅读时长: 156分钟 │
│ ████████████░░░░ 60% [去阅读 →] │
└────────────────────────────────────────────────────────┘
```
### 4.2 文章(全在心理#2)
心智页 **心理 Tab 底部**和 **认知 Tab 底部都放**推荐文章:
```
┌─ 推荐阅读 ─────────────────────────────────────────────┐
│ ┌────────────────────────────────────────────────┐ │
│ │ [情绪管理] 如何帮助孩子管理情绪 │ │
│ │ 掌握3个简单技巧... │ │
│ │ 阅读 2.3k │ │
│ ├────────────────────────────────────────────────┤ │
│ │ [认知发展] 提升逻辑思维的5个日常游戏 │ │
│ │ 在家就能玩的思维训练... │ │
│ │ 阅读 1.8k │ │
│ └────────────────────────────────────────────────┘ │
│ [更多文章 →] │
└────────────────────────────────────────────────────────┘
```
文章根据 `relatedDimensions` 筛选相关维度:心理 Tab 显示 `relatedDimensions` 包含 `mind` 的文章;认知 Tab 显示包含 `wisdom` 的文章。
### 4.3 功能入口
| 入口 | 图标 | 跳转 |
|:----:|:----:|------|
| 阅读 | 📖 | `pages/mind/articles` (已有) |
| 小游戏 | 🎮 | `pages/games/list` (已有) |
| 测评报告 | 📊 | 心理报告/认知报告 (已有) |
| 训练中心 | 🎯 | `pages/mind/training` (已有) |
### 4.4 能量柱状图特殊处理 — 堆叠图
心智 Tab 合并了「心」和「智」两个维度。横放柱状图采用**堆叠图(Stacked Bar)**模式:每个成员一根柱,叠加显示心能量 + 智能量:
```
心智能量总览:
┌──────────────────────────────────────────────────────┐
│ 全家 ████████████████████████████████████░░ 82+88=170│
│ └── 心 82 ──┘└─── 智 88 ───┘ │
│ │
│ 妈妈 ████████████████████████████░░░░ 72+82=154 │
│ └── 心 72 ──┘└─── 智 82 ───┘ │
│ │
│ 爸爸 ██████████████████████████████████░░ 78+86=164 │
│ └── 心 78 ──┘└─── 智 86 ───┘ │
│ │
│ 小宝 ████████████████████████░░░░░░░ 65+78=143 │
│ └── 心 65 ──┘└─── 智 78 ───┘ │
│ │
│ (柱长 = 心分数 + 智分数,上限200) │
│ 点击心色段 → 心理报告 点击智色段 → 认知报告 │
└──────────────────────────────────────────────────────┘
```
**堆叠图设计要点:**
| 属性 | 值 |
|:----:|-----|
| 柱总长 | `mindScore + wisdomScore`(上限 200,即 100+100) |
| 心色段 | 暖色(如 `#FF6B35` 橙),居左 |
| 智色段 | 冷色(如 `#667eea` 蓝紫),居右 |
| 刻度标签 | 显示 `心分数+智分数=总分`(如 `72+82=154`) |
| 点击心段 | 跳转到心理报告页 |
| 点击智段 | 跳转到认知报告页 |
| 无数据时 | 柱显示为浅灰色占位,点击引导预约测评 |
**数据改造:** `FamilyEnergyBar` 组件新增 `stackedDimensions` prop,心智页传入 `['mind', 'wisdom']`,组件内部渲染两段堆叠而非单段。
### 4.5 调用接口
| 数据 | 接口 | 状态 |
|:----:|------|:----:|
| 家庭能量 | `/api/energy/sandbox` → mindScore/wisdomScore + members[].mindScore/wisdomScore | ✅ 已有 |
| EMI 心理报告 | `POST /api/assessment/emi/latest` | ✅ 已有 |
| DAN 认知结果 | `POST /api/assessment/latest` | ✅ 已有 |
| 六维家族数据 | `POST /api/cognitive/family` | ✅ 已有 |
| 文章列表(按维度) | `POST /api/article/list?dimension=body/mind/wisdom` | ✅ 已有改造 |
| 阅读统计 | `POST /api/reading/stats` | ✅ 已有 |
| 按维度商品 | `POST /api/product/list?dimension=心智` | ✨ 新增改造 |
| 按维度活动 | `POST /api/activity/list?dimension=心智` | ✨ 新增 |
---
## 5. 行动页面 `pages/action/index.vue`
### 5.1 维度专属内容
```
┌─ ③ 维度专属内容 ──────────────────────────────────────┐
│ ┌─ 今日任务 ────────────────────────────────────────┐ │
│ │ 📋 完成晨跑 30 分钟 +20分 ⏰ 今日截止 │ │
│ │ 📋 整理书桌 +10分 ⏰ 今日截止 │ │
│ │ 📋 阅读打卡 15 分钟 +15分 ⏰ 明日截止 │ │
│ │ [查看全部任务 →] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 任务完成统计 ────────────────────────────────────┐ │
│ │ 本周完成: 12/15 ████████████░░ 80% │ │
│ │ 本月连续打卡: 8天 🔥 │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 进行中的活动 ────────────────────────────────────┐ │
│ │ 🔥 21天亲子运动打卡营 │ │
│ │ 📅 5/1 ~ 5/21 | 进度: 12/21天 │ │
│ │ ██████████████░░░░░░ │ │
│ └──────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
```
### 5.2 功能入口
| 入口 | 图标 | 跳转 |
|:----:|:----:|------|
| 任务 | 📋 | `pages/tasks/tasks` (已有 TabBar) |
| 活动 | 🔥 | `pages/discover/index?type=activity` (已有) |
| 商城 | 🛍️ | `pages/shop/index` (已有) |
| 课程 | 🎓 | `pages/discover/index?type=course` (已有) |
### 5.3 调用接口
| 数据 | 接口 | 状态 |
|:----:|------|:----:|
| 家庭能量 | `/api/energy/sandbox` → actionScore + members[].actionScore | ✅ 已有 |
| 今日任务(按维度) | `POST /api/tasks/list?dimension=action` | ✅ 已有改造 |
| 任务统计 | `POST /api/tasks/stats?childId=X` | ✅ 已有 |
| 按维度商品 | `POST /api/product/list?dimension=行动` | ✨ 新增改造 |
| 按维度活动 | `POST /api/activity/list?dimension=行动` | ✨ 新增 |
---
## 6. 新增/改造接口总览
### 6.1 后端新增接口
| 端点 | 方法 | 说明 | 优先级 |
|------|:----:|------|:------:|
| `POST /api/activity/list` | 新增 | 活动列表(支持按 dimension 筛选) | P1 |
| `POST /api/activity/detail` | 新增 | 活动详情 | P1 |
| `POST /api/checkin/today` | 新增 | 今日健康打卡状态 | P1 (身体页) |
| `POST /api/checkin/do` | 新增 | 执行打卡 | P1 |
| `POST /api/checkin/list` | 新增 | 打卡记录 | P2 |
| `POST /api/product/list` | 改造 | 增加 dimension 筛选参数 | P1 |
| `POST /api/tasks/list` | 改造 | 增加 dimension 筛选参数 | P1 |
### 6.2 前端新增/改造页面
| 页面 | 操作 | 说明 |
|:----:|:----:|------|
| `pages/body/index.vue` | 🔄 改造 | 统一布局 + 能量柱状图 + 健康数据 + 通用区块 |
| `pages/mind/index.vue` | 🔄 改造 | 统一布局 + 能量柱状图 + 双Tab + 通用区块 |
| `pages/action/index.vue` | 🔄 改造 | 统一布局 + 能量柱状图 + 今日任务 + 通用区块 |
| `pages/body/health-report.vue` | ✨ 新增 | 健康报告详情 (已有设计) |
| `pages/body/checkin.vue` | ✨ 新增 | 健康打卡 (已有设计) |
| `pages/body/member-body-detail.vue` | ✨ 新增 | 成员身体维度详情(柱状图点击跳转目标) |
| `pages/mind/member-mind-detail.vue` | ✨ 新增 | 成员心/智维度详情 |
| `pages/action/member-action-detail.vue` | ✨ 新增 | 成员行动维度详情 |
---
## 7. 成员维度详情页(柱状图跳转目标)
当用户点击能量柱状图中某个成员的能量条时,跳转到对应成员的该维度详情页。
### 通用设计
每个成员维度详情页展示该成员在某维度下的详细信息:
```
┌─ 返回 ────────────────────────────────────────────────┐
│ │
│ 成员名称:小宝 │
│ 身体能量值:65/100 │
│ │
│ ┌─ 能量构成 ────────────────────────────────────────┐ │
│ │ 获得来源: │ │
│ │ 完成任务 +120 │ │
│ │ 健康打卡 +45 │ │
│ │ 商品购买 -30 │ │
│ │ 当前余额: 135 │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌─ 能量流水(近7天) ───────────────────────────────┐ │
│ │ 06/07 完成晨跑 +10 ⚡ │ │
│ │ 06/07 健康打卡 +5 ⚡ │ │
│ │ 06/06 购买运动用品 -15 ⚡ │ │
│ │ [查看更多 →] │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ [维度专属内容] │
│ body: 健康报告/指标/身体数据 │
│ mind: EMI心理结果/DAN认知结果 │
│ action: 任务/活动参与记录 │
└────────────────────────────────────────────────────────┘
```
---
## 8. 数据模型补充
### 8.1 Activity(活动实体)— 新增
```java
@TableName("activities")
public class Activity {
private Long id;
private String title;
private String description;
private String coverImage;
private String dimensionCode; // body/mind/wisdom/action/wealth
private String activityType; // offline/online/campaign
private String status; // draft/published/ended
private Date startTime;
private Date endTime;
private String location;
private Integer maxParticipants;
private Integer currentParticipants;
private BigDecimal price;
private Long vendorId; // 活动方
private Date createdAt;
}
```
### 8.2 Product 增加 dimension 筛选
Product 实体已有 `domain` 字段(来源域)和 `externalSource`(外部来源)。可以复用现有字段或新增 `energyDimensionId`(与 `energy_dimension` 表关联)。推荐新增 `energyDimensionId` 字段以统一维度筛选逻辑。
---
## 9. 实现任务分解
### Task 1: 统一布局组件
**文件:**
- New: `cfc-frontend/components/FamilyEnergyBar.vue` — 家庭能量横放柱状图组件
- New: `cfc-frontend/components/UserQuickEntry.vue` — 用户信息+快捷入口组件
**说明:**
- 柱状图组件接收 `dimensionCode` + `sandboxData`(来自 `/api/energy/sandbox`)
- 自动筛选出该维度的全家评分+每位成员评分
- 成员条 `@click` 事件跳转到对应成员详情页
- 快捷入口组件显示当前用户身份+三个快速导航按钮
### Task 2: 通用区块组件
**文件:**
- New: `cfc-frontend/components/DimensionProducts.vue` — 按维度商品展示
- New: `cfc-frontend/components/DimensionActivities.vue` — 按维度活动展示
- New: `cfc-frontend/components/DimensionTasks.vue` — 按维度任务展示
**说明:**
- 每个组件接收 `dimensionCode` 参数
- 内部调用相应 API 获取数据并渲染
- 商品显示 2×2 网格,活动显示横向滚动卡片,任务显示列表
### Task 3: 改造身体页面
**文件:**
- Modify: `cfc-frontend/pages/body/index.vue`
**改造点:**
1. 顶部插入 ``
2. 插入 ``
3. 维度专属内容:健康报告摘要 + 指标解读 + 今日数据 + 健康打卡
4. 通用区块:`` + ``
5. 功能入口 Grid:运动/饮食/作息/菌群
### Task 4: 改造心智页面
**文件:**
- Modify: `cfc-frontend/pages/mind/index.vue`
**改造点:**
1. 顶部插入 ``(双维度)
2. 插入 ``
3. 维度专属内容:保留现有 心理Tab / 认知Tab 结构
4. 心理Tab底部 + 认知Tab底部加文章推荐
5. 通用区块:`` + ``
6. 功能入口 Grid:阅读/小游戏/测评报告/训练中心
### Task 5: 改造行动页面
**文件:**
- Modify: `cfc-frontend/pages/action/index.vue`
**改造点:**
1. 顶部插入 ``
2. 插入 ``
3. 维度专属内容:今日任务列表 + 完成统计
4. 通用区块:`` + ``
5. 功能入口 Grid:任务/活动/商城/课程(已有)
### Task 6: 成员维度详情页
**文件:**
- Create: `cfc-frontend/pages/body/member-body-detail.vue`
- Create: `cfc-frontend/pages/mind/member-mind-detail.vue`
- Create: `cfc-frontend/pages/action/member-action-detail.vue`
**说明:**
- 跳转参数 `childId` + `dimensionCode`
- 展示该成员在该维度的能量值、能量构成、近期流水
- Body 额外展示健康报告摘要
- Mind 额外展示 EMI/DAN 结果
- Action 额外展示任务完成统计
### Task 7: 后端接口
**文件:**
- Create: `ActivityController.java` — 活动 CRUD
- Create: `ActivityService.java`
- Create: `entity/Activity.java`
- Create: `mapper/ActivityMapper.java`
**说明:**
- Activities 表设计(见 8.1)
- 商品接口增加维度筛选:改造 `ProductController` 增加 `dimensionCode` 参数
- 任务接口增加维度筛选:改造 `TaskController` 增加 `dimensionCode` 参数
- 打卡接口已有设计(参见身体页面设计方案)
---
## 10. 设计约束
### 10.1 TabBar 不变
```
TabBar: 首页 | 身体 | 心智 | 行动 | 我的
```
### 10.2 小程序限制
- 禁用可选链 `?.`(用 `&&` 代替)
- 禁用 CSS Grid(用 flexbox 代替)
- Vue 2 Options API,不引入 Composition API
### 10.3 现有 LSP 错误
项目已有预存的 LSP entity getter 缺失错误(entity 未生成 getter),这些是已有问题,不影响本次设计的内容。
---
## 11. 视觉参考
### 能量横放柱状图 (FamilyEnergyBar)
```
┌──────────────────────────────────────────────────────────┐
│ 🏃 身体能量 ⚡ 85 │
│ │
│ 全家 ████████████████████████████████░░ 85 │
│ 妈妈 ██████████████████████░░░░░░░░░░ 72 ←点击跳转 │
│ 爸爸 ██████████████████████████░░░░░░ 80 ←点击跳转 │
│ 小宝 ████████████████████░░░░░░░░░░░░ 65 ←点击跳转 │
│ │
│ 颜色渐变: #10B981 → #34D399 (body) │
│ #8B5CF6 → #A78BFA (mind) │
│ #F97316 → #FB923C (action) │
└──────────────────────────────────────────────────────────┘
```
Click member bar → `uni.navigateTo` 带参数:
```js
uni.navigateTo({
url: '/pages/body/member-body-detail?childId=' + member.memberId
})
```
### 用户快捷入口 (UserQuickEntry)
```
┌──────────────────────────────────────────────────────────┐
│ 👤 当前用户: 妈妈(家长) 切换孩子: [小宝 ▼] │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 📋 今日 │ │ 🔥 相关 │ │ 🛍️ 推荐 │ │
│ │ 任务 │ │ 活动 │ │ 商品 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────┘
```
三个按钮分别滚动页面到对应区块,或跳转到对应 TabBar 页面。
---
## 12. 文件变更清单
| 操作 | 文件 | 说明 |
|:----:|------|------|
| ✨ | `cfc-frontend/components/FamilyEnergyBar.vue` | 能量横放柱状图组件 |
| ✨ | `cfc-frontend/components/UserQuickEntry.vue` | 用户信息+快捷入口组件 |
| ✨ | `cfc-frontend/components/DimensionProducts.vue` | 按维度商品展示组件 |
| ✨ | `cfc-frontend/components/DimensionActivities.vue` | 按维度活动展示组件 |
| ✨ | `cfc-frontend/components/DimensionTasks.vue` | 按维度任务展示组件 |
| 🔄 | `cfc-frontend/pages/body/index.vue` | 身体页统一布局改造 |
| 🔄 | `cfc-frontend/pages/mind/index.vue` | 心智页统一布局改造 |
| 🔄 | `cfc-frontend/pages/action/index.vue` | 行动页统一布局改造 |
| ✨ | `cfc-frontend/pages/body/member-body-detail.vue` | 身体成员详情页 |
| ✨ | `cfc-frontend/pages/mind/member-mind-detail.vue` | 心智成员详情页 |
| ✨ | `cfc-frontend/pages/action/member-action-detail.vue` | 行动成员详情页 |
| ✨ | `cfc-backend/.../entity/Activity.java` | 活动实体 |
| ✨ | `cfc-backend/.../mapper/ActivityMapper.java` | 活动 Mapper |
| ✨ | `cfc-backend/.../controller/ActivityController.java` | 活动 CRUD |
| ✨ | `cfc-backend/.../service/ActivityService.java` | 活动服务 |
| 🔄 | `cfc-backend/.../controller/ProductController.java` | 增加维度筛选参数 |
| 🔄 | `cfc-backend/.../controller/TaskController.java` | 增加维度筛选参数 |
| 🔄 | `cfc-frontend/pages.json` | 注册新增子页面 |
| 🔄 | `cfc-frontend/utils/api.js` | 新增 API 封装 |
---
## 13. 设计决策记录
| 决策 | 选项 | 选择 |
|:----:|:----|:----:|
| 能量值使用 | balance值(整数) vs 评分(0-100) | **评分(0-100)** — 标准化,跨成员可比 |
| 心智双维度展示 | 分两组并列 vs 堆叠图 | **堆叠图** — 一根柱同时显示心+智,节省空间且直观对比两者比例,点击对应色段可分别跳转报告 |
| 商品按维度筛选 | 新字段 vs 复用 `domain` | **新增 `energyDimensionId`** — 与 energy_dimension 表统一关联 |
| Activity 实现 | 新表 vs 用 Product 扩展 | **新表** — Activity 有独立生命周期和业务逻辑 |
| 成员详情页数量 | 3个独立页 vs 1个通用页+参数 | **3个独立页** — 每个维度详情内容差异大,独立页面更清晰 |
| 登录前价格 | 隐藏 vs 显示"登录查看" | **隐藏数值,显示"登录查看价格"** — 不暴露定价信息 |
| 私密内容过滤 | 前端过滤 vs 后端过滤 | **后端统一过滤** — 后端根据 auth 状态和角色返回不同数据集 |
| 私密活动可见范围 | public/member/private 三态 | **`visibility` + `visibleScope` + `visibleTo` 三字段** — 支持 family/role/user 三层级,扩展性好 |
| 游客无数据占位 | 直接隐藏 vs 显示"登录后查看更多" | **显示「🔒 登录后查看更多」占位** — 提示用户有更多内容需登录解锁 |
| 游客点击商品/活动 | 弹登录 vs 可直接看详情页(无价格) | **弹登录提示** — 私密活动不能暴露,详情页也依赖登录态 |
---
## 14. 登录前(游客)模式设计
### 14.1 设计原则
| # | 原则 | 说明 |
|:-:|------|------|
| A | 商品/活动/文章**登录前可浏览** | 三个页面的通用区块在未登录时可见 |
| B | 商品和活动**不显示价格** | 价格数值隐藏,替换为"登录查看"提示 |
| C | 私密活动**从列表即过滤** | 未授权用户完全看不到私密活动,不显示无权限条目 |
| D | 文章按可见性过滤 | 复用 `Article.visibility` + `Article.visibleTo` 字段 |
| E | **后端统一过滤** | 后端根据 `@RequestAttribute("userId")` 是否存在 + 角色决定返回什么数据 |
| F | 个性化板块变为引导 | 原本登录后的能量柱状图、健康数据、测评报告、今日任务 → 替换为登录引导卡 |
| G | 无数据时显示占位提示 | 游客模式下某维度无公开活动/商品时,显示「登录后查看更多」占位,而非直接隐藏区块 |
### 14.2 权限字段补充
#### Activity 新增可见性字段
支持 3 种可见范围(scope),每种对应不同的 `visibleTo` 存储格式:
| visibility | 含义 | visibleTo 格式 | 说明 |
|:----------:|------|---------------|------|
| `public` | 所有人可见 | — | 游客和登录用户均可浏览 |
| `member` | 登录用户可见 | — | 任意登录用户可浏览 |
| `restricted` | 限定范围可见 | 见下方 scope 说明 | 按家庭/角色/具体人过滤 |
restricted 模式下还需 `visibleScope` 字段说明限定类型:
| visibleScope | 含义 | visibleTo 示例 | 匹配逻辑 |
|:------------:|------|---------------|---------|
| `family` | 特定家庭 | `"42"` 或 `"[42,55]"` | 用户的 familyId 匹配 |
| `role` | 特定角色 | `"[\"parent\",\"teacher\"]"` | 用户的 role 字段匹配 |
| `user` | 特定用户 | `"[\"101\",\"102\"]"` | 用户的 userId 在可见列表中(JSON_CONTAINS) |
```java
// 在 Activity 实体中新增
/** 可见性: public / member / restricted */
private String visibility;
/** 限定模式: family / role / user — 仅 visibility=restricted 时有效 */
private String visibleScope;
/** 可见范围标识: family_id(s) / role(s) / user_id(s) — JSON 格式 */
private String visibleTo;
```
> **设计决策理由:** 选用 `visibility` + `visibleScope` + `visibleTo` 三字段组合而非单一 `visibility` 枚举,是因为 scope 隔离了不同类型的可见判断逻辑(SQL 条件不同),且支持扩展新 scope 类型(如将来增加 `grade` 年级可见)而不需改枚举。
#### Article 已有字段(复用)
```java
private String visibility; // public / member / private
private String visibleTo; // 可见的user_id列表(JSON数组) 或 role列表
private String status; // draft / published / archived
```
#### Product 不新增可见性字段(沿用现有 `status` + `memberEligible`)
```java
private String status; // approved / rejected / pending
private String memberEligible; // 是否仅会员可见(yes/no)
```
### 14.3 游客模式统一布局
```
┌───────────────────────────────────────────────────────────┐
│ PageBanner (dimension 主题,与登录后一致) │
│ + 副标题: 登录后展示个性化数据 │
├───────────────────────────────────────────────────────────┤
│ ┌─ 登录引导横条 ──────────────────────────────────────┐ │
│ │ 🔒 登录后查看家庭能量和个性化数据 │ │
│ │ [立即登录 / 注册] │ │
│ └──────────────────────────────────────────────────────┘ │
├───────────────────────────────────────────────────────────┤
│ ③ 维度专属内容(游客版) 看下文各页详述 │
├───────────────────────────────────────────────────────────┤
│ ④ 推荐商品(按维度筛选) │
│ 有公开商品 → 商品卡片: 封面 + 名称 + [登录查看价格] │
│ 无公开商品 → 「🔒 登录后查看更多推荐商品」占位 │
├───────────────────────────────────────────────────────────┤
│ ⑤ 热门活动(按维度筛选) │
│ 有公开活动 → 活动卡片: 封面 + 名称 + 日期 + 地点 │
│ 无公开活动 → 「🔒 登录后查看更多相关活动」占位 │
│ 私密活动直接不返回(后端过滤) │
├───────────────────────────────────────────────────────────┤
│ ⑥ 功能入口 Grid │
│ 保留图标,点击部分跳转需要登录时弹登录提示 │
└───────────────────────────────────────────────────────────┘
```
**商品/活动空占位设计:**
```
┌─────────────────────────────────────┐
│ 🔒 登录后查看更多推荐商品 │ ← 灰色小字,不可点击
│ 或 │
│ 🔒 登录后查看更多相关活动 │
└─────────────────────────────────────┘
```
占位条件:游客模式下,对应维度无任何 `visibility=public` 的数据。点击占位无事件(仅为提示,不跳转登录)。
### 14.4 身体页 — 游客模式
```
页面元素 | 游客(未登录) | 登录后(已有设计)
----------------------|----------------------------|----------------------------
PageBanner | 显示,tagline 不变 | 显示
家庭能量柱状图 | ❌ 隐藏 | ✅ 显示
用户快捷入口 | ❌ 隐藏 | ✅ 显示
健康报告/指标 | ❌ 隐藏 | ✅ 显示
今日身体数据 | ❌ 隐藏 | ✅ 显示
健康打卡 | ❌ 隐藏 | ✅ 显示
推荐商品 | ✅ 显示(无价格)/ 无商品→占位 | ✅ 显示(有价格)
热门活动 | ✅ 显示(无价格)/ 无活动→占位 | ✅ 显示(有价格)
登录引导卡 | ✅ 显示 | ❌ 隐藏
健康小贴士(游客版) | ✅ 从文章库取 body 类文章 | ❌ 隐藏(已有替代区块)
```
**商品/活动空占位:** 身体页 body 维度下无公开商品时显示「🔒 登录后查看更多推荐商品」,无公开活动时显示「🔒 登录后查看更多相关活动」。
**登录引导卡设计:**
```
┌──────────────────────────────────────────────────┐
│ 🔒 登录后可以 │
│ · 查看全家的身体能量数据和健康报告 │
│ · 记录每日健康打卡,获取身体能量 │
│ · 查看专属健康商品和活动价格 │
│ [立即登录] [注册账号] │
└──────────────────────────────────────────────────┘
```
**健康小贴士(游客专属):**
身体页在游客模式下展示从 `Article` 表筛选的 body 相关健康文章,作为「健康小贴士」板块:
```
┌─ 健康小贴士(从 articles 表取) ─────────────────┐
│ 📋 儿童每日运动指南 │
│ 🍎 五行饮食搭配法则 │
│ 😴 优质睡眠的5个习惯 │
│ [阅读更多 →] │
└──────────────────────────────────────────────────┘
```
筛选条件:`visibility='public' AND status='published' AND (relatedDimensions LIKE '%body%' OR categoryId IN (身体类目))`
### 14.5 心智页 — 游客模式
```
页面元素 | 游客(未登录) | 登录后(已有设计)
----------------------|----------------------------|----------------------------
PageBanner | 显示 | 显示
家庭能量柱状图 | ❌ 隐藏 | ✅ 显示
用户快捷入口 | ❌ 隐藏 | ✅ 显示
心理 Tab(EMI) | ❌ 隐藏(无数据) | ✅ 显示
认知 Tab(DAN+雷达图) | ❌ 隐藏(无数据) | ✅ 显示
认知训练(小游戏) | ❌ 隐藏(需登录) | ✅ 显示
阅读统计 | ❌ 隐藏 | ✅ 显示
推荐阅读(文章) | ✅ 公开文章 | ✅ 全部可见文章
推荐商品 | ✅ 显示(无价格)/ 无→占位 | ✅ 显示(有价格)
热门活动 | ✅ 显示(无价格)/ 无→占位 | ✅ 显示(有价格)
登录引导卡 | ✅ 显示(专属文案) | ❌ 隐藏
```
**心智页游客布局(双Tab依然保留,但内容不同):**
#### 心理 Tab(游客)
```
┌─ 登录引导卡 ───────────────────────────────────────┐
│ 🔒 登录后查看 EMI 心理测评报告 │
│ · 情绪商数、心理韧性、压力应对、自我认知四维分析 │
│ [立即登录] │
└────────────────────────────────────────────────────┘
┌─ 推荐阅读(心理维度) ──────────────────────────────┐
│ 从文章库筛选 relatedDimensions 含 mind 的公开文章 │
└────────────────────────────────────────────────────┘
```
#### 认知 Tab(游客)
```
┌─ 登录引导卡 ───────────────────────────────────────┐
│ 🔒 登录后查看 DAN 认知评估报告 │
│ · 六维认知雷达图:感知/专注/记忆/逻辑/空间/加工速度 │
│ [立即登录] │
└────────────────────────────────────────────────────┘
┌─ 推荐阅读(认知维度) ──────────────────────────────┐
│ 从文章库筛选 relatedDimensions 含 wisdom 的公开文章 │
└────────────────────────────────────────────────────┘
```
### 14.6 行动页 — 游客模式
```
页面元素 | 游客(未登录) | 登录后(已有设计)
----------------------|----------------------------|----------------------------
PageBanner | 显示 | 显示
家庭能量柱状图 | ❌ 隐藏 | ✅ 显示
用户快捷入口 | ❌ 隐藏 | ✅ 显示
今日任务 | ❌ 隐藏(无数据) | ✅ 显示
推荐商品 | ✅ 显示(无价格)/ 无→占位 | ✅ 显示(有价格)
热门活动 | ✅ 显示(无价格)/ 无→占位 | ✅ 显示(有价格)
登录引导卡 | ✅ 显示(专属文案) | ❌ 隐藏
功能入口 | ✅ 显示,部分需弹登录 | ✅ 全部可用
```
**行动页游客布局:**
```
┌─ 登录引导卡 ───────────────────────────────────────┐
│ 🔒 登录后查看任务和活动参与记录 │
│ · 查看今日任务,完成打卡获取行动能量 │
│ · 报名参加热门活动,记录成长足迹 │
│ [立即登录] │
└────────────────────────────────────────────────────┘
┌─ 热门活动(按 action 维度筛选) ──────────────────┐
│ 横向滚动卡片,全部公开活动,不显示价格 │
└────────────────────────────────────────────────────┘
┌─ 推荐商品(按 action 维度筛选) ──────────────────┐
│ 2×2 网格商品卡片,不显示价格 │
└────────────────────────────────────────────────────┘
```
### 14.7 后端过滤逻辑
所有列表接口根据请求中是否携带有效 JWT Token,返回不同数据集:
```
请求到达
│
├─ 有 JWT Token(已登录)
│ ├─ userId 存在 → 正常返回全部可见数据
│ ├─ 商品: status=approved + memberEligible 检查
│ ├─ 活动: visiblity IN (public, member, private) + visibleTo 匹配
│ ├─ 文章: visibility IN (public, member, private) + visibleTo 匹配
│ └─ 价格: 正常返回 price 字段
│
└─ 无 JWT Token(游客)
├─ userId = null
├─ 商品: status=approved AND memberEligible!='yes'(非会员专属)
├─ 活动: visibility='public'
├─ 文章: visibility='public'
└─ 价格: 返回 price=null 或 0(前端据此显示"登录查看")
```
#### 商品列表接口改造
```java
@PostMapping("/list")
public Result> list(@RequestBody Map params,
@RequestAttribute(value = "userId", required = false) Long userId) {
// ... 现有参数解析 ...
LambdaQueryWrapper query = new LambdaQueryWrapper()
.eq(Product::getStatus, "approved");
// 游客过滤:排除会员专属商品
if (userId == null) {
query.ne(Product::getMemberEligible, "yes");
}
// 维度筛选
String dimensionCode = (String) params.get("dimensionCode");
if (dimensionCode != null && !dimensionCode.isEmpty()) {
query.eq(Product::getEnergyDimensionId, getDimensionId(dimensionCode));
}
// 查询并转换DTO(游客不返回价格)
Page pageResult = productService.page(new Page<>(page, size), query);
Page dtoPage = toDTOPage(pageResult, userId == null);
return Result.success(dtoPage);
}
```
#### 活动列表接口改造
后端根据 `visibility` / `visibleScope` / `visibleTo` 三字段组合判断可见性:
```java
@PostMapping("/list")
public Result> list(@RequestBody Map params,
@RequestAttribute(value = "userId", required = false) Long userId,
@RequestAttribute(value = "familyId", required = false) Long familyId,
@RequestAttribute(value = "role", required = false) String role) {
LambdaQueryWrapper query = new LambdaQueryWrapper()
.eq(Activity::getStatus, "published");
if (userId == null) {
// 游客:只看公开活动
query.eq(Activity::getVisibility, "public");
} else {
// 登录用户:public + member + restricted 中自己符合条件的
query.and(w -> {
w.eq(Activity::getVisibility, "public")
.or().eq(Activity::getVisibility, "member");
// restricted 模式:按 scope 类型分别匹配
if (familyId != null) {
// family 范围 → 匹配 familyId
w.or().and(w2 -> w2.eq(Activity::getVisibility, "restricted")
.eq(Activity::getVisibleScope, "family")
.apply("JSON_CONTAINS(visible_to, {0})", "\"" + familyId + "\""));
}
// role 范围 → 匹配用户 role
if (role != null) {
w.or().and(w2 -> w2.eq(Activity::getVisibility, "restricted")
.eq(Activity::getVisibleScope, "role")
.apply("JSON_CONTAINS(visible_to, {0})", "\"" + role + "\""));
}
// user 范围 → 匹配具体 userId
w.or().and(w2 -> w2.eq(Activity::getVisibility, "restricted")
.eq(Activity::getVisibleScope, "user")
.apply("JSON_CONTAINS(visible_to, {0})", "\"" + userId + "\""));
});
}
String dimensionCode = (String) params.get("dimensionCode");
if (dimensionCode != null && !dimensionCode.isEmpty()) {
query.eq(Activity::getDimensionCode, dimensionCode);
}
Page pageResult = activityService.page(new Page<>(page, size), query);
Page dtoPage = toDTOPage(pageResult, userId == null);
return Result.success(dtoPage);
}
```
> 若 `familyId` 非必须(用户可能无家庭),用 `null` 安全防护避免 SQL 异常。
#### 文章列表接口改造
```java
@PostMapping("/list")
public Result> list(@RequestBody Map params,
@RequestAttribute(value = "userId", required = false) Long userId) {
LambdaQueryWrapper query = new LambdaQueryWrapper()
.eq(Article::getStatus, "published");
if (userId == null) {
query.eq(Article::getVisibility, "public");
} else {
// 登录用户:public + member + 指定给自己的 private
query.and(w -> w.eq(Article::getVisibility, "public")
.or().eq(Article::getVisibility, "member")
.or().and(w2 -> w2.eq(Article::getVisibility, "private")
.apply("JSON_CONTAINS(visible_to, {0})", "\"" + userId + "\"")));
}
String dimension = (String) params.get("dimension");
if (dimension != null && !dimension.isEmpty()) {
query.like(Article::getRelatedDimensions, dimension);
}
Page pageResult = articleService.page(new Page<>(page, size), query);
return Result.success(toDTOPage(pageResult, userId == null));
}
```
#### ProductDTO(游客版不返回价格)
```java
@Data
public class ProductDTO {
private Long id;
private String name;
private String description;
private String coverImage;
private BigDecimal price; // 游客 = null
private String priceLabel; // 游客 = "登录查看价格",登录后 = "¥XXX"
private String vendorName;
private String productType;
// 其他非敏感字段
}
```
#### ActivityDTO(游客版不返回价格)
```java
@Data
public class ActivityDTO {
private Long id;
private String title;
private String coverImage;
private String startTime;
private String endTime;
private String location;
private BigDecimal price; // 游客 = null
private String priceLabel; // 游客 = "登录查看",登录后 = "¥XXX"
private Integer maxParticipants;
private Integer currentParticipants;
private String vendorName;
// 其他非敏感字段
}
```
### 14.8 前端游客模式判断逻辑
所有页面统一使用 `isLoggedIn` 变量控制渲染分支:
```javascript
// 每个页面的 onShow 中
onShow() {
var token = uni.getStorageSync('token')
this.isLoggedIn = !!token
if (this.isLoggedIn) {
this.loadPersonalData() // 能量、健康、测评、任务等
}
// 无论是否登录,都加载公共数据
this.loadPublicData() // 商品、活动、文章
}
// 组件内部根据 props hidePrice 控制价格显示
// 后端在未登录时返回 price=null, priceLabel="登录查看价格"
```
**商品区块渲染逻辑(含占位):**
```vue
{{ prod.name }}
登录查看价格
¥{{ prod.price }}
🔒 登录后查看更多推荐商品
```
**活动区块渲染逻辑(含占位):**
```vue
{{ act.title }}
{{ act.startTime }} · {{ act.location }}
登录查看
¥{{ act.price }}
🔒 登录后查看更多相关活动
```
### 14.9 文件变更补充
在原有文件变更清单基础上新增:
| 操作 | 文件 | 说明 |
|:----:|------|------|
| 🔄 | `cfc-backend/.../entity/Activity.java` | 补充 `visibility` + `visibleTo` 字段 |
| 🔄 | `cfc-backend/.../dto/ProductDTO.java` | 新增 `priceLabel` 字段 |
| ✨ | `cfc-backend/.../dto/ActivityDTO.java` | 新增 `priceLabel` 字段 |
| 🔄 | `cfc-backend/.../dto/ArticleDTO.java` | 若尚无,新增 DTO 类 |
| 🔄 | `cfc-backend/.../controller/ProductController.java` | list 接口增加 `@RequestAttribute("userId")` 和游客逻辑 |
| 🔄 | `cfc-backend/.../controller/ActivityController.java` | list 接口增加 userId 参数和可见性过滤 |
| 🔄 | `cfc-backend/.../controller/ArticleController.java` | list 接口增加 userId 参数和可见性过滤 |
| 🔄 | `cfc-frontend/pages/body/index.vue` | 增加游客分支渲染 |
| 🔄 | `cfc-frontend/pages/mind/index.vue` | 增加游客分支渲染 |
| 🔄 | `cfc-frontend/pages/action/index.vue` | 增加游客分支渲染 |