| 能力 | 位置 | 说明 |
|---|---|---|
| 八字四柱 | family_member_attributes.eight_characters |
JSON {"year":"甲子","month":"丙寅","day":"戊辰","hour":"壬申"} |
| 五行元素 | family_member_attributes.wuxing_elements |
JSON {"wood":30,"fire":45,"earth":60,"metal":25,"water":40} |
| 生肖 | family_member_attributes.zodiac |
rat/ox/... |
| 出生时间 | family_member_attributes.birth_datetime |
精确到分钟,用于排盘 |
| 生命灵数 | NumSoulCalculator + InnatePortraitService.calculateNumSoul() |
lifePath/天赋数/生日数/命运数,主数 11/22/33 保留 |
| 灵数配置 | numsoul_detail_config 表 |
1-9 号人 title/keywords/advice/colorHex |
| 先天分 | family_member_attributes.mind_base_score / wisdom_base_score |
仅心/智两维已有 |
| 天盘聚合 | TianpanService.buildDashboard() / buildMemberDetail() |
已返回八字/星座/灵数/五行/能量快照 |
NumSoulCalculator)| 维度 | code | 五行 | 颜色 |
|---|---|---|---|
| 身 | body | 土 earth | #FF8C42 |
| 智 | wisdom | 金 metal | #6366F1 |
| 富 | wealth | 水 water | #F59E0B |
| 行 | action | 木 wood | #10B981 |
| 心 | mind | 火 fire | #FF6B9D |
五维基础分[dim] = round( 八字五行[dim] × 0.6 + 星座命中[dim] × 20 + 灵数命中[dim] × 20 )
直接取 wuxingElements 中对应五行值(0-100 量纲)乘以 0.6:
| 五行 | 映射维度 |
|---|---|
| wood 木 | action 行 |
| fire 火 | mind 心 |
| earth 土 | body 身 |
| metal 金 | wisdom 智 |
| water 水 | wealth 富 |
缺数据兜底:某成员无 wuxingElements(或某五行缺失)时,该维度取中性值 50。
西方 12 星座四元素 → 五行 → 五维映射,命中维度 +20 分:
| 四元素 | 星座 | 五行 | 维度 |
|---|---|---|---|
| 火象 | 白羊/狮子/射手 | 火 | 心 |
| 土象 | 金牛/处女/摩羯 | 土 | 身 |
| 风象 | 双子/天秤/水瓶 | 木 | 行 |
| 水象 | 巨蟹/天蝎/双鱼 | 水 | 富 |
边界说明:西方占星无「金」元素,金(智)在星座层恒 0 贡献。智维度由八字金 + 灵数(3/7)覆盖,不影响整体平衡。星座数据来源:TianpanService.enrichMembers() 已通过 zodiacAnnualEnergyService.getWesternSign(month, day) 计算 westernSign。
无星座数据兜底:westernSign 为空时星座层全部 0 贡献。
灵数(生命数 lifePath,1-9)映射主维度,命中维度 +20 分:
| 灵数 | 人格特质 | 主维度 |
|---|---|---|
| 1 | 开创/独立/领导 | 行 |
| 2 | 合群/同理/协调 | 心 |
| 3 | 创意/表达 | 智 |
| 4 | 务实/规律/稳定 | 身 |
| 5 | 自由/冒险 | 行 |
| 6 | 关怀/责任/家庭 | 心 |
| 7 | 分析/策略/求知 | 智 |
| 8 | 商业/权力/物质 | 富 |
| 9 | 博爱/理想 | 心 |
灵数来源:现有 NumSoulCalculator.calcLifePath(year, month, day)(主数 11/22/33 保留)。TianpanMemberVO.lifeNumber 来自 behaviorModifier 中存储值,服务内做防御性化简:11→2、22→4、33→6(主数化简),其余 >9 值按 digit sum 递归化简至 1-9,null 则不命中。
无灵数数据兜底:无 birthDatetime 时灵数层全部 0 贡献。
输入:八字五行 {wood:40, fire:60, earth:50, metal:30, water:20}、星座狮子座(火象→心)、灵数 7(→智)
| 维度 | 八字×0.6 | 星座 | 灵数 | 基础分 |
|---|---|---|---|---|
| 身 body(土) | 50×0.6=30 | 0 | 0 | 30 |
| 智 wisdom(金) | 30×0.6=18 | 0 | 20 | 38 |
| 富 wealth(水) | 20×0.6=12 | 0 | 0 | 12 |
| 行 action(木) | 40×0.6=24 | 0 | 0 | 24 |
| 心 mind(火) | 60×0.6=36 | 20 | 0 | 56 |
FiveDimensionScoreService文件:cfc-backend/src/main/java/com/etotem/cfc/service/FiveDimensionScoreService.java
@Service
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
* @param operator 计算来源(system/manual)
*/
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) { ... }
}
private static final Map<String, String> ZODIAC_ELEMENT = ...;
// 白羊座/狮子座/射手座 -> FIRE
// 金牛座/处女座/摩羯座 -> EARTH
// 双子座/天秤座/水瓶座 -> AIR
// 巨蟹座/天蝎座/双鱼座 -> WATER
// 元素 -> 维度: FIRE->mind, EARTH->body, AIR->action, WATER->wealth
private static final Map<Integer, String> LIFE_NUMBER_DIM = ...;
// 1->action, 2->mind, 3->wisdom, 4->body, 5->action, 6->mind, 7->wisdom, 8->wealth, 9->mind
// 1. 初始化五维 map,八字层: 各维度 = (wuxing 对应五行值 ?? 50) × 0.6
// 2. 星座命中: elementToDim[westernSign元素] += 20
// 3. 灵数命中: numberToDim[reduceMaster(lifeNumber)] += 20 // 11->2, 22->4, 33->6, >9 digit sum
// 4. round 取整返回
单测:cfc-backend/src/test/java/com/etotem/cfc/unit/FiveDimensionScoreServiceTest.java
TianpanMemberVO 新增字段:
private Map<String, Integer> dimensionBaseScores; // 五维基础分 {body,mind,wisdom,action,wealth}
TianpanService.enrichMembers()(第 174 行附近):
m.getWuxingElements()、vo.getWesternSign()、m.getLifeNumber() 保持不变fiveDimensionScoreService.getScores(m.getMemberId())calcBaseScores(...))并立即落库zodiacName 填充(见 3.6)TianpanService.buildMemberDetail():经 enrichMembers 自动填充,无需额外改动。
依赖注入:TianpanService 增加 @Resource private FiveDimensionScoreService fiveDimensionScoreService;
新增 Controller 接口:
POST /api/tianpan/recalibrate — 手动触发单个成员重算
{memberId, memberType, operator: "admin"}dimensionBaseScoresPOST /api/tianpan/recalibrate-family — 批量重算全家(管理员用)
{familyId, operator: "admin"}管理端集成:在 Web 管理端家庭成员详情页新增「重新计算五维基础分」按钮,调用上述接口。
新增表 family_member_dimension_base_scores:
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 有数据则触发一次性重算写入)。
pages/tianpan/index.vue)drawMemberNodes()(第 375 行附近):
生肖·灵数(如 兔·7)member.zodiacName(生肖名)+ member.lifeNumbergetMemberColor(member.effectiveRole)注意:enrichMembers 目前只设置了 vo.setZodiac(m.getZodiac())(生肖代码,如 rat),未设置 zodiacName(生肖中文名)。前端弹窗/节点展示生肖名必须补齐:在 enrichMembers 中通过生肖代码映射中文名(映射表参考 ZodiacConfig/findZodiacName 逻辑,rat→鼠/ox→牛/...)并 vo.setZodiacName(...)。
pages/tianpan/index.vue member-popup)弹窗内容重构为两区块:
① 基本信息区(现有 + 扩展):
member.lifeNumber,显示 灵数 N)、八字四柱(member.eightCharacters:年/月/日/时柱横向四格排布,复用 FamilyTianpanCard 的 pillarLabels 样式)redactEightCharacters),前端直接渲染② 能量区(双条对比):
selectedMember.energy)selectedMember.dimensionBaseScores,用五维标准色,复用现有 .energy-bar 样式)pages/tianpan/traditional.vue入口:pages/tianpan/index.vue canvas 下方、tab 栏之前新增「家庭成员命理解读」入口卡片(样式参考现有 fortune-card)
页面结构(全家成员传统文化对比):
mapGetters('tianpan', ['members']) 数据(复用 dashboard 已加载数据,不重复请求)FamilyTianpanCard wuxingData 样式member.lifeNumber)+ 灵数称号(member.lifeNumberTitle)。完整的天赋数/生日数/命运数(NumSoulDetailVO)不随 dashboard 返回,如需完整版走 /api/tianpan/member/{id} 详情扩展(本迭代不做,列入 out of scope)页面注册:pages.json 的 pages/tianpan 分包新增 traditional
API 去重规范:本页复用 store tianpan/members(dashboard 已加载),禁止重复请求 /api/tianpan/dashboard;成员展开明细如需更多数据走 /api/tianpan/member/{id}(按需点击加载,遵守规则 4 不 N+1)
| 前端展示项 | 后端字段 | 现状 | 动作 |
|---|---|---|---|
| 生肖名 | zodiacName |
❌ enrichMembers 未设置(仅 zodiac 代码) |
补齐:代码→中文名映射 + setZodiacName |
| 星座 | westernSign |
✅ 已设置 | 无 |
| 灵数 | lifeNumber |
✅ 已设置 | 无 |
| 八字四柱 | eightCharacters |
✅ 已设置(含脱敏) | 无 |
| 五行 | wuxingElements |
✅ 已设置 | 无 |
| 五维基础分 | dimensionBaseScores |
❌ 新增 | 3.3 实现 |
| 灵数详情(天赋/生日/命运数) | numSoul | TianpanMemberVO 未含 |
传统页简化版仅展示 lifeNumber |
FiveDimensionScoreServiceTest:
node --check 提取的 script 块语法校验(按 cfc-frontend/AGENTS.md 规范,Agent 不打包)node scripts/audit-duplicate-api-calls.js 通过?.、无 CSS Grid、无 :key 表达式、无 new Date(string)cd cfc-backend && mvn clean compile
In scope:
family_member_dimension_base_scores 表 + 迁移 + 批量回填TianpanMemberVO 扩展(dimensionBaseScores)+ enrichMembers 填充(含 zodiacName 补齐)POST /api/tianpan/recalibrate / recalibrate-familypages/tianpan/traditional.vue + 入口卡片 + pages.json 注册Out of scope: