# 五维能量系统设计 **日期:** 2026-06-05(最后更新:2026-07-13) **状态:** 已实施(核心) + 富维度子维度已落地 **分支:** cfclub **版本:** v2.1 ## 概述 本项目服务于身、心、智、行、富五个维度,服务内容包括活动、课程、商品、任务、咨询五大类。每个服务实例可影响多个维度,能量值按比例分配。能量系统为全新独立系统,与现有积分系统并行但解耦。 > **哲学基础:** 五维之间的相生相克关系详见 [`2026-06-08-five-dimension-wuxing-philosophy.md`](./2026-06-08-five-dimension-wuxing-philosophy.md)。所有维度顺序、健康指数算法、内容推荐策略均以此为依据。 > > **v2.1 更新(2026-07-13):** 富维度子维度拆分 + 身克富杠杆落地 + `POST /api/energy/wealth-detail` 富维度详情接口。详见 §6。 ### 关键决策 | 决策项 | 结论 | |--------|------| | 维度比例配置方式 | 按服务实例配置(每个具体任务/课程/商品创建时可指定维度比例) | | 能量值性质 | 可消耗值(类似积分,可增可减) | | 健康指数算法 | 已实施:各维度子分加权 + 五行相生增益 + 相克校准(v2.0),富维度子维度已落地(v2.1) | | 与积分系统关系 | 全新独立系统,不复用积分,但家长富-金钱/收入复用积分总量做参照 | | 架构方案 | 方案B:维度定义表+流水表+余额表 | ## 1. 数据模型 ### 1.1 energy_dimension — 维度定义表 | 列名 | 类型 | 说明 | |------|------|------| | id | BIGINT AUTO_INCREMENT PK | | | code | VARCHAR(16) UNIQUE | body/mind/wisdom/action/wealth | | name | VARCHAR(20) | 身/心/智/行/富 | | icon | VARCHAR(16) | 🌏/🔥/⚔️/🌿/💧 | | element | VARCHAR(10) | 土/火/金/木/水 | | sort_order | INT | 显示顺序 | | status | TINYINT DEFAULT 1 | 1启用/0禁用 | 种子数据(排序遵循相生链:智→富→行→心→身,详见[五维五行哲学体系](./2026-06-08-five-dimension-wuxing-philosophy.md)): | code | name | icon | element | sort_order | |------|------|------|---------|:----------:| | wisdom | 智 | ⚔️ | 金 | 1 | | wealth | 富 | 💧 | 水 | 2 | | action | 行 | 🌿 | 木 | 3 | | mind | 心 | 🔥 | 火 | 4 | | body | 身 | 🌏 | 土 | 5 | ### 1.2 energy_source_config — 服务-维度比例配置表 | 列名 | 类型 | 说明 | |------|------|------| | id | BIGINT AUTO_INCREMENT PK | | | source_type | VARCHAR(32) | task/activity/course/product/consultation | | source_id | BIGINT | 对应业务表ID | | source_name | VARCHAR(200) | 冗余名称,方便展示 | | dimension_id | BIGINT | 维度ID | | ratio | DECIMAL(5,4) | 该维度占比,如0.6000=60% | | created_at | DATETIME DEFAULT CURRENT_TIMESTAMP | | 约束:同一 source_type+source_id 的所有 ratio 之和应 = 1.0。一个服务实例配多行记录。 示例:任务#42 → 行60%+心40% = 2行记录。 ### 1.3 energy_log — 能量流水表 | 列名 | 类型 | 说明 | |------|------|------| | id | BIGINT AUTO_INCREMENT PK | | | child_id | BIGINT | 孩子ID | | dimension_id | BIGINT | 维度ID | | amount | INT | 变动量(正=获得,负=消耗) | | balance_after | INT | 变动后该维度余额 | | source_type | VARCHAR(32) | 来源类型 | | source_id | BIGINT | 来源ID | | description | VARCHAR(500) | 描述 | | created_at | DATETIME DEFAULT CURRENT_TIMESTAMP | | 索引:`idx_child_dim (child_id, dimension_id)`,`idx_created (created_at)` ### 1.4 energy_balance — 各维度当前余额表 | 列名 | 类型 | 说明 | |------|------|------| | id | BIGINT AUTO_INCREMENT PK | | | child_id | BIGINT | 孩子ID | | dimension_id | BIGINT | 维度ID | | balance | INT DEFAULT 0 | 当前能量值 | | total_earned | INT DEFAULT 0 | 累计获得 | | total_spent | INT DEFAULT 0 | 累计消耗 | | updated_at | DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | | UNIQUE(child_id, dimension_id) ### 1.5 API 响应结构 ```json GET /api/energy/overview?childId=123 { "code": 0, "data": { "dimensions": [ { "code": "wisdom", "name": "智", "icon": "⚔️", "element": "金", "energy": 310, "healthIndex": 0 }, { "code": "wealth", "name": "富", "icon": "💧", "element": "水", "energy": 200, "healthIndex": 0 }, { "code": "action", "name": "行", "icon": "🌿", "element": "木", "energy": 350, "healthIndex": 0 }, { "code": "mind", "name": "心", "icon": "🔥", "element": "火", "energy": 280, "healthIndex": 0 }, { "code": "body", "name": "身", "icon": "🌏", "element": "土", "energy": 380, "healthIndex": 0 } ], "totalEnergy": 1520, "totalHealthIndex": 0 } } ``` healthIndex 和 totalHealthIndex 算法待定,先返回0。 ## 2. 后端服务架构 ### 2.1 新增文件清单 | 文件 | 位置 | 职责 | |------|------|------| | EnergyDimension | entity/ | 维度定义实体 | | EnergySourceConfig | entity/ | 服务-维度比例配置实体 | | EnergyLog | entity/ | 能量流水实体 | | EnergyBalance | entity/ | 维度余额实体 | | EnergyDimensionMapper | mapper/ | 维度CRUD | | EnergySourceConfigMapper | mapper/ | 比例配置CRUD | | EnergyLogMapper | mapper/ | 流水查询 | | EnergyBalanceMapper | mapper/ | 余额查询/更新 | | EnergyService | service/ | 核心业务:发放/扣除能量、查余额、算指数 | | EnergyController | controller/energy/ | API入口:概览、流水、配置 | ### 2.2 EnergyService 核心方法 ```java /** * 发放能量 — 指定source_type+source_id,自动查比例配置,按比例分配到各维度 * @return 各维度实际发放量 Map */ Map awardEnergy(Long childId, String sourceType, Long sourceId, Integer totalAmount, String description) /** * 扣除能量 — 指定维度,检查余额,余额不足返回-1 * @return 扣除后余额,-1表示余额不足 */ int deductEnergy(Long childId, Long dimensionId, Integer amount, String reason) /** * 查询概览 — 返回5维度能量值+健康指数+总能量+总指数 */ Map getOverview(Long childId) /** * 查询流水 — 按维度筛选,分页 */ Page getLogs(Long childId, String dimensionCode, Integer page, Integer size) /** * 配置比例 — 为某服务实例设置维度比例 * ratios: [{dimensionCode:"action", ratio:0.6}, {dimensionCode:"mind", ratio:0.4}] */ void configureSourceRatios(String sourceType, Long sourceId, String sourceName, List> ratios) ``` ### 2.3 与现有系统的集成点 | 业务场景 | 调用位置 | 调用方式 | |----------|----------|----------| | 完成任务 | TaskService.completeTask() | energyService.awardEnergy(childId, "task", taskId, energyAmount, "完成任务: "+title) | | 购买商品 | 商品订单支付成功回调 | energyService.awardEnergy(childId, "product", productId, energyAmount, "购买商品: "+name) | | 参加活动 | 活动报名/签到 | energyService.awardEnergy(childId, "activity", activityId, energyAmount, "参加活动: "+title) | | 课程学习 | 课程完成/打卡 | energyService.awardEnergy(childId, "course", courseId, energyAmount, "完成课程: "+title) | | 咨询完成 | 咨询结束后 | energyService.awardEnergy(childId, "consultation", consultId, energyAmount, "完成咨询") | 能量发放额度由各业务方自行决定,EnergyService只负责按比例分配。 ### 2.4 awardEnergy 核心流程 ``` 1. 根据 sourceType+sourceId 查 energy_source_config 获取比例列表 2. 若无配置,查 Product.domain 作为 fallback(单维度100%) 3. 若仍无配置,默认分配到"行"维度100% 4. 按 ratio * totalAmount 计算各维度发放量(整数,余数加到最大比例维度) 5. 对每个维度: a. 查 energy_balance 获取当前余额 b. 计算新余额 c. 更新 energy_balance d. 写入 energy_log 6. 返回各维度实际发放量 ``` ## 3. 前端可视化设计 ### 3.1 五角星布局(五行顺序:木→火→土→金→水,从最左侧顺时针排列) ``` 心·火 (顶) ↗ ↖ 行·木 (左) (右) 身·土 ↖ ↗ 富·水 (左下) (右下) 智·金 ``` ### 3.2 三层视觉结构 **外层 — 维度角(五角形顶点)** 每个角显示: - 图标 + 名称(如 🔥心·火) - 能量值:绝对数字,如 `320` - 点击可跳转该维度详情页 **中层 — 健康指数扇区(角底边→中心的三角形区域)** 每个维度的三角形区域外围显示该维度的健康指数: - 数字显示,如 `78` - 背景色按指数高低渐变(绿→黄→红) - 指数算法待定,先显示0占位 **内层 — 中心圆** 中央圆形区域显示: - 总体能量值:五维度能量值之和,如 `1520` - 总体健康指数:综合指数,如 `75` - 算法待定,先显示0占位 ### 3.3 wuxing-sandbox.vue Props 接口 ```js props: { mode: String, // 'preview' | 'parent' | 'child' dimensions: { // API返回的维度数据 type: Array, default: () => [] }, totalEnergy: { type: Number, default: 0 }, totalHealthIndex: { type: Number, default: 0 } } ``` dimensions 数组元素结构: ```json { "code": "body", "name": "身", "icon": "🌏", "element": "土", "energy": 320, "healthIndex": 0 } ``` ### 3.4 新增页面 | 页面 | 路径 | 说明 | |------|------|------| | 维度详情页 | pages/energy/detail.vue | 某维度能量值、流水记录、提升建议 | 在 pages.json 中注册(非TabBar页),从沙盘点位点击 navigateTo 进入。 ### 3.5 API 调用 ```js // utils/api.js 新增 getEnergyOverview(childId) // POST /api/energy/overview getEnergyLogs(childId, dimensionCode, page, size) // POST /api/energy/logs ``` ### 3.6 现有引用更新 | 页面 | 当前用法 | 更新为 | |------|----------|--------| | parent-index.vue | `` | 传入从API获取的 dimensions/totalEnergy/totalHealthIndex | | child-index.vue | `` | 同上 | | discover/index.vue | `` | 保持预览模式,用空数据 | ## 4. 数据库迁移与兼容性 ### 4.1 DatabaseInitializer 迁移步骤 1. 创建4张新表(IF NOT EXISTS) 2. 插入5条维度种子数据 3. 为现有Product种子数据插入默认 energy_source_config(1:1单维度映射,与当前Product.domain一致) 4. 为任务模板插入默认比例配置(任务默认→行100%) ### 4.2 现有系统兼容 | 项目 | 处理方式 | |------|----------| | 积分系统(PointsService) | 完全不动,能量系统独立运行 | | TaskService.completeTask() | 新增一行 energyService.awardEnergy(...) 调用,积分和能量并行发放 | | Product.domain 字段 | 保留不删除,作为无 energy_source_config 时的 fallback | | wuxing-sandbox.vue | 组件接口从硬编码改为接收 props 数据 | | 前端3处引用 | parent-index/child-index/discover 传入实际数据 | ### 4.3 无比例配置时的 Fallback 链 ``` 1. 查 energy_source_config → 有 → 使用配置比例 2. 无 → source_type 为 "product" 时查 Product.domain → 有 → 单维度100% 3. 无 → 默认分配到"行"维度100% ``` ## 6. 富维度算法(v2.1) **日期:** 2026-07-12 实施,2026-07-13 文档化 **实施提交:** `3a302b3` — feat: 电商体系升级 — 五维能量富维度详情 **关联计划:** [`2026-07-12-wealth-dimension-redesign.md`](../plans/2026-07-12-wealth-dimension-redesign.md) ### 6.1 背景 成人和孩子的"富"原为单一值(成人=积分总量/500,孩子=积分获取效率),无差异化"富"定义,也无身克富的系统体现。v2.1 将"富"拆为 3 个子维度,并在 `calcParentEnergy`/`calcChildEnergy` 末尾调用 `applyBodyWealthRestraint` 施加身克富杠杆。 ### 6.2 孩子子维度(`calcChildWealth`) | 子维度 | 符号 | 数据源 | 权重 | |:------|:----:|--------|:----:| | 学业成绩 | `wealthEducation` | DanAssessmentResult 最近3次综合分均值 + 进步趋势修正(最近一次 vs 前面平均的 10% delta) | 30% | | 社交筹码 | `wealthSocial` | 活动参与次数(活动系统)— **第一阶段返回 0** | 20% | | 规则博弈(积分效率) | `wealthPoints` | 一年内已 earned 积分 / 一年内可获取总积分 × 100 | 50% | 评分公式:`wealth = edu*0.3 + social*0.2 + points*0.5` 实现位置:`EnergyService.calcChildWealthEducation/Social/Points`(540-614 行)。 ### 6.3 成人子维度(`calcParentWealth`) | 子维度 | 符号 | 数据源 | 权重 | |:------|:----:|--------|:----:| | 金钱/收入 | `wealthIncome` | `User.totalPoints / 500 × 100`,clamp[0,100] | 50% | | 社会成就 | `wealthAchievement` | `User.achievements` 扩展字段 JSON — **第一阶段返回 0** | 30% | | 资源网络 | `wealthNetwork` | 推荐团队人数 — **第一阶段返回 0** | 20% | 评分公式:`wealth = income*0.5 + achievement*0.3 + network*0.2` 实现位置:`EnergyService.calcParentWealthIncome/Achievement/Network`(253-280 行)。 ### 6.4 身克富杠杆(`applyBodyWealthRestraint`) 在 `calcParentEnergy`/`calcChildEnergy` 中,`wealthScore` 计算完成后、综合分 `overallScore` 之前调用: ```java applyBodyWealthRestraint(bodyScore, dto.getWealthScore(), dto); ``` | 条件 | 状态 (`bodyWealthStatus`) | 行为 | 用户文案 (`bodyWealthMessage`) | |------|------------------------|------|----------------------------| | 身 < 40 | `penalty` | wealth *= (0.5 + 0.5 × 身/100),即最低打对折 | "健康正在稀释财富能量,建议优先关注身体健康" | | 身 < 50 且 富 > 身+20 | `overdraw` | 不下调 wealthScore,仅透支预警 | "财富能量超出身体承受范围,注意劳逸结合" | | 否则 | `normal` | 不调整;身≥70 给正向文案 | 身≥70:"身体底盘稳固,财富能量充沛" / 其他:空串 | 实现位置:`EnergyService.applyBodyWealthRestraint`(622-645 行)。 > **算法哲学依据:** 见 [五维五行哲学体系 §2 相克关系](./2026-06-08-five-dimension-wuxing-philosophy.md#2-相克关系v20-更新)。身克富 = "健康是创富的底盘,身体不好财富没有意义"。v2.0 将"克"从惩罚层面升级为信号/平衡层面:penalty 是校准触发,overdraw 是引导触发,normal 是正向标记。 ### 6.5 DTO 扩展 `MemberEnergyDTO` v2.1 新增字段: ```java // 富的子维度(parent) private Integer wealthIncome; // 金钱/收入 private Integer wealthAchievement; // 社会成就 private Integer wealthNetwork; // 资源网络 // 富的子维度(child) private Integer wealthEducation; // 学业成绩 private Integer wealthSocial; // 社交筹码 private Integer wealthPoints; // 规则博弈(积分效率) // 身克富标记 private String bodyWealthStatus; // normal / overdraw / penalty private String bodyWealthMessage; // 用户可见的消息 ``` > 注:`wealthScore`(综合富分)已在 v1 定义,v2.1 由 `calcChildWealth`/`calcParentWealth` 赋值,并可被 `applyBodyWealthRestraint` 在 penalty 状态下下调。 ### 6.6 富维度详情接口 ``` POST /api/energy/wealth-detail Body: { "memberId": , "memberType": "child"|"parent" } Header: Authorization: Bearer ``` **逻辑**(`EnergyController.getWealthDetail`,221-250 行): 1. 取当前 JWT 用户,校验已加入家庭 2. 调用 `energyService.calculateFamilyEnergy(familyId)` 算家庭整个 sandbox 3. 按 `memberId + memberType` 过滤出该成员的 `MemberEnergyDTO` 4. 返回含全部子维度字段 + 身克富标记 **前端调用:** `utils/api.js` 新增 `getWealthDetail(memberId, memberType)`,`pages/wealth/index.vue` 用其替代原 `getEnergyOverview` 单独加载富维度数据。 ### 6.7 不做的事 - 不新建 schema 表、不改 schema.sql、不改 DatabaseInitializer(富子维度无需存储,全部由现有数据源即时计算) - 不改 `EnergySandboxDTO`(家庭聚合值不受影响,子维度只在单成员 DTO 上承载) - 不改任何 Mapper ## 7. 待定事项 | 事项 | 说明 | 影响 | |------|------|------| | 能量过期/衰减 | 是否需要能量值过期机制 | 暂不实现,energy_log.created_at 可支撑后续时间窗口计算 | | Web管理端 | 管理端维度比例配置页面 | 后端API已就绪,管理端UI后续迭代 | | 能量兑换/消耗 | 扣除能量的具体业务场景 | deductEnergy 方法已预留,具体场景待定 | | 成人富-成就/网络数据源 | 第一阶段回 0,待 `User.achievements` 字段和推荐团队体系落地 | 子维度结构已定,仅需补充数据源 | | 孩子富-社交筹码数据源 | 第一阶段回 0,待活动参与系统完善 | 同上 | ## 附录:文档演变 | 版本 | 日期 | 变更内容 | |:----:|:----:|----------| | v1.0 | 2026-06-05 | 初稿,能量系统架构方案B(维度定义表+流水表+余额表),健康指数先返回0占位 | | v2.1 | 2026-07-13 | 富维度子维度拆分(孩子3+成人3)+ 身克富三态杠杆算法 + `POST /api/energy/wealth-detail` 接口 + DTO 扩展文档化 |