Prechádzať zdrojové kódy

docs: 更新天盘设计——五维基础分改为落库+重算接口

iwt 1 týždeň pred
rodič
commit
4cb9a1b168

+ 70 - 13
docs/superpowers/specs/2026-09-09-tianpan-tradition-design.md

@@ -127,18 +127,44 @@
 public class FiveDimensionScoreService {
 
     /**
-     * 计算五维基础能量分(确定性规则,无状态
+     * 计算并落库(INSERT ON DUPLICATE KEY UPDATE
      *
+     * @param memberId 成员 ID
+     * @param memberType 成员类型
      * @param wuxingElements 五行元素 {"wood":..,"fire":..,"earth":..,"metal":..,"water":..},可为 null
      * @param westernSign    西方星座中文名(如 "狮子座"),可为 null
      * @param lifeNumber     生命灵数(主数 11/22/33 已化简为 1-9),可为 null
-     * @return Map<String,Integer> { body, mind, wisdom, action, wealth }
+     * @param operator       计算来源(system/manual)
      */
-    public Map<String, Integer> calcBaseScores(Map<String, Integer> wuxingElements,
-                                               String westernSign,
-                                               Integer lifeNumber) {
-        // 实现要点见 3.1.1 - 3.1.3
+    public void calcAndSave(Long memberId, String memberType,
+                            Map<String, Integer> wuxingElements,
+                            String westernSign, Integer lifeNumber,
+                            String operator) {
+        Map<String, Integer> scores = calcBaseScores(wuxingElements, westernSign, lifeNumber);
+        saveScores(memberId, memberType, scores, operator);
     }
+
+    /**
+     * 重算指定成员(覆盖现有记录)
+     */
+    public void recalibrate(Long memberId, String memberType, String operator) {
+        FamilyMemberAttributes attrs = familyMemberAttributeService.getByMember(memberId, memberType);
+        if (attrs == null) return;
+        String westernSign = calcWesternSignFromAttrs(attrs); // 复用 zodiacAnnualEnergyService 逻辑
+        Integer lifeNumber = attrs.getLifeNumber(); // 若未存则从 birthDatetime 重新算
+        calcAndSave(memberId, memberType, parseWuxingMap(attrs.getWuxingElements()),
+                    westernSign, lifeNumber, operator);
+    }
+
+    /**
+     * 批量重算全家(用于数据修复/策略调整)
+     */
+    public int recalibrateFamily(Long familyId, String operator) { ... }
+
+    /**
+     * 查询五维基础分(供 dashboard/member 接口读取)
+     */
+    public Map<String, Integer> getScores(Long memberId) { ... }
 }
 ```
 
@@ -185,18 +211,46 @@ private Map<String, Integer> dimensionBaseScores;  // 五维基础分 {body,mind
 ### 3.3 改动点
 
 **`TianpanService.enrichMembers()`**(第 174 行附近):
-- 成员已有 `m.getWuxingElements()`、`vo.getWesternSign()`、`m.getLifeNumber()`
-- 在填充 `vo` 时调用 `fiveDimensionScoreService.calcBaseScores(...)` 并 `vo.setDimensionBaseScores(...)`
+- 原有 `m.getWuxingElements()`、`vo.getWesternSign()`、`m.getLifeNumber()` 保持不变
+- 改为从新表读取已落库的五维基础分:`fiveDimensionScoreService.getScores(m.getMemberId())`
+- 若表无数据(首次部署或重算未完成)则 fallback 到内存计算(`calcBaseScores(...)`)并立即落库
+- 新增 `zodiacName` 填充(见 3.6)
 
 **`TianpanService.buildMemberDetail()`**:经 `enrichMembers` 自动填充,无需额外改动。
 
-**依赖注入**:`TianpanService` 增加 `@Resource private FiveDimensionScoreService fiveDimensionScoreService;`(注意 Bean 名与字段名一致)。
+**依赖注入**:`TianpanService` 增加 `@Resource private FiveDimensionScoreService fiveDimensionScoreService;`
+
+**新增 Controller 接口**:
+- `POST /api/tianpan/recalibrate` — 手动触发单个成员重算
+  - 请求体:`{memberId, memberType, operator: "admin"}`
+  - 返回:更新后的 `dimensionBaseScores`
+- `POST /api/tianpan/recalibrate-family` — 批量重算全家(管理员用)
+  - 请求体:`{familyId, operator: "admin"}`
+  - 返回:成功重算的成员数
+
+**管理端集成**:在 Web 管理端家庭成员详情页新增「重新计算五维基础分」按钮,调用上述接口。
+
+### 3.4 数据库迁移
+
+**新增表 `family_member_dimension_base_scores`**:
+```sql
+CREATE TABLE IF NOT EXISTS family_member_dimension_base_scores (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    member_id BIGINT NOT NULL COMMENT '家庭成员ID',
+    member_type VARCHAR(20) NOT NULL COMMENT '成员类型: child/parent',
+    dimension_code VARCHAR(20) NOT NULL COMMENT '维度: body/mind/wisdom/action/wealth',
+    base_score INT NOT NULL COMMENT '基础能量分(0-100)',
+    last_calculated_at DATETIME NOT NULL COMMENT '最后计算时间',
+    calculated_by VARCHAR(50) DEFAULT 'system' COMMENT '计算来源(system/manual)',
+    UNIQUE KEY uk_member_dimension (member_id, dimension_code),
+    INDEX idx_member (member_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='五维基础能量分(落库,支持重算)';
+```
+
+**迁移逻辑**:`DatabaseInitializer.runMigrations()` 追加迁移,对已有成员批量回填(若 `family_member_attributes` 有数据则触发一次性重算写入)。
 
-### 3.4 明确不做的事
+### 3.5 显式不做的事
 
-- ❌ 不新增数据库表 —— 八字/星座/灵数数据均已存在 `family_member_attributes`,五维基础分为实时计算(确定性、无状态)
-- ❌ 不落库缓存 —— 计算成本极低(纯内存映射),无性能压力
-- ❌ 不新增 Controller 接口 —— 通过现有 `/api/tianpan/dashboard` 和 `/api/tianpan/member/{id}` 返回
 - ❌ 不引入 AI/LangGraph —— 用户已确认走确定性加权计算
 
 ## 4. 前端设计(三处增强)
@@ -281,9 +335,12 @@ cd cfc-backend && mvn clean compile
 
 **In scope**:
 - 五维基础分算法服务 + 单测
+- `family_member_dimension_base_scores` 表 + 迁移 + 批量回填
 - `TianpanMemberVO` 扩展(dimensionBaseScores)+ `enrichMembers` 填充(含 zodiacName 补齐)
+- 重算接口 `POST /api/tianpan/recalibrate` / `recalibrate-family`
 - 天盘首页 canvas 节点标注 + 成员弹窗增强
 - 新增 `pages/tianpan/traditional.vue` + 入口卡片 + pages.json 注册
+- Web 管理端家庭成员详情「重新计算五维基础分」按钮(可选)
 
 **Out of scope**:
 - 姓名数理(五格剖象法)—— 需汉字笔画库,单独需求