# 五维 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 ``` **活动区块渲染逻辑(含占位):** ```vue ``` ### 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` | 增加游客分支渲染 |