2026-06-05-five-dimension-energy-design.md 11 KB

五维能量系统设计

日期: 2026-06-05 状态: 已确认,待实施 分支: cfclub

概述

本项目服务于身、心、智、行、富五个维度,服务内容包括活动、课程、商品、任务、咨询五大类。每个服务实例可影响多个维度,能量值按比例分配。能量系统为全新独立系统,与现有积分系统并行但解耦。

关键决策

决策项 结论
维度比例配置方式 按服务实例配置(每个具体任务/课程/商品创建时可指定维度比例)
能量值性质 可消耗值(类似积分,可增可减)
健康指数算法 待定,先搭框架返回0占位
与积分系统关系 全新独立系统,不复用积分
架构方案 方案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禁用

种子数据:

code name icon element sort_order
mind 🔥 1
action 🌿 2
wealth 💧 3
wisdom ⚔️ 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 响应结构

GET /api/energy/overview?childId=123
{
  "code": 0,
  "data": {
    "dimensions": [
      {
        "code": "mind",
        "name": "心",
        "icon": "🔥",
        "element": "火",
        "energy": 280,
        "healthIndex": 0
      },
      {
        "code": "action",
        "name": "行",
        "icon": "🌿",
        "element": "木",
        "energy": 350,
        "healthIndex": 0
      },
      {
        "code": "wealth",
        "name": "富",
        "icon": "💧",
        "element": "水",
        "energy": 200,
        "healthIndex": 0
      },
      {
        "code": "wisdom",
        "name": "智",
        "icon": "⚔️",
        "element": "金",
        "energy": 310,
        "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 核心方法

/**
 * 发放能量 — 指定source_type+source_id,自动查比例配置,按比例分配到各维度
 * @return 各维度实际发放量 Map<dimensionCode, amount>
 */
Map<String, Integer> 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<String, Object> getOverview(Long childId)

/**
 * 查询流水 — 按维度筛选,分页
 */
Page<EnergyLog> 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<Map<String, Object>> 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 接口

props: {
  mode: String,        // 'preview' | 'parent' | 'child'
  dimensions: {        // API返回的维度数据
    type: Array,
    default: () => []
  },
  totalEnergy: {
    type: Number,
    default: 0
  },
  totalHealthIndex: {
    type: Number,
    default: 0
  }
}

dimensions 数组元素结构:

{ "code": "body", "name": "身", "icon": "🌏", "element": "土", "energy": 320, "healthIndex": 0 }

3.4 新增页面

页面 路径 说明
维度详情页 pages/energy/detail.vue 某维度能量值、流水记录、提升建议

在 pages.json 中注册(非TabBar页),从沙盘点位点击 navigateTo 进入。

3.5 API 调用

// utils/api.js 新增
getEnergyOverview(childId)      // POST /api/energy/overview
getEnergyLogs(childId, dimensionCode, page, size)  // POST /api/energy/logs

3.6 现有引用更新

页面 当前用法 更新为
parent-index.vue <wuxing-sandbox mode="parent" badgeText="综合成长力 0%" /> 传入从API获取的 dimensions/totalEnergy/totalHealthIndex
child-index.vue <wuxing-sandbox mode="child" badgeText="综合 0%" /> 同上
discover/index.vue <wuxing-sandbox mode="preview" badgeText="登录查看完整报告" /> 保持预览模式,用空数据

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%

5. 待定事项

事项 说明 影响
健康指数算法 各维度健康指数 + 总体健康指数的计算公式 API返回0占位,不影响数据结构
能量过期/衰减 是否需要能量值过期机制 暂不实现,energy_log.created_at 可支撑后续时间窗口计算
Web管理端 管理端维度比例配置页面 本次只做后端API,管理端UI后续迭代
能量兑换/消耗 扣除能量的具体业务场景 deductEnergy 方法已预留,具体场景待定