Procházet zdrojové kódy

docs: v20260604.3 提现机制+主题系统+术语统一+关系重构

liaoxg před 3 měsíci
rodič
revize
78343bfd5d
55 změnil soubory, kde provedl 4754 přidání a 746 odebrání
  1. 302 0
      .sisyphus/plans/dev-plan-v20260604.md
  2. 381 0
      .sisyphus/plans/epic10-dev-plan.md
  3. 46 28
      README.md
  4. 29 21
      client/App.vue
  5. 2 6
      client/components/ChartShareCanvas.vue
  6. 57 0
      client/components/ThemeToggle.vue
  7. 30 30
      client/components/TriangleChart.vue
  8. 24 0
      client/components/_numColors.js
  9. 18 12
      client/pages.json
  10. 11 9
      client/pages/admin/index.vue
  11. 396 0
      client/pages/analysis/index.vue
  12. 76 12
      client/pages/chart/index.vue
  13. 28 26
      client/pages/commission/index.vue
  14. 2 2
      client/pages/index/index.vue
  15. 3 1
      client/pages/login/index.vue
  16. 2 2
      client/pages/payment/index.vue
  17. 2 0
      client/pages/plan/apply.vue
  18. 110 20
      client/pages/profile/index.vue
  19. 2 0
      client/pages/records/index.vue
  20. 3 1
      client/pages/register/index.vue
  21. 333 0
      client/pages/relations/add-relation.vue
  22. 313 0
      client/pages/relations/chart-compare.vue
  23. 477 0
      client/pages/relations/index.vue
  24. 375 0
      client/pages/relations/number-analysis.vue
  25. 3 3
      client/pages/subscribe/index.vue
  26. 12 10
      client/pages/withdraw/index.vue
  27. binární
      client/static/analysis-active.png
  28. binární
      client/static/analysis.png
  29. binární
      client/static/relations-active.png
  30. binární
      client/static/relations.png
  31. 88 0
      client/stores/theme.js
  32. 219 0
      client/styles/theme.scss
  33. 26 35
      client/uni.scss
  34. 17 1
      client/utils/api.js
  35. 17 17
      docs/1.0产品对齐方案.md
  36. 42 42
      docs/dify-chatflow-prompt.md
  37. 6 6
      docs/executive-summary.md
  38. 25 25
      docs/knowledge-base-design.md
  39. 25 25
      docs/phase1-product-plan.md
  40. 239 188
      docs/phase1-user-stories.md
  41. 13 13
      docs/platform-value.md
  42. 9 9
      docs/presentation/comparison/index.html
  43. 26 26
      docs/presentation/index.html
  44. 105 12
      docs/requirements-changelog.md
  45. 123 76
      docs/style-guide.md
  46. 1 1
      docs/superpowers/plans/2026-05-26-admin-panel.md
  47. 2 2
      docs/superpowers/plans/2026-05-26-backend-springboot.md
  48. 6 6
      docs/superpowers/plans/2026-05-26-dify-workflow.md
  49. 14 14
      docs/superpowers/plans/2026-05-26-miniprogram-uniapp.md
  50. 5 5
      docs/superpowers/plans/2026-05-26-phase1-implementation-plan.md
  51. 1 1
      docs/superpowers/specs/2026-05-22-numerology-agent-design.md
  52. 20 20
      docs/superpowers/specs/2026-05-24-triangle-life-chart-miniprogram-design.md
  53. 27 27
      docs/system-spec.md
  54. 649 0
      docs/withdrawal-design.md
  55. 12 12
      docs/需求差异分析-客户1.0vs当前Phase1.md

+ 302 - 0
.sisyphus/plans/dev-plan-v20260604.md

@@ -0,0 +1,302 @@
+# 开发计划 v20260604
+
+**制定日期:** 2026-06-04
+**制定依据:** `docs/requirements-changelog.md` (v20260604.1 + v20260604.2) + `docs/test-coverage-report.md` + 当前代码审计
+**当前代码状态:** ⚠️ 测试编译失败(7处) + EPIC 10 后端大部分就绪 + 关系分析需重构
+
+---
+
+## 状态摘要
+
+| 维度 | 状态 |
+|------|------|
+| 后端编译 | ✅ 通过 |
+| 测试编译 | ❌ 7处失败(ChatService/OrderService 签名变更导致)|
+| 测试运行 | ⏳ 修复后需验证 |
+| v20260604.1 (EPIC 10 超级会员) 完成度 | ~60%(后端支付/佣金/升级就绪,前端支付模板就绪,订阅入口待补充) |
+| v20260604.2 (重命名+关系分析重设计) 完成度 | ~0%(代码未动)|
+
+---
+
+## PHASE 0:阻塞项修复(P0,1天)
+
+### 0.1 修复测试编译失败
+
+**问题:** 7处测试编译失败,原因:
+
+| 文件 | 位置 | 失败原因 |
+|------|------|---------|
+| `ControllerIntegrationTest.java` | L295 | `ChatService.sendMessage` 签名变更 — 新增 `String` 参数(chartRecordId/sessionId) |
+| `ControllerIntegrationTest.java` | L333 | `OrderService.createOrder` 签名变更 — 参数从 5→6 个(新增 isSeedPrice 等) |
+| `ChatServiceTest.java` | L53, L76, L90, L108, L130 | 同 sendMessage 签名变更 |
+
+**修复策略:** 为每个调用点补齐缺少的参数(`null` 占位或合理的默认值),确保编译通过后运行全量测试验证。
+
+**涉及文件:**
+- `num-server/src/test/java/.../controller/ControllerIntegrationTest.java`(2处)
+- `num-server/src/test/java/.../service/ChatServiceTest.java`(5处)
+
+**验收标准:** `mvn test` 编译通过,运行 `Tests run: N, Failures: 0`
+
+### 0.2 验证已知 Bug 修复
+
+| Bug | 状态 | 验证方式 |
+|-----|------|---------|
+| `upgradeVip` 不认 `"super_member"` productType | ✅ 已修复(0.1中添加别名) | 重启后端,annual→super_member 支付,检查 user.vipType = 'super_annual' |
+| `chart-compare` 页面未注册 pages.json | ✅ 已修复(0.2中注册) | 导航到 relations/chart-compare → 正常打开 |
+| `number-analysis` 页面未注册 pages.json | ✅ 已修复(0.2中注册) | 导航到 relations/number-analysis → 正常打开 |
+| `POST /api/profile/info` 缺 `isSeedPriceUser` 字段 | ⏳ 待验证 | 检查 ProfileController.getInfo 返回值 |
+
+---
+
+## PHASE 1:EPIC 10 超级会员收尾(P1,1-2天)
+
+### 1.1 超级会员订阅入口 × 3
+
+参考 US-10.1,需要在 3 处嵌入订阅入口:
+
+| 位置 | 状态 | 需要做的事 |
+|------|------|----------|
+| 关系页(未授权时) | ❌ 待实现 | `relations/index.vue` 顶部 Banner:`🔒 开通超级会员...` |
+| 我的页面(免费用户/年费用户) | ✅ 已实现 | 免费用户双方案卡片 + 年费用户"升超级"按钮已存在 |
+| AI 解读页(咨询结束后) | ❌ 待实现 | `chart/index.vue` 底部或右上角入口 |
+
+**文件:**
+- `client/pages/relations/index.vue`
+- `client/pages/chart/index.vue`
+
+### 1.2 超级会员升级→能量师补差价
+
+**当前状态:** `UserService.upgradeVip()` 的 `super_annual → practitioner` 路径已存在。但需要验证:
+- 佣金补差逻辑:`OrderService.handlePractitionerCommission()` 中的 `sumAnnualCommissionTo()` 已扩展到包含 `super_member` 订单的佣金
+- 前端入口:超级会员卡片上的"升级能量师"按钮已存在(`profile/index.vue` L97)
+
+**待验证项:** 升级定价前端是否正确调用了 `pricingApi.upgrade()` 并传 `productType: 'practitioner'`
+
+### 1.3 超级会员佣金
+
+**当前状态:** `OrderService.handleSuperMemberCommission()` 已实现,使用 `commission.super_member.direct_rate(3000)/upstream_rate(500)` 费率。
+
+**待验证:** 推广超级会员的佣金结算是否正确,佣金明细是否显示"超级会员直接推荐佣金"等备注。
+
+### 1.4 管理后台配置卡片
+
+**当前状态:** 管理后台是否存在超级会员定价+佣金配置卡片?
+
+**需检查:** `admin/src/views/settings/index.vue` — 确认是否已有超级会员定价(`pricing.super_member`)和超级会员佣金(`commission.super_member.*`)的配置卡片。
+
+---
+
+## PHASE 2:全代码库"命盘→能量盘"重命名(P1,1天)
+
+### 2.1 范围
+
+v20260604.2 要求将所有"命盘"改为"能量盘"(含 3 处"数字能量能量盘"→"数字能量盘")。文档部分(README, style-guide, system-spec 等)已在需求变更中更新,**但代码内仍包含大量"命盘"字样**。
+
+### 2.2 搜索范围
+
+| 层 | 搜索关键词 | 文件量 | 优先级 |
+|---|-----------|-------|-------|
+| 后端 Java | "命盘" 在注释/异常消息/字段描述 | ~15-20处 | 高(用户可见) |
+| 前端 Vue | "命盘" 在模板文本/变量名/注释 | ~30-40处 | 高(用户可见) |
+| 前端 utils | calculator.js 注释 | ~5处 | 低(仅参考) |
+| 测试文件 | "命盘" 在测试描述 | ~10处 | 低(内部) |
+
+### 2.3 注意
+
+- **变量名、数据库字段名、API 路径** — 不改(避免破坏性变更)
+- **用户可见文案** — 全改(Toast提示、页面标题、功能描述)
+- **注释/文档字符串** — 全改(保持一致性)
+- **3处特例**:"数字能量能量盘"→"数字能量盘"
+
+---
+
+## PHASE 3:关系能量分析重设计(P1-P2,3-4天)
+
+### 3.1 背景
+
+v20260604.2 彻底重设了关系能量分析流程:
+
+```
+旧: 添加关系人 → 双命盘对比(静态)→ AI 合盘解读(Workflow)
+新: 添加关系人 → 选择多人 → 提问 → AI 对话(Chatflow)→ 分析记录留存
+```
+
+### 3.2 数据库变更
+
+| 表 | 变更 | 说明 |
+|---|------|------|
+| `relations` | 移除 `compatibility_score`, `ai_analysis_cache`, `last_analyzed_at` | 旧字段废弃 |
+| `relation_analysis_records` | **新增** | 分析会话,含成员快照(JSON) |
+
+`relation_analysis_records` 表结构(参考 US-10.6):
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | Long PK | |
+| userId | Long | 创建者 |
+| title | String | 分析主题(自动生成 or 用户填写) |
+| member_snapshot | Text (JSON) | 参与成员快照(用户本人+选取的关系人,含姓名/生日/性别/关系类型)|
+| chat_session_id | String | Dify Chatflow 会话 ID |
+| status | String | active / archived |
+| create_time | LocalDateTime | |
+| update_time | LocalDateTime | |
+
+### 3.3 后端 API
+
+| 端点 | 方法 | 说明 |
+|------|------|------|
+| `POST /api/relation/analysis/start` | 新建分析会话 | 选关系人→创建会话→返回 session_id |
+| `POST /api/relation/analysis/list` | 历史记录 | |
+| `POST /api/relation/analysis/detail` | 单条详情 | |
+| `POST /api/relation/analysis/delete` | 删除记录 | |
+| `POST /api/relation/analysis/chatSend` | 发送消息 | 调用 Dify Chatflow |
+| `POST /api/relation/analysis/chatHistory` | 聊天历史 | |
+
+**注意:** 旧 API(`/api/relation/compare`, `relation/compare/interpret`)可保留或标记废弃。
+
+### 3.4 Dify 变更
+
+| 变更 | 说明 |
+|------|------|
+| Workflow → Chatflow | 关系分析从结构化输出改为自然语言对话 |
+| 新增 Chatflow | inputs: 成员快照(JSON) + 用户问题; 输出: AI 回答 |
+| sys_config 新增 | `dify.chatflow.relation_app_id`(Chatflow ID) |
+
+### 3.5 前端页面
+
+| 页面 | 说明 | 状态 |
+|------|------|------|
+| `relations/index.vue` | 关系首页:关系人列表 + 分析记录列表 + 新建分析入口 | ❌ 需重写 |
+| `relations/analysis-chat.vue`(新建)| 分析对话页:成员列表 + 对话区 + 输入框 | 🆕 新建 |
+| `relations/number-analysis.vue` | 八星号码分析(不受影响,保持原有设计) | ✅ 已存在 |
+
+### 3.6 现有资产复用
+
+| 资产 | 用途 |
+|------|------|
+| `TriangleChart.vue` | 对话中可嵌入展示每个成员的三角图(作为参考信息) |
+| `ChatService` / Dify Chatflow 集成 | 复用现有 AI 对话框架 |
+| `CalculatorService` | 成员能量盘数据由后端计算,前端直接渲染 |
+| `Relation` entity / repository | 关系人 CRUD 仍可用 |
+
+---
+
+## PHASE 4:测试质量改进(P2,2天)
+
+### 4.1 WxPayService 单元测试(P0 推荐)
+
+**优先级理由:** 支付是资金核心,且为当前完全未覆盖模块(189行,🔴风险)。
+
+**测试内容:**
+- `createUnifiedOrder`:参数组装、签名验证、Mock RestTemplate 响应
+- 异常路径:微信返回错误、网络超时
+- Mock 模式验证
+
+### 4.2 calculator.js 一致性验证
+
+**方案:** 取 N≥50 组生日,分别在前端(Node 环境运行 calculator.js)和后端(CalculatorService)计算,对比 24 位置结果。
+
+### 4.3 修复 @Disabled 测试
+
+| 位置 | 问题 |
+|------|------|
+| `CommissionServiceTest.testCommissionStatusFlow_pendingToSettled` | 状态流转断链 |
+| `CommissionServiceTest.testCommissionStatusFlow_settledToAvailable` | 自动流转未实现 |
+| `CalculatorServiceTest.testExternalPosition_Formulas_Documented` | 外部位置公式待验证 |
+| `CalculatorServiceTest.testExternalPosition_30PositionNaming` | 30位置命名待验证 |
+
+### 4.4 前端测试框架搭建(基建)
+
+搭建 vitest + @vue/test-utils,先覆盖核心模块:
+1. `stores/user.js` — Pinia store 测试
+2. `TriangleChart.vue` — 组件渲染测试
+
+---
+
+## PHASE 5:文档与收尾(P3,1天)
+
+### 5.1 更新测试报告
+
+```yaml
+生成日期: 2026-06-04
+后端单元测试: N 运行, 0 失败
+Playwright E2E: 3/3 通过
+测试编译: ✅ 通过
+新增测试: WxPayService, calculator.js 一致性
+```
+
+### 5.2 更新需求变更日志
+
+需追加 v20260604.3 版本(如果本次开发引入新的需求变更)。
+
+---
+
+## 执行顺序与依赖图
+
+```
+PHASE 0 (1天)
+ ┌─────────────────────────────┐
+ │ 0.1 修复测试编译             │ ← 无依赖
+ │ 0.2 验证已知 Bug             │ ← 重启后端后验证
+ └──────────┬──────────────────┘
+            │
+            ▼
+PHASE 1 (1-2天)      PHASE 2 (1天)
+ ┌──────────────┐   ┌────────────────┐
+ │ 1.1 订阅入口   │   │ 命盘→能量盘重命名│ ← 无依赖,可并行
+ │ 1.2 升级验证   │   └────────────────┘
+ │ 1.3 佣金验证   │
+ │ 1.4 管理后台   │
+ └──────┬───────┘
+        │
+        ▼
+PHASE 3 (3-4天)     ← 依赖 PHASE 2(命名一致性)
+ ┌─────────────────────────────┐
+ │ 3.2 DB: relation_analysis   │
+ │ 3.3 后端 API (6个)          │
+ │ 3.4 Dify Chatflow 迁移      │
+ │ 3.5 前端页面重写/新建        │
+ └─────────────────────────────┘
+
+PHASE 4 (2天)        ← 可与 PHASE 1-3 并行
+ ┌─────────────────────────────┐
+ │ 4.1 WxPayService 测试       │
+ │ 4.2 calculator.js 一致性    │
+ │ 4.3 修复 @Disabled 测试     │
+ │ 4.4 前端测试框架             │
+ └─────────────────────────────┘
+
+PHASE 5 (1天)
+ ┌─────────────────────────────┐
+ │ 5.1 更新测试报告             │
+ │ 5.2 更新变更日志             │
+ └─────────────────────────────┘
+```
+
+## 预估总工期
+
+| Phase | 估算 | 并行 |
+|-------|------|------|
+| PHASE 0 | 1天 | — |
+| PHASE 1 | 1-2天 | 与 Phase 2 并行 |
+| PHASE 2 | 1天 | 与 Phase 1 并行 |
+| PHASE 3 | 3-4天 | — |
+| PHASE 4 | 2天 | 与 Phase 1-3 并行 |
+| PHASE 5 | 1天 | 最后收尾 |
+| **合计** | **5-8天** | 含并行(1人全栈) |
+
+## 验收检查清单
+
+- [ ] `mvn test` 编译通过,183+ 测试运行通过
+- [ ] 超级会员可购买 ¥1,314/年并开通,vipType='super_annual'
+- [ ] C端年费→超级会员补差价升级(前后端完整链路)
+- [ ] 超级会员→能量师补差价升级含佣金补差
+- [ ] 3处超级会员订阅入口全部就绪
+- [ ] 所有用户可见"命盘"→"能量盘"(3处特例处理)
+- [ ] 关系分析:选择多人→提问→AI对话→分析记录完整链路
+- [ ] 关系分析记录可查看历史
+- [ ] WxPayService 单元测试通过
+- [ ] calculator.js 与后端计算结果一致(50+组生日验证)
+- [ ] 前端单元测试框架搭建完成
+- [ ] 测试报告更新并反映最新状态

+ 381 - 0
.sisyphus/plans/epic10-dev-plan.md

@@ -0,0 +1,381 @@
+# EPIC 10 开发计划:超级会员 + 关系能量分析 + 八星号码
+
+> 基于 `v20260604.1` 需求变更 | 当前代码状态评估日期:2026-06-04
+
+---
+
+## 状态摘要
+
+| 总工作量 | 后端原子任务 | 前端原子任务 | 预估工期 |
+|---------|------------|------------|---------|
+| 26 项 | 14 | 12 | 5-7 天(1人全栈) |
+
+---
+
+## 现有资产(无需重复开发)
+
+| 资产 | 说明 |
+|------|------|
+| **EightStarService** | 八星类型枚举 + 星对定义已完整实现,可直接复用 |
+| **CalculatorService** | 已含 `calculateMissingNumbers()` + `calculateTalentNumbers()`,可直接用于关系合盘 |
+| **DifyService** | 基础 `invokeWorkflow()` 已实现,新增关系/号码分析只需加新方法 |
+| **OrderService** | `createOrder()` + `paySuccess()` + `handleAnnualCommission()` 基础框架完整 |
+| **UserService.upgradeVip()** | VIP 升级框架已实现,可扩展 `super_annual` 类型 |
+| **Quota 框架** | UserService 中已存在配额读写逻辑 |
+| **CommerceService** | 接口 + Stub 已实现,Phase 2+ 才需接入 lilishop |
+| **三角图组件** | TriangleChart.vue 可直接用于双命盘对比展示 |
+
+---
+
+## Phase 1:基础设施 — 超级会员 DB + 配置(后端)
+
+### P1.1 Entity:User.vipType 增加 `super_annual`
+
+**文件**: `num-server/.../entity/User.java`
+- vipType 注释增加枚举值 `"super_annual"`
+- 实际字段类型不变(String),纯文档变更
+
+### P1.2 ConfigService:新增 3 个种子配置项
+
+**文件**: `num-server/.../service/ConfigService.java`
+- 在两个 `getAllSeeds()` 方法(init 和 reset)各加 3 项:
+
+| Key | Value | Type | 说明 |
+|-----|-------|------|------|
+| `pricing.super_member` | `131400` | price | 超级会员年费(分)¥1,314 |
+| `commission.super_member.direct_rate` | `3000` | percent | 超级会员直推佣金(千分比)30% |
+| `commission.super_member.upstream_rate` | `500` | percent | 超级会员上级佣金(千分比)5% |
+
+### P1.3 Entity:新建 Relation 实体
+
+**文件**: `num-server/.../entity/Relation.java`
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | Long (PK, auto) | |
+| userId | Long | 所属用户 ID(FK → user) |
+| relationType | String | 关系类型:spouse/亲子/colleague/friend/superior |
+| relationTypeLabel | String | 关系类型中文显示名 |
+| name | String | 关系人姓名(用户填写) |
+| birthDate | LocalDate | 关系人生日 |
+| birthDateText | String | 生日原文(YYYY-MM-DD) |
+| gender | Integer | 关系人性别 0/1/2 |
+| tags | String (JSON) | 自定义标签 |
+| note | String | 备注 |
+| createTime | LocalDateTime | |
+| updateTime | LocalDateTime | |
+
+### P1.4 Repository:新建 RelationRepository
+
+**文件**: `num-server/.../repository/RelationRepository.java`
+- `findByUserIdOrderByCreateTimeDesc(Long userId)`
+- `findByIdAndUserId(Long id, Long userId)`
+
+### P1.5 Entity:新建 NumberAnalysis 实体
+
+**文件**: `num-server/.../entity/NumberAnalysis.java`
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | Long (PK, auto) | |
+| userId | Long | 所属用户 ID(FK → user) |
+| phoneNumber | String | 被分析的手机号 |
+| starCombinations | Text (JSON) | 八星组合分析结果 |
+| summary | Text | 综合解读文字 |
+| createTime | LocalDateTime | |
+
+### P1.6 Repository:新建 NumberAnalysisRepository
+
+**文件**: `num-server/.../repository/NumberAnalysisRepository.java`
+- `findByUserIdOrderByCreateTimeDesc(Long userId)`
+- `findByPhoneNumberAndUserId(String phone, Long userId, Pageable page)`
+- `findTopByPhoneNumberAndUserIdOrderByCreateTimeDesc(String phone, Long userId)` — 查重
+
+---
+
+## Phase 2:超级会员业务逻辑(后端)
+
+### P2.1 OrderService:支持 `productType = "super_member"`
+
+**文件**: `num-server/.../service/OrderService.java`
+
+**变更**:
+1. `inferProductType()` — 增加 `superMemberFee` 价格判断
+2. `paySuccess()` — 增加 `"super_member".equals(productType)` 分支
+   - 调用 `userService.upgradeVip(buyerId, 365, "super_annual")`
+   - 调用 `handleSuperMemberCommission(order, buyer, inviter)`(同 handleAnnualCommission 逻辑,使用 super_member 费率)
+3. 新建 `handleSuperMemberCommission()` — 复制 handleAnnualCommission 模式,读取 `commission.super_member.direct_rate` / `upstream_rate`
+4. `sumAnnualCommissionTo()` — 扩展为同时统计 annual + super_annual 佣金
+
+### P2.2 UserService:upgradeVip 支持 `super_annual`
+
+**文件**: `num-server/.../service/UserService.java`
+- 确认 `upgradeVip()` 可将 vipType 设为 `"super_annual"`
+- 配额(quota)逻辑:超级会员自动获得全部功能配额(如 chart/chat/share/academic 不设限)
+
+### P2.3 权限校验中间件
+
+**文件**: 无新建,在现有 Controller 方法上加注解或手动校验
+- Relation/NemberAnalysis 接口:`@AuthRequired(vip = {"super_annual", "practitioner"})`
+- 让超级会员和能量师均可访问关系分析功能
+
+---
+
+## Phase 3:关系分析与八星号码接口(后端)
+
+### P3.1 RelationController
+
+**文件**: `num-server/.../controller/RelationController.java`
+
+| 端点 | 方法 | 说明 |
+|------|------|------|
+| `/api/relation/create` | POST | 添加关系人 |
+| `/api/relation/list` | POST | 关系人列表 |
+| `/api/relation/update` | POST | 编辑关系人 |
+| `/api/relation/delete` | POST | 删除关系人 |
+| `/api/relation/compare` | POST | 双命盘对比合盘(调用 CalculatorService 计算双方 24 位置) |
+| `/api/relation/compare/interpret` | POST | 发起 AI 合盘解读(调用 DifyService.invokeRelationWorkflow) |
+
+### P3.2 NumberAnalysisController
+
+**文件**: `num-server/.../controller/NumberAnalysisController.java`
+
+| 端点 | 方法 | 说明 |
+|------|------|------|
+| `/api/number-analysis/analyze` | POST | 分析手机号(调用 CalculatorService 解析号码 → EightStarService 匹配星对 → Dify AI 生成解读) |
+| `/api/number-analysis/list` | POST | 历史分析记录 |
+| `/api/number-analysis/detail` | POST | 单条记录详情 |
+
+### P3.3 DifyService:新增 2 个 Workflow 方法
+
+**文件**: `num-server/.../service/DifyService.java`
+
+1. `invokeRelationWorkflow(Map<String, Object> inputs, String userId)`
+   - POST `/v1/workflows/run`
+   - inputs 包含:user1 的 24 位置数据 + user2 的 24 位置数据 + 关系类型
+   - 返回合盘解读 JSON
+
+2. `invokeNumberAnalysisWorkflow(Map<String, Object> inputs, String userId)`
+   - POST `/v1/workflows/run`
+   - inputs 包含:手机号 + 分解后的八星组合列表
+   - 返回号码能量解读 JSON
+
+### P3.4 管理后台:超级会员佣金配置卡片
+
+**文件**: `client/pages/admin/index.vue`
+- 在现有系统配置卡片列表中增加「超级会员佣金配置」卡片
+- 包含 3 个配置项:super_member 定价、直推佣金率、上级佣金率
+
+---
+
+## Phase 4:前端 — TabBar 改造 + 关系页面
+
+### P4.1 TabBar 改造(US-10.5)
+
+**文件**: `client/pages.json`
+
+**原 3 项**:
+| 记录 → 分析 | 我的 → 我的 | 首页 → 首页 |
+
+**新 4 项**:
+| 首页 | 关系 | 分析 | 我的 |
+|------|------|------|------|
+| pages/index/index | **pages/relations/index** | pages/analysis/index | pages/profile/index |
+
+> **记→分析**:原有「记录」页签改名为「分析」,路径不变或迁移到 pages/analysis/index
+> **分析页内容**:合并历史咨询记录入口 + AI 解读入口 + 号码分析入口(超级会员可见)
+
+**注意**:
+- 条件编译处理微信小程序 tabBar 限制(最多 5 项,没问题)
+- 关系页签未授权时显示锁图标 + 引导订阅(需确保编译后非超级会员可见入口但可引导升级)
+- 需要在 stores/user.js 中暴露 `hasSuperMember` 或 `isVip` 计算属性
+
+### P4.2 分析页改造
+
+**文件**: `client/pages/analysis/index.vue`(新建或改造自 records/index.vue)
+
+布局:
+```
+┌─────────────────────────┐
+│   分析 (Analysis Hub)    │
+├─────────────────────────┤
+│  📋 咨询记录             │ ← 原有 records 列表
+│                          │
+│  ── 超级会员专属 ──      │ ← 非超级会员显示锁图标
+│  🔗 关系能量分析          │ → relations/index
+│  📱 八星号码分析          │ → number-analysis/index
+└─────────────────────────┘
+```
+
+### P4.3 关系页面 → relations/index.vue
+
+**文件**: `client/pages/relations/index.vue`
+
+布局:
+```
+┌─────────────────────────┐
+│  关系能量分析             │
+├─────────────────────────┤
+│  ┌─── 添加关系人 ──┐    │ → add-relation.vue
+│  │ 选择类型+输入生日 │    │
+│  └─────────────────┘    │
+│                          │
+│  我的关系人               │
+│  ┌── spouse ──┐         │ → chart-compare.vue
+│  │ 张三 1990-01-15 │    │
+│  └─────────────┘         │
+│  ┌── col1eague ─┐        │
+│  │ 李四 1988-06-20 │    │
+│  └─────────────┘         │
+└─────────────────────────┘
+```
+
+### P4.4 添加关系人 → relations/add-relation.vue
+
+**文件**: `client/pages/relations/add-relation.vue`
+
+表单字段:
+- 关系类型:下拉选择(夫妻/亲子/同事/朋友/上下级)
+- 姓名(选填,仅用于显示)
+- 生日:日期选择器(同首页风格)
+- 性别:单选
+- 备注(选填)
+
+### P4.5 双命盘对比 → relations/chart-compare.vue
+
+**文件**: `client/pages/relations/chart-compare.vue`
+
+布局:
+```
+┌─────────────────────────┐
+│   ← 关系能量对比         │
+├─────────────────────────┤
+│  用户命盘     vs  关系人命盘│
+│  ┌──────┐      ┌──────┐ │
+│  │三角图│      │三角图│ │
+│  └──────┘      └──────┘ │
+│                          │
+│  合盘分析(差异/相似)    │
+│  ┌─ 数字能量互补 ──┐    │
+│  │ 某星在某位置匹配... │    │
+│  ├─ AI 合盘解读 ──┤    │
+│  │ 点击 → Dify 生成... │    │
+│  └─────────────────┘    │
+└─────────────────────────┘
+```
+
+### P4.6 八星号码分析 → relations/number-analysis.vue
+
+**文件**: `client/pages/relations/number-analysis.vue`
+
+布局:
+```
+┌─────────────────────────┐
+│  八星号码能量分析         │
+├─────────────────────────┤
+│  [输入手机号] [分析按钮] │
+│                          │
+│  分析结果                 │
+│  号码: 138xxxx1234       │
+│  天医: 13 (一级+)        │
+│  延年: 34 (三级-)        │
+│  绝命: 12 (二级)          │
+│  ...                     │
+│                          │
+│  [AI 深度解读]           │
+└─────────────────────────┘
+```
+
+### P4.7 超级会员订阅入口 × 3
+
+**1. 关系页(未授权时)** — relations/index.vue
+- 页面顶部大 Banner:`🔒 开通超级会员,解锁关系能量分析 ¥1,314/年`
+
+**2. 我的页面** — pages/profile/index.vue
+- 增加「超级会员」卡片(类似现有订阅卡片样式)
+
+**3. AI 解读页** — pages/chart/index.vue(咨询结束后右上角或底部)
+- 小入口:「关系能量分析(超级会员)」
+
+---
+
+## Phase 5:Dify Workflow 配置(平台配置)
+
+### P5.1 Dify Workflow:关系合盘解读
+
+**配置项**:
+- 在 Dify 平台创建新 Workflow
+- inputs:`user1_name, user2_name, relation_type, user1_positions (JSON), user2_positions (JSON)`
+- 提示词:要求输出双方命盘的数字能量互补、冲突、关系建议
+- knowledge:引用数字能量学知识库(现有)
+- sys_config key:`dify.workflow.relation_app_id`(新增配置项)
+
+### P5.2 Dify Workflow:八星号码解读
+
+**配置项**:
+- 在 Dify 平台创建新 Workflow
+- inputs:`phone_number, star_combinations (JSON)`
+- 提示词:要求输出号码总体能量、各星对含义、是否适合使用
+- sys_config key:`dify.workflow.number_analysis_app_id`(新增配置项)
+
+### P5.3 ConfigService 添加 2 个 Dify App ID 配置
+
+**文件**: `num-server/.../service/ConfigService.java`
+- `dify.workflow.relation_app_id` — string,默认 ""
+- `dify.workflow.number_analysis_app_id` — string,默认 ""
+
+---
+
+## 依赖与并行度
+
+```
+Phase 1 (基础设施)    Phase 2 (业务逻辑)     Phase 3 (接口)        Phase 4 (前端)
+──────────────────  ──────────────────  ──────────────────  ──────────────────
+P1.1 User.vipType                                                      
+     │                                                                 
+P1.2 ConfigService 3项                                                 
+     │                                                                 
+P1.3 Relation Entity → P2.1 OrderService → P3.1 RelationController → P4.3~P4.5 关系页面
+P1.4 RelationRepo      │                                               
+     │                  │                                              
+P1.5 NumberAnalysis → P2.2 UserService → P3.2 NumberAnalysisCtl → P4.6 号码页面
+P1.6 NumberAnalysisRepo  │            │                                
+     │                   │            │                                
+P2.3 权限校验┘───────────┘            │                                
+                                      │                                
+P3.3 DifyService 2个方法──────────────┘    → 依赖 Dify 平台创建
+                                           → 依赖 Frontend 页面展示
+P3.4 管理后台卡片 ────────────────────────── P4.x 前端可并行
+P4.1 TabBar + P4.2 分析页 ───── 可独立并行
+P4.7 订阅入口 × 3 ──────────── 依赖 Phase 2 支付能力,可并行于 P2.1 后
+```
+
+## 推荐执行顺序(基于依赖)
+
+```
+Week 1:
+  Mon-Tue:  P1.1+P1.2+P1.3+P1.4+P1.5+P1.6  (基础设施, 可全并行)
+  Tue-Wed:  P2.1+P2.2+P2.3                 (后端业务逻辑)
+  Wed-Thu:  P3.1+P3.2+P3.3                  (后端API, 可全并行)
+  Thu:      P4.1+P4.2                       (TabBar+分析页, 可并行)
+  
+Week 2:
+  Fri:      P4.3+P4.4+P4.5+P4.6             (前端页面, 可全并行)
+  Fri-Sat:  P3.4+P4.7+P5.1+P5.2+P5.3       (管理后台+Dify配置, 可并行)
+  Sat-Sun:  联调 + Bugfix + 验收
+```
+
+## 验收检查清单
+
+- [ ] 超级会员可购买 ¥1,314/年并开通
+- [ ] C端年费→超级会员可补差价升级
+- [ ] 超级会员→能量师可补差价升级+佣金补差
+- [ ] 超级会员推荐年费获30%佣金+5%上级佣金
+- [ ] TabBar 显示 首页·关系·分析·我的
+- [ ] 关系页超级会员专属,未授权显示引导
+- [ ] 添加关系人表单可用
+- [ ] 双命盘对比图渲染正确
+- [ ] AI 合盘解读可用
+- [ ] 手机号号码能量分析可用(本地八星匹配+AI解读)
+- [ ] 管理后台可配置超级会员价格和佣金
+- [ ] Dify 2个新Workflow可正确调用

+ 46 - 28
README.md

@@ -1,6 +1,6 @@
 # 数字能量学智能体(Digital Energy Numerology Agent)
 
-基于数字能量学理论的 AI 分析与咨询系统。结合数字能量学知识库与 LLM 能力,提供数字命理分析、AI 解读、分销推广等服务。
+基于数字能量学理论的 AI 分析与咨询系统。结合数字能量学知识库与 LLM 能力,提供数字能量盘分析、AI 解读、分销推广、关系能量分析等服务。
 
 ## 技术栈
 
@@ -9,7 +9,7 @@
 | **前端** | uni-app (Vue 3 + Pinia + SCSS), 微信小程序 |
 | **注册** | 微信一键登录 + 生日性别等资料完善 |
 | **后端** | Spring Boot 2.7.18 + JPA + Redis |
-| **AI** | Dify Workflow(盘解读)+ Dify Chatflow(AI问答)+ 知识库(RAG) |
+| **AI** | Dify Workflow(能量盘解读)+ Dify Chatflow(AI问答)+ 知识库(RAG) |
 | **支付** | 微信支付 |
 | **构建** | Maven |
 
@@ -22,38 +22,43 @@ num/
 │   │   └── TriangleChart.vue  # 数字能量三角图组件
 │   ├── pages/
 │   │   ├── index/index.vue    # 首页(生日输入 → 发起咨询)
-│   │   ├── chart/index.vue    # 盘展示 + AI 问答
+│   │   ├── chart/index.vue    # 能量盘展示 + AI 问答
 │   │   ├── records/index.vue  # 历史咨询记录
 │   │   ├── login/index.vue    # 微信登录
 │   │   ├── register/index.vue # 注册资料完善(生日/性别/社交资料)
 │   │   ├── payment/index.vue  # 支付
 │   │   ├── profile/index.vue  # 个人中心
 │   │   ├── subscribe/index.vue # 订阅
+│   │   ├── my-charts/index.vue # 我的能量盘列表
 │   │   └── relations/          # 🔗 关系能量分析(超级会员专属)
-│   │       ├── index.vue       # 关系首页(分类入口+关系人列表
+│   │       ├── index.vue       # 关系首页(用户能量盘+关系人列表+分析记录
 │   │       ├── add-relation.vue # 添加关系人
-│   │       ├── chart-compare.vue # 双命盘对比
+│   │       ├── analysis-select.vue # 多人分析选择(选人+提问)
+│   │       ├── analysis-chat.vue   # 关系分析 AI 对话
+│   │       ├── analysis-records.vue # 分析记录列表
 │   │       └── number-analysis.vue # 八星号码分析
 │   ├── stores/
-│   │   ├── chart.js           # 盘状态管理
+│   │   ├── chart.js           # 能量盘状态管理
 │   │   └── user.js            # 用户状态管理
 │   └── utils/
 │       ├── api.js             # 后端 API 封装
-│       └── calculator.js      # 盘计算(已移至后端)
+│       └── calculator.js      # 能量盘计算(已移至后端)
 ├── num-server/                # Java 后端 (Spring Boot)
 │   └── src/main/java/com/etotem/num/
-│       ├── controller/        # REST 控制器
-│       │   ├── ChartController.java    # 命盘 CRUD + 咨询发起
-│       │   ├── ChatController.java     # AI 问答
-│       │   ├── AuthController.java     # 微信登录
-│       │   ├── PayController.java      # 微信支付
-│       │   ├── ProfileController.java  # 用户信息
-│       │   ├── CommissionController.java # 佣金
-│       │   ├── AdminController.java    # 管理后台
-│       │   └── ...
+│   ├── controller/        # REST 控制器
+│   │   ├── ChartController.java        # 能量盘 CRUD + 咨询发起
+│   │   ├── ChatController.java         # AI 问答
+│   │   ├── AuthController.java         # 微信登录
+│   │   ├── PayController.java          # 微信支付
+│   │   ├── ProfileController.java      # 用户信息+个人统计
+│   │   ├── CommissionController.java   # 佣金
+│   │   ├── AdminController.java        # 管理后台
+│   │   ├── RelationController.java     # 关系人 CRUD
+│   │   ├── RelationAnalysisController.java # 关系分析会话+AI对话
+│   │   └── ...
 │   ├── service/
-│   │   ├── CalculatorService.java  # 命盘计算引擎
+│   │   ├── CalculatorService.java  # 能量盘计算引擎
 │   │   ├── ChartService.java       # 咨询会话管理
 │   │   ├── ChatService.java        # AI 问答 + 配额控制
 │   │   ├── UserService.java        # 用户/登录/配额
@@ -124,22 +129,25 @@ npm install
 
 | 模块 | 说明 | 状态 |
 |------|------|------|
-| **命盘生成** | 输入生日,后台计算 24 个数字位置(三角命盘) | ✅ 已完成 |
-| **AI 解读** | LLM 自动生成盘解读,支持追问互动 | ✅ 已完成 |
+| **能量盘生成** | 输入姓名+生日,后台计算 24 个数字位置(三角能量盘) | ✅ 已完成 |
+| **AI 解读** | LLM 自动生成能量盘解读,支持追问互动 | ✅ 已完成 |
 | **付费订阅** | 能量师年费 ¥1,314/¥1,986,C端年费 ¥131,超级会员 ¥1,314 | ✅ 已完成 |
-| **注册完善** | 微信登录 → 选昵称头像 + 填生日性别 + 社交资料 | ✅ 已完成 |
+| **注册完善** | 微信登录 → 选昵称头像 + 填姓名生日性别 + 社交资料 | ✅ 已完成 |
 | **分销推广** | 推广码 + 上下级绑定 + 两级佣金(固定/比例) | ✅ 已完成 |
+| **我的能量盘** | 自动匹配用户注册姓名+生日,展示个人能量盘记录 | 🚧 Phase 1 |
+| **个人中心统计** | 按角色展示咨询/推广/收入等统计数据卡片 | 🚧 Phase 1 |
 | **分销面板** | 佣金统计、团队数据、推广码展示 | 🚧 Phase 1 |
-| **管理后台** | 系统配置、订单管理、佣金查看 | 🚧 Phase 1 |
+| **管理后台** | 系统配置(含关系类型动态管理)、订单管理、佣金查看 | 🚧 Phase 1 |
 | **C端分销** | C 端用户推广 C 端年费,40%+5% 分成 | 🚧 Phase 1 |
 | **学业方向AI** | 家长为孩子选学业方向,AI深度解读天赋倾向 | 🚧 EPIC 9 |
 | **人工方案** | 申请能量师出方案 + 价格协商 + 在线支付 | 🚧 EPIC 9 |
-| **🔗 关系能量分析** | 夫妻/亲子/同事/朋友/上下级命盘对比 + 八星号码分析(超级会员专属) | 🚧 EPIC 10 |
-| **超级会员** | ¥1,314/年,含关系能量分析+分销权限 | 🚧 EPIC 10 |
+| **🔗 关系能量分析** | 超级会员添加关系人,多人选择+提问+AI对话分析,含分析记录(9类关系:夫妻/父母/子女/祖父母/孙子女/同事/朋友/上级/下级) | 🚧 EPIC 10 |
+| **八星号码分析** | 手机号/车牌号数字能量分布分析(超级会员专属) | 🚧 EPIC 10 |
+| **超级会员** | ¥1,314/年,含关系能量分析+八星号码+分销权限 | 🚧 EPIC 10 |
 | **提现管理** | 佣金提现功能 | 📅 Phase 2 |
 | **lilishop商城** | B2B2C电商底座,预留接口,暂不实现支付 | 📅 Phase 2+ |
 
-## 盘位置命名
+## 能量盘位置命名
 
 项目采用 **A-X** 24 位置命名体系:
 
@@ -156,24 +164,34 @@ npm install
 | 端点 | 方法 | 说明 |
 |------|------|------|
 | `/api/auth/login` | POST | 微信登录/注册 |
-| `/api/consultation/start` | POST | 发起咨询(查重) |
-| `/api/chart/create` | POST | 创建盘记录 |
+| `/api/consultation/start` | POST | 发起咨询(按 userId+name+birthday 查重) |
+| `/api/chart/create` | POST | 创建能量盘记录 |
 | `/api/chart/list` | POST | 咨询历史列表 |
 | `/api/chart/detail` | POST | 咨询详情 |
 | `/api/chat/send` | POST | AI 问答 |
 | `/api/chat/history` | POST | 聊天历史 |
 | `/api/pay/create` | POST | 创建支付订单 |
 | `/api/profile/quota` | POST | 查询当日配额 |
+| `/api/profile/stats` | POST | 获取个人统计数据(按角色) |
 | `/api/commission/list` | POST | 佣金明细 |
 | `/api/admin/config/list` | POST | 系统配置列表 |
 | `/api/admin/config/update` | POST | 更新系统配置 |
+| `/api/relation/create` | POST | 添加关系人 |
+| `/api/relation/list` | POST | 关系人列表(支持 type 筛选) |
+| `/api/relation/update` | POST | 修改关系人备注/类型 |
+| `/api/relation/delete` | POST | 删除关系人 |
+| `/api/relation/analysis/start` | POST | 发起关系分析(选人+提问,创建分析会话) |
+| `/api/relation/analysis/list` | POST | 分析记录列表 |
+| `/api/relation/analysis/delete` | POST | 删除分析记录 |
+| `/api/relation/analysis/chat/send` | POST | 关系分析 AI 对话 |
+| `/api/relation/analysis/chat/history` | POST | 分析对话历史 |
 
 ## 定价方案
 
 | 角色 | 种子价 | 标准价 | 权益 |
 |------|--------|--------|------|
-| 能量师 | ¥1,314(创始人码+有效期+名额) | ¥1,986 | 完整命盘+AI解读+客户管理+分销推广 |
-| **超级会员** | **—(固定价)** | **¥1,314/年** | **完整AI+关系能量分析+八星号码+分销推广** |
+| 能量师 | ¥1,314(创始人码+有效期+名额) | ¥1,986 | 完整能量盘+AI解读+客户管理+分销推广 |
+| **超级会员** | **—(固定价)** | **¥1,314/年** | **完整AI+关系能量分析(多人选择+AI对话)+八星号码+分销推广** |
 | C端会员 | — | ¥131/年 | AI互动问答+分销权限 |
 
 ## 文档索引

+ 29 - 21
client/App.vue

@@ -1,26 +1,34 @@
 <template>
-  <view class="app-container">
-    <slot />
-  </view>
-</template>
+ <view class="app-container" :data-theme="themeStore.theme">
+ <slot />
+ </view>
+ </template>
 
-<script setup>
-import { onLaunch } from '@dcloudio/uni-app'
-import { useUserStore } from '@/stores/user'
+ <script setup>
+ import { onLaunch } from '@dcloudio/uni-app'
+ import { useUserStore } from '@/stores/user'
+ import { useThemeStore } from '@/stores/theme'
 
-const userStore = useUserStore()
+ const userStore = useUserStore()
+ const themeStore = useThemeStore()
 
-onLaunch(() => {
-  if (userStore.isLoggedIn) {
-    userStore.fetchProfile().catch(() => {})
-  }
-})
-</script>
+ onLaunch(() => {
+ // Initialize theme first (before anything renders)
+ themeStore.init()
 
-<style>
-.app-container {
-  min-height: 100vh;
-  background: #0c0a1a;
-  color: #ffffff;
-}
-</style>
+ // Fetch user profile if logged in
+ if (userStore.isLoggedIn) {
+ userStore.fetchProfile().catch(() => {})
+ }
+ })
+ </script>
+
+ <style>
+ .app-container {
+ min-height: 100vh;
+ /* Use CSS variables for theme-aware backgrounds */
+ background: var(--color-bg);
+ color: var(--color-text-primary);
+ transition: background var(--transition-normal), color var(--transition-normal);
+ }
+ </style>

+ 2 - 6
client/components/ChartShareCanvas.vue

@@ -6,6 +6,7 @@
 
 <script setup>
 import { ref, onMounted, watch } from 'vue'
+import { getNumColorFromTheme } from './_numColors.js'
 
 const props = defineProps({
   chart: { type: Object, required: true },
@@ -18,11 +19,6 @@ const canvasHeight = 800
 
 const emit = defineEmits(['ready'])
 
-function getNumColor(num) {
-  const colors = { 1: '#D94A4A', 2: '#4A90D9', 3: '#E8A238', 4: '#2D8B67', 5: '#D4A017', 6: '#7B6FA0', 7: '#4A6FA5', 8: '#C9A84C', 9: '#B85C3A' }
-  return colors[num] || '#FFFFFF'
-}
-
 function isMasterNum(num) {
   return num === 11 || num === 22 || num === 33
 }
@@ -147,7 +143,7 @@ function drawChart() {
       ctx.setFontSize(32)
       ctx.setTextAlign('center')
       const footerY = h - 80
-      const displayName = props.name || '数字能量盘'
+      const displayName = props.name || '数字能量盘'
       ctx.fillText(displayName, cx, footerY)
       ctx.setFontSize(24)
       ctx.setFillStyle('#D1D5DB')

+ 57 - 0
client/components/ThemeToggle.vue

@@ -0,0 +1,57 @@
+<template>
+ <view class="theme-switcher">
+ <text
+ class="theme-btn"
+ :class="{ active: isDark }"
+ @click="setDark"
+ >深色</text>
+ <text
+ class="theme-btn"
+ :class="{ active: !isDark }"
+ @click="setLight"
+ >浅色</text>
+ </view>
+ </template>
+
+ <script setup>
+ import { computed } from 'vue'
+ import { useThemeStore } from '@/stores/theme'
+
+ const themeStore = useThemeStore()
+
+ const isDark = computed(() => themeStore.theme === 'dark')
+
+ function setDark() {
+ themeStore.setTheme('dark')
+ }
+
+ function setLight() {
+ themeStore.setTheme('light')
+ }
+ </script>
+
+ <style>
+ .theme-switcher {
+ display: inline-flex;
+ align-items: center;
+ background: rgba(255, 255, 255, 0.12);
+ border-radius: 8px;
+ padding: 2px;
+ gap: 2px;
+ }
+
+ .theme-btn {
+ font-size: 12px;
+ padding: 4px 12px;
+ border-radius: 6px;
+ color: rgba(255, 255, 255, 0.7);
+ transition: all 0.2s ease;
+ line-height: 1.4;
+ }
+
+ .theme-btn.active {
+ background: rgba(255, 255, 255, 0.95);
+ color: #1A1A2E;
+ font-weight: 600;
+ }
+ </style>

+ 30 - 30
client/components/TriangleChart.vue

@@ -215,13 +215,13 @@
 
 <script>
 const NUM_COLORS = {
-  1: '#D94A4A', 2: '#4A90D9', 3: '#E8A238',
-  4: '#2D8B67', 5: '#D4A017', 6: '#7B6FA0',
-  7: '#4A6FA5', 8: '#C9A84C', 9: '#B85C3A'
+  1: 'var(--num-1)', 2: 'var(--num-2)', 3: 'var(--num-3)',
+  4: 'var(--num-4)', 5: 'var(--num-5)', 6: 'var(--num-6)',
+  7: 'var(--num-7)', 8: 'var(--num-8)', 9: 'var(--num-9)'
 }
 
 const POSITION_INFO = {
-  O: { label: '主性格', zone: 'main',  trait: '核心人格特质', desc: '代表你的核心性格、人生方向和主要能量特征,是整个盘的中心。' },
+  O: { label: '主性格', zone: 'main',  trait: '核心人格特质', desc: '代表你的核心性格、人生方向和主要能量特征,是整个能量盘的中心。' },
   M: { label: '青年综合数', zone: 'left',  trait: '青年期自身力量的呈现', desc: '由月能量与日能量结合而成,代表青年期的内在动力与外在表现。' },
   N: { label: '晚年综合数', zone: 'right', trait: '晚年期自身力量的呈现', desc: '由年前位与年后位结合而成,代表晚年的人生经验积累与智慧沉淀。' },
   I: { label: '日能量', zone: 'left',  trait: '出生日能量', desc: '代表你出生当天的能量特质,影响你的日常行为和表达方式。' },
@@ -431,7 +431,7 @@ export default {
   width: 55%;
   height: 85%;
   clip-path: polygon(0% 100%, 15% 0%, 100% 100%);
-  background: linear-gradient(135deg, #f59e0b, #fbbf24);
+  background: linear-gradient(135deg, #f59e0b, var(--color-gold));
 }
 .zone-right-bg {
   right: 0;
@@ -478,28 +478,28 @@ export default {
   transform: translateX(-50%);
   width: 1rpx;
   background: linear-gradient(180deg,
-    rgba(255, 255, 255, 0.06) 0%,
-    rgba(255, 255, 255, 0.10) 15%,
-    rgba(255, 255, 255, 0.10) 85%,
-    rgba(255, 255, 255, 0.04) 100%
+    var(--color-bg-card) 0%,
+    rgba(255,255,255,0.1) 15%,
+    rgba(255,255,255,0.1) 85%,
+    var(--color-bg-tag) 100%
   );
   pointer-events: none;
   z-index: 1;
 }
 
-.num-color-1 { color: #D94A4A !important; }
-.num-color-2 { color: #4A90D9 !important; }
-.num-color-3 { color: #E8A238 !important; }
-.num-color-4 { color: #2D8B67 !important; }
-.num-color-5 { color: #D4A017 !important; }
-.num-color-6 { color: #7B6FA0 !important; }
-.num-color-7 { color: #4A6FA5 !important; }
-.num-color-8 { color: #C9A84C !important; }
-.num-color-9 { color: #B85C3A !important; }
+.num-color-1 { color: var(--num-1) !important; }
+.num-color-2 { color: var(--num-2) !important; }
+.num-color-3 { color: var(--num-3) !important; }
+.num-color-4 { color: var(--num-4) !important; }
+.num-color-5 { color: var(--num-5) !important; }
+.num-color-6 { color: var(--num-6) !important; }
+.num-color-7 { color: var(--num-7) !important; }
+.num-color-8 { color: var(--num-8) !important; }
+.num-color-9 { color: var(--num-9) !important; }
 
 .master-star {
   font-size: 28rpx;
-  color: #fbbf24;
+  color: var(--color-gold);
   text-shadow: 0 0 16rpx rgba(251, 191, 36, 0.8);
   display: inline-block;
   margin-left: 4rpx;
@@ -507,7 +507,7 @@ export default {
 }
 .master-star-sm {
   font-size: 20rpx;
-  color: #fbbf24;
+  color: var(--color-gold);
   text-shadow: 0 0 12rpx rgba(251, 191, 36, 0.6);
   display: inline-block;
   margin-left: 2rpx;
@@ -525,7 +525,7 @@ export default {
   right: 44rpx;
   bottom: 10rpx;
   clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
-  background: linear-gradient(135deg, rgba(255, 200, 50, 0.2), rgba(255, 100, 200, 0.15));
+  background: linear-gradient(135deg, var(--color-gold-bg), rgba(255, 100, 200, 0.15));
   filter: blur(20rpx);
 }
 
@@ -536,7 +536,7 @@ export default {
   right: 48rpx;
   bottom: 14rpx;
   clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
-  background: linear-gradient(165deg, #fbbf24 0%, #f59e0b 30%, #d97706 60%, #b45309 100%);
+  background: linear-gradient(165deg, var(--color-gold) 0%, #f59e0b 30%, #d97706 60%, #b45309 100%);
   padding: 3rpx;
   box-sizing: border-box;
 }
@@ -617,7 +617,7 @@ export default {
 .cell-main {
   font-size: 64rpx;
   font-weight: 700;
-  color: #fbbf24;
+  color: var(--color-gold);
   text-shadow: 0 0 24rpx rgba(251, 191, 36, 0.5), 0 0 80rpx rgba(251, 191, 36, 0.2);
   letter-spacing: 2rpx;
 }
@@ -665,7 +665,7 @@ export default {
   color: rgba(255, 255, 255, 0.75);
 }
 .top-tri { top: -58rpx; left: 50%; transform: translateX(-50%); position: absolute; }
-.top-tri .tri-main { font-size: 52rpx; color: #fbbf24; text-shadow: 0 0 28rpx rgba(251, 191, 36, 0.4); }
+.top-tri .tri-main { font-size: 52rpx; color: var(--color-gold); text-shadow: 0 0 28rpx rgba(251, 191, 36, 0.4); }
 .left-tri { top: 28%; left: 58rpx; position: absolute; }
 .right-tri { top: 28%; right: 58rpx; position: absolute; }
 .top-tri .tri-subs { position: relative; }
@@ -743,14 +743,14 @@ export default {
 .detail-num { font-size: 80rpx; font-weight: 700; text-align: center; text-shadow: 0 0 30rpx currentColor; margin-bottom: 8rpx; }
 .detail-name { font-size: 30rpx; font-weight: 600; color: #ffffff; text-align: center; margin-bottom: 16rpx; }
 .detail-zone-tag { display: inline-block; font-size: 20rpx; padding: 4rpx 16rpx; border-radius: 20rpx; text-align: center; margin: 0 auto 20rpx; width: fit-content; }
-.tag-main { background: rgba(251, 191, 36, 0.15); color: #fbbf24; border: 1rpx solid rgba(251, 191, 36, 0.2); }
-.tag-left { background: rgba(245, 158, 11, 0.15); color: #fbbf24; border: 1rpx solid rgba(245, 158, 11, 0.2); }
-.tag-right { background: rgba(74, 144, 217, 0.15); color: #4A90D9; border: 1rpx solid rgba(74, 144, 217, 0.2); }
-.tag-father { background: rgba(74, 144, 217, 0.15); color: #4A90D9; border: 1rpx solid rgba(74, 144, 217, 0.2); }
-.tag-mother { background: rgba(123, 111, 160, 0.15); color: #7B6FA0; border: 1rpx solid rgba(123, 111, 160, 0.2); }
+.tag-main { background: rgba(251, 191, 36, 0.15); color: var(--color-gold); border: 1rpx solid rgba(251, 191, 36, 0.2); }
+.tag-left { background: rgba(245, 158, 11, 0.15); color: var(--color-gold); border: 1rpx solid rgba(245, 158, 11, 0.2); }
+.tag-right { background: var(--color-info-bg); color: var(--num-2); border: 1rpx solid rgba(74, 144, 217, 0.2); }
+.tag-father { background: var(--color-info-bg); color: var(--num-2); border: 1rpx solid rgba(74, 144, 217, 0.2); }
+.tag-mother { background: rgba(123,111,160,0.15); color: var(--num-6); border: 1rpx solid rgba(123, 111, 160, 0.2); }
 .detail-trait { font-size: 26rpx; font-weight: 500; color: rgba(255, 255, 255, 0.8); text-align: center; margin-bottom: 16rpx; }
 .detail-desc { font-size: 24rpx; color: rgba(255, 255, 255, 0.5); line-height: 1.8; text-align: center; padding: 0 20rpx; }
-.detail-master { margin-top: 24rpx; text-align: center; font-size: 22rpx; color: #fbbf24; background: rgba(251, 191, 36, 0.1); border: 1rpx solid rgba(251, 191, 36, 0.15); border-radius: 12rpx; padding: 12rpx; letter-spacing: 2rpx; }
+.detail-master { margin-top: 24rpx; text-align: center; font-size: 22rpx; color: var(--color-gold); background: rgba(251, 191, 36, 0.1); border: 1rpx solid rgba(251, 191, 36, 0.15); border-radius: 12rpx; padding: 12rpx; letter-spacing: 2rpx; }
 
 /* ===== Annotation section ===== */
 .annotation-section {

+ 24 - 0
client/components/_numColors.js

@@ -0,0 +1,24 @@
+import { ref, onMounted, watch } from 'vue'
+
+// Theme-aware: reads from CSS custom properties when available
+function getNumColorFromTheme(num) {
+  const themeMap = {
+    1: '--num-1',
+    2: '--num-2',
+    3: '--num-3',
+    4: '--num-4',
+    5: '--num-5',
+    6: '--num-6',
+    7: '--num-7',
+    8: '--num-8',
+    9: '--num-9',
+  }
+  // Fallback (dark theme default — matches CSS :root)
+  const DEFAULTS = {
+    1: '#D94A4A', 2: '#4A90D9', 3: '#E8A238', 4: '#2D8B67',
+    5: '#D4A017', 6: '#7B6FA0', 7: '#4A6FA5', 8: '#C9A84C', 9: '#B85C3A'
+  }
+  return DEFAULTS[num] || '#FFFFFF'
+}
+
+export { getNumColorFromTheme }

+ 18 - 12
client/pages.json

@@ -2,6 +2,11 @@
   "pages": [
     {"path": "pages/index/index", "style": {"navigationBarTitleText": "数字能量"}},
     {"path": "pages/records/index", "style": {"navigationBarTitleText": "分析记录"}},
+    {"path": "pages/relations/index", "style": {"navigationBarTitleText": "关系能量分析"}},
+    {"path": "pages/relations/add-relation", "style": {"navigationBarTitleText": "添加关系人", "backgroundColor": "#F8F6F1"}},
+    {"path": "pages/relations/chart-compare", "style": {"navigationBarTitleText": "关系命盘对比", "backgroundColor": "#0c0a1a"}},
+    {"path": "pages/relations/number-analysis", "style": {"navigationBarTitleText": "八星号码分析", "backgroundColor": "#0c0a1a"}},
+    {"path": "pages/analysis/index", "style": {"navigationBarTitleText": "分析"}},
     {"path": "pages/profile/index", "style": {"navigationBarTitleText": "我的"}},
     {"path": "pages/payment/index", "style": {"navigationBarTitleText": "VIP 开通"}},
     {"path": "pages/profile/edit", "style": {"navigationBarTitleText": "编辑资料"}},
@@ -15,20 +20,21 @@
     {"path": "pages/plan/monitor", "style": {"navigationBarTitleText": "咨询监看", "enablePullDownRefresh": true, "backgroundColor": "#0c0a1a"}},
     {"path": "pages/admin/index", "style": {"navigationBarTitleText": "管理后台", "backgroundColor": "#0c0a1a", "enablePullDownRefresh": true}}
   ],
-  "globalStyle": {
-    "navigationBarTextStyle": "black",
-    "navigationBarTitleText": "数字能量学",
-    "navigationBarBackgroundColor": "#F8F8F8",
-    "backgroundColor": "#F8F8F8"
-  },
-  "tabBar": {
-    "color": "#999",
-    "selectedColor": "#3B82F6",
-    "backgroundColor": "#FFFFFF",
-    "borderStyle": "black",
+"globalStyle": {
+ "navigationBarTextStyle": "white",
+ "navigationBarTitleText": "数字能量学",
+ "navigationBarBackgroundColor": "#1E3A5F",
+ "backgroundColor": "#0c0a1a"
+ },
+ "tabBar": {
+ "color": "#A0AEC0",
+ "selectedColor": "#C9A84C",
+ "backgroundColor": "#1E3A5F",
+ "borderStyle": "white",
     "list": [
       {"pagePath": "pages/index/index", "text": "首页", "iconPath": "static/home.png", "selectedIconPath": "static/home-active.png"},
-      {"pagePath": "pages/records/index", "text": "记录", "iconPath": "static/records.png", "selectedIconPath": "static/records-active.png"},
+      {"pagePath": "pages/relations/index", "text": "关系", "iconPath": "static/relations.png", "selectedIconPath": "static/relations-active.png"},
+      {"pagePath": "pages/analysis/index", "text": "分析", "iconPath": "static/analysis.png", "selectedIconPath": "static/analysis-active.png"},
       {"pagePath": "pages/profile/index", "text": "我的", "iconPath": "static/profile.png", "selectedIconPath": "static/profile-active.png"}
     ]
   }

+ 11 - 9
client/pages/admin/index.vue

@@ -70,7 +70,7 @@
           </view>
           <view class="stat-card">
             <text class="stat-value accent-blue">{{ stats.totalCharts }}</text>
-            <text class="stat-label">盘总数</text>
+            <text class="stat-label">能量盘总数</text>
           </view>
           <view class="stat-card">
             <text class="stat-value accent-green">{{ stats.totalCommissions }}</text>
@@ -626,6 +626,8 @@ async function handleResetConfig(configKey) {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-admin {
   min-height: 100vh;
   background: linear-gradient(180deg, #0c0a1a 0%, #1a1232 100%);
@@ -668,7 +670,7 @@ async function handleResetConfig(configKey) {
 .login-subtitle {
   display: block;
   font-size: 13px;
-  color: rgba(255, 255, 255, 0.4);
+  color: var(--color-text-tertiary);
   text-align: center;
   margin-bottom: 32px;
 }
@@ -688,7 +690,7 @@ async function handleResetConfig(configKey) {
 .field-label {
   font-size: 13px;
   font-weight: 500;
-  color: rgba(255, 255, 255, 0.6);
+  color: var(--color-text-secondary);
 }
 
 .field-input {
@@ -740,7 +742,7 @@ async function handleResetConfig(configKey) {
 
 .loading-text {
   font-size: 14px;
-  color: rgba(255, 255, 255, 0.4);
+  color: var(--color-text-tertiary);
 }
 
 // ─── Stats Grid ───
@@ -822,7 +824,7 @@ async function handleResetConfig(configKey) {
 
 .mini-desc {
   font-size: 11px;
-  color: rgba(255, 255, 255, 0.4);
+  color: var(--color-text-tertiary);
 }
 
 .mini-right {
@@ -870,7 +872,7 @@ async function handleResetConfig(configKey) {
 .tab-text {
   font-size: 13px;
   font-weight: 500;
-  color: rgba(255, 255, 255, 0.5);
+  color: var(--color-text-tertiary);
 }
 
 .tab-active .tab-text {
@@ -916,7 +918,7 @@ async function handleResetConfig(configKey) {
 
 .data-meta {
   font-size: 11px;
-  color: rgba(255, 255, 255, 0.4);
+  color: var(--color-text-tertiary);
 }
 
 .data-right {
@@ -946,7 +948,7 @@ async function handleResetConfig(configKey) {
   padding: 2px 10px;
   border-radius: 999px;
   background: rgba(107, 114, 128, 0.2);
-  color: rgba(255, 255, 255, 0.4);
+  color: var(--color-text-tertiary);
 }
 
 .tag-vip-active {
@@ -1139,7 +1141,7 @@ async function handleResetConfig(configKey) {
 
 .logout-text {
   font-size: 12px;
-  color: rgba(255, 255, 255, 0.3);
+  color: var(--color-text-tertiary);
   text-decoration: underline;
 }
 </style>

+ 396 - 0
client/pages/analysis/index.vue

@@ -0,0 +1,396 @@
+<template>
+  <view class="page-analysis">
+    <!-- ========== Section 1: My Analysis Records ========== -->
+    <view class="section">
+      <view class="section__header">
+        <text class="section__title">📋 我的分析记录</text>
+      </view>
+
+      <!-- Empty state -->
+      <view v-if="chartStore.records.length === 0" class="empty-state">
+        <text class="empty-icon">📋</text>
+        <text class="empty-text">暂无分析记录</text>
+        <text class="empty-desc">去首页分析您的手机号码</text>
+      </view>
+
+      <!-- Records list -->
+      <view v-else class="records-list">
+        <view
+          v-for="record in chartStore.records"
+          :key="record.id"
+          class="record-card"
+          @click="viewDetail(record)"
+        >
+          <view class="record-header">
+            <text class="record-name">{{ record.name || record.birthday || '未知' }}</text>
+            <text class="record-date">{{ formatDate(record.createdAt) }}</text>
+          </view>
+          <text class="record-phone">{{ record.birthday || '' }}</text>
+          <view class="record-tags">
+            <text v-if="record.difyResponse" class="tag-status">已解读</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- ========== Divider: Super Member Zone ========== -->
+    <view class="section-divider">
+      <text class="section-divider__line"></text>
+      <text class="section-divider__text">超级会员专属</text>
+      <text class="section-divider__line"></text>
+    </view>
+
+    <!-- ========== Section 2: Relationship Analysis ========== -->
+    <view
+      class="feature-card"
+      :class="{ 'feature-card--locked': !isSuperMember }"
+      @click="goRelations"
+    >
+      <view class="feature-card__icon">
+        <text>🔗</text>
+      </view>
+      <view class="feature-card__body">
+        <text class="feature-card__title">关系能量分析</text>
+        <text class="feature-card__desc">夫妻/亲子/同事等关系合盘对比分析</text>
+      </view>
+      <text v-if="!isSuperMember" class="feature-card__lock">🔒</text>
+      <text v-else class="feature-card__arrow">›</text>
+    </view>
+
+    <!-- ========== Section 3: Number Analysis ========== -->
+    <view
+      class="feature-card"
+      :class="{ 'feature-card--locked': !isSuperMember }"
+      @click="goNumberAnalysis"
+    >
+      <view class="feature-card__icon">
+        <text>🔢</text>
+      </view>
+      <view class="feature-card__body">
+        <text class="feature-card__title">八星号码分析</text>
+        <text class="feature-card__desc">手机号/车牌号等数字能量解读</text>
+      </view>
+      <text v-if="!isSuperMember" class="feature-card__lock">🔒</text>
+      <text v-else class="feature-card__arrow">›</text>
+    </view>
+
+    <!-- ========== Upsell Banner (non-super logged-in users) ========== -->
+    <view v-if="!isSuperMember && userStore.isLoggedIn" class="upsell-banner">
+      <view class="upsell-banner__content">
+        <text class="upsell-banner__title">开通超级会员 ¥1,314/年</text>
+        <text class="upsell-banner__desc">解锁关系能量分析 + 八星号码解读</text>
+      </view>
+      <button class="upsell-banner__btn" @click="goSubscribe">立即开通</button>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { computed } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import { useUserStore } from '@/stores/user'
+import { useChartStore } from '@/stores/chart'
+
+const userStore = useUserStore()
+const chartStore = useChartStore()
+
+// Super member check: practitioner (能量师) or super_annual tier
+const isSuperMember = computed(() => {
+  if (!userStore.isVip) return false
+  return userStore.vipType === 'super_annual' || userStore.vipType === 'practitioner'
+})
+
+onShow(() => {
+  // Fetch user profile for up-to-date VIP status
+  if (userStore.isLoggedIn) {
+    userStore.fetchProfile()
+  }
+  // Fetch records list
+  chartStore.fetchRecords()
+})
+
+function formatDate(dateStr) {
+  if (!dateStr) return ''
+  return dateStr.slice(0, 10)
+}
+
+function viewDetail(record) {
+  chartStore.loadChart(record.id).then(() => {
+    uni.navigateTo({ url: '/pages/chart/index' })
+  })
+}
+
+function goRelations() {
+  if (isSuperMember.value) {
+    uni.navigateTo({ url: '/pages/relations/index' })
+  } else {
+    uni.showToast({ title: '开通超级会员解锁', icon: 'none' })
+  }
+}
+
+function goNumberAnalysis() {
+  if (isSuperMember.value) {
+    uni.navigateTo({ url: '/pages/relations/number-analysis' })
+  } else {
+    uni.showToast({ title: '开通超级会员解锁', icon: 'none' })
+  }
+}
+
+function goSubscribe() {
+  uni.navigateTo({ url: '/pages/payment/index?product=super_member' })
+}
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/theme.scss";
+
+// Brand colors from style-guide.md
+$blue-dark: var(--color-brand);
+$gold: var(--color-gold);
+$gold-light: #F8F0D8;
+$warm-white: var(--color-bg);
+$white: var(--color-bg-card);
+$text-primary: #1F2937;
+$text-secondary: #6B7280;
+$text-muted: #9CA3AF;
+$border-light: var(--color-border);
+$shadow-card: var(--shadow-card);
+
+.page-analysis {
+  padding: 16px;
+  min-height: 100vh;
+  background: $warm-white;
+}
+
+// ========== Section ==========
+.section {
+  background: $white;
+  border-radius: 16px;
+  padding: 20px 16px;
+  margin-bottom: 16px;
+  box-shadow: $shadow-card;
+
+  &__header {
+    margin-bottom: 12px;
+  }
+
+  &__title {
+    font-size: 17px;
+    font-weight: 600;
+    color: $text-primary;
+  }
+}
+
+// ========== Empty State ==========
+.empty-state {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 24px 0;
+}
+
+.empty-icon {
+  font-size: 40px;
+  margin-bottom: 10px;
+}
+
+.empty-text {
+  font-size: 15px;
+  color: $text-secondary;
+  margin-bottom: 4px;
+}
+
+.empty-desc {
+  font-size: 13px;
+  color: $text-muted;
+}
+
+// ========== Records List ==========
+.records-list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+
+.record-card {
+  background: $warm-white;
+  border-radius: 12px;
+  padding: 14px;
+  cursor: pointer;
+  transition: background 0.15s;
+
+  &:active {
+    background: darken($warm-white, 2%);
+  }
+}
+
+.record-header {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 4px;
+}
+
+.record-name {
+  font-weight: 600;
+  font-size: 15px;
+  color: $text-primary;
+}
+
+.record-date {
+  font-size: 12px;
+  color: $text-muted;
+}
+
+.record-phone {
+  font-size: 18px;
+  color: $blue-dark;
+  font-weight: 500;
+}
+
+.tag-status {
+  display: inline-block;
+  background: #D1FAE5;
+  color: #059669;
+  font-size: 11px;
+  padding: 2px 8px;
+  border-radius: 10px;
+  margin-top: 8px;
+}
+
+// ========== Section Divider ==========
+.section-divider {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  margin: 20px 0;
+  padding: 0 4px;
+
+  &__line {
+    flex: 1;
+    height: 1px;
+    background: $border-light;
+  }
+
+  &__text {
+    font-size: 12px;
+    font-weight: 600;
+    color: $gold;
+    white-space: nowrap;
+    letter-spacing: 1px;
+  }
+}
+
+// ========== Feature Cards ==========
+.feature-card {
+  display: flex;
+  align-items: center;
+  gap: 14px;
+  background: $white;
+  border-radius: 16px;
+  padding: 18px 16px;
+  margin-bottom: 12px;
+  box-shadow: $shadow-card;
+  cursor: pointer;
+  transition: all 0.15s;
+
+  &:active {
+    transform: scale(0.98);
+  }
+
+  &--locked {
+    opacity: 0.55;
+  }
+
+  &__icon {
+    width: 48px;
+    height: 48px;
+    border-radius: 12px;
+    background: $gold-light;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 24px;
+    flex-shrink: 0;
+  }
+
+  &__body {
+    flex: 1;
+    min-width: 0;
+  }
+
+  &__title {
+    font-size: 16px;
+    font-weight: 600;
+    color: $text-primary;
+    display: block;
+    margin-bottom: 2px;
+  }
+
+  &__desc {
+    font-size: 13px;
+    color: $text-secondary;
+    display: block;
+  }
+
+  &__lock {
+    font-size: 20px;
+    flex-shrink: 0;
+  }
+
+  &__arrow {
+    font-size: 22px;
+    color: $text-muted;
+    flex-shrink: 0;
+  }
+}
+
+// ========== Upsell Banner ==========
+.upsell-banner {
+  background: linear-gradient(135deg, $blue-dark, darken($blue-dark, 4%));
+  border-radius: 16px;
+  padding: 20px;
+  margin-top: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px;
+
+  &__content {
+    flex: 1;
+  }
+
+  &__title {
+    font-size: 16px;
+    font-weight: 700;
+    color: $gold;
+    display: block;
+    margin-bottom: 4px;
+  }
+
+  &__desc {
+    font-size: 12px;
+    color: var(--color-text-secondary);
+    display: block;
+  }
+
+  &__btn {
+    flex-shrink: 0;
+    background: $gold;
+    color: $blue-dark;
+    font-size: 14px;
+    font-weight: 700;
+    border: none;
+    border-radius: 10px;
+    padding: 10px 18px;
+    min-height: 44px;
+    line-height: 1;
+    cursor: pointer;
+    transition: all 0.15s;
+
+    &:active {
+      transform: scale(0.97);
+      opacity: 0.9;
+    }
+  }
+}
+</style>

+ 76 - 12
client/pages/chart/index.vue

@@ -4,7 +4,7 @@
     <view class="top-bar">
       <view class="spacer"></view>
       <view class="collapse-btn" @click="chartCollapsed = !chartCollapsed">
-        {{ chartCollapsed ? '▾ 展开命盘图' : '▴ 折叠命盘图' }}
+        {{ chartCollapsed ? '▾ 展开能量盘图' : '▴ 折叠能量盘图' }}
       </view>
     </view>
 
@@ -25,7 +25,7 @@
         />
       </view>
       <view class="chart-section__toggle" @click="chartCollapsed = !chartCollapsed">
-        <text class="chart-section__toggle-label">{{ chartCollapsed ? '展开命盘图' : '收起命盘图' }}</text>
+        <text class="chart-section__toggle-label">{{ chartCollapsed ? '展开能量盘图' : '收起能量盘图' }}</text>
         <text class="chart-section__toggle-arrow">{{ chartCollapsed ? '▾' : '▴' }}</text>
       </view>
     </view>
@@ -39,7 +39,7 @@
     <view class="chat-section">
       <view class="section-title">
         <text class="title-icon">◈</text>
-        盘解读
+        能量盘解读
         <text v-if="!userStore.isVipActive && maxChats > 0" class="quota-badge">
           {{ usedChats }}/{{ maxChats }}
         </text>
@@ -135,6 +135,16 @@
       </view>
     </view>
 
+     <!-- Super member entry point (non-super users who have seen AI interpretation) -->
+     <view v-if="messages.length >= 2 && !isSuperMember" class="super-entry" @click="goSuperMember">
+       <view class="super-entry__icon">🏆</view>
+       <view class="super-entry__body">
+         <text class="super-entry__title">超级会员专属</text>
+         <text class="super-entry__desc">关系能量分析 · 八星号码解读</text>
+       </view>
+       <view class="super-entry__action">开通</view>
+     </view>
+
      <!-- US-9.4: Proposal card for negotiating state -->
      <view v-if="planRequest && planRequest.status === 'negotiating'" class="proposal-section">
        <view class="proposal-title">📋 人工方案</view>
@@ -222,8 +232,8 @@ export default {
     const recordId = page?.options?.recordId || ''
     const store = this.$scope?.store
     const title = store?.currentChart?.O
-      ? `我的盘主性格数字是${store.currentChart.O},快来测测你的!`
-      : '数字能量盘分析'
+      ? `我的能量盘主性格数字是${store.currentChart.O},快来测测你的!`
+      : '数字能量盘分析'
     return {
       title,
       path: `/pages/chart/index?recordId=${recordId}`,
@@ -235,7 +245,7 @@ export default {
     const page = pages[pages.length - 1]
     const recordId = page?.options?.recordId || ''
     return {
-      title: '数字能量盘分析',
+      title: '数字能量盘分析',
       query: `recordId=${recordId}`,
       imageUrl: '/static/share-card.png'
     }
@@ -290,6 +300,11 @@ const deliveryData = ref([])
 const annotations = ref([])
 const allTags = ref([])
 
+const isSuperMember = computed(() => {
+  if (!userStore.isVip) return false
+  return userStore.vipType === 'super_annual' || userStore.vipType === 'practitioner'
+})
+
 const quotaExceeded = computed(() => {
   if (userStore.isVipActive) return false
   return maxChats.value > 0 && usedChats.value >= maxChats.value
@@ -373,14 +388,14 @@ onMounted(async () => {
     if (messages.value.length === 0) {
       messages.value = [{
         role: 'ai',
-        content: `已为您生成盘。主性格数字为${store.currentChart.O}。请点击下方问题或输入您想了解的内容。`,
+        content: `已为您生成能量盘。主性格数字为${store.currentChart.O}。请点击下方问题或输入您想了解的内容。`,
         createdAt: new Date().toISOString()
       }]
     }
   } else {
     messages.value = [{
       role: 'ai',
-      content: '暂无盘数据,请先返回首页输入出生信息。',
+      content: '暂无能量盘数据,请先返回首页输入出生信息。',
       createdAt: new Date().toISOString()
     }]
   }
@@ -701,11 +716,11 @@ function showMenu() {
 async function confirmRegenerate() {
   uni.showModal({
     title: '重新开始',
-    content: '将清除当前对话记录并重新生成盘解读,确定吗?',
+    content: '将清除当前对话记录并重新生成能量盘解读,确定吗?',
     success: async (confirm) => {
       if (!confirm.confirm) return
       if (!store.currentRecordId) {
-        uni.showToast({ title: '暂无盘数据', icon: 'none' })
+        uni.showToast({ title: '暂无能量盘数据', icon: 'none' })
         return
       }
       try {
@@ -731,7 +746,7 @@ async function confirmRegenerate() {
 // US-9.2: Navigate to plan application page
 function handlePlanApply() {
   if (!store.currentRecordId) {
-    uni.showToast({ title: '暂无盘数据', icon: 'none' })
+    uni.showToast({ title: '暂无能量盘数据', icon: 'none' })
     return
   }
   uni.navigateTo({ url: `/pages/plan/apply?chartRecordId=${store.currentRecordId}` })
@@ -759,10 +774,14 @@ function goSubscribeC() {
   uni.navigateTo({ url: '/pages/payment/index?product=annual' })
 }
 
+function goSuperMember() {
+  uni.navigateTo({ url: '/pages/payment/index?product=super_member' })
+}
+
 // US-2.2: Export PDF (paid users only)
 async function exportPdf() {
   if (!store.currentRecordId) {
-    uni.showToast({ title: '暂无命盘记录', icon: 'none' })
+    uni.showToast({ title: '暂无能量盘记录', icon: 'none' })
     return
   }
   uni.showLoading({ title: '生成中...' })
@@ -1631,6 +1650,51 @@ async function submitCounter() {
   white-space: pre-wrap;
 }
 
+/* Super member entry point */
+.super-entry {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  background: linear-gradient(135deg, rgba(30, 58, 95, 0.08), rgba(201, 168, 76, 0.06));
+  border: 1px solid rgba(201, 168, 76, 0.2);
+  border-radius: 12px;
+  padding: 12px 14px;
+  margin-top: 12px;
+  cursor: pointer;
+}
+.super-entry:active {
+  transform: scale(0.98);
+  opacity: 0.9;
+}
+.super-entry__icon {
+  font-size: 28px;
+  flex-shrink: 0;
+}
+.super-entry__body {
+  flex: 1;
+}
+.super-entry__title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #1E3A5F;
+  display: block;
+}
+.super-entry__desc {
+  font-size: 12px;
+  color: #A0AEC0;
+  display: block;
+  margin-top: 1px;
+}
+.super-entry__action {
+  flex-shrink: 0;
+  font-size: 13px;
+  font-weight: 600;
+  color: #C9A84C;
+  background: #1E3A5F;
+  padding: 6px 14px;
+  border-radius: 8px;
+}
+
 /* US-9.5: Paid waiting state */
 .paid-waiting {
   text-align: center;

+ 28 - 26
client/pages/commission/index.vue

@@ -345,9 +345,11 @@ function formatDate(dateStr) {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-commission {
   min-height: 100vh;
-  background: #F8F6F1;
+  background: var(--color-bg);
   padding: 16px;
 }
 
@@ -363,7 +365,7 @@ function formatDate(dateStr) {
 }
 .error-text {
   font-size: 14px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
 }
 
 /* Loading */
@@ -373,7 +375,7 @@ function formatDate(dateStr) {
 }
 .loading-text {
   font-size: 14px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
 }
 
 /* Section */
@@ -392,7 +394,7 @@ function formatDate(dateStr) {
 .section-title {
   font-size: 16px;
   font-weight: 700;
-  color: #1A1A2E;
+  color: var(--color-text-primary);
 }
 .section-sub {
   font-size: 12px;
@@ -402,7 +404,7 @@ function formatDate(dateStr) {
 
 /* ===== Earnings ===== */
 .earnings-section {
-  background: linear-gradient(135deg, #1E3A5F, #2D4A7A);
+  background: linear-gradient(135deg, var(--color-brand), #2D4A7A);
 }
 .earnings-section .section-title {
   color: rgba(255,255,255,0.9);
@@ -429,7 +431,7 @@ function formatDate(dateStr) {
   display: block;
 }
 .earn-value.accent {
-  color: #C9A84C;
+  color: var(--color-gold);
 }
 .withdraw-bar {
   margin-top: 14px;
@@ -445,11 +447,11 @@ function formatDate(dateStr) {
 .withdraw-text {
   font-size: 14px;
   font-weight: 600;
-  color: #C9A84C;
+  color: var(--color-gold);
 }
 .withdraw-arrow {
   font-size: 16px;
-  color: #C9A84C;
+  color: var(--color-gold);
 }
 
 /* ===== Earnings Breakdown ===== */
@@ -505,25 +507,25 @@ function formatDate(dateStr) {
 .stat-num {
   font-size: 24px;
   font-weight: 700;
-  color: #1E3A5F;
+  color: var(--color-brand);
   display: block;
 }
 .stat-label {
   font-size: 11px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
   margin-top: 2px;
   display: block;
 }
 
 .team-preview {
-  border-top: 1px solid #F3F4F6;
+  border-top: 1px solid var(--color-bg-input);
   padding-top: 10px;
 }
 .member-row {
   display: flex;
   align-items: center;
   padding: 8px 0;
-  border-bottom: 1px solid #F8F6F1;
+  border-bottom: 1px solid var(--color-bg);
 }
 .member-row:last-child { border-bottom: none; }
 .member-avatar {
@@ -536,18 +538,18 @@ function formatDate(dateStr) {
 .member-info { flex: 1; }
 .member-name {
   font-size: 13px;
-  color: #1A1A2E;
+  color: var(--color-text-primary);
   display: block;
 }
 .member-date {
   font-size: 11px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
   margin-top: 1px;
   display: block;
 }
 .member-vip {
   font-size: 10px;
-  color: #C9A84C;
+  color: var(--color-gold);
   background: #FEF3C7;
   padding: 2px 8px;
   border-radius: 4px;
@@ -560,7 +562,7 @@ function formatDate(dateStr) {
   justify-content: space-between;
   align-items: center;
   padding: 14px 0;
-  border-bottom: 1px solid #F3F4F6;
+  border-bottom: 1px solid var(--color-bg-input);
 }
 .tool-card:last-child { border-bottom: none; }
 .tool-left {
@@ -573,23 +575,23 @@ function formatDate(dateStr) {
   width: 36px;
   height: 36px;
   border-radius: 8px;
-  background: #F8F6F1;
+  background: var(--color-bg);
   display: flex;
   align-items: center;
   justify-content: center;
   font-size: 16px;
-  color: #1E3A5F;
+  color: var(--color-brand);
   flex-shrink: 0;
 }
 .tool-name {
   font-size: 14px;
   font-weight: 600;
-  color: #1A1A2E;
+  color: var(--color-text-primary);
   display: block;
 }
 .tool-desc {
   font-size: 11px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
   margin-top: 2px;
   display: block;
 }
@@ -601,7 +603,7 @@ function formatDate(dateStr) {
 .ref-code-tag {
   font-size: 12px;
   font-weight: 600;
-  color: #C9A84C;
+  color: var(--color-gold);
   background: #FEF3C7;
   padding: 2px 10px;
   border-radius: 4px;
@@ -618,7 +620,7 @@ function formatDate(dateStr) {
   justify-content: space-between;
   align-items: center;
   padding: 12px 0;
-  border-bottom: 1px solid #F3F4F6;
+  border-bottom: 1px solid var(--color-bg-input);
 }
 .commission-row:last-child { border-bottom: none; }
 .comm-left { flex: 1; }
@@ -630,7 +632,7 @@ function formatDate(dateStr) {
 }
 .comm-level {
   font-size: 12px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
   margin-top: 2px;
   display: block;
 }
@@ -650,11 +652,11 @@ function formatDate(dateStr) {
 }
 .comm-status.status-settled { background: #ECFDF5; color: #2D8B67; }
 .comm-status.status-pending { background: #FEF3C7; color: #D4A017; }
-.comm-status.status-withdrawn { background: #F3F4F6; color: #A0AEC0; }
+.comm-status.status-withdrawn { background: var(--color-bg-input); color: var(--color-text-secondary); }
 .comm-status.status-available { background: #EFF6FF; color: #3B82F6; }
 .comm-date {
   font-size: 11px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
   display: block;
 }
 
@@ -665,6 +667,6 @@ function formatDate(dateStr) {
 }
 .empty-text {
   font-size: 13px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
 }
 </style>

+ 2 - 2
client/pages/index/index.vue

@@ -3,7 +3,7 @@
     <!-- Hero header -->
     <view class="hero">
       <text class="hero-title">数字能量</text>
-      <text class="hero-sub">输入出生信息,解锁专属盘</text>
+      <text class="hero-sub">输入出生信息,解锁专属能量盘</text>
     </view>
 
     <!-- Birth input section -->
@@ -156,7 +156,7 @@ async function onAnalyze() {
   // New birthday — show confirm dialog (US-1.1 §9-11)
   uni.showModal({
     title: '确认咨询',
-    content: '此生日将开启全新的盘咨询,确认吗?',
+    content: '此生日将开启全新的能量盘咨询,确认吗?',
     confirmText: '确认开启',
     cancelText: '再想想',
     success: async (res) => {

+ 3 - 1
client/pages/login/index.vue

@@ -211,6 +211,8 @@ function continueToChart() {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-login {
   min-height: 100vh;
   background: linear-gradient(180deg, #F8F9FF 0%, #EEF2FF 100%);
@@ -373,7 +375,7 @@ function continueToChart() {
   font-weight: 500;
 }
 .profile-card__btn--skip {
-  background: #F3F4F6;
+  background: var(--color-bg-input);
   color: #6B7280;
 }
 .profile-card__btn--save {

+ 2 - 2
client/pages/payment/index.vue

@@ -69,7 +69,7 @@
         </view>
         <view class="plan-features">
           <text class="feature">✦ 包含 C 端全部权益</text>
-          <text class="feature">✦ 无限盘生成</text>
+          <text class="feature">✦ 无限能量盘生成</text>
           <text class="feature">✦ AI 五区完整解读,随问随答</text>
           <text class="feature">✦ 全部历史记录永久保存</text>
           <text class="feature">✦ 推广佣金 — 固定 ¥500/人 + 二级 ¥100/人</text>
@@ -109,7 +109,7 @@ const pageTitle = computed(() => {
   return product.value === 'annual' ? 'C端会员' : '能量师专业版'
 })
 const pageDesc = computed(() => {
-  return product.value === 'annual' ? '解锁无限AI解读,获取推广佣金' : '获取完整盘分析、AI解读与分销推广权限'
+  return product.value === 'annual' ? '解锁无限AI解读,获取推广佣金' : '获取完整能量盘分析、AI解读与分销推广权限'
 })
 
 const currentPrice = computed(() => {

+ 2 - 0
client/pages/plan/apply.vue

@@ -141,6 +141,8 @@ const onSubmit = async () => {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-apply {
   padding: 20px;
   min-height: 100vh;

+ 110 - 20
client/pages/profile/index.vue

@@ -39,9 +39,15 @@
               {{ userStore.city || '' }}{{ userStore.city && userStore.bio ? ' · ' : '' }}{{ userStore.bio || '' }}
             </text>
           </view>
-          <text class="user-card__arrow">›</text>
-        </view>
-      </view>
+<text class="user-card__arrow">›</text>
+
+ <!-- Theme switcher inside user card -->
+ <view class="user-card__theme">
+ <ThemeToggle />
+ </view>
+ </view>
+ </view>
+ </view>
     </view>
 
     <!-- ========== Region 2: Membership Status Cards ========== -->
@@ -78,7 +84,26 @@
       <text class="vip-card__action" @click="goRenew">续费</text>
     </view>
 
-    <!-- Case 2: C-end annual subscriber (in valid period) -->
+    <!-- Case 2: Super annual subscriber (in valid period) -->
+    <view
+      v-else-if="userStore.vipType === 'super_annual' && userStore.isVip && !isExpired"
+      class="vip-card vip-card--super"
+    >
+      <view class="vip-card__body">
+        <text class="vip-card__title">超级会员 🏆</text>
+        <text class="vip-card__desc">
+          有效期至 {{ formatDate(userStore.vipEndTime) }}
+        </text>
+        <view class="vip-card__perks">
+          <text class="perk-tag">关系能量</text>
+          <text class="perk-tag">八星号码</text>
+          <text class="perk-tag">分销推广</text>
+        </view>
+      </view>
+      <text class="vip-card__action" @click="goUpgradePractitioner">升级能量师</text>
+    </view>
+
+    <!-- Case 3: C-end annual subscriber (in valid period) -->
     <view
       v-else-if="userStore.vipType === 'annual' && userStore.isVip && !isExpired"
       class="vip-card vip-card--annual"
@@ -89,10 +114,13 @@
           有效期至 {{ formatDate(userStore.vipEndTime) }}
         </text>
       </view>
-      <text class="vip-card__action" @click="goUpgradePractitioner">升级能量师</text>
+      <view style="display:flex;gap:8px;flex-shrink:0;">
+        <text class="vip-card__action" @click="goSuperMember">升超级</text>
+        <text class="vip-card__action" @click="goUpgradePractitioner">升能量师</text>
+      </view>
     </view>
 
-    <!-- Case 3: Expired member (vipEndTime < now) -->
+    <!-- Case 4: Expired member (vipEndTime < now) -->
     <view v-else-if="userStore.vipType && isExpired" class="vip-card vip-card--expired">
       <view class="vip-card__body">
         <text class="vip-card__title">会员已过期</text>
@@ -103,7 +131,7 @@
       <text class="vip-card__action" @click="goPayment">重新开通</text>
     </view>
 
-    <!-- Case 4: Free user — two payment options -->
+    <!-- Case 5: Free user — three payment options -->
     <view v-else class="vip-card vip-card--upsell">
       <view class="vip-card__body">
         <text class="vip-card__title">选择方案</text>
@@ -114,6 +142,12 @@
             <text class="option-desc">无限AI解读</text>
             <button class="option-btn light">开通</button>
           </view>
+          <view class="vip-card__option" @click="goSuperMember">
+            <text class="option-title">超级会员</text>
+            <text class="option-price">¥1,314/年</text>
+            <text class="option-desc">关系能量+号码分析</text>
+            <button class="option-btn light">开通</button>
+          </view>
           <view class="vip-card__option vip-card__option--pro" @click="goUpgradePractitioner">
             <text class="option-title">能量师</text>
             <text class="option-price">¥1,314/年</text>
@@ -137,7 +171,13 @@
       </view>
     </view>
 
-    <!-- ========== Region 3: Feature Menu ========== -->
+<!-- ========== Region 2.5: Theme Toggle ========== -->
+<view class="theme-row">
+ <text class="theme-row__label">🎨 外观</text>
+ <ThemeToggle />
+ </view>
+
+ <!-- ========== Region 3: Feature Menu ========== -->
 
     <!-- Group 1: My Services -->
     <view class="menu-section">
@@ -209,12 +249,19 @@
 </template>
 
 <script setup>
-import { computed, getCurrentInstance } from 'vue'
-import { onShow } from '@dcloudio/uni-app'
-import { useUserStore } from '@/stores/user'
-import { profileApi } from '@/utils/api'
+ import { computed, getCurrentInstance } from 'vue'
+ import { onShow } from '@dcloudio/uni-app'
+ import { useUserStore } from '@/stores/user'
+ import { useThemeStore } from '@/stores/theme'
+ import { profileApi } from '@/utils/api'
+
+ const userStore = useUserStore()
+ const themeStore = useThemeStore()
 
-const userStore = useUserStore()
+ // Initialize theme on page show
+ onShow(() => {
+ themeStore.init()
+ })
 
 // US-4.3: Renewal reminder if expiry within 7 days
 const isExpiringSoon = computed(() => {
@@ -269,6 +316,10 @@ function goUpgradePractitioner() {
   uni.navigateTo({ url: '/pages/payment/index?product=practitioner' })
 }
 
+function goSuperMember() {
+  uni.navigateTo({ url: '/pages/payment/index?product=super_member' })
+}
+
 function goRecords() {
   uni.switchTab({ url: '/pages/records/index' })
 }
@@ -690,6 +741,29 @@ $danger: #EF4444;
     }
   }
 
+  // Super member
+  &--super {
+    background: linear-gradient(135deg, #C9A84C, #B8922E);
+    .vip-card__title, .vip-card__desc { color: #1E3A5F; }
+    .vip-card__action {
+      color: #C9A84C;
+      background: #1E3A5F;
+    }
+    .vip-card__perks {
+      display: flex;
+      gap: 6px;
+      margin-top: 6px;
+    }
+    .perk-tag {
+      font-size: 10px;
+      font-weight: 500;
+      padding: 2px 8px;
+      border-radius: 4px;
+      background: rgba(30, 58, 95, 0.15);
+      color: #1E3A5F;
+    }
+  }
+
   // Annual
   &--annual {
     background: linear-gradient(135deg, #f59e0b, #d97706);
@@ -948,10 +1022,26 @@ $danger: #EF4444;
 }
 
 .poster-canvas {
-  position: fixed;
-  left: -9999px;
-  top: -9999px;
-  width: 375px;
-  height: 670px;
-}
-</style>
+position: fixed;
+ left: -9999px;
+ top: -9999px;
+ width: 375px;
+ height: 670px;
+ }
+
+ /* Theme toggle row (Region 2.5) */
+ .theme-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 0 16px 14px;
+ padding: 14px 16px;
+ background: var(--color-bg-card, rgba(255, 255, 255, 0.06));
+ border-radius: var(--radius-lg, 16px);
+ }
+
+ .theme-row__label {
+ font-size: var(--font-sm, 14px);
+ color: var(--color-text-secondary, #A0AEC0);
+ }
+ </style>

+ 2 - 0
client/pages/records/index.vue

@@ -49,6 +49,8 @@ function viewDetail(record) {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-records { padding: 16px; }
 .empty-state {
   display: flex; flex-direction: column; align-items: center;

+ 3 - 1
client/pages/register/index.vue

@@ -190,6 +190,8 @@ async function handleSubmit() {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-register {
   min-height: 100vh;
   background: linear-gradient(180deg, #F8F9FF 0%, #EEF2FF 100%);
@@ -332,7 +334,7 @@ async function handleSubmit() {
   border-radius: 20px;
   font-size: 13px;
   color: #6B7280;
-  background: #F3F4F6;
+  background: var(--color-bg-input);
   border: 1px solid transparent;
 }
 .tag-item.active {

+ 333 - 0
client/pages/relations/add-relation.vue

@@ -0,0 +1,333 @@
+<template>
+  <view class="page-add-relation">
+    <view class="form-card">
+      <!-- Relation Type -->
+      <view class="form-group">
+        <text class="form-label">关系类型 *</text>
+        <view class="type-grid">
+          <view
+            v-for="opt in relationTypeOptions"
+            :key="opt.value"
+            class="type-chip"
+            :class="{ active: form.relationType === opt.value }"
+            @click="form.relationType = opt.value"
+          >
+            <text class="chip-text">{{ opt.label }}</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- Name -->
+      <view class="form-group">
+        <text class="form-label">姓名</text>
+        <input
+          v-model="form.name"
+          class="form-input"
+          placeholder="请输入姓名"
+          placeholder-class="input-placeholder"
+          maxlength="20"
+        />
+      </view>
+
+      <!-- Birth Date -->
+      <view class="form-group">
+        <text class="form-label">生日 *</text>
+        <picker mode="date" :value="form.birthDate" @change="onBirthDateChange">
+          <view class="form-input picker-trigger">
+            <text :class="{ 'text-placeholder': !form.birthDate }">
+              {{ form.birthDate || '请选择出生日期' }}
+            </text>
+          </view>
+        </picker>
+      </view>
+
+      <!-- Gender -->
+      <view class="form-group">
+        <text class="form-label">性别</text>
+        <view class="gender-row">
+          <view
+            v-for="opt in genderOptions"
+            :key="opt.value"
+            class="gender-option"
+            :class="{ active: form.gender === opt.value }"
+            @click="form.gender = opt.value"
+          >
+            <text class="gender-text">{{ opt.label }}</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- Note -->
+      <view class="form-group">
+        <text class="form-label">备注</text>
+        <input
+          v-model="form.note"
+          class="form-input"
+          placeholder="选填,如:工作中的合作伙伴"
+          placeholder-class="input-placeholder"
+          maxlength="50"
+        />
+      </view>
+    </view>
+
+    <!-- Save Button -->
+    <view class="save-bar">
+      <view class="btn-save" :class="{ saving: saving }" @click="handleSave">
+        <text class="btn-save-text">{{ saving ? '保存中...' : '保存' }}</text>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import requestInstance from '@/utils/api'
+
+const relationApi = {
+  create: (data) => requestInstance.post('/relation/create', data),
+  update: (data) => requestInstance.post('/relation/update', data),
+  get: (id) => requestInstance.post('/relation/get', { id })
+}
+
+const relationTypeOptions = [
+  { value: 'spouse', label: '夫妻' },
+  { value: 'parent_child', label: '亲子' },
+  { value: 'colleague', label: '同事' },
+  { value: 'friend', label: '朋友' },
+  { value: 'superior', label: '上下级' }
+]
+
+const genderOptions = [
+  { value: 0, label: '保密' },
+  { value: 1, label: '男' },
+  { value: 2, label: '女' }
+]
+
+const form = reactive({
+  relationType: '',
+  name: '',
+  birthDate: '',
+  gender: 0,
+  note: ''
+})
+
+const isEdit = ref(false)
+const editId = ref(null)
+const saving = ref(false)
+
+onLoad((query) => {
+  if (query && query.id) {
+    isEdit.value = true
+    editId.value = query.id
+    uni.setNavigationBarTitle({ title: '编辑关系人' })
+    fetchRelation(query.id)
+  }
+})
+
+async function fetchRelation(id) {
+  try {
+    const data = await relationApi.get(id)
+    if (data) {
+      form.relationType = data.relationType || ''
+      form.name = data.name || ''
+      form.birthDate = data.birthDate || ''
+      form.gender = data.gender ?? 0
+      form.note = data.note || ''
+    }
+  } catch (e) {
+    uni.showToast({ title: '加载关系人信息失败', icon: 'none' })
+  }
+}
+
+function onBirthDateChange(e) {
+  form.birthDate = e.detail.value
+}
+
+function validate() {
+  if (!form.relationType) {
+    uni.showToast({ title: '请选择关系类型', icon: 'none' })
+    return false
+  }
+  if (!form.birthDate) {
+    uni.showToast({ title: '请选择出生日期', icon: 'none' })
+    return false
+  }
+  return true
+}
+
+async function handleSave() {
+  if (!validate()) return
+  if (saving.value) return
+
+  saving.value = true
+  try {
+    if (isEdit.value) {
+      await relationApi.update({ id: editId.value, ...form })
+      uni.showToast({ title: '更新成功', icon: 'success' })
+    } else {
+      await relationApi.create(form)
+      uni.showToast({ title: '添加成功', icon: 'success' })
+    }
+    setTimeout(() => {
+      uni.navigateBack()
+    }, 1200)
+  } catch (e) {
+    // error toast already handled by requestInstance
+  } finally {
+    saving.value = false
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/theme.scss";
+
+.page-add-relation {
+  min-height: 100vh;
+  background: var(--color-bg);
+  padding: 16px;
+}
+
+/* Form card */
+.form-card {
+  background: var(--color-bg-card);
+  border-radius: 16px;
+  padding: 24px 20px;
+  box-shadow: var(--shadow-card);
+}
+
+.form-group {
+  margin-bottom: 24px;
+}
+.form-group:last-child {
+  margin-bottom: 0;
+}
+
+.form-label {
+  display: block;
+  font-size: 14px;
+  font-weight: 600;
+  color: var(--color-text-secondary);
+  margin-bottom: 10px;
+}
+
+/* Input fields */
+.form-input {
+  width: 100%;
+  height: 44px;
+  background: var(--color-bg-card);
+  border: 1px solid var(--color-border);
+  border-radius: 10px;
+  padding: 0 14px;
+  font-size: 15px;
+  color: var(--color-text-primary);
+  box-sizing: border-box;
+}
+.form-input:focus {
+  border-color: var(--color-brand);
+  box-shadow: 0 0 0 2px rgba(30, 58, 95, 0.1);
+}
+.input-placeholder {
+  color: var(--color-text-secondary);
+  font-size: 15px;
+}
+
+/* Picker */
+.picker-trigger {
+  display: flex;
+  align-items: center;
+}
+.text-placeholder {
+  color: var(--color-text-secondary);
+  font-size: 15px;
+}
+
+/* Relation type chips */
+.type-grid {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+}
+.type-chip {
+  padding: 10px 20px;
+  border: 1px solid var(--color-border);
+  border-radius: 10px;
+  background: var(--color-bg-card);
+  text-align: center;
+  flex: 0 0 auto;
+  min-width: 80px;
+}
+.type-chip:active {
+  transform: scale(0.97);
+}
+.type-chip.active {
+  border-color: var(--color-brand);
+  background: var(--color-brand);
+}
+.type-chip.active .chip-text {
+  color: var(--color-bg-card);
+}
+.chip-text {
+  font-size: 14px;
+  font-weight: 500;
+  color: var(--color-text-secondary);
+}
+
+/* Gender row */
+.gender-row {
+  display: flex;
+  gap: 12px;
+}
+.gender-option {
+  flex: 1;
+  padding: 10px 0;
+  border: 1px solid var(--color-border);
+  border-radius: 10px;
+  text-align: center;
+  background: var(--color-bg-card);
+}
+.gender-option:active {
+  transform: scale(0.97);
+}
+.gender-option.active {
+  border-color: var(--color-brand);
+  background: var(--color-brand);
+}
+.gender-option.active .gender-text {
+  color: var(--color-bg-card);
+}
+.gender-text {
+  font-size: 14px;
+  font-weight: 500;
+  color: var(--color-text-secondary);
+}
+
+/* Save button */
+.save-bar {
+  margin-top: 24px;
+  padding-bottom: 16px;
+}
+.btn-save {
+  width: 100%;
+  height: 48px;
+  background: var(--color-brand);
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.btn-save:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.btn-save.saving {
+  opacity: 0.7;
+  pointer-events: none;
+}
+.btn-save-text {
+  color: var(--color-bg-card);
+  font-size: 16px;
+  font-weight: 600;
+}
+</style>

+ 313 - 0
client/pages/relations/chart-compare.vue

@@ -0,0 +1,313 @@
+<template>
+  <view class="page-compare">
+    <!-- Loading state -->
+    <view v-if="loading" class="loading-state">
+      <view class="skeleton-chart" />
+      <view class="skeleton-chart" />
+    </view>
+
+    <template v-else>
+      <!-- Info header -->
+      <view class="compare-header">
+        <text class="compare-title">{{ relationName }} vs 我</text>
+        <text class="compare-subtitle">{{ relationTypeLabel(relationType) }}关系能量对比</text>
+      </view>
+
+      <!-- Dual charts -->
+      <view class="charts-row">
+        <view class="chart-wrapper">
+          <view class="chart-label">
+            <text class="chart-label-name">{{ relationName }}</text>
+            <text class="chart-label-date">{{ relationBirthDate }}</text>
+          </view>
+          <TriangleChart
+            :chartData="relationChart"
+            :birthYear="relationBirthYear"
+            :birthMonth="relationBirthMonth"
+            :birthDay="relationBirthDay"
+          />
+        </view>
+        <view class="chart-wrapper">
+          <view class="chart-label">
+            <text class="chart-label-name">我</text>
+            <text class="chart-label-date">{{ myBirthDate }}</text>
+          </view>
+          <TriangleChart
+            :chartData="myChart"
+            :birthYear="myBirthYear"
+            :birthMonth="myBirthMonth"
+            :birthDay="myBirthDay"
+          />
+        </view>
+      </view>
+
+      <!-- AI Interpretation button -->
+      <view class="action-bar">
+        <view class="btn-interpret" :class="{ interpreting: interpreting }" @click="handleInterpret">
+          <text class="btn-interpret-text">
+            {{ interpreting ? '解读中...' : interpretation ? '重新解读' : 'AI 关系能量解读' }}
+          </text>
+        </view>
+      </view>
+
+      <!-- Interpretation result -->
+      <view v-if="interpretation" class="interpretation-card">
+        <view class="interpretation-header">
+          <text class="interpretation-title">🔗 关系能量解读</text>
+          <text v-if="interpretDate" class="interpretation-date">{{ interpretDate }}</text>
+        </view>
+        <view class="interpretation-body">
+          <text class="interpretation-content">{{ interpretation }}</text>
+        </view>
+      </view>
+    </template>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { onLoad } from '@dcloudio/uni-app'
+import requestInstance from '@/utils/api'
+import TriangleChart from '@/components/TriangleChart.vue'
+
+const relationId = ref(null)
+const loading = ref(true)
+const relationName = ref('')
+const relationType = ref('')
+const relationBirthDate = ref('')
+const relationBirthYear = ref(0)
+const relationBirthMonth = ref(0)
+const relationBirthDay = ref(0)
+const relationChart = ref(null)
+const myChart = ref(null)
+const myBirthDate = ref('')
+const myBirthYear = ref(0)
+const myBirthMonth = ref(0)
+const myBirthDay = ref(0)
+const interpretation = ref('')
+const interpretDate = ref('')
+const interpreting = ref(false)
+
+const relationApi = {
+  get: (id) => requestInstance.post('/relation/get', { id }),
+  compare: (relationId) => requestInstance.post('/relation/compare', { relationId }),
+  interpret: (relationId) => requestInstance.post('/relation/compare/interpret', { relationId })
+}
+
+const myApi = {
+  profile: () => requestInstance.post('/profile/get', {})
+}
+
+const relationTypeMap = {
+  spouse: '夫妻',
+  parent_child: '亲子',
+  colleague: '同事',
+  friend: '朋友',
+  superior: '上下级'
+}
+
+function relationTypeLabel(type) {
+  return relationTypeMap[type] || type || '未知'
+}
+
+onLoad(async (query) => {
+  relationId.value = query?.id || null
+  if (!relationId.value) {
+    uni.showToast({ title: '缺少关系人信息', icon: 'none' })
+    setTimeout(() => uni.navigateBack(), 1500)
+    return
+  }
+  await fetchData(relationId.value)
+})
+
+async function fetchData(relationId) {
+  loading.value = true
+  try {
+    const [rel, profile] = await Promise.all([
+      relationApi.get(relationId),
+      myApi.profile()
+    ])
+
+    // Relation data
+    relationName.value = rel.name || '未知'
+    relationType.value = rel.relationType || ''
+    relationBirthDate.value = rel.birthDate || ''
+    relationChart.value = rel.chartData || null
+    if (rel.birthDate) {
+      const parts = rel.birthDate.split('-')
+      relationBirthYear.value = parseInt(parts[0]) || 0
+      relationBirthMonth.value = parseInt(parts[1]) || 0
+      relationBirthDay.value = parseInt(parts[2]) || 0
+    }
+
+    // Current user data
+    myChart.value = profile.chartData || null
+    if (profile.birthDate) {
+      myBirthDate.value = profile.birthDate
+      const parts = profile.birthDate.split('-')
+      myBirthYear.value = parseInt(parts[0]) || 0
+      myBirthMonth.value = parseInt(parts[1]) || 0
+      myBirthDay.value = parseInt(parts[2]) || 0
+    }
+
+    // Check if interpretation already exists
+    try {
+      const cmp = await relationApi.compare(relationId)
+      if (cmp && cmp.interpretation) {
+        interpretation.value = cmp.interpretation
+        interpretDate.value = cmp.updatedAt || cmp.createdAt || ''
+      }
+    } catch (e) {
+      // No existing comparison — user can trigger interpret
+    }
+  } catch (e) {
+    uni.showToast({ title: '加载数据失败', icon: 'none' })
+  } finally {
+    loading.value = false
+  }
+}
+
+async function handleInterpret() {
+  if (interpreting.value) return
+  interpreting.value = true
+  try {
+    const result = await relationApi.interpret(relationId.value)
+    if (result && result.interpretation) {
+      interpretation.value = result.interpretation
+      interpretDate.value = result.updatedAt || result.createdAt || ''
+    } else {
+      uni.showToast({ title: '解读失败,请重试', icon: 'none' })
+    }
+  } catch (e) {
+    uni.showToast({ title: '解读请求失败', icon: 'none' })
+  } finally {
+    interpreting.value = false
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.page-compare {
+  min-height: 100vh;
+  background: #F8F6F1;
+  padding: 16px;
+}
+
+.loading-state {
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+  padding-top: 20px;
+}
+.skeleton-chart {
+  height: 320px;
+  background: linear-gradient(90deg, #F0EEEA 25%, #F8F6F1 50%, #F0EEEA 75%);
+  background-size: 400px 100%;
+  animation: shimmer 1.5s ease-in-out infinite;
+  border-radius: 16px;
+}
+@keyframes shimmer {
+  0% { background-position: -200px 0; }
+  100% { background-position: 200px 0; }
+}
+
+.compare-header {
+  margin-bottom: 16px;
+}
+.compare-title {
+  font-size: 20px;
+  font-weight: 700;
+  color: #1A1A2E;
+  display: block;
+  margin-bottom: 4px;
+}
+.compare-subtitle {
+  font-size: 13px;
+  color: #A0AEC0;
+}
+
+.charts-row {
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+.chart-wrapper {
+  width: 100%;
+}
+.chart-label {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 8px;
+  padding: 0 4px;
+}
+.chart-label-name {
+  font-size: 14px;
+  font-weight: 600;
+  color: #1A1A2E;
+}
+.chart-label-date {
+  font-size: 12px;
+  color: #A0AEC0;
+}
+
+.action-bar {
+  margin-top: 20px;
+  margin-bottom: 16px;
+}
+.btn-interpret {
+  width: 100%;
+  height: 48px;
+  background: linear-gradient(135deg, #1E3A5F, darken(#1E3A5F, 4%));
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.btn-interpret:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.btn-interpret.interpreting {
+  opacity: 0.7;
+  pointer-events: none;
+}
+.btn-interpret-text {
+  color: #FFFFFF;
+  font-size: 16px;
+  font-weight: 600;
+}
+
+.interpretation-card {
+  background: #FFFFFF;
+  border-radius: 16px;
+  padding: 20px 16px;
+  box-shadow: 0 2px 12px rgba(26, 26, 46, 0.06);
+}
+.interpretation-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
+}
+.interpretation-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #1A1A2E;
+}
+.interpretation-date {
+  font-size: 12px;
+  color: #A0AEC0;
+}
+.interpretation-body {
+  background: #F8F6F1;
+  border-radius: 12px;
+  padding: 16px;
+}
+.interpretation-content {
+  font-size: 14px;
+  color: #4A5568;
+  line-height: 1.8;
+  white-space: pre-wrap;
+}
+</style>

+ 477 - 0
client/pages/relations/index.vue

@@ -0,0 +1,477 @@
+<template>
+  <view class="page-relations">
+    <!-- ========== Super Member Guard ========== -->
+    <view v-if="!isSuperMember" class="locked-screen">
+      <view class="locked-icon-wrap">
+        <text class="locked-icon">🔒</text>
+      </view>
+      <text class="locked-title">超级会员专属</text>
+      <text class="locked-desc">开通超级会员后可进行夫妻、亲子、同事等关系能量匹配分析</text>
+      <view class="locked-features">
+        <view class="locked-feature">🔗 关系能量合盘对比</view>
+        <view class="locked-feature">🔢 八星号码能量解读</view>
+        <view class="locked-feature">📊 AI 深度解读报告</view>
+      </view>
+      <view class="btn-upgrade" @click="goSubscribe">
+        <text class="btn-upgrade-text">开通超级会员 ¥1,314/年</text>
+      </view>
+      <view class="btn-back" @click="goBack">
+        <text class="btn-back-text">返回首页</text>
+      </view>
+    </view>
+
+    <!-- ========== Authorized Content ========== -->
+    <template v-else>
+      <!-- Upsell banner: annual → super member upgrade -->
+      <view v-if="showUpgradeBanner" class="upsell-banner">
+        <text class="upsell-banner__text">升级超级会员,解锁关系能量 + 八星号码分析</text>
+        <text class="upsell-banner__btn" @click="goSubscribe">升级</text>
+      </view>
+
+      <!-- Header bar -->
+      <view class="header-bar">
+        <text class="header-title">关系能量分析</text>
+        <view class="btn-add" @click="goAddRelation">
+          <text class="btn-add-text">+ 添加</text>
+        </view>
+      </view>
+
+      <!-- Loading state -->
+      <view v-if="loading" class="loading-state">
+        <view v-for="i in 3" :key="i" class="skeleton-card" />
+      </view>
+
+      <!-- Empty state -->
+      <view v-else-if="relations.length === 0" class="empty-state">
+        <view class="empty-icon-wrap">
+          <text class="empty-icon-symbol">+</text>
+        </view>
+        <text class="empty-text">暂无关系人</text>
+        <text class="empty-desc">添加关系人后,可进行夫妻、亲子、同事等关系能量匹配分析</text>
+        <view class="btn-empty-add" @click="goAddRelation">
+          <text class="btn-empty-add-text">添加关系人</text>
+        </view>
+      </view>
+
+      <!-- Relations list -->
+      <view v-else class="relations-list">
+        <text class="section-count">我的关系人 ({{ relations.length }})</text>
+        <view
+          v-for="item in relations"
+          :key="item.id"
+          class="relation-card"
+        >
+          <view class="card-header">
+            <view class="type-tag">
+              <text class="type-tag-text">{{ relationTypeLabel(item.relationType) }}</text>
+            </view>
+          </view>
+          <view class="card-body">
+            <text class="card-name">{{ item.name || '未知' }}</text>
+            <text class="card-birth">{{ item.birthDate || '' }}</text>
+          </view>
+          <view class="card-footer">
+            <view class="action-btn action-compare" @click="goCompare(item.id)">对比分析</view>
+            <view class="action-btn action-edit" @click="goEdit(item.id)">编辑</view>
+            <view class="action-btn action-delete" @click="handleDelete(item.id)">删除</view>
+          </view>
+        </view>
+      </view>
+    </template>
+  </view>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import { useUserStore } from '@/stores/user'
+import requestInstance from '@/utils/api'
+
+const userStore = useUserStore()
+const relations = ref([])
+const loading = ref(false)
+
+const isSuperMember = computed(() => {
+  if (!userStore.isVip) return false
+  return userStore.vipType === 'super_annual' || userStore.vipType === 'practitioner'
+})
+
+const showUpgradeBanner = computed(() => {
+  // Show upgrade prompt for annual members who aren't super yet
+  return userStore.isVip && userStore.vipType === 'annual'
+})
+
+const relationApi = {
+  list: (data) => requestInstance.post('/relation/list', data),
+  delete: (id) => requestInstance.post('/relation/delete', { id })
+}
+
+const relationTypeMap = {
+  spouse: '夫妻',
+  parent_child: '亲子',
+  colleague: '同事',
+  friend: '朋友',
+  superior: '上下级'
+}
+
+function relationTypeLabel(type) {
+  return relationTypeMap[type] || type || '未知'
+}
+
+onShow(() => {
+  if (userStore.isLoggedIn) {
+    userStore.fetchProfile()
+  }
+  if (isSuperMember.value) {
+    fetchRelations()
+  }
+})
+
+async function fetchRelations() {
+  loading.value = true
+  try {
+    relations.value = await relationApi.list({})
+  } catch (e) {
+    relations.value = []
+  } finally {
+    loading.value = false
+  }
+}
+
+function goAddRelation() {
+  uni.navigateTo({ url: '/pages/relations/add-relation' })
+}
+
+function goCompare(id) {
+  uni.navigateTo({ url: '/pages/relations/chart-compare?id=' + id })
+}
+
+function goEdit(id) {
+  uni.navigateTo({ url: '/pages/relations/add-relation?id=' + id })
+}
+
+function goSubscribe() {
+  uni.navigateTo({ url: '/pages/payment/index?product=super_member' })
+}
+
+function goBack() {
+  uni.switchTab({ url: '/pages/index/index' })
+}
+
+function handleDelete(id) {
+  uni.showModal({
+    title: '确认删除',
+    content: '删除后无法恢复,确定要删除该关系人吗?',
+    success: async (res) => {
+      if (res.confirm) {
+        try {
+          await relationApi.delete(id)
+          uni.showToast({ title: '删除成功', icon: 'success' })
+          fetchRelations()
+        } catch (e) {
+          uni.showToast({ title: '删除失败', icon: 'none' })
+        }
+      }
+    }
+  })
+}
+</script>
+
+<style scoped lang="scss">
+@import "@/styles/theme.scss";
+
+.page-relations {
+  min-height: 100vh;
+  background: var(--color-bg);
+  padding: 16px;
+}
+
+/* Header */
+.header-bar {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 20px;
+}
+.header-title {
+  font-size: 20px;
+  font-weight: 700;
+  color: var(--color-text-primary);
+  letter-spacing: 0.5px;
+}
+.btn-add {
+  background: var(--color-gold);
+  border-radius: 999px;
+  padding: 8px 18px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.btn-add:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.btn-add-text {
+  color: var(--color-bg-card);
+  font-size: 14px;
+  font-weight: 600;
+}
+
+/* Section count */
+.section-count {
+  display: block;
+  font-size: 13px;
+  color: var(--color-text-secondary);
+  margin-bottom: 12px;
+  padding-left: 2px;
+}
+
+/* Loading skeleton */
+.loading-state {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+.skeleton-card {
+  height: 120px;
+  background: linear-gradient(90deg, var(--color-bg-secondary) 25%, var(--color-bg) 50%, var(--color-bg-secondary) 75%);
+  background-size: 400px 100%;
+  animation: shimmer 1.5s ease-in-out infinite;
+  border-radius: 16px;
+}
+@keyframes shimmer {
+  0% { background-position: -200px 0; }
+  100% { background-position: 200px 0; }
+}
+
+/* Empty state */
+.empty-state {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding-top: 60px;
+}
+.empty-icon-wrap {
+  width: 64px;
+  height: 64px;
+  border-radius: 50%;
+  background: var(--color-bg-secondary);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 16px;
+}
+.empty-icon-symbol {
+  font-size: 28px;
+  color: var(--color-text-secondary);
+  font-weight: 300;
+}
+.empty-text {
+  font-size: 16px;
+  font-weight: 600;
+  color: var(--color-text-primary);
+  margin-bottom: 8px;
+}
+.empty-desc {
+  font-size: 13px;
+  color: var(--color-text-secondary);
+  text-align: center;
+  line-height: 1.6;
+  max-width: 260px;
+  margin-bottom: 24px;
+}
+.btn-empty-add {
+  background: var(--color-brand);
+  border-radius: 12px;
+  padding: 12px 32px;
+}
+.btn-empty-add:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.btn-empty-add-text {
+  color: var(--color-bg-card);
+  font-size: 15px;
+  font-weight: 600;
+}
+
+/* Relation cards */
+.relations-list {
+  display: flex;
+  flex-direction: column;
+}
+.relation-card {
+  background: var(--color-bg-card);
+  border-radius: 16px;
+  padding: 16px;
+  margin-bottom: 12px;
+  box-shadow: var(--shadow-card);
+}
+.card-header {
+  margin-bottom: 10px;
+}
+.type-tag {
+  display: inline-flex;
+  align-items: center;
+  background: #EBF2FA;
+  border-radius: 6px;
+  padding: 3px 10px;
+}
+.type-tag-text {
+  font-size: 12px;
+  font-weight: 500;
+  color: var(--color-brand);
+}
+.card-body {
+  margin-bottom: 12px;
+}
+.card-name {
+  display: block;
+  font-size: 16px;
+  font-weight: 600;
+  color: var(--color-text-primary);
+  margin-bottom: 4px;
+}
+.card-birth {
+  display: block;
+  font-size: 13px;
+  color: var(--color-text-secondary);
+}
+.card-footer {
+  display: flex;
+  gap: 10px;
+  border-top: 1px solid var(--color-border);
+  padding-top: 12px;
+}
+.action-btn {
+  font-size: 13px;
+  font-weight: 500;
+  padding: 6px 14px;
+  border-radius: 8px;
+  flex: 1;
+  text-align: center;
+}
+.action-btn:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.action-compare {
+  background: var(--color-brand);
+  color: var(--color-bg-card);
+}
+.action-edit {
+  background: var(--color-bg-card);
+  border: 1px solid var(--color-border);
+  color: var(--color-text-secondary);
+}
+.action-delete {
+  background: var(--color-bg-card);
+  border: 1px solid var(--color-border);
+  color: #D94A4A;
+}
+
+/* ========== Upsell Banner ========== */
+.upsell-banner {
+  background: linear-gradient(135deg, var(--color-brand), darken(var(--color-brand), 4%));
+  border-radius: 14px;
+  padding: 14px 16px;
+  margin-bottom: 16px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  gap: 10px;
+}
+.upsell-banner__text {
+  font-size: 13px;
+  color: rgba(255, 255, 255, 0.85);
+  flex: 1;
+  line-height: 1.4;
+}
+.upsell-banner__btn {
+  flex-shrink: 0;
+  background: var(--color-gold);
+  color: var(--color-brand);
+  font-size: 13px;
+  font-weight: 700;
+  padding: 8px 16px;
+  border-radius: 8px;
+}
+.upsell-banner__btn:active {
+  transform: scale(0.97);
+}
+
+/* ========== Locked Screen ========== */
+.locked-screen {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding-top: 80px;
+  padding-bottom: 40px;
+}
+.locked-icon-wrap {
+  width: 80px;
+  height: 80px;
+  border-radius: 50%;
+  background: var(--color-bg-secondary);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 20px;
+}
+.locked-icon {
+  font-size: 36px;
+}
+.locked-title {
+  font-size: 20px;
+  font-weight: 700;
+  color: var(--color-text-primary);
+  margin-bottom: 10px;
+}
+.locked-desc {
+  font-size: 14px;
+  color: var(--color-text-secondary);
+  text-align: center;
+  line-height: 1.6;
+  max-width: 280px;
+  margin-bottom: 28px;
+}
+.locked-features {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+  margin-bottom: 32px;
+}
+.locked-feature {
+  font-size: 15px;
+  color: var(--color-text-secondary);
+}
+.btn-upgrade {
+  width: 80%;
+  height: 50px;
+  background: linear-gradient(135deg, var(--color-brand), darken(var(--color-brand), 4%));
+  border-radius: 14px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 16px;
+}
+.btn-upgrade:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.btn-upgrade-text {
+  color: var(--color-bg-card);
+  font-size: 17px;
+  font-weight: 700;
+}
+.btn-back {
+  padding: 10px 20px;
+}
+.btn-back:active {
+  opacity: 0.7;
+}
+.btn-back-text {
+  font-size: 14px;
+  color: var(--color-text-secondary);
+}
+</style>

+ 375 - 0
client/pages/relations/number-analysis.vue

@@ -0,0 +1,375 @@
+<template>
+  <view class="page-number-analysis">
+    <!-- ========== Phone Input Section ========== -->
+    <view class="input-card">
+      <text class="input-label">手机号码</text>
+      <view class="input-row">
+        <input
+          v-model="phoneNumber"
+          class="phone-input"
+          type="number"
+          maxlength="11"
+          placeholder="请输入11位手机号码"
+          placeholder-class="input-placeholder"
+          @confirm="handleAnalyze"
+        />
+        <view class="btn-analyze" :class="{ analyzing: analyzing }" @click="handleAnalyze">
+          <text class="btn-analyze-text">{{ analyzing ? '分析中' : '分析' }}</text>
+        </view>
+      </view>
+    </view>
+
+    <!-- ========== Star Combinations Result ========== -->
+    <view v-if="starCombinations.length > 0" class="result-section">
+      <view class="section-header">
+        <text class="section-title">🔢 八星数组</text>
+      </view>
+      <view class="star-grid">
+        <view
+          v-for="(star, index) in starCombinations"
+          :key="index"
+          class="star-card"
+          :class="'star-type-' + star.type"
+        >
+          <view class="star-card-header">
+            <text class="star-pair">{{ star.pair }}</text>
+            <text class="star-name">{{ star.name }}</text>
+          </view>
+          <view class="star-card-body">
+            <text class="star-energy">{{ star.energy }}</text>
+            <text class="star-desc">{{ star.description || '' }}</text>
+          </view>
+        </view>
+      </view>
+    </view>
+
+    <!-- ========== AI Summary ========== -->
+    <view v-if="summary" class="summary-card">
+      <view class="summary-header">
+        <text class="summary-title">🤖 AI 综合解读</text>
+        <text v-if="summaryDate" class="summary-date">{{ summaryDate }}</text>
+      </view>
+      <view class="summary-body">
+        <text class="summary-content">{{ summary }}</text>
+      </view>
+    </view>
+
+    <!-- ========== Analysis History ========== -->
+    <view v-if="history.length > 0" class="history-section">
+      <view class="section-header">
+        <text class="section-title">📋 历史分析</text>
+      </view>
+      <view
+        v-for="item in history"
+        :key="item.id"
+        class="history-card"
+        @click="loadHistory(item)"
+      >
+        <text class="history-phone">{{ maskPhone(item.phoneNumber) }}</text>
+        <view class="history-meta">
+          <text class="history-date">{{ formatDate(item.createdAt) }}</text>
+          <text v-if="item.summary" class="history-status">已解读</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { onShow } from '@dcloudio/uni-app'
+import requestInstance from '@/utils/api'
+
+const phoneNumber = ref('')
+const analyzing = ref(false)
+const starCombinations = ref([])
+const summary = ref('')
+const summaryDate = ref('')
+const history = ref([])
+
+const analysisApi = {
+  analyze: (data) => requestInstance.post('/number-analysis/analyze', data),
+  list: (data) => requestInstance.post('/number-analysis/list', data),
+  get: (id) => requestInstance.post('/number-analysis/detail', { id })
+}
+
+onShow(() => {
+  fetchHistory()
+})
+
+async function fetchHistory() {
+  try {
+    history.value = await analysisApi.list({})
+  } catch (e) {
+    history.value = []
+  }
+}
+
+async function handleAnalyze() {
+  const num = phoneNumber.value.trim()
+  if (num.length < 7) {
+    uni.showToast({ title: '请输入至少7位数字', icon: 'none' })
+    return
+  }
+  if (analyzing.value) return
+
+  analyzing.value = true
+  try {
+    const result = await analysisApi.analyze({ phoneNumber: num })
+    if (result) {
+      starCombinations.value = result.starCombinations || []
+      summary.value = result.summary || ''
+      summaryDate.value = result.createdAt || ''
+    }
+    // Refresh history
+    fetchHistory()
+  } catch (e) {
+    uni.showToast({ title: '分析失败,请重试', icon: 'none' })
+  } finally {
+    analyzing.value = false
+  }
+}
+
+function loadHistory(item) {
+  phoneNumber.value = item.phoneNumber || ''
+  if (item.starCombinations) {
+    try {
+      starCombinations.value = typeof item.starCombinations === 'string'
+        ? JSON.parse(item.starCombinations)
+        : item.starCombinations
+    } catch (e) {
+      starCombinations.value = []
+    }
+  } else {
+    starCombinations.value = []
+  }
+  summary.value = item.summary || ''
+  summaryDate.value = item.createdAt || ''
+}
+
+function maskPhone(phone) {
+  if (!phone) return ''
+  if (phone.length >= 7) {
+    return phone.slice(0, 3) + '****' + phone.slice(-4)
+  }
+  return phone
+}
+
+function formatDate(dateStr) {
+  if (!dateStr) return ''
+  return dateStr.slice(0, 10)
+}
+</script>
+
+<style scoped lang="scss">
+.page-number-analysis {
+  min-height: 100vh;
+  background: #F8F6F1;
+  padding: 16px;
+}
+
+/* ========== Input Card ========== */
+.input-card {
+  background: #FFFFFF;
+  border-radius: 16px;
+  padding: 20px;
+  box-shadow: 0 2px 12px rgba(26, 26, 46, 0.06);
+  margin-bottom: 16px;
+}
+.input-label {
+  display: block;
+  font-size: 14px;
+  font-weight: 600;
+  color: #4A5568;
+  margin-bottom: 12px;
+}
+.input-row {
+  display: flex;
+  gap: 12px;
+}
+.phone-input {
+  flex: 1;
+  height: 48px;
+  border: 1px solid #E2E8F0;
+  border-radius: 12px;
+  padding: 0 14px;
+  font-size: 18px;
+  color: #1A1A2E;
+  background: #FFFFFF;
+  box-sizing: border-box;
+}
+.phone-input:focus {
+  border-color: #1E3A5F;
+  box-shadow: 0 0 0 2px rgba(30, 58, 95, 0.1);
+}
+.input-placeholder {
+  color: #A0AEC0;
+  font-size: 16px;
+}
+.btn-analyze {
+  flex-shrink: 0;
+  height: 48px;
+  padding: 0 24px;
+  background: #1E3A5F;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.btn-analyze:active {
+  transform: scale(0.97);
+  opacity: 0.9;
+}
+.btn-analyze.analyzing {
+  opacity: 0.7;
+  pointer-events: none;
+}
+.btn-analyze-text {
+  color: #FFFFFF;
+  font-size: 16px;
+  font-weight: 600;
+}
+
+/* ========== Sections ========== */
+.result-section,
+.history-section {
+  margin-bottom: 16px;
+}
+.section-header {
+  margin-bottom: 12px;
+}
+.section-title {
+  font-size: 17px;
+  font-weight: 600;
+  color: #1F2937;
+}
+
+/* ========== Star Grid ========== */
+.star-grid {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+.star-card {
+  background: #FFFFFF;
+  border-radius: 14px;
+  padding: 14px 16px;
+  box-shadow: 0 2px 12px rgba(26, 26, 46, 0.06);
+  border-left: 4px solid #A0AEC0;
+}
+.star-card.star-type-ji { border-left-color: #D94A4A; }
+.star-card.star-type-huo { border-left-color: #E8A238; }
+.star-card.star-type-yan { border-left-color: #4A90D9; }
+.star-card.star-type-tian { border-left-color: #2D8B67; }
+.star-card.star-type-sheng { border-left-color: #7B6FA0; }
+.star-card.star-type-ju { border-left-color: #C9A84C; }
+.star-card.star-type-fu { border-left-color: #4A6FA5; }
+.star-card.star-type-jue { border-left-color: #B85C3A; }
+
+.star-card-header {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 6px;
+}
+.star-pair {
+  font-size: 20px;
+  font-weight: 700;
+  color: #1A1A2E;
+}
+.star-name {
+  font-size: 14px;
+  font-weight: 500;
+  color: #4A5568;
+}
+.star-card-body {
+  padding-left: 2px;
+}
+.star-energy {
+  font-size: 13px;
+  font-weight: 600;
+  color: #1E3A5F;
+  display: block;
+  margin-bottom: 2px;
+  text-transform: capitalize;
+}
+.star-desc {
+  font-size: 12px;
+  color: #A0AEC0;
+  line-height: 1.5;
+  display: block;
+}
+
+/* ========== Summary Card ========== */
+.summary-card {
+  background: #FFFFFF;
+  border-radius: 16px;
+  padding: 20px 16px;
+  box-shadow: 0 2px 12px rgba(26, 26, 46, 0.06);
+  margin-bottom: 16px;
+}
+.summary-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 12px;
+}
+.summary-title {
+  font-size: 16px;
+  font-weight: 600;
+  color: #1A1A2E;
+}
+.summary-date {
+  font-size: 12px;
+  color: #A0AEC0;
+}
+.summary-body {
+  background: #F8F6F1;
+  border-radius: 12px;
+  padding: 16px;
+}
+.summary-content {
+  font-size: 14px;
+  color: #4A5568;
+  line-height: 1.8;
+  white-space: pre-wrap;
+}
+
+/* ========== History ========== */
+.history-card {
+  background: #FFFFFF;
+  border-radius: 14px;
+  padding: 14px 16px;
+  margin-bottom: 10px;
+  box-shadow: 0 2px 12px rgba(26, 26, 46, 0.06);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.history-card:active {
+  transform: scale(0.98);
+  opacity: 0.9;
+}
+.history-phone {
+  font-size: 16px;
+  font-weight: 600;
+  color: #1A1A2E;
+}
+.history-meta {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.history-date {
+  font-size: 12px;
+  color: #A0AEC0;
+}
+.history-status {
+  font-size: 11px;
+  color: #059669;
+  background: #D1FAE5;
+  padding: 2px 8px;
+  border-radius: 10px;
+  font-weight: 500;
+}
+</style>

+ 3 - 3
client/pages/subscribe/index.vue

@@ -13,7 +13,7 @@
       <view v-if="visiblePlans.length === 0" class="already-vip">
         <text class="already-vip__icon">✓</text>
         <text class="already-vip__title">您已是能量师</text>
-        <text class="already-vip__desc">解锁了全部功能,可在盘页使用 AI 解读</text>
+        <text class="already-vip__desc">解锁了全部功能,可在能量盘页使用 AI 解读</text>
       </view>
 
       <view v-show="visiblePlans.length > 0" class="plans-section">
@@ -62,7 +62,7 @@
           </view>
           <view class="plan-features">
             <text class="feature">✦ 包含 C 端全部权益</text>
-            <text class="feature">✦ 无限盘生成</text>
+            <text class="feature">✦ 无限能量盘生成</text>
             <text class="feature">✦ AI 五区完整解读,随问随答</text>
             <text class="feature">✦ 全部历史记录永久保存</text>
             <text class="feature">✦ 推广佣金 — 固定 ¥500/人 + 二级 ¥100/人</text>
@@ -113,7 +113,7 @@ const pricing = ref({
 })
 
 const compareData = [
-  { label: '盘生成', free: '3次/天', c: '3次/天', pro: '不限' },
+  { label: '能量盘生成', free: '3次/天', c: '3次/天', pro: '不限' },
   { label: 'AI 解读', free: '3轮/天', c: '无限次', pro: '无限次' },
   { label: '历史记录', free: '7天', c: '永久', pro: '永久' },
   { label: '推广佣金', free: '--', c: '40%+5%', pro: '¥500+¥100/人' },

+ 12 - 10
client/pages/withdraw/index.vue

@@ -98,14 +98,16 @@ function formatMoney(cents) {
 </script>
 
 <style scoped lang="scss">
+@import "@/styles/theme.scss";
+
 .page-withdraw {
   min-height: 100vh;
-  background: #F8F6F1;
+  background: var(--color-bg);
   padding: 16px;
 }
 
 .balance-card {
-  background: linear-gradient(135deg, #1E3A5F, #2D4A7A);
+  background: linear-gradient(135deg, var(--color-brand), #2D4A7A);
   border-radius: 14px;
   padding: 28px 20px;
   text-align: center;
@@ -119,7 +121,7 @@ function formatMoney(cents) {
 .balance-amount {
   font-size: 40px;
   font-weight: 700;
-  color: #C9A84C;
+  color: var(--color-gold);
   display: block;
   margin-top: 6px;
 }
@@ -133,14 +135,14 @@ function formatMoney(cents) {
 .input-label {
   font-size: 14px;
   font-weight: 600;
-  color: #1A1A2E;
+  color: var(--color-text-primary);
   display: block;
   margin-bottom: 12px;
 }
 .input-row {
   display: flex;
   align-items: center;
-  border: 1px solid #E2E8F0;
+  border: 1px solid var(--color-border);
   border-radius: 10px;
   padding: 0 14px;
   height: 48px;
@@ -148,7 +150,7 @@ function formatMoney(cents) {
 .input-prefix {
   font-size: 20px;
   font-weight: 700;
-  color: #1E3A5F;
+  color: var(--color-brand);
   margin-right: 6px;
 }
 .amount-input {
@@ -156,7 +158,7 @@ function formatMoney(cents) {
   height: 100%;
   font-size: 22px;
   font-weight: 600;
-  color: #1A1A2E;
+  color: var(--color-text-primary);
 }
 .amount-hints {
   display: flex;
@@ -165,7 +167,7 @@ function formatMoney(cents) {
 }
 .hint {
   font-size: 12px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
 }
 .hint-link {
   font-size: 12px;
@@ -188,13 +190,13 @@ function formatMoney(cents) {
 .rules-title {
   font-size: 13px;
   font-weight: 600;
-  color: #1A1A2E;
+  color: var(--color-text-primary);
   display: block;
   margin-bottom: 8px;
 }
 .rule {
   font-size: 12px;
-  color: #A0AEC0;
+  color: var(--color-text-secondary);
   display: block;
   padding: 3px 0;
   line-height: 1.5;

binární
client/static/analysis-active.png


binární
client/static/analysis.png


binární
client/static/relations-active.png


binární
client/static/relations.png


+ 88 - 0
client/stores/theme.js

@@ -0,0 +1,88 @@
+import { defineStore } from 'pinia'
+import { ref, watch } from 'vue'
+
+export const useThemeStore = defineStore('theme', () => {
+  // State
+  const theme = ref('dark') // 'dark' | 'light'
+
+  // Load persisted theme on init
+  function init() {
+    try {
+      const saved = uni.getStorageSync('theme')
+      if (saved === 'light' || saved === 'dark') {
+        theme.value = saved
+      } else {
+        // Follow system preference if available
+        try {
+          const sysInfo = uni.getSystemInfoSync()
+          if (sysInfo.theme && sysInfo.theme === 'light') {
+            theme.value = 'light'
+          }
+        } catch (e) {
+          // Default to dark (brand identity)
+        }
+      }
+    } catch (e) {
+      theme.value = 'dark'
+    }
+    applyTheme(theme.value)
+  }
+
+  // Toggle theme
+  function toggle() {
+    theme.value = theme.value === 'dark' ? 'light' : 'dark'
+    applyTheme(theme.value)
+    persistTheme(theme.value)
+  }
+
+  // Set specific theme
+  function setTheme(t) {
+    if (t !== 'dark' && t !== 'light') return
+    theme.value = t
+    applyTheme(t)
+    persistTheme(t)
+  }
+
+  // Apply to DOM
+  function applyTheme(t) {
+    try {
+      const pages = getCurrentPages()
+      const curPage = pages[pages.length - 1]
+      if (curPage && curPage.$page && curPage.$page.$el) {
+        curPage.$page.$el.setAttribute('data-theme', t)
+      }
+    } catch (e) {
+      // Silent fallback
+    }
+  }
+
+  // Persist to storage
+  function persistTheme(t) {
+    try {
+      uni.setStorageSync('theme', t)
+    } catch (e) {
+      // Silent
+    }
+  }
+
+  // Listen for system theme changes
+  function watchSystemTheme() {
+    try {
+      uni.onThemeChange((res) => {
+        // Optional: auto-follow system
+        // theme.value = res.theme
+        // applyTheme(res.theme)
+      })
+    } catch (e) {
+      // onThemeChange not supported on this platform
+    }
+  }
+
+  return {
+    theme,
+    init,
+    toggle,
+    setTheme,
+    watchSystemTheme
+  }
+})

+ 219 - 0
client/styles/theme.scss

@@ -0,0 +1,219 @@
+/* ============================================
+   Theme System — CSS Custom Properties
+   ============================================
+   Two themes: dark (universe) and light (warm).
+   Deep-cosmos pages (index/chart/payment/subscribe)
+   always use dark palette via explicit page styles.
+   All other pages use CSS variables below.
+   ============================================ */
+
+/* ----- Default: Dark Theme (Universe) ----- */
+:root {
+  // Backgrounds
+  --color-bg: #0c0a1a;
+  --color-bg-secondary: #120d28;
+  --color-bg-tertiary: #0f0c1e;
+  --color-bg-card: rgba(255, 255, 255, 0.06);
+  --color-bg-card-hover: rgba(255, 255, 255, 0.1);
+  --color-bg-input: rgba(255, 255, 255, 0.1);
+  --color-bg-tag: rgba(255, 255, 255, 0.08);
+  --color-bg-overlay: rgba(12, 10, 26, 0.85);
+
+  // Text
+  --color-text-primary: #FFFFFF;
+  --color-text-secondary: #A0AEC0;
+  --color-text-tertiary: rgba(255, 255, 255, 0.5);
+  --color-text-link: #60A5FA;
+  --color-text-gold: #C9A84C;
+
+  // Brand
+  --color-brand: #1E3A5F;
+  --color-brand-light: #2C5282;
+  --color-gold: #C9A84C;
+  --color-gold-bg: rgba(201, 168, 76, 0.15);
+  --color-gold-light: #FEF3C7;
+
+  // Borders
+  --color-border: rgba(255, 255, 255, 0.1);
+  --color-border-light: rgba(255, 255, 255, 0.06);
+  --color-border-focus: rgba(201, 168, 76, 0.5);
+
+  // Status
+  --color-success: #10b981;
+  --color-success-bg: rgba(16, 185, 129, 0.15);
+  --color-warning: #fbbf24;
+  --color-warning-bg: rgba(251, 191, 36, 0.15);
+  --color-danger: #ef4444;
+  --color-danger-bg: rgba(239, 68, 68, 0.15);
+  --color-info: #3B82F6;
+  --color-info-bg: rgba(59, 130, 246, 0.15);
+
+  // UI Elements
+  --color-tab-active: #1E3A5F;
+  --color-tab-inactive: #A0AEC0;
+  --color-nav-bg: #1E3A5F;
+  --color-nav-text: #FFFFFF;
+  --color-btn-primary: #1E3A5F;
+  --color-btn-primary-text: #FFFFFF;
+  --color-btn-gold: #C9A84C;
+  --color-btn-gold-text: #1A1A2E;
+  --color-badge-super: linear-gradient(135deg, #06b6d4, #0891b2);
+  --color-badge-practitioner: linear-gradient(135deg, #7c3aed, #6d28d9);
+  --color-badge-vip: linear-gradient(135deg, #C9A84C, #A0843C);
+
+  // Typography
+  --font-xs: 12px;
+  --font-sm: 14px;
+  --font-base: 16px;
+  --font-lg: 18px;
+  --font-xl: 24px;
+  --font-2xl: 32px;
+
+  // Spacing
+  --spacing-xs: 4px;
+  --spacing-sm: 8px;
+  --spacing-md: 16px;
+  --spacing-lg: 24px;
+  --spacing-xl: 32px;
+
+  // Border radius
+  --radius-xs: 4px;
+  --radius-sm: 6px;
+  --radius-md: 10px;
+  --radius-lg: 16px;
+  --radius-xl: 24px;
+  --radius-full: 999px;
+
+  // Shadows
+  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
+  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
+  --shadow-lg: var(--shadow-card);
+  --shadow-card: 0 4px 20px rgba(0, 0, 0, 0.3);
+  --shadow-modal: 0 10px 40px rgba(0, 0, 0, 0.5);
+  --shadow-btn: 0 4px 15px rgba(30, 58, 95, 0.4);
+  --shadow-gold: 0 4px 15px rgba(201, 168, 76, 0.3);
+
+  // Z-index
+  --z-tabbar: 100;
+  --z-navbar: 90;
+  --z-modal: 200;
+  --z-toast: 300;
+
+  // Transitions
+  --transition-fast: 0.15s ease;
+  --transition-normal: 0.3s ease;
+  --transition-slow: 0.5s ease;
+}
+
+/* ----- Light Theme (Warm) ----- */
+[data-theme="light"] {
+  --color-bg: #F8F6F1;
+  --color-bg-secondary: #F0EDE6;
+  --color-bg-tertiary: #E8E5DE;
+  --color-bg-card: #FFFFFF;
+  --color-bg-card-hover: #F7F8FC;
+  --color-bg-input: #F3F4F6;
+  --color-bg-tag: #F3F4F6;
+  --color-bg-overlay: rgba(248, 246, 241, 0.9);
+
+  --color-text-primary: #1A1A2E;
+  --color-text-secondary: #4A5568;
+  --color-text-tertiary: #9CA3AF;
+  --color-text-link: #2563EB;
+  --color-text-gold: #92400E;
+
+  --color-brand: #1E3A5F;
+  --color-brand-light: #1E3A5F;
+  --color-gold: #C9A84C;
+  --color-gold-bg: #FEF3C7;
+  --color-gold-light: #FEF3C7;
+
+  --color-border: #E2E8F0;
+  --color-border-light: #F3F4F6;
+  --color-border-focus: rgba(201, 168, 76, 0.6);
+
+  --color-success: #059669;
+  --color-success-bg: #D1FAE5;
+  --color-warning: #D97706;
+  --color-warning-bg: #FEF3C7;
+  --color-danger: #DC2626;
+  --color-danger-bg: #FEE2E2;
+  --color-info: #2563EB;
+  --color-info-bg: #DBEAFE;
+
+  --color-tab-active: #1E3A5F;
+  --color-tab-inactive: #A0AEC0;
+  --color-nav-bg: #1E3A5F;
+  --color-nav-text: #FFFFFF;
+  --color-btn-primary: #1E3A5F;
+  --color-btn-primary-text: #FFFFFF;
+  --color-btn-gold: #C9A84C;
+  --color-btn-gold-text: #1A1A2E;
+
+  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.06);
+  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
+  --shadow-card: 0 2px 12px rgba(0, 0, 0, 0.06);
+  --shadow-modal: 0 8px 30px rgba(0, 0, 0, 0.1);
+  --shadow-btn: 0 4px 12px rgba(30, 58, 95, 0.2);
+  --shadow-gold: 0 4px 12px rgba(201, 168, 76, 0.2);
+}
+
+/* ============================================
+   Number Energy Colors (single source of truth)
+   ============================================ */
+$num-colors: (
+  1: #D94A4A,
+  2: #4A90D9,
+  3: #E8A238,
+  4: #2D8B67,
+  5: #D4A017,
+  6: #7B6FA0,
+  7: #4A6FA5,
+  8: #C9A84C,
+  9: #B85C3A
+);
+
+@function num-color($n) {
+  @return map-get($num-colors, $n);
+}
+
+// Export as CSS custom properties for JS access
+:root {
+  --num-1: #D94A4A;
+  --num-2: #4A90D9;
+  --num-3: #E8A238;
+  --num-4: #2D8B67;
+  --num-5: #D4A017;
+  --num-6: #7B6FA0;
+  --num-7: #4A6FA5;
+  --num-8: #C9A84C;
+  --num-9: #B85C3A;
+}
+
+/* ============================================
+   SCSS Variable Mapping (backward compatibility)
+   New code should use var(--xxx) directly.
+   ============================================ */
+$primary-color: var(--color-brand);
+$success-color: var(--color-success);
+$warning-color: var(--color-warning);
+$danger-color: var(--color-danger);
+$text-primary: var(--color-text-primary);
+$text-secondary: var(--color-text-secondary);
+$bg-color: var(--color-bg);
+$bg-color-secondary: var(--color-bg-secondary);
+$card-bg: var(--color-bg-card);
+$border-color: var(--color-border);
+$gold: var(--color-gold);
+$font-xs: var(--font-xs);
+$font-sm: var(--font-sm);
+$font-base: var(--font-base);
+$font-lg: var(--font-lg);
+$font-xl: var(--font-xl);
+$radius-sm: var(--radius-sm);
+$radius-md: var(--radius-md);
+$radius-lg: var(--radius-lg);
+$radius-full: var(--radius-full);
+$shadow-sm: var(--shadow-sm);
+$shadow-md: var(--shadow-md);
+$shadow-lg: var(--shadow-card);

+ 26 - 35
client/uni.scss

@@ -1,41 +1,32 @@
-/* Color variables */
-$primary-color: #3B82F6;
-$success-color: #10B981;
-$warning-color: #F59E0B;
-$danger-color: #EF4444;
-$text-primary: #1F2937;
-$text-secondary: #6B7280;
-$bg-color: #F8FAFC;
-$card-bg: #FFFFFF;
-$border-color: #E5E7EB;
+/* ============================================
+   uni.scss — Global SCSS Variables
+   
+   All colors are now CSS custom properties
+   defined in styles/theme.scss.
+   Only structural tokens remain here.
+   ============================================ */
 
-/* Font sizes */
-$font-xs: 12px;
-$font-sm: 14px;
-$font-base: 16px;
-$font-lg: 18px;
-$font-xl: 24px;
+// Import theme system
+@import './styles/theme.scss';
 
-/* Spacing */
+/* Spacing (unchanged) */
 $spacing-xs: 4px;
 $spacing-sm: 8px;
-$spacing-md: 16px;
-$spacing-lg: 24px;
-$spacing-xl: 32px;
+$spacing-md: var(--spacing-md);
+$spacing-lg: var(--spacing-lg);
+$spacing-xl: var(--spacing-xl);
 
-/* Border radius */
-$radius-sm: 6px;
-$radius-md: 10px;
-$radius-lg: 16px;
-$radius-full: 999px;
+/* Border radius (unchanged) */
+$radius-xs: var(--radius-xs);
+$radius-sm: var(--radius-sm);
+$radius-md: var(--radius-md);
+$radius-lg: var(--radius-lg);
+$radius-xl: var(--radius-xl);
+$radius-full: var(--radius-full);
 
-/* Triangle chart colors */
-$gold: #D4A847;
-$blue: #3B82F6;
-$green: #10B981;
-$line-color: #CBD5E1;
-
-/* Shadows */
-$shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
-$shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
-$shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1);
+/* Typography (unchanged) */
+$font-xs: var(--font-xs);
+$font-sm: var(--font-sm);
+$font-base: var(--font-base);
+$font-lg: var(--font-lg);
+$font-xl: var(--font-xl);

+ 17 - 1
client/utils/api.js

@@ -102,7 +102,7 @@ export const payApi = {
 
 export const pricingApi = {
   current: () => requestInstance.post('/pricing/current', {}),
-  upgrade: () => requestInstance.post('/pricing/upgrade', {})
+  upgrade: (productType) => requestInstance.post('/pricing/upgrade', { productType })
 }
 
 export const planApi = {
@@ -145,6 +145,22 @@ export const annotationApi = {
   deleteTag: (id) => requestInstance.post('/annotation/tag/delete', { id })
 }
 
+export const relationApi = {
+  list: () => requestInstance.post('/relation/list', {}),
+  create: (data) => requestInstance.post('/relation/create', data),
+  update: (data) => requestInstance.post('/relation/update', data),
+  delete: (id) => requestInstance.post('/relation/delete', { id }),
+  get: (id) => requestInstance.post('/relation/get', { id }),
+  compare: (relationId) => requestInstance.post('/relation/compare', { relationId }),
+  interpret: (relationId) => requestInstance.post('/relation/compare/interpret', { relationId })
+}
+
+export const numberAnalysisApi = {
+  analyze: (data) => requestInstance.post('/number-analysis/analyze', data),
+  list: () => requestInstance.post('/number-analysis/list', {}),
+  detail: (id) => requestInstance.post('/number-analysis/detail', { id })
+}
+
 export const commissionApi = {
   list: () => requestInstance.post('/commission/list', {}),
   total: () => requestInstance.post('/commission/total', {}),

+ 17 - 17
docs/1.0产品对齐方案.md

@@ -17,7 +17,7 @@
 | 产品名称 | 数字心理学·全生命周期AI赋能系统 | ✅ 数字心理学AI智能体 |
 | 目标用户 | C端大众 + B端从业者 | ✅ **第一阶段从能量师切入**,C端通过能量师链接引流 |
 | 1.0 定位 | 免费锁客版 | ✅ **B端收费作为核心**,1.0 不能完全免费 |
-| 功能范围 | 少儿+成人6大领域 | ✅ **盘+AI五区+少儿板块**,其余Phase 2 |
+| 功能范围 | 少儿+成人6大领域 | ✅ **能量盘+AI五区+少儿板块**,其余Phase 2 |
 | B端收费 | 能量师年费 | ✅ **¥1,914/年**(种子价¥1,314/首100人) |
 | C端收费 | 个人订阅 | ✅ **¥299/年**(能量师分销40%+5%+平台55%) |
 | 合作模式 | — | ✅ **技术方+运营方**:B端技术方固定¥998/人,剩余归运营方(含佣金);C端40%技术+15%运营 |
@@ -41,7 +41,7 @@
 ```
 1.0 第一阶段(当前开发)
   ├── 用户角色:普通用户(C端) + 能量师(B端)
-  │   ├── 普通用户:通过能量师分享的小程序进入,免费体验
+  │   ├── 普通用户:通过能量师分享的小程序进入,免费体验能量
   │   │               购买C端年费(¥299)获得完整解读
   │   └── 能量师:付费订阅(¥1,314-1,914/年)获得AI工具
   │                 分享小程序给客户 → 建立客户关系
@@ -66,8 +66,8 @@
 
 ```
 能量师付费订阅(¥1,314-1,914/年)
-  ├── 获得 AI 辅助工具(盘生成+AI解读+少儿板块)
-  │       → 为线下/线上的客户快速出盘解读
+  ├── 获得 AI 辅助工具(能量盘生成+AI解读+少儿板块)
+  │       → 为线下/线上的客户快速出能量盘解读
   ├── 获得推广工具(专属小程序码)
   │       → 分享给客户 → 客户绑定到能量师名下
   │       → 查看客户与AI的互动记录
@@ -85,10 +85,10 @@
 
 | 模块 | 功能 | 说明 |
 |------|------|------|
-| 三角形盘生成 | 输入姓名+生日 → 3秒出图 | Canvas 可视化,五区色块区分 |
+| 三角形能量盘生成 | 输入姓名+生日 → 3秒出图 | Canvas 可视化,五区色块区分 |
 | AI 五区解读 | 主性格+父源+母源+左区+中区+右区 | LLM 自动生成 |
 | 少儿解读 | 核心性格+天赋潜能+学习判定 | 能量师增值服务 |
-| 盘分享/导出 | 分享图片 + PDF 导出 | 含完整解读 |
+| 能量盘分享/导出 | 分享图片 + PDF 导出 | 含完整解读 |
 | C端年费订阅 | 普通用户¥299/年 | 完整解读+无限使用 |
 | B端年费订阅 | 能量师¥1,314-1,914/年 | 含少儿板块+CRM+分销 |
 | 专属推广码 | 每个能量师唯一小程序码 | 客户扫码绑定关系 |
@@ -117,8 +117,8 @@
 |------|------|------|
 | **能量师年费(标准价)** | **¥1,914/年** | 含AI工具+少儿+CRM+分销 |
 | **能量师年费(种子价)** | **¥1,314/年** | 首批100人,锁定价 |
-| **C端用户年费** | **¥299/年** | 完整盘+解读,不限次数 |
-| 普通用户免费试用 | ¥0 | 每日3次盘+1次主性格概要 |
+| **C端用户年费** | **¥299/年** | 完整能量盘+解读,不限次数 |
+| 普通用户免费试用 | ¥0 | 每日3次能量盘+1次主性格概要 |
 
 ### 4.2 收入分配(B端)
 
@@ -195,7 +195,7 @@ C端用户订阅 ¥299/年
 
 | 节点 | 触发动作 | 引流方式 |
 |------|---------|---------|
-| 首次使用工具 | 体验盘+AI解读的精准度 | 工具内植入培训宣传 |
+| 首次使用工具 | 体验能量盘+AI解读的精准度 | 工具内植入培训宣传 |
 | 少儿板块使用 | 发现少儿解读的深度价值 | 展示"认证能量师"高级功能 |
 | 分销佣金到账 | 看到推广收益 | 展示"学习进阶才能扩大收入" |
 | 客户互动记录 | 发现客户问题超出工具范围 | 提示"参加培训提升专业度" |
@@ -210,7 +210,7 @@ C端用户订阅 ¥299/年
 |---------|---------|
 | 产品名称含"全生命周期" | ✅ 统一为"数字心理学·全生命周期AI赋能系统" |
 | AI 驱动解读 | ✅ LLM 自动生成 |
-| 三角形盘基础 | ✅ 核心能力一致 |
+| 三角形能量盘基础 | ✅ 核心能力一致 |
 | 分销裂变机制 | ✅ 两级佣金 + C端分销(40%+5%) |
 | 微信生态 | ✅ 小程序 + 微信支付 |
 | 高毛利商业模型 | ✅ AI 自动交付,边际成本低 |
@@ -233,7 +233,7 @@ C端用户订阅 ¥299/年
 
 | # | 模块 | 核心功能 | 估工 |
 |---|------|---------|------|
-| 1 | 三角形盘引擎 | Canvas可视化,五区色块,3秒出图 | 3周 |
+| 1 | 三角形能量盘引擎 | Canvas可视化,五区色块,3秒出图 | 3周 |
 | 2 | AI五区完整解读 | LLM五区解读,Prompt调优迭代 | 4周 |
 | 3 | 少儿板块 | 性格+天赋+学习判定(独立Prompt体系) | 3周 |
 | 4 | 能量师CRM | 客户绑定/互动记录/信息补充/客户列表/活跃度 | 4周 |
@@ -246,7 +246,7 @@ C端用户订阅 ¥299/年
 
 | 功能 | 免费访客 | C端 ¥299/年 | 能量师 ¥1,314+/年 |
 |------|---------|-------------|------------------|
-| 盘生成 | ✅ 3次/日 | ✅ 不限 | ✅ 不限 |
+| 能量盘生成 | ✅ 3次/日 | ✅ 不限 | ✅ 不限 |
 | 主性格概要 | ✅ 文字概要 | ✅ 完整 | ✅ 完整 |
 | AI五区完整解读 | ❌ 仅预览 | ✅ | ✅ |
 | 少儿板块 | ❌ | ✅ | ✅ |
@@ -261,7 +261,7 @@ C端用户订阅 ¥299/年
 | 角色 | 人数 | 职责 | 风险等级 |
 |------|------|------|---------|
 | 后端开发 | 1 | API开发 + 数据库设计 + 服务器部署 + 运维 | 🔴 最大单点风险 |
-| 前端开发 | 2 | 盘Canvas/CRM/分销面板/管理后台等多个界面 | 🟡 4周一迭代偏紧 |
+| 前端开发 | 2 | 能量盘Canvas/CRM/分销面板/管理后台等多个界面 | 🟡 4周一迭代偏紧 |
 | AI工程师 | 1 | Prompt调优 + 模型选型 + 成本控制 | 🟡 深度调优需时间 |
 | 产品经理 | 1 | 功能定义 + 需求管理 + 跨团队协调 | 🟢 |
 
@@ -269,9 +269,9 @@ C端用户订阅 ¥299/年
 
 ## 十一、分阶段开发路线图
 
-### Phase 1(第1-2个月)— MVP基础:盘+AI初步+天赋解码+分销基础
+### Phase 1(第1-2个月)— MVP基础:能量盘+AI初步+天赋解码+分销基础
 **开发完成目标:**
-- ①三角形盘引擎(Canvas可视化,3秒出图,五区色块)
+- ①三角形能量盘引擎(Canvas可视化,3秒出图,五区色块)
 - ②成人主性格AI解读(首发仅主性格,后续P3扩展五区)
 - ③少儿天赋解码(首发仅天赋潜能,后续P4扩展全板块)
 - ⑤分销基础(推广码生成+佣金记录,完整面板在P2上线)
@@ -384,7 +384,7 @@ C端用户订阅 ¥299/年
 | 产品定位 | 数字心理学AI智能体,第一阶段从能量师切入 |
 | B端收费 | 种子价¥1,314/首100人(含AI),标准价¥1,914/年(含1.0六大板块);技术方固定¥998/人,运营方得剩余部分并负责佣金 |
 | C端收费 | ¥299/年,能量师40%+上级5%+平台55%(分销裂变:技术40%+运营15%) |
-| 功能范围 | 盘+AI五区+少儿板块+能量师CRM+客户互动查看 |
+| 功能范围 | 能量盘+AI五区+少儿板块+能量师CRM+客户互动查看 |
 | 合作模式 | 技术方搭平台(¥998/人)+运营方推广(B端分润+C端15%+培训引流) |
 | 培训体系 | 已存在,本项目为培训平台引流 |
 | 客户关系 | 能量师分享小程序码建立绑定,可查看互动记录 |
@@ -410,7 +410,7 @@ P4 (M5) → 决策 → P5 (M6) → 决策 → P6 (M7) → 盈亏平衡 ✓
 
 1. **运营驱动节奏**:收入完全取决于运营推广能力。P1需300种子,2个月内达成压力大。运营不达预期则项目暂停。双方需建立透明数据共享机制。
 
-2. **团队资源瓶颈**:后端1人是最大单点风险(全栈+数据库+部署+运维)。2前端需覆盖盘Canvas、CRM、分销面板、管理后台等多界面,4周迭代偏紧。AI调优需持续投入。
+2. **团队资源瓶颈**:后端1人是最大单点风险(全栈+数据库+部署+运维)。2前端需覆盖能量盘Canvas、CRM、分销面板、管理后台等多界面,4周迭代偏紧。AI调优需持续投入。
 
 3. **AI解读质量**:天赋解码、五区解读依赖Prompt质量。初期AI可能不够"惊艳",用户预期与实际体验的差距是口碑风险。需上线后持续迭代。
 

+ 42 - 42
docs/dify-chatflow-prompt.md

@@ -4,7 +4,7 @@
 
 本文档定义数字能量学智能体 Dify Chatflow 工作流的完整配置,包括系统提示词、输入架构、输出格式和节点配置。
 
-**用途:** 用户在微信小程序中生成盘后,向 AI 提问获得数字能量学专业解读。
+**用途:** 用户在微信小程序中生成能量盘后,向 AI 提问获得数字能量学专业解读。
 
 **知识库集成:** Chatflow 在 LLM 节点之前插入**知识检索节点**,从 Dify 知识库(ID: `3ff939b3-8686-44f6-8ef5-65b1e53b55d3`)中动态检索与用户问题相关的命理知识,将检索结果注入 LLM 上下文,实现 RAG(检索增强生成)。
 
@@ -34,7 +34,7 @@ Content-Type: application/json
 
 ### 2.2 chart_context JSON 格式
 
-后端传入的 `chart_context` 字段包含完整的盘数据,格式如下:
+后端传入的 `chart_context` 字段包含完整的能量盘数据,格式如下:
 
 ```json
 {
@@ -88,7 +88,7 @@ Content-Type: application/json
 
 | 变量名 | 类型 | 说明 | 来源 |
 |--------|------|------|------|
-| `chart_context` | JSON | 完整的盘数据 | 后端传入 |
+| `chart_context` | JSON | 完整的能量盘数据 | 后端传入 |
 | `query` | String | 用户提问内容 | 用户输入 |
 
 ---
@@ -97,7 +97,7 @@ Content-Type: application/json
 
 ```text
 # 角色设定
-你是「数字能量学智能解读师」,一位精通数字能量学(Digital Numerology)的资深专家。你擅长通过 Classic A 三角形盘(5行15格)为用户提供性格分析、天赋解码和人生指引。
+你是「数字能量学智能解读师」,一位精通数字能量学(Digital Numerology)的资深专家。你擅长通过 Classic A 三角形能量盘(5行15格)为用户提供性格分析、天赋解码和人生指引。
 
 # 专业背景
 - 精通数字能量学理论,包括主性格数字 1-9 及卓越数 11、22、33 的解读
@@ -106,12 +106,12 @@ Content-Type: application/json
 - 能够结合多位置数字组合进行综合分析
 
 # 解读原则
-1. 基于提供的盘数据进行专业解读,不编造或臆测数字
+1. 基于提供的能量盘数据进行专业解读,不编造或臆测数字
 2. 聚焦性格倾向、天赋优势、潜在挑战和发展建议
 3. 以积极正向的视角进行解读,强调成长和发展的可能性
 4. 语言专业但不晦涩,温暖且有洞察力
 5. 不预测具体未来事件(财运数字、结婚年份等),不提供医疗建议
-6. 若用户询问盘数据范围之外的领域,委婉说明数字能量学的局限性
+6. 若用户询问能量盘数据范围之外的领域,委婉说明数字能量学的局限性
 
 # 知识库检索使用规则(优先级最高)
 
@@ -119,7 +119,7 @@ Content-Type: application/json
 
 **检索结果使用规则:**
 1. `knowledge_retrieval` 中包含多个匹配的文档片段(chunks),每个 chunk 包含文件名、标题和内容
-2. 根据 `knowledge_retrieval` 的来源文件标记(如 `命盘24位置详解.md`、`三角命盘组合对判读规则.md`、`数字能量分析维度手册.md`、`五区三组分析指南.md`),判断该信息适用于盘的哪个方面
+2. 根据 `knowledge_retrieval` 的来源文件标记(如 `能量盘24位置详解.md`、`三角能量盘组合对判读规则.md`、`数字能量分析维度手册.md`、`五区三组分析指南.md`),判断该信息适用于能量盘的哪个方面
 3. 如果多个 chunk 提供同一主题的不同视角,合并使用以给出全面解读
 4. 如果知识库检索结果与你的内部记忆冲突,**以检索结果为准**
 5. 如果在检索结果中找不到相关信息,再使用下方"数字含义参考"中的内置信息
@@ -140,13 +140,13 @@ Content-Type: application/json
 
 # 响应格式
 1. 首先回应用户的具体问题
-2. 引用盘中的具体位置和数字进行解释
+2. 引用能量盘中的具体位置和数字进行解释
 3. 提供有针对性的建议
 4. 保持友好、鼓励的语气
 5. 回复语言使用中文
 
 # chart_context JSON 结构说明
-用户盘数据通过 chart_context 变量传入,包含以下关键字段:
+用户能量盘数据通过 chart_context 变量传入,包含以下关键字段:
 - mainCharacter: 主性格数字(位于 O 位)
 - positions: 全部 15 个位置(A-O)的数字值
 - zones: 五区数据,每区包含名称、位置列表和对应数字值
@@ -174,7 +174,7 @@ Chatflow 在 LLM 节点之前插入**知识检索(Knowledge Retrieval)节点
 
 | 轮次 | 检索策略 | 说明 |
 |------|---------|------|
-| **第一轮**(首次发送) | chart_context 智能构建查询 | 后端首次发送时附带 `chart_context`,Chatflow 通过代码节点/LLM 节点**自动提取盘关键信息**生成结构化 KB 查询 |
+| **第一轮**(首次发送) | chart_context 智能构建查询 | 后端首次发送时附带 `chart_context`,Chatflow 通过代码节点/LLM 节点**自动提取能量盘关键信息**生成结构化 KB 查询 |
 | **后续轮次** | 直接用用户 query 检索 | Dify Chatflow 自动保存会话上下文,后续直接以 `query` 检索 |
 | **深度追问** | 一次对话多次检索 | 每次用户提问都触发 KB 检索,确保每轮回复都有最新知识支撑 |
 
@@ -251,7 +251,7 @@ START ──→ Knowledge Retrieval ──→ LLM ──→ END
 
 | Dify 变量 | 映射到 | 说明 |
 |-----------|--------|------|
-| `chart_context` | LLM 系统提示词中的上下文变量 | 盘数据,嵌入提示词中供 LLM 引用 |
+| `chart_context` | LLM 系统提示词中的上下文变量 | 能量盘数据,嵌入提示词中供 LLM 引用 |
 | `query` | LLM 用户消息输入 | 用户提问内容 |
 | `knowledge_retrieval` | LLM 系统提示词中的检索结果上下文 | 知识库检索返回的 chunks,LLM 需优先使用 |
 
@@ -326,7 +326,7 @@ END (answer)
 
 **预期回复(示例):**
 ```
-你好!根据你的数字盘,你的主性格数字是 7。
+你好!根据你的数字能量盘,你的主性格数字是 7。
 
 🔹 主性格 7 号 — 探索者
 
@@ -365,7 +365,7 @@ END (answer)
 
 **预期回复(示例):**
 ```
-感谢你的提问!从你的数字盘来看,非常有亮点。
+感谢你的提问!从你的数字能量盘来看,非常有亮点。
 
 🔹 主性格 8 号 — 掌控者
 
@@ -448,7 +448,7 @@ num:
 
 ```json
 {
-  "answer": "你的盘主性格数字是 7...",
+  "answer": "你的能量盘主性格数字是 7...",
   "conversation_id": "conv_abc123",
   "message_id": "msg_abc123",
   "created_at": 1717200000,
@@ -462,7 +462,7 @@ num:
       {
         "dataset_id": "3ff939b3-8686-44f6-8ef5-65b1e53b55d3",
         "document_id": "doc_abc",
-        "document_name": "盘24位置详解.md",
+        "document_name": "能量盘24位置详解.md",
         "segment_id": "seg_abc",
         "score": 0.85,
         "content": "O位置代表..."
@@ -520,7 +520,7 @@ public class DifyService {
 
 ### 7.1 概述
 
-用户在三角盘上点击某一位置(A-X)时,前端弹出底部面板显示 3 个 Tab 的内容。
+用户在三角能量盘上点击某一位置(A-X)时,前端弹出底部面板显示 3 个 Tab 的内容。
 这些内容由 **Dify Workflow「位置详情面板」** 生成,该 Workflow 独立于 Chatflow(不共享对话上下文),每次点击独立请求。
 
 | 属性 | 值 |
@@ -615,7 +615,7 @@ Content-Type: application/json
 **System Prompt(完整版):**
 
 ```
-你是一个数字能量学专家。请根据以下知识库内容,为盘位置的详情面板生成内容。
+你是一个数字能量学专家。请根据以下知识库内容,为能量盘位置的详情面板生成内容。
 
 ## 位置信息
 - 字母:{position_letter}
@@ -722,7 +722,7 @@ public Result<?> positionDetail(HttpServletRequest request, @RequestBody Map<Str
     // Verify chart ownership
     ChartRecord record = chartService.getById(chartRecordId);
     if (!record.getUserId().equals(userId)) {
-        return Result.error(1006, "无权访问此盘");
+        return Result.error(1006, "无权访问此能量盘");
     }
     
     // Calculate auspiciousness & adjacent combos (backend)
@@ -781,7 +781,7 @@ private PositionDetailResponse generateMockPositionDetail(
     PositionDetailResponse resp = new PositionDetailResponse();
     resp.tab1 = positionName + ":" + POSITION_CORE_MEANINGS.getOrDefault(position, "能量位置");
     resp.tab2 = position + "=" + digit + " 代表" + digitDesc + "。";
-    resp.tab3 = "1. 了解该能量的优势和挑战\n2. 结合整体盘综合分析\n3. 在实践中觉察能量表现";
+    resp.tab3 = "1. 了解该能量的优势和挑战\n2. 结合整体能量盘综合分析\n3. 在实践中觉察能量表现";
     return resp;
 }
 ```
@@ -839,19 +839,19 @@ private PositionDetailResponse generateMockPositionDetail(
 
 ---
 
-## 9. 盘解读 Workflow(US-3.1)
+## 9. 能量盘解读 Workflow(US-3.1)
 
 ### 9.1 概述
 
-用户在输入生日并创建盘后,系统自动调用此 Workflow 生成完整的 AI 解读内容,展示在解读页五区卡片中。该 Workflow 独立于 Chatflow,每次创建盘时调用一次。
+用户在输入生日并创建能量盘后,系统自动调用此 Workflow 生成完整的 AI 解读内容,展示在解读页五区卡片中。该 Workflow 独立于 Chatflow,每次创建能量盘时调用一次。
 
 | 属性 | 值 |
 |------|-----|
-| 目的 | 为 US-3.1 "AI解读展示" 生成完整盘文字解读 |
+| 目的 | 为 US-3.1 "AI解读展示" 生成完整能量盘文字解读 |
 | Dify 应用类型 | Workflow(非 Chatflow) |
-| 触发时机 | 用户确认生日 → 盘创建成功后立即触发 |
+| 触发时机 | 用户确认生日 → 能量盘创建成功后立即触发 |
 | 数据流 | 后端 → Dify Workflow → 并行 KB 检索 (A1/A2/B2/C1/C2) → LLM 合成 → 结构化 JSON |
-| 记忆 | 无,每次创建盘执行一次;后续查看走缓存(US-3.3) |
+| 记忆 | 无,每次创建能量盘执行一次;后续查看走缓存(US-3.3) |
 
 ### 9.2 数据流
 
@@ -867,7 +867,7 @@ POST /api/consultation/start
     POST /v1/workflows/run (blocking, timeout=15s)
-    Dify Workflow "盘解读"
+    Dify Workflow "能量盘解读"
         ├─ [并行] KB 检索 1 → A2 主性格 + A1 位置含义(O位)
         ├─ [并行] KB 检索 2 → C2 五区三组 + B2 组合对(左区 P/Q/R)
         ├─ [并行] KB 检索 3 → C2 五区三组 + B2 组合对(顶部 V/W/X)
@@ -910,7 +910,7 @@ Content-Type: application/json
 
 | 变量名 | 类型 | 说明 | 示例 |
 |--------|------|------|------|
-| `chart_context` | String (JSON) | 24 个盘位置数字(A-X) + 五区聚合的完整 JSON | 见下方 |
+| `chart_context` | String (JSON) | 24 个能量盘位置数字(A-X) + 五区聚合的完整 JSON | 见下方 |
 | `user_name` | String | 用户姓名,用于解读文案 | "张三" |
 | `birthday` | String | 出生日期,用于年龄计算 | "1990-01-15" |
 
@@ -952,7 +952,7 @@ Content-Type: application/json
 | **KB 2** 左区 (P/Q/R) | C2 五区三组 + B2 组合对 | 数字能量学知识库 | `左区 21-40岁 {P} {Q} {R} 组合 发展 早年运势 人生课题` | 3 |
 | **KB 3** 顶部 (V/W/X) | C2 五区三组 + B2 组合对 | 数字能量学知识库 | `顶部 41-60岁 {V} {W} {X} 中年 事业 人际关系 成就` | 3 |
 | **KB 4** 右区 (S/T/U) | C2 五区三组 + B2 组合对 | 数字能量学知识库 | `右区 61岁 {S} {T} {U} 晚年 财运 家庭 沉淀` | 3 |
-| **KB 5** 特殊组合 | B1 八星 + B2 组合对 + C1 维度 | 数字能量学知识库 | `组合 八星 {I}{J} {M}{N} {M}{O} 能量 盘解读` | 3 |
+| **KB 5** 特殊组合 | B1 八星 + B2 组合对 + C1 维度 | 数字能量学知识库 | `组合 八星 {I}{J} {M}{N} {M}{O} 能量 能量盘解读` | 3 |
 
 > 所有检索节点的检索模式统一设置为 `hybrid_search`,与知识库全局配置一致。
 
@@ -1011,11 +1011,11 @@ def main(input_data: dict) -> dict:
 你是一个专业的数字能量学全盘解读分析师。
 
 ## 背景
-用户的盘数据已通过 chart_context 变量传入,包含 24 个位置(A-X)的数字值。
+用户的能量盘数据已通过 chart_context 变量传入,包含 24 个位置(A-X)的数字值。
 知识库检索结果(KB 1-5)已提供相关命理知识作为参考。
 
 ## 解读要求
-请按以下结构和规则,生成完整的盘解读。
+请按以下结构和规则,生成完整的能量盘解读。
 
 ### 1. 主性格解读(O 位)
 - 根据 KB 1 中该数字的性格特征
@@ -1039,12 +1039,12 @@ def main(input_data: dict) -> dict:
 - 说明晚年阶段的人生智慧课题
 
 ### 5. 特殊组合分析
-- 根据 KB 5 识别盘中的特殊数字组合
+- 根据 KB 5 识别能量盘中的特殊数字组合
 - 重点关注:I+J, M+N, M+O 等相邻位置形成的组合
 - 分析八星能量(天医/延年/生气/绝命/五鬼/六煞/祸害/伏位)
 
 ### 6. 总评(summary)
-- 对整体盘能量做出概括性评价
+- 对整体能量盘能量做出概括性评价
 - 指出最突出的优势能量和需要注意的挑战
 - 用 2-3 句话总结
 
@@ -1089,7 +1089,7 @@ def main(input_data: dict) -> dict:
       "keywords": ["合作", "独立", "创造"]
     }
   ],
-  "summary": "整体盘能量评价...",
+  "summary": "整体能量盘能量评价...",
   "combinationNotes": [
     "数字 I(1)+J(6)=7,形成...",
     "M(7)+O(8)=15→6,形成..."
@@ -1131,7 +1131,7 @@ def main(input_data: dict) -> dict:
       "keywords": ["合作", "独立", "创造"]
     }
   ],
-  "summary": "整体盘综合评价...",
+  "summary": "整体能量盘综合评价...",
   "combinationNotes": [
     "数字组合分析说明 1",
     "数字组合分析说明 2"
@@ -1146,7 +1146,7 @@ def main(input_data: dict) -> dict:
 | `sections[].values` | Int[] | 对应位置的数字值 |
 | `sections[].content` | String | 解读文案正文,100-200 字 |
 | `sections[].keywords` | String[] | 3-5 个关键词,每词 2-4 字 |
-| `summary` | String | 整体盘评价,2-3 句话 |
+| `summary` | String | 整体能量盘评价,2-3 句话 |
 | `combinationNotes` | String[] | 特殊组合分析说明列表 |
 
 ### 9.7 Java 后端集成
@@ -1157,7 +1157,7 @@ def main(input_data: dict) -> dict:
 // --- US-3.1 Chart Interpretation Workflow ---
 
 /**
- * 调用 Dify Workflow 生成盘完整解读(US-3.1)
+ * 调用 Dify Workflow 生成能量盘完整解读(US-3.1)
  * @param chartContext  chart_context JSON 字符串(含 positions + zones + metadata)
  * @param userName      用户姓名
  * @param birthday      出生日期 YYYY-MM-DD
@@ -1248,7 +1248,7 @@ public class InterpretationResponse {
 
 ```java
 /**
- * 获取盘 AI 解读(US-3.1)
+ * 获取能量盘 AI 解读(US-3.1)
  * 首次调用触发 Dify Workflow,后续走缓存(US-3.3)
  */
 @PostMapping("/chart/interpret")
@@ -1275,7 +1275,7 @@ public class ChartService {
     private ChartRecordRepository chartRecordRepository;
 
     /**
-     * 获取盘解读(优先缓存)
+     * 获取能量盘解读(优先缓存)
      */
     public String getInterpretation(Long chartRecordId) {
         ChartRecord record = chartRecordRepository.findById(chartRecordId);
@@ -1367,7 +1367,7 @@ private InterpretationResponse generateMockInterpretation(
 ### 9.9 Dify 控制台配置步骤
 
 1. **登录 Dify** → 点击「创建应用」→ 选择「Workflow」
-2. **命名应用**:`盘解读`
+2. **命名应用**:`能量盘解读`
 3. **配置 START 节点**:添加 3 个输入变量
    - `chart_context`(String, JSON)
    - `user_name`(String)
@@ -1401,13 +1401,13 @@ private InterpretationResponse generateMockInterpretation(
 
 ### 9.10 与 Chatflow 的差异对比
 
-| 维度 | Chatflow(AI问答) | Workflow(盘解读) |
+| 维度 | Chatflow(AI问答) | Workflow(能量盘解读) |
 |------|--------------------|---------------------|
-| 用途 | 多轮自由问答 | 一次性盘全盘解读 |
+| 用途 | 多轮自由问答 | 一次性能量盘全盘解读 |
 | 输出格式 | 自然语言(`answer` 字段) | 结构化 JSON(sections + summary) |
 | 记忆 | 6 轮对话记忆(Dify 维护) | 无记忆,每次独立执行 |
-| 触发时机 | 用户输入问题 | 盘创建后自动触发 |
-| 调用频率 | 用户每次提问 | 每个盘仅 1 次(后续走缓存) |
+| 触发时机 | 用户输入问题 | 能量盘创建后自动触发 |
+| 调用频率 | 用户每次提问 | 每个能量盘仅 1 次(后续走缓存) |
 | 输入变量 | `chart_context` + `query` | `chart_context` + `user_name` + `birthday` |
 | KB 检索数 | 1 个检索节点(按需) | 5 个并行检索节点 |
 | API 端点 | `POST /v1/chat-messages` | `POST /v1/workflows/run` |

+ 6 - 6
docs/executive-summary.md

@@ -12,9 +12,9 @@
 
 | 面向谁 | 给什么 | 怎么赚钱 |
 |--------|--------|----------|
-| **大众用户** | 3 秒生成盘 + AI 解读 + 人格匹配交友 | VIP 月卡/年卡订阅 |
+| **大众用户** | 3 秒生成能量盘 + AI 解读 + 人格匹配交友 | VIP 月卡/年卡订阅 |
 | **能量师** | 客户管理 + 批量工具 + 平台获客 | 专业版年费 + 每单抽佣 20% |
-| **平台自身** | 海量盘数据 → 训练专属 AI 模型 → 输出 API | 数据壁垒 + B 端 API 服务 |
+| **平台自身** | 海量能量盘数据 → 训练专属 AI 模型 → 输出 API | 数据壁垒 + B 端 API 服务 |
 
 ## 最大的创新:数字人格匹配
 
@@ -24,11 +24,11 @@
 
 传统命理是一锤子买卖——出完报告关系结束。我们引入**数字调理**,让服务延续:
 
-- 分析先天盘缺失/过旺的数字能量
+- 分析先天能量盘缺失/过旺的数字能量
 - 提供个性化调理建议:命名用数、号码选择、色彩搭配、方位建议、配饰能量补充等
 - **从"解读一次"变成"长期调理顾问"**,极大提升 LTV
 
-同时开辟**电商闭环**:数字产品(报告/方案)平台自营 100% 毛利,实物商品(水晶/饰品)由能量师供货平台抽佣 20-30%,第三方商家入驻抽佣 15-25%。AI 根据每位用户的盘缺失数字精准推荐,天然是"一人一策"的个性化电商。
+同时开辟**电商闭环**:数字产品(报告/方案)平台自营 100% 毛利,实物商品(水晶/饰品)由能量师供货平台抽佣 20-30%,第三方商家入驻抽佣 15-25%。AI 根据每位用户的能量盘缺失数字精准推荐,天然是"一人一策"的个性化电商。
 
 ## 数据飞轮 = 护城河
 
@@ -51,14 +51,14 @@
 
 ## 阶段路径
 
-- **Phase 1** — MVP 上线(盘 + 免费解读 + VIP 支付),验证核心转化
+- **Phase 1** — MVP 上线(能量盘 + 免费解读 + VIP 支付),验证核心转化
 - **Phase 2** — AI 对话 + 能量师入驻 + 轻量匹配,建立数据飞轮
 - **Phase 3** — 陌生人社交 + 内容社区,冲击月活 10 万
 - **Phase 4** — 知识库 API + 企业服务,B 端营收占比 30%
 
 ## 团队在做的事
 
-目前已完产品方向探索,形成了完整的三角形盘方案、用户流程、功能分层,准备进入 MVP 开发阶段。技术选型为微信小程序 + 后端接入 LLM,轻资产启动。
+目前已完产品方向探索,形成了完整的三角形能量盘方案、用户流程、功能分层,准备进入 MVP 开发阶段。技术选型为微信小程序 + 后端接入 LLM,轻资产启动。
 
 ---
 

+ 25 - 25
docs/knowledge-base-design.md

@@ -28,7 +28,7 @@
 |------|---------|
 | AI 解读主性格 | "主性格=7"需从 `生命灵数1-9号性格解析.md` 检索,但该文档混合了天赋数、空缺数、九宫格等内容 |
 | AI 分析财富格局 | 需同时检索八星能量(天医财星)、组合递进、24位置含义 —— 散落在不同文档 |
-| AI 识别组合对 | 三角盘中相邻位置形成八星组合对,当前无文档解释如何在三角形中识别这些组合 |
+| AI 识别组合对 | 三角能量盘中相邻位置形成八星组合对,当前无文档解释如何在三角形中识别这些组合 |
 | 用户点击数字 | US-1.4 要求显示"该位置含义+Tabs",当前无文档定义每个位置(A-X)的含义 |
 | 维度映射 | 事业↔延年、财富↔天医、感情↔六煞 —— 无系统化的分析维度手册 |
 
@@ -52,12 +52,12 @@
 数字能量学知识库 V2 (单一知识库)
 ├─ [A] 位置含义体系 (Position Meaning)
-│   ├── A1 盘24位置详解 *NEW
+│   ├── A1 能量盘24位置详解 *NEW
 │   └── A2 主性格数字1-9+卓越数深度解读 *RESTRUCTURE
 ├─ [B] 能量与组合分析 (Energy & Combo Analysis)
 │   ├── B1 八星数字能量完整参考 (现有)
-│   ├── B2 三角盘组合对判读规则 *NEW
+│   ├── B2 三角能量盘组合对判读规则 *NEW
 │   └── B3 联合密码详解 (现有)
 ├─ [C] 分析维度和实战 (Analysis Dimensions)
@@ -78,8 +78,8 @@
 
 | 编号 | 文档名 | 层级 | 状态 | 说明 |
 |------|--------|------|------|------|
-| A1 | `盘24位置详解.md` (462行) | A | P0 ✅ | 24位置含义速查 |
-| B2 | `三角盘组合对判读规则.md` (465行) | B | P0 ✅ | 三角形中识别八星组合 |
+| A1 | `能量盘24位置详解.md` (462行) | A | P0 ✅ | 24位置含义速查 |
+| B2 | `三角能量盘组合对判读规则.md` (465行) | B | P0 ✅ | 三角形中识别八星组合 |
 | C1 | `数字能量分析维度手册.md` (585行) | C | P0 ✅ | 事业/财富/感情/健康映射 |
 | C2 | `五区三组分析指南.md` (434行) | C | P0 ✅ | 五区三组交叉分析 |
 | A2 | `主性格数字深度解读.md` (606行) | A | P1 ✅ | 1-9/11/22/33 深度解读(拆分自原1-9号解析)|
@@ -88,8 +88,8 @@
 
 | 编号 | 文档名 | 必要性 | 优先级 |
 |------|--------|--------|--------|
-| A1 | `盘24位置详解.md` | US-1.4 数字点击含义的**数据源**,Workflow/Chatflow 的**位置上下文** | **P0** |
-| B2 | `三角盘组合对判读规则.md` | AI 识别三角形中相邻位置的八星组合,是五区/财富/事业解读的**核心规则** | **P0** |
+| A1 | `能量盘24位置详解.md` | US-1.4 数字点击含义的**数据源**,Workflow/Chatflow 的**位置上下文** | **P0** |
+| B2 | `三角能量盘组合对判读规则.md` | AI 识别三角形中相邻位置的八星组合,是五区/财富/事业解读的**核心规则** | **P0** |
 | C1 | `数字能量分析维度手册.md` | 事业/财富/感情/健康维度映射,AI "知其然也知其所以然"的**推理骨架** | **P0** |
 | C2 | `五区三组分析指南.md` | 五区解读(主性格/左区/右区/父源/母源)+ 三组年龄阶段(21-40/41-60/61+)的**交叉分析方法论** | **P0** |
 
@@ -104,7 +104,7 @@
 
 ## 四、核心文档详细设计
 
-### 4.1 A1「盘24位置详解」(NEW)
+### 4.1 A1「能量盘24位置详解」(NEW)
 
 **定位**:US-1.4 的"数字点击查看含义"的数据源,也是 AI 理解每个位置的参考手册。
 
@@ -112,11 +112,11 @@
 
 ```markdown
 ---
-title: 盘24位置详解
-tags: [位置, 盘, A-X, 计算规则, 含义]
+title: 能量盘24位置详解
+tags: [位置, 能量盘, A-X, 计算规则, 含义]
 ---
 
-# 盘24位置详解
+# 能量盘24位置详解
 
 ## 一、位置命名总表(A-X)
 (含字母、公式、中文名、年龄区间、视觉层级)
@@ -160,24 +160,24 @@ tags: [位置, 命盘, A-X, 计算规则, 含义]
 
 ---
 
-### 4.2 B2「三角盘组合对判读规则」(NEW)
+### 4.2 B2「三角能量盘组合对判读规则」(NEW)
 
-**定位**:AI 在三角形盘中识别八星组合对的方法论。
+**定位**:AI 在三角形能量盘中识别八星组合对的方法论。
 
-**为什么要单独写:** 三角形盘的组合对识别不同于手机号码判读。在三角形中,相邻位置的数字两两配对形成八星组合,但并非所有相邻都产生有意义的关系。
+**为什么要单独写:** 三角形能量盘的组合对识别不同于手机号码判读。在三角形中,相邻位置的数字两两配对形成八星组合,但并非所有相邻都产生有意义的关系。
 
 **结构设计**:
 
 ```markdown
 ---
-title: 三角盘组合对判读规则
+title: 三角能量盘组合对判读规则
 tags: [组合对, 八星, 三角形, 判读]
 ---
 
-# 三角盘组合对判读规则
+# 三角能量盘组合对判读规则
 
 ## 一、三角形中的组合对概述
-(三角形盘中哪些相邻位置形成有意义的八星组合)
+(三角形能量盘中哪些相邻位置形成有意义的八星组合)
 
 ## 二、横向组合对(同层左右相邻)
 - I-J 月日线(父源区)
@@ -256,7 +256,7 @@ tags: [维度, 事业, 财富, 感情, 健康, 推理]
 ```markdown
 ---
 title: 五区三组分析指南
-tags: [五区, 三组, 盘结构, 区域分析, 交叉分析, 年龄阶段]
+tags: [五区, 三组, 能量盘结构, 区域分析, 交叉分析, 年龄阶段]
 ---
 
 # 五区三组分析指南
@@ -271,7 +271,7 @@ tags: [五区, 三组, 命盘结构, 区域分析, 交叉分析, 年龄阶段]
 (左侧组21-40岁、顶部组41-60岁、右侧组61+岁)
 
 ## 七、五区三组交叉分析方法
-(五区看"当下本质" + 三组看"时间发展" → 完整盘解读)
+(五区看"当下本质" + 三组看"时间发展" → 完整能量盘解读)
 ```
 
 ---
@@ -344,7 +344,7 @@ Dify v1.11.4 支持文档级 metadata,可在 Workflow 中通过 `knowledge_fil
 
 ## 七、Workflow / Chatflow 集成方案
 
-### 7.1 盘解读 Workflow
+### 7.1 能量盘解读 Workflow
 
 ```
 用户输入 (chart_data)
@@ -401,9 +401,9 @@ Dify v1.11.4 支持文档级 metadata,可在 Workflow 中通过 `knowledge_fil
 
 | 步骤 | 产出 | 工作量 |
 |------|------|--------|
-| 1. 撰写 `盘24位置详解.md` | 1 篇 × ~300 行 | ✅ 已完成 |
+| 1. 撰写 `能量盘24位置详解.md` | 1 篇 × ~300 行 | ✅ 已完成 |
 | 2. 撰写 `数字能量分析维度手册.md` | 1 篇 × ~400 行 | ✅ 已完成 |
-| 3. 撰写 `三角盘组合对判读规则.md` | 1 篇 × ~300 行 | ✅ 已完成 |
+| 3. 撰写 `三角能量盘组合对判读规则.md` | 1 篇 × ~300 行 | ✅ 已完成 |
 | 3.5 撰写 `五区三组分析指南.md` | 1 篇 × ~400 行 | ✅ 已完成 |
 | 4. 导入 4 篇新文档到 Dify KB | 4 篇 → Dify 索引 | ✅ 已完成 |
 | 5. 更新知识体系总纲导航 | 总纲扩展 → 第二部分分析指南 | ✅ 已完成 |
@@ -580,7 +580,7 @@ Section 11 描述了 AI 组合策略(A1+A2)的概念方案,但未明确以
 前端 POST /api/position/detail
 { "chartRecordId": 123, "position": "O", "digit": 7 }
-    ├─ 后端:验证盘归属 → 计算吉凶(Item 8)→ 检测相邻组合(Item 9)
+    ├─ 后端:验证能量盘归属 → 计算吉凶(Item 8)→ 检测相邻组合(Item 9)
     └─ ChartController → DifyService.invokeWorkflow(inputs)
@@ -630,7 +630,7 @@ Section 11 描述了 AI 组合策略(A1+A2)的概念方案,但未明确以
 **System Prompt(精确版):**
 
 ```
-你是一个数字能量学专家。请根据以下知识库内容,为盘位置的详情面板生成内容。
+你是一个数字能量学专家。请根据以下知识库内容,为能量盘位置的详情面板生成内容。
 
 ## 位置信息
 - 字母:{position_letter}
@@ -750,7 +750,7 @@ private PositionDetailResponse generateMockPositionDetail(
     PositionDetailResponse resp = new PositionDetailResponse();
     resp.tab1 = positionName + ":" + POSITION_CORE_MEANINGS.getOrDefault(position, "能量位置");
     resp.tab2 = position + "=" + digit + " 代表" + digitDesc + "。";
-    resp.tab3 = "1. 了解该能量的优势和挑战\n2. 结合整体盘综合分析\n3. 在实践中觉察能量表现";
+    resp.tab3 = "1. 了解该能量的优势和挑战\n2. 结合整体能量盘综合分析\n3. 在实践中觉察能量表现";
     return resp;
 }
 ```

+ 25 - 25
docs/phase1-product-plan.md

@@ -2,7 +2,7 @@
 
 > 版本: v1.2
 > 定位: 面向数字能量师的AI智能工具,最小成本 + 最快回血
-> 口号: 3秒出盘 + AI自动解读,让能量师聚焦客户沟通,而非画图和查资料
+> 口号: 3秒出能量盘 + AI自动解读,让能量师聚焦客户沟通,而非画图和查资料
 
 ---
 
@@ -13,14 +13,14 @@
 ```
 用户注册 → 普通用户(免费,体验入口)
-              ├── 每日3次盘生成
+              ├── 每日3次能量盘生成
               ├── 每日1次主性格概要解读
               └── 通过能量师分享链接注册(建立上下级关系)
               ▼(购买年服务包)
          能量师用户(¥1,314/年起,核心付费用户)
-              ├── 无限盘生成 + AI五区完整解读
+              ├── 无限能量盘生成 + AI五区完整解读
               ├── 无限分享 + PDF导出 + 全部历史
               ├── 获得专属推广二维码/卡片
               └── 发展下级用户,为分销模式打基础
@@ -42,9 +42,9 @@
 
 ```
 做(Phase 1 范围):
-  ✅ 三角形盘快速生成(输入生日 → 3秒出图)
+  ✅ 三角形能量盘快速生成(输入生日 → 3秒出图)
   ✅ AI 自动解读(主性格 + 五区深度解读)
-  ✅ 盘分享 / 导出图片 / 导出PDF(含解读内容)
+  ✅ 能量盘分享 / 导出图片 / 导出PDF(含解读内容)
   ✅ 能量师年费订阅 & 支付
   ✅ 基础个人中心 + 历史记录
   ✅ 分销系统基础(推广码生成 + 分享带参注册 + 上下级关系绑定)
@@ -86,16 +86,16 @@
 
 | 优先级 | 模块 | 功能 | 说明 |
 |--------|------|------|------|
-| **P0** | 命盘生成 | 输入姓名+生日 → 自动生成三角形命盘 | 核心引擎,纯前端计算 |
-| **P0** | 盘展示 | 三角形可视化,15格数字填充 | Canvas绘制 |
-| **P0** | AI解读 | 根据盘数字自动生成主性格+五区解读文本 | LLM API(云函数调用) |
-| **P0** | 盘分享 | 生成分享图/导出PDF(含解读) | 微信小程序分享卡片 |
+| **P0** | 能量盘生成 | 输入姓名+生日 → 自动生成三角形能量盘 | 核心引擎,纯前端计算 |
+| **P0** | 能量盘展示 | 三角形可视化,15格数字填充 | Canvas绘制 |
+| **P0** | AI解读 | 根据能量盘数字自动生成主性格+五区解读文本 | LLM API(云函数调用) |
+| **P0** | 能量盘分享 | 生成分享图/导出PDF(含解读) | 微信小程序分享卡片 |
 | **P0** | 付费订阅 | 能量师年费支付(微信支付) | 核心变现入口 |
 | **P0** | **分销推广** | **生成专属推广码(小程序码/卡片),分享带参注册** | **分销裂变入口** |
 | **P1** | 用户体系 | 微信登录 + 订阅状态管理 + 上下级关系 | 必要底层 |
-| **P1** | 历史记录 | 已生成的盘列表、查看、删除 | 留存和复访 |
+| **P1** | 历史记录 | 已生成的能量盘列表、查看、删除 | 留存和复访 |
 | **P1** | **分销后台** | **收益统计 / 团队列表 / 提现申请** | **能量师推广中心** |
-| **P2** | 批注功能 | 在盘图上添加备注/标记 | 能量师自行标注用 |
+| **P2** | 批注功能 | 在能量盘图上添加备注/标记 | 能量师自行标注用 |
 | **P2** | 客户分组 | 简单管理客户(标签/分组) | 客户管理雏形 |
 | **P3** | 报告模板 | 预设几种报告样式供选择 | 可后续补 |
 
@@ -109,11 +109,11 @@
 ┌─────────────────────┐
 │  首页 (输入页)       │  P0  — 核心入口
 │  - 姓名 + 生日输入   │        微信用户可直接操作
-│  - "生成盘"按钮    │
+│  - "生成能量盘"按钮    │
 └────────┬────────────┘
 ┌─────────────────────┐
-│  盘展示页           │  P0  — 核心功能
+│  能量盘展示页           │  P0  — 核心功能
 │  - 三角形可视化       │        支持点击数字查看含义
 │  - "查看AI解读"按钮   │
 │  - 底部:分享/导出    │
@@ -138,7 +138,7 @@
 ┌─────────────────────┐
 │  个人中心             │  P1  — 基础留存
 │  - 订阅状态/到期日    │
-│  - 历史盘列表       │
+│  - 历史能量盘列表       │
 │  - 订阅/续费入口      │
 │  - (能量师) 我的收益 → │  ← 分销入口
 │  - (能量师) 推广工具 → │  ← 分销入口
@@ -184,11 +184,11 @@
 
 | 功能 | 普通用户(免费) | 能量师(¥1,314/年起) |
 |------|----------------|----------------------|
-| 生成盘 | 每日 3 次 | 不限次数 |
-| 查看盘 | ✅ | ✅ |
+| 生成能量盘 | 每日 3 次 | 不限次数 |
+| 查看能量盘 | ✅ | ✅ |
 | **AI 基础解读(主性格概要)** | ✅(每日1次) | ✅ 不限 |
 | **AI 完整解读(五区全解)** | ❌ | ✅ 不限 |
-| 分享盘图片(含解读) | 每日 1 次 | 不限 |
+| 分享能量盘图片(含解读) | 每日 1 次 | 不限 |
 | 导出 PDF(含解读) | ❌ | ✅ |
 | 历史记录 | 近 7 天 | 全部 |
 | **生成专属推广码** | ❌ | ✅ |
@@ -198,11 +198,11 @@
 > 免费额度足够能量师**试用体验**,但不足以替代日常工作。
 > 3次/天试完正好到付费决策点——"一天都不够我用"。
 
-**C端年费:** C端用户可订阅 ¥131/年 获得AI解读完整版、无限盘生成和推广佣金权益。
+**C端年费:** C端用户可订阅 ¥131/年 获得AI解读完整版、无限能量盘生成和推广佣金权益。
 
 ---
 
-## 六、三角形盘计算引擎(通用算法)
+## 六、三角形能量盘计算引擎(通用算法)
 
 ### 6.1 输入
 
@@ -355,8 +355,8 @@ function calculateTriangle(birthYear, birthMonth, birthDay) {
 | 数据库 | **微信云开发数据库** | 免运维,与小程序深度集成 |
 | 登录 | **微信一键登录** | 零成本 |
 | 支付 | **微信支付** | 小程序内直接支付 |
-| 盘计算 | **前端计算** | 纯数学运算,无需后端,秒级出结果 |
-| **AI 解读** | **云函数 + LLM API** | 接受盘数据,调用LLM生成解读文本 |
+| 能量盘计算 | **前端计算** | 纯数学运算,无需后端,秒级出结果 |
+| **AI 解读** | **云函数 + LLM API** | 接受能量盘数据,调用LLM生成解读文本 |
 | PDF导出 | **html2canvas + jspdf** | 前端生成,省掉后端渲染服务 |
 | 部署 | **云开发一键部署** | 免运维 |
 
@@ -377,7 +377,7 @@ function calculateTriangle(birthYear, birthMonth, birthDay) {
 | 天数 | 里程碑 |
 |------|--------|
 | D1-2 | 项目初始化 + 小程序框架搭建 |
-| D3-4 | 三角形盘计算引擎(含单元测试) |
+| D3-4 | 三角形能量盘计算引擎(含单元测试) |
 | D5-7 | 三角形Canvas可视化组件 |
 | D8-9 | AI解读引擎(Prompt设计 + 云函数接入LLM API) |
 | D10 | 联调、修复、demo |
@@ -442,7 +442,7 @@ Phase 1 (Week 7 上线)
 | 能量师获客慢 | 中 | 现金流延迟 | 首发¥1,314种子价锁定种子用户,朋友圈裂变奖励 + 分销佣金驱动 |
 | 算法与能量师预期不符 | 高 | 产品不可用 | 上线前先给5个能量师验证算法正确性 |
 | **AI解读质量不够专业** | **中** | **能量师不认可** | Prompt中融入数字能量学专业术语和体系,支持能量师自行调整润色 |
-| **LLM API成本失控** | **低** | **利润被吃掉** | 限流+缓存机制,同一盘重复请求时不重复调用API |
+| **LLM API成本失控** | **低** | **利润被吃掉** | 限流+缓存机制,同一能量盘重复请求时不重复调用API |
 | **分销佣金纠纷** | **中** | **口碑受损** | 注册时明确提示"上级关系终身锁定",退款从后续佣金抵扣 |
 | **分销模式涉传风险** | **低** | **封禁/处罚** | 严格控制在两级分销,无团队计酬、无入门费,合规底线 |
 | 竞品快速跟进 | 中 | 价格战 | 用数据+AI壁垒,竞品只有工具我们有平台+数据 |
@@ -457,7 +457,7 @@ Phase 1 (Week 7 上线)
 |------|-------------|
 | 种子用户 | 100个能量师(付费) |
 | 年费收入 | ¥131,400 — ¥262,800(100-200人 × ¥1,314起) |
-| 日盘生成量 | 500+ |
+| 日能量盘生成量 | 500+ |
 | 日活用户 | 50+ 能量师 |
 | 净推荐值(NPS) | > 60(口碑种子) |
 | 用户留存(7日) | > 60% |
@@ -468,4 +468,4 @@ Phase 1 (Week 7 上线)
 
 ---
 
-> **一句话总结:** 用 6 周做一个"能量师的AI智能工具",输入生日即得命盘+AI完整解读,让能量师付 **¥1,314/年(种子价)** 换来命盘解读一步到位,快速滚起现金流,再拿钱迭代大众版 + 电商。
+> **一句话总结:** 用 6 周做一个"能量师的AI智能工具",输入生日即得能量盘+AI完整解读,让能量师付 **¥1,314/年(种子价)** 换来能量盘解读一步到位,快速滚起现金流,再拿钱迭代大众版 + 电商。

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 239 - 188
docs/phase1-user-stories.md


+ 13 - 13
docs/platform-value.md

@@ -25,7 +25,7 @@
 
 | 功能 | 解决什么问题 | 传播机制 |
 |------|-------------|----------|
-| 生日输入 → 三角形命盘 | 零门槛获得个人命盘,3 秒出结果 | 社交裂变:测测你的主性格数字 |
+| 生日输入 → 三角形能量盘 | 零门槛获得个人能量盘,3 秒出结果 | 社交裂变:测测你的主性格数字 |
 | 免费基础解读 | 理解自己的性格、天赋、运势走向 | 生成海报分享朋友圈 |
 | AI 对话咨询 | 针对具体问题(事业/感情/财运)获得建议 | 高粘性,每日打开 |
 | 人格匹配 | 发现与谁"数字相合" | 邀请好友匹配 → 病毒传播 |
@@ -50,8 +50,8 @@
 | 功能 | 价值点 | 收益模式 |
 |------|--------|----------|
 | 客户管理(添加/分组/标注) | 代替 Excel,提升 10 倍效率 | 专业版年费订阅 |
-| 批量导入分析 | 一次导入 50 人,自动生成全部盘 | 专业版功能亮点 |
-| 客户盘标注批注 | 每次咨询记录留痕,归档可查 | 专业版 |
+| 批量导入分析 | 一次导入 50 人,自动生成全部能量盘 | 专业版功能亮点 |
+| 客户能量盘标注批注 | 每次咨询记录留痕,归档可查 | 专业版 |
 | 平台展示 / 获取客源 | 免费曝光,平台按地域/专长推荐 | 能量师入驻费或抽佣 |
 | 付费咨询(平台抽 20%) | 线上完成咨询-支付闭环 | 持续流水抽成 |
 
@@ -68,7 +68,7 @@
 **这是真正的护城河:**
 
 ```
-更多用户 → 更多生日盘数据 → AI 学习解读模式 → 解读更准确
+更多用户 → 更多生日能量盘数据 → AI 学习解读模式 → 解读更准确
     ↑                                             │
     └────────── 更好的体验吸引更多用户 ←───────────┘
@@ -80,7 +80,7 @@
 
 | 数据来源 | 规模预期 | 商业价值 |
 |----------|---------|----------|
-| 用户输入生日信息 | 万级 → 百万级 | 数字能量学最大的中国人口盘数据库 |
+| 用户输入生日信息 | 万级 → 百万级 | 数字能量学最大的中国人口能量盘数据库 |
 | AI 对话记录(脱敏) | 每日千条 → 十万条 | 训练行业专属大模型 |
 | 能量师标注/解读内容 | 专业级数据 | 标准化知识库,可输出为 API 服务 |
 | 匹配关系数据 | 社交行为数据 | 建立"数字人格 × 社会关系"映射 |
@@ -121,7 +121,7 @@
 ```
 方案 A:轻量匹配(MVP 方向)
    ┌─────────────────────────────────────┐
-   │  输入你的生日 → 生成盘            │
+   │  输入你的生日 → 生成能量盘            │
    │  邀请好友 / 输入对方生日             │
    │  生成「你们数字合拍度」卡片          │
    │  分享到朋友圈 / 微信对话             │
@@ -158,7 +158,7 @@
 
 | 调理维度 | 具体内容 | 变现形式 |
 |----------|---------|----------|
-| **命名用数** | 分析名字中的数字能量是否与先天盘匹配,提出改名/用名建议 | 付费增值报告 |
+| **命名用数** | 分析名字中的数字能量是否与先天能量盘匹配,提出改名/用名建议 | 付费增值报告 |
 | **号码能量** | 手机号/车牌号数字组合的能量分析与优化建议 | 增值服务 |
 | **色彩调理** | 根据缺失数字推荐穿搭/家居色彩方案 | 可电商带货 |
 | **方位建议** | 卧室/办公位朝向、城市选择等 | 增值服务 |
@@ -224,10 +224,10 @@
 
 > 数字产品(报告/方案)是最高毛利品类,应作为第一阶段电商主力。
 
-#### 转化链路(用户从盘到下单)
+#### 转化链路(用户从能量盘到下单)
 
 ```
-用户生成盘 → 解读显示"你缺少 5 号能量"
+用户生成能量盘 → 解读显示"你缺少 5 号能量"
 系统推荐调理方案(含商品)
@@ -240,7 +240,7 @@
 
 #### 为什么电商和命理天生匹配
 
-- **推荐精准**:AI 根据盘缺失数字推荐对应商品,每个用户推荐不同,天然个性化
+- **推荐精准**:AI 根据能量盘缺失数字推荐对应商品,每个用户推荐不同,天然个性化
 - **转化率高**:用户刚看完"我缺什么",立即看到"补什么",购买意愿最强
 - **退货率低**:开运/调理类商品带有心理属性,退货率远低于普通电商(预期 < 5%)
 - **复购自然**:流年变化、新需求出现时,用户会回来重新匹配
@@ -296,8 +296,8 @@
 
 | 阶段 | 目标 | 关键动作 | 数据指标 |
 |------|------|---------|---------|
-| **Phase 1** | 验证核心价值 | MVP 上线(输入→盘→免费解读→VIP) | DAU > 1000, VIP 转化率 > 3% |
-| **Phase 2** | 建立数据飞轮 | AI 对话上线 + 能量师入驻 + 人格匹配 | 月活 > 1 万, 日盘生成 > 5000 |
+| **Phase 1** | 验证核心价值 | MVP 上线(输入→能量盘→免费解读→VIP) | DAU > 1000, VIP 转化率 > 3% |
+| **Phase 2** | 建立数据飞轮 | AI 对话上线 + 能量师入驻 + 人格匹配 | 月活 > 1 万, 日能量盘生成 > 5000 |
 | **Phase 3** | 社交化爆发 | 陌生人匹配 + 社群 + 内容社区 | 月活 > 10 万, 匹配互动率 > 30% |
 | **Phase 4** | 平台化输出 | 知识库 API + 企业服务 + 行业标准 | B 端营收占比 > 30% |
 
@@ -308,7 +308,7 @@
 1. **人人都在寻找"认识自己"的工具。** 从星座到 MBTI 到数字能量学,人类从未停止。
 2. **AI 让玄学变得可用。** 过去命理分析靠师傅经验,未来靠 AI + 海量数据。
 3. **匹配是最高频的社交场景。** 当"合不合"能用数字说话,用户会自发传播。
-4. **数据是终极壁垒。** 谁拥有最多的盘数据 + 解读数据,谁就定义了行业标准。
+4. **数据是终极壁垒。** 谁拥有最多的能量盘数据 + 解读数据,谁就定义了行业标准。
 
 ---
 

+ 9 - 9
docs/presentation/comparison/index.html

@@ -101,7 +101,7 @@
   <h1 class="h1 anim-fade-up" data-anim="fade-up">1.0 分阶段开发与运营对齐方案</h1>
   <p class="lede" style="max-width:560px">数字心理学·全生命周期AI赋能系统<br>技术方 + 运营方 · 量入为出 · 数据决定节奏</p>
   <div class="phase-strip" style="max-width:520px;margin:16px auto 0">
-    <div class="seg" style="background:#1565c0;flex:2">Phase 1<br>2个月 · 盘+解读基础</div>
+    <div class="seg" style="background:#1565c0;flex:2">Phase 1<br>2个月 · 能量盘+解读基础</div>
     <span style="color:#999;font-size:10px">▶</span>
     <div class="seg" style="background:#1976d2">P2<br>⑤分销支付</div>
     <span style="color:#999;font-size:10px">▶</span>
@@ -147,7 +147,7 @@
   <table class="diff-table">
     <thead><tr><th style="width:40px">#</th><th>模块</th><th>核心功能</th><th>估工</th></tr></thead>
     <tbody>
-      <tr><td><strong>1</strong></td><td><strong>三角形盘引擎</strong></td><td>姓名+生日 → 3秒出图,Canvas可视化,五区色块</td><td>3周</td></tr>
+      <tr><td><strong>1</strong></td><td><strong>三角形能量盘引擎</strong></td><td>姓名+生日 → 3秒出图,Canvas可视化,五区色块</td><td>3周</td></tr>
       <tr><td><strong>2</strong></td><td><strong>AI五区完整解读</strong></td><td>LLM自动生成主性格+父源+母源+左中右区,Prompt调优</td><td>4周</td></tr>
       <tr><td><strong>3</strong></td><td><strong>少儿板块</strong></td><td>核心性格+天赋潜能+学习判定(独立Prompt体系)</td><td>3周</td></tr>
       <tr><td><strong>4</strong></td><td><strong>能量师CRM</strong></td><td>客户绑定/互动记录/信息补充/客户列表/活跃度</td><td>4周</td></tr>
@@ -166,7 +166,7 @@
   <table class="diff-table">
     <thead><tr><th>功能</th><th style="text-align:center">免费访客</th><th style="text-align:center">C端 ¥299/年</th><th style="text-align:center">能量师 ¥1,314+/年</th></tr></thead>
     <tbody>
-      <tr><td>盘生成</td><td style="text-align:center">✅ 3次/日</td><td style="text-align:center">✅ 不限</td><td style="text-align:center">✅ 不限</td></tr>
+      <tr><td>能量盘生成</td><td style="text-align:center">✅ 3次/日</td><td style="text-align:center">✅ 不限</td><td style="text-align:center">✅ 不限</td></tr>
       <tr><td>主性格概要</td><td style="text-align:center">✅ 文字概要</td><td style="text-align:center">✅ 完整</td><td style="text-align:center">✅ 完整</td></tr>
       <tr><td>AI五区完整解读</td><td style="text-align:center">❌ 仅预览</td><td style="text-align:center">✅</td><td style="text-align:center">✅</td></tr>
       <tr><td>少儿板块</td><td style="text-align:center">❌</td><td style="text-align:center">✅</td><td style="text-align:center">✅</td></tr>
@@ -252,7 +252,7 @@
     <div class="phase-card" style="flex:2;border-color:#1565c0;background:#e3f2fd">
       <div class="pnum" style="color:#1565c0">P1</div>
       <div class="ptitle" style="font-size:10px;color:#1565c0">2个月</div>
-      <div style="font-size:9px;margin-top:4px">盘+解读基础</div>
+      <div style="font-size:9px;margin-top:4px">能量盘+解读基础</div>
     </div>
     <span style="color:#1565c0;font-size:10px">▶</span>
     <div class="phase-card" style="border-color:#1976d2">
@@ -287,7 +287,7 @@
   <table class="diff-table mt-m">
     <thead><tr><th>阶段</th><th>时间</th><th>开发完成目标</th><th>运营推广目标</th><th>技术方累计收入</th></tr></thead>
     <tbody>
-      <tr><td><strong>P1</strong></td><td>M1-2</td><td>盘+AI初步+天赋解码+分销基础+支付+CRM</td><td><strong>300种子能量师</strong></td><td><strong>¥29.94万</strong></td></tr>
+      <tr><td><strong>P1</strong></td><td>M1-2</td><td>能量盘+AI初步+天赋解码+分销基础+支付+CRM</td><td><strong>300种子能量师</strong></td><td><strong>¥29.94万</strong></td></tr>
       <tr><td>P2</td><td>M3</td><td><strong>⑤分销支付板块</strong>(面板+C端支付+裂变)</td><td>+100能量师 +50C端</td><td>¥40.52万</td></tr>
       <tr><td>P3</td><td>M4</td><td><strong>②成人五区完整</strong>+CRM完善+分享导出</td><td>+100能量师 +150C端</td><td>¥52.29万</td></tr>
       <tr><td>P4</td><td>M5</td><td><strong>③少儿完整板块</strong>+培训引流+数据</td><td>+150能量师 +200C端</td><td>¥69.65万</td></tr>
@@ -301,12 +301,12 @@
 
 <section class="slide" data-title="Phase 1">
   <p class="kicker">Phase 1 · 第1-2个月</p>
-  <h2 class="h2">MVP基础 · 盘+主性格+天赋解码</h2>
+  <h2 class="h2">MVP基础 · 能量盘+主性格+天赋解码</h2>
   <div class="phase-detail">
     <div class="phase-col dev">
       <h4>🛠 开发完成目标</h4>
       <ul>
-        <li><strong>① 三角形盘引擎</strong> — Canvas可视化,3秒出图,五区色块</li>
+        <li><strong>① 三角形能量盘引擎</strong> — Canvas可视化,3秒出图,五区色块</li>
         <li><strong>② AI初步解读</strong> — 成人主性格深度分析(首发仅主性格,后续P3扩展五区)</li>
         <li><strong>③ 少儿天赋解码</strong> — 首发仅天赋潜能,后续P4扩展全板块</li>
         <li><strong>④ CRM基础</strong> — 客户绑定+客户列表</li>
@@ -538,11 +538,11 @@
     </div>
     <div style="padding:11px 16px;background:var(--surface-2);border-radius:10px;border-left:4px solid #c62828">
       <strong style="color:#c62828">🔐 数据隐私与安全</strong>
-      <div class="hint" style="margin-top:3px">盘信息涉及姓名+生日等个人隐私数据。平台积累大量用户性格分析记录,一旦泄露影响面广。需从架构层设计数据脱敏与权限控制,避免合规风险。</div>
+      <div class="hint" style="margin-top:3px">能量盘信息涉及姓名+生日等个人隐私数据。平台积累大量用户性格分析记录,一旦泄露影响面广。需从架构层设计数据脱敏与权限控制,避免合规风险。</div>
     </div>
     <div style="padding:11px 16px;background:var(--surface-2);border-radius:10px;border-left:4px solid #1565c0">
       <strong style="color:#1565c0">⏱ 进度超期风险</strong>
-      <div class="hint" style="margin-top:3px">5人团队做6个月开发量,P1仅8周需交付盘+AI+CRM+支付+分销基础,排期紧凑。1人后端是最大瓶颈——API+数据库+部署全在他身上。任一环节延期将连锁影响后续所有阶段。</div>
+      <div class="hint" style="margin-top:3px">5人团队做6个月开发量,P1仅8周需交付能量盘+AI+CRM+支付+分销基础,排期紧凑。1人后端是最大瓶颈——API+数据库+部署全在他身上。任一环节延期将连锁影响后续所有阶段。</div>
     </div>
     <div style="padding:11px 16px;background:var(--surface-2);border-radius:10px;border-left:4px solid #f57c00">
       <strong style="color:#f57c00">🔗 能量师长期绑定</strong>

+ 26 - 26
docs/presentation/index.html

@@ -69,7 +69,7 @@
     <div class="cover-content">
       <p class="kicker">1.0 第一阶段 · 产品介绍</p>
       <h1 class="h1">数字心理学<br>AI智能体</h1>
-      <p class="lede">3秒出盘 · AI自动解读 · 能量师CRM · 少儿天赋</p>
+      <p class="lede">3秒出能量盘 · AI自动解读 · 能量师CRM · 少儿天赋</p>
       <p class="cover-sub">专为数字心理学能量师打造的 AI 智能工具 + 客户管理系统</p>
       <div class="cover-meta">
         <span>✦ 能量师 ¥1,314-1,914/年</span>
@@ -88,7 +88,7 @@
       <div class="problem-stack mt-l">
         <div class="problem-item">
           <div class="problem-num">①</div>
-          <div><h4>手绘三角形</h4><p class="dim">每一张盘都要手动画三角形、填数字,步骤繁琐容易出错</p></div>
+          <div><h4>手绘三角形</h4><p class="dim">每一张能量盘都要手动画三角形、填数字,步骤繁琐容易出错</p></div>
         </div>
         <div class="problem-item">
           <div class="problem-num">②</div>
@@ -100,7 +100,7 @@
         </div>
         <div class="problem-item">
           <div class="problem-num">④</div>
-          <div><h4>客户难跟进</h4><p class="dim">做完盘客户就流失了,无法建立长期关系和持续服务</p></div>
+          <div><h4>客户难跟进</h4><p class="dim">做完能量盘客户就流失了,无法建立长期关系和持续服务</p></div>
         </div>
       </div>
     </div>
@@ -116,7 +116,7 @@
       <div class="grid g3">
         <div class="feature-card">
           <div class="feature-icon">✦</div>
-          <h4>盘+AI解读</h4>
+          <h4>能量盘+AI解读</h4>
           <p class="dim">纯前端计算,3秒出图,AI五区完整解读,支持语音追问</p>
         </div>
         <div class="feature-card">
@@ -144,7 +144,7 @@
           <div class="role-badge">普通用户</div>
           <div class="role-price">免费</div>
           <ul>
-            <li>每日 3 次盘生成</li>
+            <li>每日 3 次能量盘生成</li>
             <li>每日 1 次主性格概要</li>
             <li>近 7 天历史记录</li>
             <li>每日 1 次分享图片</li>
@@ -155,7 +155,7 @@
           <div class="role-badge" style="background:#7B2DC8">C端年费用户</div>
           <div class="role-price">¥299/年</div>
           <ul>
-            <li>✅ 无限盘生成</li>
+            <li>✅ 无限能量盘生成</li>
             <li>✅ AI 五区完整解读</li>
             <li>✅ 少儿板块解读</li>
             <li>✅ 无限分享 + PDF 导出</li>
@@ -184,7 +184,7 @@
       <h2 class="h2">输入姓名和出生日期</h2>
       <div class="page-layout mt-l">
         <div class="page-desc">
-          <p class="lede">3 秒完成盘生成。推广打开时自动显示分享者信息,裂变入口天然嵌入。</p>
+          <p class="lede">3 秒完成能量盘生成。推广打开时自动显示分享者信息,裂变入口天然嵌入。</p>
           <ul class="page-features">
             <li><strong>核心操作:</strong>姓名 + 年月日选择器</li>
             <li><strong>推广入口:</strong>通过能量师链接打开时,顶部醒目标示"由 XX 能量师分享"</li>
@@ -199,7 +199,7 @@
             <div class="mock-body">
               <div class="mock-referrer">由 <strong>李明</strong> 能量师分享</div>
               <div class="mock-hero">✦</div>
-              <div class="mock-title">数字盘</div>
+              <div class="mock-title">数字能量盘</div>
               <div class="mock-sub">输入出生信息,3秒生成专属数字三角形</div>
               <div class="mock-inputs">
                 <div class="mock-field"><label>姓名(选填)</label><div class="mock-input">输入姓名</div></div>
@@ -209,8 +209,8 @@
                   <div class="mock-field sm"><label>日</label><div class="mock-input">01</div></div>
                 </div>
               </div>
-              <div class="mock-btn">生成盘</div>
-              <div class="mock-quota">今日免费:盘 0/3 | 解读 0/1</div>
+              <div class="mock-btn">生成能量盘</div>
+              <div class="mock-quota">今日免费:能量盘 0/3 | 解读 0/1</div>
             </div>
           </div>
         </div>
@@ -220,15 +220,15 @@
   </section>
 
   <!-- 6. Page: Chart Display -->
-  <section class="slide page-slide" data-title="盘展示">
+  <section class="slide page-slide" data-title="能量盘展示">
     <div class="slide-inner">
-      <p class="kicker">页面 · 盘展示页</p>
-      <h2 class="h2">三角形盘 + AI 交互对话</h2>
+      <p class="kicker">页面 · 能量盘展示页</p>
+      <h2 class="h2">三角形能量盘 + AI 交互对话</h2>
       <div class="page-layout mt-l">
         <div class="page-desc">
-          <p class="lede">5 层三角形盘可折叠收起,五区解读全部通过 AI 聊天完成。点击区域标签一键带入聊天框,语音输入支持便捷提问。</p>
+          <p class="lede">5 层三角形能量盘可折叠收起,五区解读全部通过 AI 聊天完成。点击区域标签一键带入聊天框,语音输入支持便捷提问。</p>
           <ul class="page-features">
-            <li><strong>三角可折叠:</strong>点击"▼ 盘三角形"收起,专注聊天</li>
+            <li><strong>三角可折叠:</strong>点击"▼ 能量盘三角形"收起,专注聊天</li>
             <li><strong>点击带入聊天:</strong>点击区域标签自动填入"解读我的XX"</li>
             <li><strong>五区 AI 对话:</strong>无需跳页,对话框直接追问任何区域</li>
             <li><strong>功能输入栏:</strong>导出报告、分享图片按钮集成在输入框两侧</li>
@@ -238,14 +238,14 @@
         <div class="phone-mock">
           <div class="phone-frame">
             <div class="mock-status">9:41</div>
-            <div class="mock-header">王芳的盘</div>
+            <div class="mock-header">王芳的能量盘</div>
             <div class="mock-body" style="display:flex;flex-direction:column;padding:8px 10px">
               <div style="display:flex;align-items:center;gap:6px;padding:4px 0;margin-bottom:4px;cursor:default;user-select:none">
-                <span style="font-size:10px;color:#7B2DC8;font-weight:600">▼ 盘三角形</span>
+                <span style="font-size:10px;color:#7B2DC8;font-weight:600">▼ 能量盘三角形</span>
                 <span style="flex:1;border-top:1px solid #e8e0f0"></span>
               </div>
               <div style="background:#fff;border-radius:10px;padding:6px;margin-bottom:6px;text-align:center">
-                <img src="命盘图示例.jpg" alt="命盘图" style="width:100%;height:auto;max-width:250px;display:block;margin:0 auto;border-radius:6px">
+                <img src="能量盘图示例.jpg" alt="能量盘图" style="width:100%;height:auto;max-width:250px;display:block;margin:0 auto;border-radius:6px">
               </div>
               <div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
                 <div style="font-size:9px;padding:4px 10px;border-radius:12px;background:#4A148C;color:#fff;font-weight:500">🌱 左区 0-20</div>
@@ -353,7 +353,7 @@
       <h2 class="h2">专业呈现 · 便捷变现</h2>
       <div class="page-layout mt-l">
         <div class="page-desc">
-          <p class="lede">盘含解读一键生成精美分享图或 PDF。C端年费 ¥299,能量师年费 ¥1,314-1,914。</p>
+          <p class="lede">能量盘含解读一键生成精美分享图或 PDF。C端年费 ¥299,能量师年费 ¥1,314-1,914。</p>
           <ul class="page-features">
             <li><strong>分享图片:</strong>生成含三角形+解读的精美卡片</li>
             <li><strong>PDF 导出:</strong>A4 版式,专业报告质感</li>
@@ -371,7 +371,7 @@
                 <div style="flex:1;text-align:center;border:1px solid #ddd;border-radius:10px;padding:10px">
                   <div style="font-size:12px;color:var(--text-2)">C端年费</div>
                   <div style="font-size:22px;font-weight:800;color:#4A148C;line-height:1">¥299</div>
-                  <div style="font-size:10px;color:var(--text-3)">无限盘+解读</div>
+                  <div style="font-size:10px;color:var(--text-3)">无限能量盘+解读</div>
                 </div>
                 <div style="flex:1;text-align:center;border:2px solid #4A148C;border-radius:10px;padding:10px;background:#faf5ff">
                   <div style="font-size:12px;color:var(--text-2)">能量师年费</div>
@@ -425,7 +425,7 @@
                 <div style="font-size:9px;padding:2px 6px;border-radius:10px;background:#d4edda;color:#155724">已付费C端</div>
               </div>
               <div style="padding:6px;background:#fff;border-radius:6px;border:1px solid #eee;font-size:10px;color:var(--text-2);line-height:1.6">
-                <strong style="color:var(--text-1)">📝 客户备注:</strong>王芳 - 关注事业发展,1988年生,已婚有子。上次盘后表示对少儿分析感兴趣。
+                <strong style="color:var(--text-1)">📝 客户备注:</strong>王芳 - 关注事业发展,1988年生,已婚有子。上次能量盘后表示对少儿分析感兴趣。
               </div>
             </div>
           </div>
@@ -434,7 +434,7 @@
           <p class="lede">分享小程序码 → 客户自动绑定 → 查看互动记录 → 补充客户信息 → 持续跟进</p>
           <ul class="page-features">
             <li><strong>客户列表:</strong>展示所有绑定的客户,含主性格/活跃度/付费状态</li>
-            <li><strong>互动记录:</strong>查看客户的盘、AI解读、对话历史</li>
+            <li><strong>互动记录:</strong>查看客户的能量盘、AI解读、对话历史</li>
             <li><strong>客户备注:</strong>补充电话号码、标签、关注点等个性化信息</li>
             <li><strong>活跃度追踪:</strong>了解客户使用频率,及时跟进激活</li>
             <li><strong>C端佣金:</strong>绑定客户付费立即获得 40% 佣金 + 上级 5%</li>
@@ -490,13 +490,13 @@
         <div class="pb-item" style="min-width:140px">
           <div class="pb-value" style="font-size:32px">免费</div>
           <div class="pb-label">普通用户</div>
-          <div style="font-size:12px;color:var(--text-3);margin-top:4px">每日3次盘</div>
+          <div style="font-size:12px;color:var(--text-3);margin-top:4px">每日3次能量盘</div>
         </div>
         <div class="pb-plus" style="font-size:20px">→</div>
         <div class="pb-item" style="min-width:140px;border-color:var(--brand);background:var(--brand-bg)">
           <div class="pb-value" style="font-size:32px;color:var(--brand)">¥299</div>
           <div class="pb-label">C端年费</div>
-          <div style="font-size:12px;color:var(--text-3);margin-top:4px">无限盘+解读+少儿</div>
+          <div style="font-size:12px;color:var(--text-3);margin-top:4px">无限能量盘+解读+少儿</div>
         </div>
         <div class="pb-plus" style="font-size:20px">→</div>
         <div class="pb-item" style="min-width:140px;border-color:#f57f17">
@@ -568,7 +568,7 @@
         <div class="rm-phase">
           <div class="rm-week">Week 1-2</div>
           <div class="rm-title">核心引擎</div>
-          <div class="rm-items">盘计算引擎 · Canvas可视化 · AI五区解读Prompt</div>
+          <div class="rm-items">能量盘计算引擎 · Canvas可视化 · AI五区解读Prompt</div>
         </div>
         <div class="rm-connector">→</div>
         <div class="rm-phase">
@@ -623,7 +623,7 @@
           <div style="background:#9C5CD8;color:#fff;font-size:12px;font-weight:700;padding:4px 10px;border-radius:8px;white-space:nowrap">Phase 3</div>
           <div style="flex:1">
             <div style="font-size:15px;font-weight:600;margin-bottom:4px">客户匹配 + 企业服务</div>
-            <div style="font-size:13px;color:var(--text-2)">平台智能匹配客户,企业团购盘分析</div>
+            <div style="font-size:13px;color:var(--text-2)">平台智能匹配客户,企业团购能量盘分析</div>
           </div>
         </div>
       </div>

+ 105 - 12
docs/requirements-changelog.md

@@ -5,6 +5,99 @@
 
 ---
 
+## v20260604.3
+
+**发布日期:** 2026-06-04
+**变更类型:** 新增功能
+**状态:** ✅ 已确认
+
+### 版本摘要
+
+新增 **「提现」功能**(sys_manage 管理后台专属),覆盖提现规则配置、手续费设置、提现记录查询与导出、风控告警全流程。提现方式采用微信「企业付款到零钱」(夜间批量处理,23:30 定时作业),叠加劳务报酬个税预扣与节税策略。
+
+### 变更清单
+
+| # | 类型 | 变更 | 涉及位置 |
+|---|------|------|---------|
+| 1 | 🆕 新增 | `withdraw_records` 表(提现记录:金额/税务/通道/风控/审计字段) | US 新功能 |
+| 2 | 🆕 新增 | `user_wallet` 表(余额快照:可提现/冻结/累计/周限/失败计数) | US 新功能 |
+| 3 | 🆕 新增 | `withdraw_rule_config` 表(提现规则配置:管理员可动态调整限额/费率/税务参数) | sys_manage |
+| 4 | 🆕 新增 | 提现申请 API(发起申请/查询进度/撤销) | 后端 API |
+| 5 | 🆕 新增 | 提现记录管理 API(列表查询/单条详情/导出 CSV) | sys_manage 管理后台 |
+| 6 | 🆕 新增 | 税务预览 API(输入金额 → 返回预计扣税+实际到账金额) | 前端 withdraw 页 |
+| 7 | 🆕 新增 | 夜间批量处理定时任务(`@Scheduled` 23:30 执行,支持余额充足的微信直付与微信退费两种通道) | 后端 Service |
+| 8 | 🆕 新增 | 风控告警机制(余额不足自动标记 `NEED_MANUAL`,超 3 天未处理进入 `FAILED` 并通知运维) | 后端 Service |
+| 9 | 🆕 新增 | `sys_config` 税务参数(8 条:劳务报酬免征额/阶梯税率/速算扣除/年度汇算开关) | US-8.1 |
+| 10 | 🆕 新增 | 节税策略:周限提 + 年度汇算退补 + ¥800 免征提示 + 代开发票引导(>¥30,000/年) | 前端/后端 |
+| 11 | 🆕 新增 | 前端提现页(`client/pages/withdraw/index.vue`:余额展示 + 输入 + 税务预览卡片 + 快捷金额 + 提现记录入口) | 前端 |
+| 12 | 🆕 新增 | 管理后台提现管理(概览卡片 + 记录列表 + 手动处理按钮 + 导出功能) | sys_manage |
+| 13 | 🔧 更新 | `commissions` 表新增字段(`wallet_locked`/`withdraw_record_id`,关联提现记录) | 数据库 |
+| 14 | 🔧 更新 | `profileApi` 新增 `withdrawSummary()`(累计提现/累计个税/本年度汇总) | API |
+| 15 | 🔧 更新 | 个人中心新增「我的提现」入口(≡ 记录列表) | 前端 profile |
+
+### 影响范围
+
+- **数据库**:新增 2 张表(`withdraw_records`/`withdraw_rule_config`)+ 1 张快照表(`user_wallet`)+ `commissions` 表 2 个字段
+- **API**:新增 6 个提现相关端点 + 1 个税务预览端点
+- **定时任务**:新增夜间批量提现处理(23:30 cron)+ 安全监控(每分钟 pending 巡检)
+- **前端**:新增 withdraw 页面 + profile 入口;管理后台新增提现模块
+- **税务**:劳务报酬所得预扣代缴(¥800 免征、20%/30%/40% 累进),平台承担微信手续费 0.6%,退费通道走微信「退款」API(不扣税,需退款余额充足)
+- **节税**:周限提策略 + 年度汇算 + 小额合并提示 + 代开发票引导
+
+### 约束与风险
+
+- **微信商户余额约束**:企业付款依赖微信「可 Master 余额」,非企业银行账户。余额不足时批量任务自动跳过,次日重试;运维需每日监控并充值
+- **提现频率限制**:每人每周 1 次(`withdraw.max_per_week`),后台可调整
+- **退款余额独立性**:首笔退费走「退款余额」,与 Master 余额分离,退款余额为 0 时退费降级为标准微信直付,首笔退费资格作废
+- **人工介入规则**:单笔 >¥500 需审核;日失败 >3 次冻结 24h;超过 3 天未处理告警运维
+
+### 迁移说明
+
+新增功能,无需数据迁移。现有佣金记录 (`commission`/`commission_history`) 需在首次提现时批量初始化 `user_wallet` 余额快照(`available_balance = SUM(settled_amount)`)。
+
+---
+
+## v20260604.2
+
+**发布日期:** 2026-06-04
+**变更类型:** 重构 + 新增
+**状态:** ✅ 已确认
+
+### 版本摘要
+
+全量重构 Phase 1 需求文档:①术语统一"命盘→能量盘";②查重逻辑改为 `(userId, name, birthday)`;③"我的能量盘"按姓名+生日匹配自动展示;④关系类型从 6 类扩为 9 类(亲子拆为父母/子女/祖父母/孙子女),并改为后台动态配置;⑤关系能量分析从双盘对比彻底重设为**多人选择+提问+AI对话+分析记录**模式;⑥"我的"页面新增按角色展示的统计卡片。
+
+### 变更清单
+
+| # | 类型 | 变更 | 涉及位置 |
+|---|------|------|---------|
+| 1 | 🔄 全局替换 | 所有"命盘"→"能量盘"(含 3 处"数字能量能量盘"→"数字能量盘") | README.md, style-guide.md, system-spec.md, phase1-product-plan.md, phase1-user-stories.md |
+| 2 | 🔧 更新 | US-1.1 查重从 `(userId, birthday)` 改为 `(userId, name, birthday)`,确认弹窗文案同步 | US-1.1 |
+| 3 | 🆕 新增 | US-5.2 "我的能量盘"入口(自动匹配用户注册姓名+生日) | US-5.2 |
+| 4 | 🆕 新增 | US-5.2 统计卡片区(按角色展示咨询/推广/收入等统计数据) | US-5.2 |
+| 5 | 🔧 更新 | US-10.6 关系类型表:亲子→父母/子女/祖父母/孙子女(6类→9类) | US-10.6 |
+| 6 | 🔧 更新 | US-10.6 关系类型改为从 `sys_config relation.types` 动态加载 | US-10.6, US-8.1 |
+| 7 | 🔄 重写 | US-10.6 核心流程重设计:静态双盘对比 → 多人选择+提问+AI对话+分析记录 | US-10.6 |
+| 8 | 🆕 新增 | `relation_analysis_records` 表(分析会话,含成员快照) | US-10.6 |
+| 9 | 🆕 新增 | 6 个分析相关 API:start/list/detail/delete/chatSend/chatHistory | US-10.6 |
+| 10 | 🆕 新增 | `relations` 表移除 `compatibility_score`/`ai_analysis_cache`/`last_analyzed_at` 字段 | US-10.6 |
+| 11 | 🔧 更新 | US-8.1 sys_config 种子数据新增 `relation.types` JSON 配置项 | US-8.1 |
+| 12 | 🔧 更新 | US-8.1 管理后台新增关系类型配置卡片(动态表格增删改) | US-8.1 |
+| 13 | 🔧 更新 | 附录A:ChartRecord 联合唯一索引 `uk_user_name_birthday` | 附录A |
+| 14 | 🔧 更新 | style-guide §6.5 个人中心布局图:新增区域三统计卡片 | style-guide.md |
+| 15 | 🔄 重写 | style-guide §8.5 关系页布局(8.5.2 首页/8.5.3 分析选择/8.5.4 分析对话) | style-guide.md |
+
+### 影响范围
+
+- **数据库**:`chart_records` 索引变更 + `relations` 表字段精简 + 新增 `relation_analysis_records` 表
+- **API**:新增分析会话类 6 个接口;`/api/relation/detail`/`/api/relation/reanalyze` 废弃
+- **sys_config**:新增 1 项(relation.types JSON),共 21 项
+- **Dify**:关系分析从 Workflow(结构化输出)改为 Chatflow(自然语言对话)
+- **前端**:个人中心新增统计卡片 + 关系页全流程重写(选择页+对话页+记录页)
+- **后端**:ChartRecord 查重逻辑改 3 字段、新增分析会话管理相关 Service
+
+---
+
 ## v20260604.1
 
 **发布日期:** 2026-06-04
@@ -13,7 +106,7 @@
 
 ### 版本摘要
 
-新增**超级会员**角色(¥1,314/年,固定价),位于C端年费与能量师之间。超级会员享有全部AI权益 + 关系能量分析页签 + 分销权限。同时新增 **🔗 关系** 小程序中间页签(首页·关系·分析·我的),包含夫妻/亲子/同事/朋友/上下级关系盘对比分析 + 八星号码能量分析功能。
+新增**超级会员**角色(¥1,314/年,固定价),位于C端年费与能量师之间。超级会员享有全部AI权益 + 关系能量分析页签 + 分销权限。同时新增 **🔗 关系** 小程序中间页签(首页·关系·分析·我的),包含夫妻/亲子/同事/朋友/上下级关系能量盘对比分析 + 八星号码能量分析功能。
 
 ### 变更清单
 
@@ -25,7 +118,7 @@
 | 4 | 🆕 新增 | US-10.3 升级路径(C端→超级会员补差价,超级→能量师补差价+佣金补差) | EPIC 10 |
 | 5 | 🆕 新增 | US-10.4 超级会员佣金结算(30%+5%比例分成,推广超级会员) | EPIC 10 |
 | 6 | 🆕 新增 | US-10.5 关系页签入口与付费引导(tabBar 改造,4页签) | EPIC 10 |
-| 7 | 🆕 新增 | US-10.6 添加关系人与双盘对比分析(6类关系,Dify Workflow) | EPIC 10 |
+| 7 | 🆕 新增 | US-10.6 添加关系人与双能量盘对比分析(6类关系,Dify Workflow) | EPIC 10 |
 | 8 | 🆕 新增 | US-10.7 八星号码能量分析(手机号/车牌号,8星映射+Dify解读) | EPIC 10 |
 | 9 | 🔄 更新 | productType 枚举:新增 'super_member' | US-6.6 |
 | 10 | 🔄 更新 | vipType 枚举:新增 'super_annual' | US-6.6 |
@@ -34,15 +127,15 @@
 | 13 | 🔄 更新 | 管理后台页面:新增超级会员定价+超级会员佣金配置卡片 | US-8.1.4 |
 | 14 | 🔄 更新 | 排期建议:新增 Week 10+(EPIC 10) | 排期建议 |
 | 15 | 🔄 更新 | 附录C 角色权限表:3类→4类(含超级会员列) | 附录C |
-| 16 | 🔄 更新 | TabBar 配置:盘页签移除→新增关系页签 | style-guide.md §8.2 |
-| 17 | 🆕 新增 | 关系页签布局规范(非会员引导/关系首页/双盘/号码分析) | style-guide.md §8.5 |
+| 16 | 🔄 更新 | TabBar 配置:能量盘页签移除→新增关系页签 | style-guide.md §8.2 |
+| 17 | 🆕 新增 | 关系页签布局规范(非会员引导/关系首页/双能量盘/号码分析) | style-guide.md §8.5 |
 | 18 | 🔄 更新 | 定价方案表 README:增加超级会员行列 | README.md |
 
 ### 影响范围
 
 - **定价体系**:4层角色,超级会员固定¥1,314,无种子价
 - **佣金体系**:超级会员推广超级会员 = 30%+5%,推广C端/能量师复用现有配置
-- **TabBar**:从 首页·命盘·分析·我的 改为 首页·关系·分析·我的(命盘页移除tab入口)
+- **TabBar**:从 首页·能量盘·分析·我的 改为 首页·关系·分析·我的(能量盘页移除tab入口)
 - **sys_config**:从17项增加到20项
 - **数据库**:新增 relations 表 + number_analyses 表
 - **Dify**:新增2个Workflow(关系能量分析 + 号码能量分析)
@@ -87,7 +180,7 @@
 
 ### 版本摘要
 
-按需求调整:学业方向分析不再作为独立菜单入口,改为**盘解读内容的组成部分**,嵌入在通用解读中展示。
+按需求调整:学业方向分析不再作为独立菜单入口,改为**能量盘解读内容的组成部分**,嵌入在通用解读中展示。
 
 ### 变更清单
 
@@ -254,7 +347,7 @@
 
 ### 版本摘要
 
-数字能量学智能体 Phase 1 完整需求规格,涵盖命盘生成、AI 解读、付费订阅、分销佣金、管理后台、前端样式指南及命盘算法命名约定。
+数字能量学智能体 Phase 1 完整需求规格,涵盖能量盘生成、AI 解读、付费订阅、分销佣金、管理后台、前端样式指南及能量盘算法命名约定。
 
 ### 包含文档
 
@@ -278,13 +371,13 @@
 | B端佣金 | 固定金额 ¥500(一级)/ ¥100(二级) |
 | C端佣金 | 比例 40%(直接)/ 5%(上级) |
 | 提现管理 | 推迟至 Phase 2 |
-| C端订阅入口 | 盘解读页底部 |
-| 盘计算 | 从 `calculator.js` 前端迁移到后端 `CalculatorService.java` |
+| C端订阅入口 | 能量盘解读页底部 |
+| 能量盘计算 | 从 `calculator.js` 前端迁移到后端 `CalculatorService.java` |
 | 咨询会话 | 按 `(userId, birthday)` 联合唯一索引,同用户+同生日始终返回同一条记录 |
-| 新生日弹窗 | "此生日将开启全新的盘咨询,确认吗?" |
-| 每日互动限制 | 非付费用户 3 轮/天,全局计数器,绑定当前盘 |
+| 新生日弹窗 | "此生日将开启全新的能量盘咨询,确认吗?" |
+| 每日互动限制 | 非付费用户 3 轮/天,全局计数器,绑定当前能量盘 |
 | 咨询字数限制 | "想了解的问题"输入框限 100 字 |
-| 盘位置命名 | A-H(输入层)+ I-X(7内部+15外部)= 30个位置 |
+| 能量盘位置命名 | A-H(输入层)+ I-X(7内部+15外部)= 30个位置 |
 | 外部公式 | P=reduce(I+M), Q=reduce(J+M), R=reduce(P+Q); S=reduce(K+N), T=reduce(L+N), U=reduce(S+T); V=reduce(M+O), W=reduce(N+O), X=reduce(V+W) |
 | 外部年龄映射 | 左=21-40岁, 顶=41-60岁, 右=61+岁 |
 

+ 123 - 76
docs/style-guide.md

@@ -7,7 +7,7 @@
 
 ## 一、品牌定位
 
-**数码能量学** — 用数字能量学 + AI 解读,帮助用户了解自己的盘。
+**数码能量学** — 用数字能量学 + AI 解读,帮助用户了解自己的能量盘。
 
 | 维度 | 描述 |
 |------|------|
@@ -48,7 +48,7 @@
 | 雾白 | `#E2E8F0` | 分割线、边框 |
 | 骨白 | `#F7F4EF` | 卡片背景(次) |
 
-### 2.4 盘数字色
+### 2.4 能量盘数字色
 
 ```
 1(创造/自主):  #D94A4A  · 赤红
@@ -81,9 +81,9 @@
 font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue',
              'Noto Sans CJK SC', 'Microsoft YaHei', sans-serif;
 
-// 数字(盘数据场景)
+// 数字(能量盘数据场景)
 font-family: 'Georgia', 'Times New Roman', serif;
-/* 盘中的关键数字使用衬线字体,与 UI 文字形成对比,强调"数字"的庄重感 */
+/* 能量盘中的关键数字使用衬线字体,与 UI 文字形成对比,强调"数字"的庄重感 */
 
 
 ```
@@ -92,7 +92,7 @@ font-family: 'Georgia', 'Times New Roman', serif;
 
 | 层级 | 字号 | 字重 | 行高 | 场景 |
 |------|------|------|------|------|
-| **H1** | 24px | 700 | 1.3 | 页面标题、盘页主数字 |
+| **H1** | 24px | 700 | 1.3 | 页面标题、能量盘页主数字 |
 | **H2** | 20px | 700 | 1.4 | 卡片标题、模態標題 |
 | **H3** | 18px | 600 | 1.4 | 区块小标题 |
 | **Body** | 15px | 400 | 1.6 | 正文、解读内容 |
@@ -169,7 +169,7 @@ $space-2xl: 48px;
 根据 DESIGN_VARIANCE = 8,优先使用非对称布局:
 
 - **首页**:输入区域居中(强引导),结果预览区错开排列
-- **盘页**:三角图居中,AI 解读区左对齐,订阅入口通栏
+- **能量盘页**:三角图居中,AI 解读区左对齐,订阅入口通栏
 - **分销面板**:顶部统计三列等宽,下方列表通栏(数据密集型简化)
 - **个人中心**:头像居中,下方功能列表通栏
 
@@ -182,7 +182,7 @@ $space-2xl: 48px;
 | 类型 | 背景 | 文字 | 圆角 | 高度 | 场景 |
 |------|------|------|------|------|------|
 | **主按钮** | `#1E3A5F` | `#FFFFFF` | `12px` | `48px` | 支付、开通、保存 |
-| **行动按钮** | `#C9A84C` | `#FFFFFF` | `12px` | `44px` | 生成盘、立即推广 |
+| **行动按钮** | `#C9A84C` | `#FFFFFF` | `12px` | `44px` | 生成能量盘、立即推广 |
 | **次要按钮** | `#FFFFFF` + 1px `#E2E8F0` 边框 | `#1A1A2E` | `10px` | `40px` | 取消、返回 |
 | **文字按钮** | 透明 | `#4A90D9` | — | `auto` | 链接、跳转 |
 
@@ -291,17 +291,17 @@ button[disabled] {
 │  │  └──┘ └──┘    │  │
 │  │               │  │
 │  │  ┌─────────┐  │  │
-│  │  │ 生成盘  │  │  行动按钮(金色)
+│  │  │ 生成能量盘  │  │  行动按钮(金色)
 │  │  └─────────┘  │  │
 │  └───────────────┘  │
 │                     │
 │  ┌───────────────┐  │
 │  │  ✦ 功能介绍    │  │  轻量卡片,展示 3 个功能点
-│  │  盘/AI/分享  │  │  水平排列,图标+文字
+│  │  能量盘/AI/分享  │  │  水平排列,图标+文字
 │  └───────────────┘  │
 │                     │
 ├─────────────────────┤
-│  首页│盘│AI│我的   │  TabBar
+│  首页│能量盘│AI│我的   │  TabBar
 └─────────────────────┘
 ```
 
@@ -309,13 +309,13 @@ button[disabled] {
 - NavBar 使用墨蓝底色,标题白色,返回箭头白色
 - 输入卡片置中,四周留呼吸空间
 - 功能引导卡片使用浅灰色圆角图标 + 文字
-- 生成盘按钮使用金色 `#C9A84C`,与品牌名呼应
+- 生成能量盘按钮使用金色 `#C9A84C`,与品牌名呼应
 
-### 6.2 盘解读页
+### 6.2 能量盘解读页
 
 ```
 ┌─────────────────────┐
-│  ← 数字能量盘      │  NavBar(透明背景,白色返回箭头)
+│  ← 数字能量盘      │  NavBar(透明背景,白色返回箭头)
 ├─────────────────────┤
 │  ┌───────────────┐  │
 │  │      O        │  │
@@ -361,7 +361,7 @@ button[disabled] {
 │  │  1号位:独立自主  ││
 │  └─────────────────┘│
 ├─────────────────────┤
-│  首页│盘│AI│我的   │
+│  首页│能量盘│AI│我的   │
 └─────────────────────┘
 ```
 
@@ -376,7 +376,7 @@ button[disabled] {
 
 ```
 ┌─────────────────────┐
-│  AI 盘解读         │
+│  AI 能量盘解读         │
 ├─────────────────────┤
 │                     │
 │  ┌───────────────┐  │
@@ -482,9 +482,19 @@ button[disabled] {
 │  └─────────────────┘    │
 │  ┌─────────────────┐    │
 │  │  种子价专属标记    │    │  仅种子价会员显示
-│  └─────────────────┘    │
-│                         │
-│  ┌─────────────────┐    │  区域三:功能菜单(分组卡片)
+  │  └─────────────────┘    │
+  │                         │
+  │  ┌─────────────────┐    │
+  │  │  种子价专属标记    │    │  仅种子价会员显示
+  │  └─────────────────┘    │
+  │                         │
+  │  ┌─────────────────┐    │  区域三:统计卡片(按角色展示)
+  │  │ 咨询 12次         │    │  (大号数字+标签, 水平等宽排列)
+  │  │ 推广收益 ¥860    │    │  浅灰蓝背景 #F7F8FC
+  │  │ 推广人数 6人     │    │  圆角 12px 内边距 16px
+  │  └─────────────────┘    │  普通用户仅"咨询次数"
+  │                         │
+  │  ┌─────────────────┐    │  区域四:功能菜单(分组卡片)
 │  │  📋 我的分析    ›│    │  「我的服务」
 │  │  💰 我的推广    ›│    │  仅付费用户可见
 │  └─────────────────┘    │
@@ -497,7 +507,7 @@ button[disabled] {
 │  │  ℹ️ 关于我们    ›│    │  所有用户
 │  └─────────────────┘    │
 │                         │
-│  ┌─────────────────┐    │  区域:退出登录
+  │  ┌─────────────────┐    │  区域:退出登录
 │  │  退出登录(红色)   │    │
 │  └─────────────────┘    │
 │                         │
@@ -511,6 +521,12 @@ button[disabled] {
 - 功能菜单每个 item 使用 1px 底部分割线
 - 右侧箭头 `#A0AEC0`
 - VIP 标记使用 `#FFF6E0` 背景 + `#C9A84C` 文字
+- 统计卡片区(区域三):背景 `#F7F8FC`,圆角 `12px`,内边距 `16px`,统计数字 `20px` 加粗,标签 `12px` 灰色 `#4A5568`
+- 统计项按角色动态展示(后端返回,前端仅渲染):
+  - 普通用户:累计咨询次数
+  - C端会员:累计咨询次数 / 累计推广收益 / 推广人数
+  - 超级会员:累计咨询次数 / 累计推广收益 / 关系人数
+  - 能量师:累计咨询次数 / 累计推广收益 / 客户数 / 本月收入
 
 ---
 
@@ -583,8 +599,8 @@ UniApp 通过 `pages.json` 配置:
 | 页面 | 标题 | 背景色 | 文字色 |
 |------|------|--------|--------|
 | 首页 | 数码能量学 | `#1E3A5F` | white |
-| 命盘解读 | 数字能量命盘 | `#1E3A5F` | white |
-| AI解读 | AI 盘解读 | 透明(自定义头) | — |
+| 能量盘解读 | 数字能量盘 | `#1E3A5F` | white |
+| AI解读 | AI 能量盘解读 | 透明(自定义头) | — |
 | 关系页(非会员) | 数字能量关系 | `#1E3A5F` | white |
 | 关系页(超级会员) | 数字能量关系 | `#1E3A5F` | white |
 | 关系详情 | 关系能量分析 | `#1E3A5F` | white |
@@ -612,7 +628,7 @@ UniApp 通过 `pages.json` 配置:
 }
 ```
 
-> **盘页面**(`pages/chart/index`)已从 tabBar 移除,通过首页"开始咨询"或分析记录"查看详情"跳转访问。
+> **能量盘页面**(`pages/chart/index`)已从 tabBar 移除,通过首页"开始咨询"或分析记录"查看详情"跳转访问。
 
 ### 8.3 触摸区域
 
@@ -653,13 +669,13 @@ UniApp 通过 `pages.json` 配置:
 │                              │
 │  了解你与TA的数字能量匹配度    │
 │                              │
-│  ┌── 功能预览(6网格) ──┐   │
-│  │ 👫 夫妻合盘           │   │
-│  │ 👨‍👩‍👧‍👦 亲子匹配       │   │
-│  │ 👔 同事合作           │   │
-│  │ 🤝 朋友兼容           │   │
-│  │ 📊 上下级关系         │   │
-│  │ 🔢 号码能量           │   │
+│  ┌── 功能预览 ─────────┐   │
+│  │ 👫 夫妻/伴侣         │   │
+│  │ 👶 子女 · 👨‍👧 父母   │   │
+│  │ 👴 祖父母 · 👼 孙子女 │   │
+│  │ 👔 同事 · 🤝 朋友    │   │
+│  │ 📊 上级 · 📊 下级    │   │
+│  │ 🔢 号码能量          │   │
 │  └──────────────────────┘   │
 │                              │
 │  ┌─────────────────────┐     │
@@ -679,71 +695,102 @@ UniApp 通过 `pages.json` 配置:
 
 ```
 ┌─────────────────────────────┐
-│  我的命盘  张三 · 主性格 8    │  ← 用户卡片
-│  📊 查看完整命盘              │
+│  ← 数字能量关系              │
+├─────────────────────────────┤
+│  我的能量盘                   │  ← 用户能量盘卡片
+│  张三 · 主性格 8             │  品牌色背景 #1E3A5F
+│  ┌──简版三角图──┐            │  白色文字,圆角12px
+│  │    8(O)     │            │  margin: 16px
+│  └────────────┘             │  点击→查看完整能量盘
 ├─────────────────────────────┤
 │  + 添加新关系人              │  ← 大号CTA按钮
 ├─────────────────────────────┤
-│  关系分类(6网格)            │
-│  👫 夫妻  👨‍👩‍👧‍👦 亲子       │
-│  👔 同事  🤝 朋友           │
-│  📊 上下级 🔢 号码           │
+│  📋 关系人   📝 分析记录     │  ← Tab 切换
 ├─────────────────────────────┤
-│  最近分析                     │
-│  ── 夫妻 ──                  │
-│  李四 · 匹配 85%  ▶          │
-│  ── 亲子 ──                  │
-│  小明 · 匹配 72%  ▶          │
+│  ── 夫妻/伴侣 ──             │  ← 关系人列表(/关系人Tab)
+│  👫 李四                     │  [新增分析] ▶
+│  ── 子女 ──                  │
+│  👶 小明 · 小宝              │  [分析] [分析]
 │  ── 号码 ──                  │
-│  138****5678 · 78分  ▶       │
+│  🔢 138****5678              │  [分析] ▶
+│                              │
+│  或(分析记录Tab):          │
+│  ── 11月20日 ──              │
+│  💬 我俩事业发展互补吗?      │  3人参与 · 10:30   ▶
+│  ── 11月19日 ──              │
+│  💬 孩子天赋方向分析          │  2人参与 · 昨天    ▶
 └─────────────────────────────┘
 ```
 
 - 顶部用户卡片:品牌色背景 `#1E3A5F`,白色文字,圆角 `12px`,`margin: 16px`
 - "添加关系人"按钮:品牌色 `#1E3A5F`,白色加粗文字,圆角 `24px`,高度 `48px`
+- Tab 切换:激活态品牌色 `#1E3A5F` 下划线 + 加粗,未激活 `#4A5568`
 - 关系人列表项:`16px` 圆角,`12px` 内边距,左侧关系类型图标
-- 匹配度颜色:≥80% `#38A169`(绿) / 60-79% `#3182CE`(蓝) / 40-59% `#D69E2E`(黄) / <40% `#DD6B20`(橙)
+- 「分析」按钮:浅色品牌色 `#EBF4FF` 背景,`#1E3A5F` 文字,圆角 `16px`,紧凑排列
+- 分析记录项:问题摘要加粗,参与人数+时间灰色小字
 
-**8.5.3 双命盘对比页(`pages/relations/chart-compare.vue`)**
+**8.5.3 多人分析选择页(`pages/relations/analysis-select.vue`)**
 
 ```
 ┌─────────────────────────────┐
-│  ← 关系分析                   │
+│  ← 发起分析                   │
 │                              │
-│  张三 · 主性格8   李四 · 主性格5│
-│  ┌──命盘──┐  ┌──命盘──┐      │
-│  │   O    │  │   O    │      │
-│  │ M    N │  │ M    N │      │
-│  │I J K L │  │I J K L │      │
-│  └────────┘  └────────┘      │
+│  您想咨询的问题               │
+│  ┌─────────────────────┐     │
+│  │ 我俩在事业发展上     │     │  ← 输入框,必填
+│  │ 是否互补?           │     │  占位符:"输入您想咨询的问题"
+│  └─────────────────────┘     │
 │                              │
-│  ═══ 能量匹配度 ═══          │
-│  ┌─────────────────┐         │
-│  │      ╭───╮      │         │
-│  │      │85%│      │         │  ← 环形进度条
-│  │      ╰───╯      │         │
-│  │  👫 夫妻关系     │         │
-│  └─────────────────┘         │
+│  选择分析成员(至少2人)       │
+│  ┌─ ☑️ 我(张三 · 主性格8)─┐ │  ← 默认选中,不可取消
+│  ├─ ☐ 李四 · 夫妻/伴侣 ────┤ │
+│  ├─ ☐ 小明 · 子女 ────────┤ │
+│  └─ ☐ 王总 · 上级 ────────┘ │
 │                              │
-│  【AI解读】                   │
-│  💬 核心互动                  │
-│  8号领导型与5号自由型...      │
+│  ┌─────────────────────┐     │
+│  │  开始分析(2人选中)  │     │  ← 品牌色渐变,至少2人启用
+│  └─────────────────────┘     │
+└─────────────────────────────┘
+```
+
+- 问题输入框:`height: 48px`,字号 `16px`,`border-radius: 12px`
+- 成员勾选框:`18px × 18px`,选中态品牌色 `#1E3A5F`
+- 成员项:左侧勾选框 + 头像占位 `32px` + 姓名 + 关系类型标签(`12px` 灰色圆角标签)
+- 我自己默认选中且不可取消,显示锁定图标或置灰不可操作
+- 底部按钮在选中 <2 人时置灰禁用
+
+**8.5.4 分析对话页(`pages/relations/analysis-chat.vue`)**
+
+```
+┌─────────────────────────────┐
+│  ← 关系能量分析   👥 3人    │  ← 导航栏,点击👥查看成员
+├─────────────────────────────┤
 │                              │
-│  ✅ 优势                      │
-│  · 互相欣赏对方的能力         │
-│  · 共同追求事业成就           │
-│  · 价值观高度一致             │
+│  ┌─────────────────────┐     │
+│  │ 💬 AI 分析回复...    │     │
+│  │ · 张三(主性格8)      │     │
+│  │ · 李四(主性格5)      │     │  ← 分析结果(自然语言)
+│  │                                                     │
+│  │ 8号领导型与5号自由型     │
+│  │ 在事业发展上的组合...    │     │
+│  └─────────────────────┘     │
 │                              │
-│  ⚠️ 注意点                   │
-│  · 8号控制欲vs5号自由需求     │
-│  · ...                       │
+│  ┌─────────────────────┐
+│  │ 用户追问...          │     │  ← 继续追问,保持上下文
+│  └─────────────────────┘
 │                              │
-│  💡 相处建议                  │
-│  ...                        │
+│  ┌──────────────────────┐    │
+│  │ 输入你的追问...  [发送]│    │  ← 输入框+发送按钮
+│  └──────────────────────┘    │
 └─────────────────────────────┘
 ```
 
-**8.5.4 号码能量分析页(`pages/relations/number-analysis.vue`)**
+- 导航栏标题 + 成员数标签(品牌色圆角标签 `12px`)
+- 点击成员图标 → 底部弹出成员列表浮层(姓名+关系类型+生日,只读)
+- 消息区域与 AI 问答页(US-6.7)样式一致
+- 成员不可在对话中修改(提示"如需更改成员,请结束当前分析重新选择")
+
+**8.5.5 号码能量分析页(`pages/relations/number-analysis.vue`)**
 
 ```
 ┌─────────────────────────────┐
@@ -862,18 +909,18 @@ UniApp 通过 `pages.json` 配置:
 
 ## 十、图片与图标
 
-### 10.1 盘分享海报
+### 10.1 能量盘分享海报
 
 - **尺寸**:`750px × 1000px`(微信分享卡片标准)
 - **背景**:深蓝到墨蓝渐变 `linear-gradient(135deg, #1E3A5F, #162A45)`
-- **内容**:盘三角图(金色线框)+ 用户昵称 + 出生日期 + 品牌 Logo + 小程序码
-- **文案**:底部"扫码查看你的数字盘"
+- **内容**:能量盘三角图(金色线框)+ 用户昵称 + 出生日期 + 品牌 Logo + 小程序码
+- **文案**:底部"扫码查看你的数字能量盘"
 
 ### 10.2 推广海报
 
 - **尺寸**:`750px × 1334px`(朋友圈长图)
 - **背景**:金色到深蓝渐变 `linear-gradient(180deg, #C9A84C 0%, #1E3A5F 100%)`
-- **内容**:用户头像 + 昵称 + 推广码 + 小程序码 + "扫码免费测盘"
+- **内容**:用户头像 + 昵称 + 推广码 + 小程序码 + "扫码免费测能量盘"
 
 ### 10.3 TabBar 图标
 
@@ -944,7 +991,7 @@ $ease-spring: cubic-bezier(0.16, 1, 0.3, 1);
 $ease-out:    ease-out;
 $ease-in:     ease-in;
 
-/* —— 盘数字色(9个数字对应色) —— */
+/* —— 能量盘数字色(9个数字对应色) —— */
 $num-colors: (
   1: #D94A4A,  /* 赤红 — 创造/自主 */
   2: #4A90D9,  /* 冰蓝 — 合作/平衡 */
@@ -977,4 +1024,4 @@ $num-colors: (
 - [ ] 无 emoji 直接使用(使用图标替代)
 - [ ] TabBar 未选中灰色 `#A0AEC0`,选中品牌色 `#1E3A5F`
 - [ ] NavBar 统一墨蓝底色白色文字
-- [ ] 盘数字使用九色体系着色
+- [ ] 能量盘数字使用九色体系着色

+ 1 - 1
docs/superpowers/plans/2026-05-26-admin-panel.md

@@ -278,7 +278,7 @@ const approve = async (id) => {
   <div>
     <h2>系统配置</h2>
     <el-form label-width="180px">
-      <el-form-item label="每日盘限额(免费用户)">
+      <el-form-item label="每日能量盘限额(免费用户)">
         <el-input-number v-model="config.quota_chart" :min="1" :max="20" />
       </el-form-item>
       <el-form-item label="每日聊天限额(免费用户)">

+ 2 - 2
docs/superpowers/plans/2026-05-26-backend-springboot.md

@@ -667,7 +667,7 @@ Expected: PASS
 
 ---
 
-### Task 5: ChartService — 盘创建+列表
+### Task 5: ChartService — 能量盘创建+列表
 
 **Files:**
 - Create: `service/ChartService.java`
@@ -727,7 +727,7 @@ public class ChartService {
     }
 
     public Chart detail(Long id, Long userId) {
-        Chart chart = chartRepository.findById(id).orElseThrow(() -> new BizException(400, "盘不存在"));
+        Chart chart = chartRepository.findById(id).orElseThrow(() -> new BizException(400, "能量盘不存在"));
         if (!chart.getUserId().equals(userId)) throw new BizException(403, "无权限");
         return chart;
     }

+ 6 - 6
docs/superpowers/plans/2026-05-26-dify-workflow.md

@@ -3,7 +3,7 @@
 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
 > **前置依赖:** Dify 实例已部署,API Key 就绪
 
-**目标:** 创建命盘对话 Chatflow,接收命盘数据 + 用户消息,返回 AI 解读
+**目标:** 创建能量盘对话 Chatflow,接收能量盘数据 + 用户消息,返回 AI 解读
 
 ---
 
@@ -36,7 +36,7 @@ def main(chart_data: dict, user_message: str, history: list) -> dict:
     positions = chart_data.get("positions", {})
     zones = chart_data.get("zones", {})
 
-    context = f"【盘数据】\n"
+    context = f"【能量盘数据】\n"
     context += f"主性格数字: {chart_data.get('mainCharacter')}\n"
     if chart_data.get('isMasterNumber'):
         context += "(卓越数,天赋异禀)\n"
@@ -61,16 +61,16 @@ def main(chart_data: dict, user_message: str, history: list) -> dict:
 
 **System Prompt:**
 ```
-你是一位专业的数字能量学解读师,精通生命密码(数字能量学)的三角形盘分析体系。
+你是一位专业的数字能量学解读师,精通生命密码(数字能量学)的三角形能量盘分析体系。
 
-以下是当前用户的完整盘数据:
+以下是当前用户的完整能量盘数据:
 {{#context_builder.system_context#}}
 
 ## 回答规则:
-1. 所有解读必须基于上述盘中的实际数字,不得编造
+1. 所有解读必须基于上述能量盘中的实际数字,不得编造
 2. 每个回答 200-300 字,言简意赅
 3. 语气温和正向,避免恐吓或绝对化表述(如"你一定会..."改为"你可能会...")
-4. 如果用户没有明确问题,主动介绍盘亮点(主性格含义、特殊数字组合等)
+4. 如果用户没有明确问题,主动介绍能量盘亮点(主性格含义、特殊数字组合等)
 5. 涉及多区域时,交叉引用各位置数字的关系
 6. 回答末尾加一句 "仅供参考"
 

+ 14 - 14
docs/superpowers/plans/2026-05-26-miniprogram-uniapp.md

@@ -3,7 +3,7 @@
 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
 > **前置依赖:** HBuilderX 或 Vue CLI uni-app 插件、后端 API 就绪
 
-**目标:** 基于 uni-app 实现「盘+聊天」一体式小程序
+**目标:** 基于 uni-app 实现「能量盘+聊天」一体式小程序
 
 **参考代码:** `miniprogram/` 目录下现有微信原生代码的 UI 设计和计算逻辑
 
@@ -14,8 +14,8 @@
 ```
 client/
 ├── pages/
-│   ├── index/                # 首页(输入 + 盘 + 聊天)
-│   ├── records/              # 历史盘列表
+│   ├── index/                # 首页(输入 + 能量盘 + 聊天)
+│   ├── records/              # 历史能量盘列表
 │   ├── profile/              # 个人中心(信息/配额/佣金)
 │   └── subscribe/            # 付费页面
 ├── components/
@@ -57,8 +57,8 @@ Run: `npx degit dcloudio/uni-preset-vue#vite client` 或 HBuilderX 创建
 ```json
 {
   "pages": [
-    {"path": "pages/index/index", "style": {"navigationBarTitleText": "数字能量盘"}},
-    {"path": "pages/records/records", "style": {"navigationBarTitleText": "盘记录"}},
+    {"path": "pages/index/index", "style": {"navigationBarTitleText": "数字能量盘"}},
+    {"path": "pages/records/records", "style": {"navigationBarTitleText": "能量盘记录"}},
     {"path": "pages/profile/profile", "style": {"navigationBarTitleText": "我的"}},
     {"path": "pages/subscribe/subscribe", "style": {"navigationBarTitleText": "开通能量师"}}
   ],
@@ -254,7 +254,7 @@ export const unifiedOrder = (productType) => request('/api/pay/unified-order', {
   <view class="chart-input">
     <view class="hero-section">
       <text class="hero-icon">✦</text>
-      <text class="hero-title">数字能量盘</text>
+      <text class="hero-title">数字能量盘</text>
       <text class="hero-desc">输入出生信息,生成你的专属数字三角形</text>
     </view>
     <view class="form-card">
@@ -472,12 +472,12 @@ export default {
     <!-- 输入态 -->
     <ChartInput v-if="!activeChart" @chartCreated="onChartCreated" />
 
-    <!-- 盘+聊天态 -->
+    <!-- 能量盘+聊天态 -->
     <view v-else class="chart-chat-layout">
-      <!-- 顶部:盘 -->
+      <!-- 顶部:能量盘 -->
       <view class="chart-area">
         <view class="chart-header">
-          <text class="chart-name">{{ chartName }}的盘</text>
+          <text class="chart-name">{{ chartName }}的能量盘</text>
           <text class="chart-back" @click="onBack">← 重新输入</text>
         </view>
         <Triangle :chartData="chartData" :width="340" :height="420" />
@@ -501,7 +501,7 @@ export default {
         </scroll-view>
 
         <view class="input-bar">
-          <input class="chat-input" v-model="inputMsg" placeholder="询问盘..." @confirm="onSend" />
+          <input class="chat-input" v-model="inputMsg" placeholder="询问能量盘..." @confirm="onSend" />
           <button class="send-btn" @click="onSend">发送</button>
         </view>
       </view>
@@ -603,7 +603,7 @@ export default {
 
     <!-- 免费用户配额 -->
     <view class="card" v-else>
-      <view>今日盘: {{ chartCount }}/3</view>
+      <view>今日能量盘: {{ chartCount }}/3</view>
       <view>今日聊天: {{ chatCount }}/5</view>
       <button @click="onSubscribe">开通能量师 ¥398/年</button>
     </view>
@@ -620,7 +620,7 @@ export default {
 
     <!-- 操作菜单 -->
     <view class="menu-card">
-      <view class="menu-item" @click="onRecords">📋 盘记录</view>
+      <view class="menu-item" @click="onRecords">📋 能量盘记录</view>
       <view class="menu-item" @click="onSubscribe" v-if="!isVip">⭐ 开通能量师</view>
       <view class="menu-item" @click="onAbout">ℹ️ 关于我们</view>
     </view>
@@ -651,7 +651,7 @@ export default {
     </view>
 
     <view class="benefits">
-      <view class="benefit-item">✅ 无限盘生成,不限次数</view>
+      <view class="benefit-item">✅ 无限能量盘生成,不限次数</view>
       <view class="benefit-item">✅ AI 五区完整解读,随问随答</view>
       <view class="benefit-item">✅ 无限分享 & PDF 导出</view>
       <view class="benefit-item">✅ 全部历史记录</view>
@@ -662,7 +662,7 @@ export default {
       <view class="compare-row header">
         <text>功能</text><text>普通用户</text><text>能量师</text>
       </view>
-      <view class="compare-row"><text>盘生成</text><text>3次/天</text><text>✅ 不限</text></view>
+      <view class="compare-row"><text>能量盘生成</text><text>3次/天</text><text>✅ 不限</text></view>
       <view class="compare-row"><text>AI 解读</text><text>主性格概要</text><text>✅ 完整解读</text></view>
       <view class="compare-row"><text>分享</text><text>1次/天</text><text>✅ 不限</text></view>
       <view class="compare-row"><text>推广佣金</text><text>❌</text><text>✅ 最高¥159.2/人</text></view>

+ 5 - 5
docs/superpowers/plans/2026-05-26-phase1-implementation-plan.md

@@ -3,10 +3,10 @@
 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans.
 > 本计划覆盖 4 个子系统,建议按顺序逐个子系统推进,每个子系统完成后验证。
 
-**目标:** 上线数字能量师工具,包含 Classic A 盘生成 + AI 聊天解读 + 付费订阅 + 分销体系 + 后台管理
+**目标:** 上线数字能量师工具,包含 Classic A 能量盘生成 + AI 聊天解读 + 付费订阅 + 分销体系 + 后台管理
 
 **架构:**
-- Spring Boot 共享后端 → uni-app 小程序(盘+聊天一体)+ Vue 3 后台管理
+- Spring Boot 共享后端 → uni-app 小程序(能量盘+聊天一体)+ Vue 3 后台管理
 - Dify Chatflow 处理 AI 解读对话
 - Classic A 5行15格三角计算引擎
 
@@ -37,7 +37,7 @@
 
 | 模块 | 说明 |
 |------|------|
-| Python 节点 | context_builder - 拼接盘数据 |
+| Python 节点 | context_builder - 拼接能量盘数据 |
 | LLM 节点 | 数字能量学 AI 解读 Prompt |
 | Chatflow 编排 | 输入→context_builder→LLM→输出 |
 
@@ -49,11 +49,11 @@
 | 项目初始化 | manifest.json, pages.json, App.vue | |
 | Classic A 引擎 | utils/calculator.js | 5行15格计算 |
 | 首页-输入态 | pages/index/ | 生日输入 |
-| 首页-盘态 | components/triangle/ | Canvas 渲染 |
+| 首页-能量盘态 | components/triangle/ | Canvas 渲染 |
 | 首页-聊天态 | pages/index/ | 聊天窗口 |
 | 付费 | pages/subscribe/ | 订阅页 |
 | 个人中心 | pages/profile/ | 信息、配额、佣金 |
-| 历史记录 | pages/records/ | 盘列表 + 标签 |
+| 历史记录 | pages/records/ | 能量盘列表 + 标签 |
 
 ### Sub-Plan D: Vue 3 后台管理
 `docs/superpowers/plans/2026-05-26-admin-panel.md`

+ 1 - 1
docs/superpowers/specs/2026-05-22-numerology-agent-design.md

@@ -187,7 +187,7 @@ def main(phone_number: str) -> dict:
 pages/
 ├── index/          # 首页(功能入口 + 号码快速输入)
 ├── analysis/       # 号码分析结果展示
-├── life-chart/     # 盘展示
+├── life-chart/     # 能量盘展示
 ├── chat/           # AI 对话(直连 Dify 对话 API)
 ├── records/        # 历史记录列表
 ├── record-detail/  # 单条记录详情

+ 20 - 20
docs/superpowers/specs/2026-05-24-triangle-life-chart-miniprogram-design.md

@@ -1,4 +1,4 @@
-# 数字能量三角形盘 — 小程序方案设计
+# 数字能量三角形能量盘 — 小程序方案设计
 
 **创建日期:** 2026-05-24
 **状态:** 设计方案(待评审)
@@ -32,7 +32,7 @@
 ```
 已有能力(Dify Chatflow)       新增能力(本方案)
 ┌─────────────────────┐        ┌─────────────────────┐
-│ 手机号八星分析       │        │ 生日三角形盘生成   │
+│ 手机号八星分析       │        │ 生日三角形能量盘生成   │
 │ 生日生命数分析       │        │ 5区深度解读          │
 │ 双人合盘匹配         │        │ 职业/财富/婚姻专项   │
 │ AI对话咨询           │        │ 数字能量师管理后台   │
@@ -43,7 +43,7 @@
 
 ---
 
-## 2. 三角形盘 — 算法引擎设计
+## 2. 三角形能量盘 — 算法引擎设计
 
 ### 2.1 基本原理
 
@@ -135,7 +135,7 @@
 
 ### 2.4 Dify Workflow 设计
 
-**工作流:三角形盘分析**(新增 Chatflow)
+**工作流:三角形能量盘分析**(新增 Chatflow)
 
 ```
 输入: { birthday: "1990-01-01", name: "张三", gender: "male", tier: "free" }
@@ -144,7 +144,7 @@
   ├── 构建三角形数字矩阵
   ├── 计算5大区域数字组合
   ├── 统计缺失数/重复数/五行
-  └── 输出: 结构化三角盘数据
+  └── 输出: 结构化三角能量盘数据
 [条件分支: tier == "free"?]
   ├── Yes → [LLM 节点: 基础解读]
@@ -169,7 +169,7 @@
 
 | 功能 | 限制 |
 |------|------|
-| 三角形盘生成 | 每日 1 次 |
+| 三角形能量盘生成 | 每日 1 次 |
 | 基础解读 | 仅主性格 + 三大年龄区概括 |
 | 手机号八星分析 | 每日 1 次(已有) |
 | AI 对话咨询 | 每日 3 轮(已有) |
@@ -180,7 +180,7 @@
 
 | 功能 | 说明 |
 |------|------|
-| 无限次盘生成 | 为自己及家人生成 |
+| 无限次能量盘生成 | 为自己及家人生成 |
 | 5区深度解读 | 每区独立详细分析报告 |
 | 专项分析 | 职业方向、财富格局、婚姻匹配 |
 | PDF 报告导出 | 可分享的完整报告 |
@@ -193,9 +193,9 @@
 | 功能 | 说明 |
 |------|------|
 | 全部 VIP 功能 | — |
-| 客户管理 | 添加/分组客户,查看客户盘 |
+| 客户管理 | 添加/分组客户,查看客户能量盘 |
 | 批量分析 | 一次导入多人批量生成报告 |
-| 标注批注 | 在客户盘上添加专业解读 |
+| 标注批注 | 在客户能量盘上添加专业解读 |
 | 咨询记录 | 图文咨询记录,可标记重点 |
 | 品牌展示 | 在平台展示个人资料,获取客户 |
 | 收益分成 | 为客户提供付费咨询,平台抽成 20% |
@@ -211,7 +211,7 @@
 ┌─────────────────────────────────────────────────────────────┐
 │                    微信小程序 (uni-app)                      │
 │  ┌──────┐ ┌──────────┐ ┌────────────┐ ┌──────────────────┐ │
-│  │ 首页  │ │ 三角形盘 │ │ 专业版工作台 │ │ 个人中心         │ │
+│  │ 首页  │ │ 三角形能量盘 │ │ 专业版工作台 │ │ 个人中心         │ │
 │  │ 快速  │ │ 交互式    │ │ 客户管理   │ │ 会员/记录/设置   │ │
 │  │ 输入  │ │ SVG图表   │ │ 批量分析   │ │                 │ │
 │  └──┬───┘ └────┬─────┘ └─────┬──────┘ └───────┬──────────┘ │
@@ -313,7 +313,7 @@ CREATE TABLE numerologist_note (
 | GET | `/api/member/status` | 查询会员状态 | user |
 | GET | `/api/professional/clients` | 客户列表 | professional |
 | POST | `/api/professional/clients` | 添加客户 | professional |
-| GET | `/api/professional/clients/{id}` | 客户盘 | professional |
+| GET | `/api/professional/clients/{id}` | 客户能量盘 | professional |
 | POST | `/api/professional/notes` | 添加批注 | professional |
 | GET | `/api/professional/notes/{record_id}` | 获取批注 | professional |
 | POST | `/api/professional/batch-analyze` | 批量分析 | professional |
@@ -333,7 +333,7 @@ pages/
 │       ├── FeatureGrid.vue  # 功能九宫格
 │       └── PromotionBanner.vue  # 会员推广横幅
-├── triangle-chart/          # 三角形
+├── triangle-chart/          # 三角形能量
 │   ├── index.vue            # SVG 三角形图表主视图
 │   ├── zone-detail.vue      # 单区详细解读
 │   ├── full-report.vue      # 完整报告页(VIP)
@@ -356,7 +356,7 @@ pages/
 ├── professional/            # 数字能量师工作台
 │   ├── dashboard.vue        # 概览仪表盘
 │   ├── clients.vue          # 客户列表
-│   ├── client-detail.vue    # 客户详情(盘 + 批注)
+│   ├── client-detail.vue    # 客户详情(能量盘 + 批注)
 │   ├── batch-import.vue     # 批量导入
 │   └── batch-results.vue    # 批量结果
@@ -368,11 +368,11 @@ pages/
 
 ### 5.2 核心页面原型描述
 
-#### 三角形盘页面 (triangle-chart/index)
+#### 三角形能量盘页面 (triangle-chart/index)
 
 ```
 ┌──────────────────────────┐
-│  ← 返回     张三 的盘   │
+│  ← 返回     张三 的能量盘   │
 ├──────────────────────────┤
 │                          │
 │        [7]               │  ← 主性格数字(大号)
@@ -395,7 +395,7 @@ pages/
 │ [🔓 解锁完整解读 →]      │  ← 免费用户显示引导
 │                          │
 ├──────────────────────────┤
-│ 底部 Tab: 首页/盘/记录/我的 │
+│ 底部 Tab: 首页/能量盘/记录/我的 │
 └──────────────────────────┘
 ```
 
@@ -430,7 +430,7 @@ pages/
 
 ## 6. Dify 工作流实现方案
 
-### 6.1 新增 Chatflow:三角形盘分析
+### 6.1 新增 Chatflow:三角形能量盘分析
 
 沿用现有 Dify 实例(http://dify.bianwoyou.cn/),新增 Chatflow:
 
@@ -446,7 +446,7 @@ pages/
 
 **基础解读 Prompt(免费版):**
 ```
-你是数字能量学解读师。以下是用户的三角形盘数据:
+你是数字能量学解读师。以下是用户的三角形能量盘数据:
 {{#engine.result#}}
 
 请以友好易懂的语言输出:
@@ -459,7 +459,7 @@ pages/
 
 **完整解读 Prompt(VIP):**
 ```
-你是资深数字能量学解读师。以下是用户的三角形盘数据:
+你是资深数字能量学解读师。以下是用户的三角形能量盘数据:
 {{#engine.result#}}
 
 请逐区详细解读:
@@ -498,7 +498,7 @@ pages/
 
 ### 第一阶段:MVP 上线(4-6 周)
 
-**目标**:快速上线核心功能,验证三角形盘理论的市场接受度
+**目标**:快速上线核心功能,验证三角形能量盘理论的市场接受度
 
 | 任务 | 交付物 | 依赖 |
 |------|--------|------|

+ 27 - 27
docs/system-spec.md

@@ -26,7 +26,7 @@
 ### 2.3 核心理念
 
 1. **B端先行、C端引流** — 第一阶段从能量师(B端)付费订阅切入,C端用户通过能量师分享引流
-2. **AI驱动交付** — 盘生成+AI解读全部自动化,能量师无需手动计算
+2. **AI驱动交付** — 能量盘生成+AI解读全部自动化,能量师无需手动计算
 3. **分销裂变** — 能量师推荐能量师(两级佣金)+ 能量师推荐C端客户(40%+5%分成)
 4. **培训引流** — 工具使用深度 → 引导能量师参加培训认证,形成"工具→学习→认证"升级路径
 
@@ -56,7 +56,7 @@
 ```
 能量师付费订阅(¥1,314-1,986/年)
   ├── 获得AI辅助工具
-  │     → 输入客户姓名+生日 → 生成三角形
+  │     → 输入客户姓名+生日 → 生成三角形能量
   │     → 获得AI完整解读(性格/天赋/职业/财富等维度)
   │     → 将解读结果用于线下服务或直接分享给客户
   ├── 获得推广工具(专属小程序码)
@@ -77,7 +77,7 @@
 
 | 编号 | 模块 | 核心功能 | 估工 |
 |------|------|---------|------|
-| ① | 三角形盘引擎 | Canvas可视化,3秒出图,五区色块 | 3周 |
+| ① | 三角形能量盘引擎 | Canvas可视化,3秒出图,五区色块 | 3周 |
 | ② | AI五区+职业+财富完整解读 | LLM自动生成多维度解读,Prompt调优迭代 | 5周 |
 | ③ | 少儿板块完整版 | 性格+天赋+职业方向+学习判定(独立Prompt体系) | 4周 |
 | ④ | 能量师CRM | 客户绑定/互动记录/信息补充/客户列表/活跃度 | 4周 |
@@ -88,7 +88,7 @@
 
 | 阶段 | 时间 | 上线功能 | 板块标签 |
 |------|------|---------|---------|
-| **P1** | M1-2(8周) | ①盘引擎 + ②成人主性格+成长财富量级 + ③少儿天赋解码+职业方向 + ④CRM基础 + ⑤分销基础+支付 + 免费访客 | — |
+| **P1** | M1-2(8周) | ①能量盘引擎 + ②成人主性格+成长财富量级 + ③少儿天赋解码+职业方向 + ④CRM基础 + ⑤分销基础+支付 + 免费访客 | — |
 | **P2** | M3(4周) | ⑤分销面板+C端支付+裂变完整版 + ④互动查看 | **⑤分销支付体系** |
 | **P3** | M4(4周) | ②成人五区完整(父源+母源+左中右区)+ ④CRM完善 + ⑥分享导出 | **②成人完整解读** |
 | **P4** | M5(4周) | ③少儿完整板块(性格+学习判定)+ ⑥培训引流+认证+数据 | **③少儿完整板块** |
@@ -101,11 +101,11 @@
 
 Phase 1 为8周MVP阶段,是最关键的交付节点。以下按功能模块逐一说明。
 
-### 5.1 三角形盘引擎(①)
+### 5.1 三角形能量盘引擎(①)
 
 #### 功能描述
 
-输入姓名和出生日期,3秒内生成数字能量学三角形盘图,包含五区色块区分。
+输入姓名和出生日期,3秒内生成数字能量学三角形能量盘图,包含五区色块区分。
 
 #### 输入
 
@@ -117,8 +117,8 @@ Phase 1 为8周MVP阶段,是最关键的交付节点。以下按功能模块
 
 #### 输出
 
-- **三角形盘图**:Canvas 渲染,包含五区色块(不同颜色区分主性格区、父源区、母源区、左区、中区/右区)
-- **数字标注**:在盘图中标注每个位置的计算结果数字
+- **三角形能量盘图**:Canvas 渲染,包含五区色块(不同颜色区分主性格区、父源区、母源区、左区、中区/右区)
+- **数字标注**:在能量盘图中标注每个位置的计算结果数字
 - **响应时间**:≤ 3秒(含AI解读请求时间)
 
 #### 交互要求
@@ -138,13 +138,13 @@ AI解读是平台的核心价值。Phase 1 首发 4 个解读维度,后续阶
 | 解读维度 | 适用对象 | 说明 | 对应模块 |
 |---------|---------|------|---------|
 | **主性格解读** | 成人 | 基于主性格数字,分析核心性格特质、优势、挑战 | ②子集 |
-| **成长财富量级** | 成人 | 基于盘数字组合,分析财富潜力、赚钱模式、财富增长阶段 | ②子集 |
+| **成长财富量级** | 成人 | 基于能量盘数字组合,分析财富潜力、赚钱模式、财富增长阶段 | ②子集 |
 | **少儿天赋解码** | 少儿 | 基于生日数字,分析天赋潜能、天生优势领域 | ③子集 |
-| **少儿职业方向** | 少儿 | 基于盘数字,分析适合的职业发展方向、职业性格匹配 | ③子集 |
+| **少儿职业方向** | 少儿 | 基于能量盘数字,分析适合的职业发展方向、职业性格匹配 | ③子集 |
 
 #### 解读交互
 
-- 命盘生成后,解读内容自动展示在命盘下方
+- 能量盘生成后,解读内容自动展示在能量盘下方
 - 以卡片式分区展示,每个解读维度一张独立卡片,可横向滑动切换
 - 解读内容应包含:**数字依据 + AI生成解读正文 + 建议/提示**
 - 支持保存为图片分享(Phase 1 可先做截图分享,完整导出功能在 P3 上线)
@@ -154,9 +154,9 @@ AI解读是平台的核心价值。Phase 1 首发 4 个解读维度,后续阶
 | 维度 | Prompt 设计要点 |
 |------|---------------|
 | 主性格 | 基于主性格数字1-9,输出性格特质、优势、挑战、适合领域 |
-| 成长财富量级 | 基于盘数字组合(先天数+后天数+主性格+外心等),分析财富格局、赚钱模式(稳定型/爆发型/积累型等)、当前所处财富阶段 |
+| 成长财富量级 | 基于能量盘数字组合(先天数+后天数+主性格+外心等),分析财富格局、赚钱模式(稳定型/爆发型/积累型等)、当前所处财富阶段 |
 | 少儿天赋解码 | 基于生日数字,分析天赋潜能(沟通/创造/逻辑/领导/艺术等维度) |
-| 少儿职业方向 | 基于盘数字,分析职业倾向(技术型/创意型/社交型/管理型/研究型等),推荐1-3个适合方向 |
+| 少儿职业方向 | 基于能量盘数字,分析职业倾向(技术型/创意型/社交型/管理型/研究型等),推荐1-3个适合方向 |
 
 #### 免费 vs 付费限制
 
@@ -213,7 +213,7 @@ AI解读是平台的核心价值。Phase 1 首发 4 个解读维度,后续阶
 
 - 未登录用户 / 未付费用户可通过能量师分享的链接进入小程序
 - 免费体验内容:
-  - 每日 3 次盘生成(含主性格概要文字版)
+  - 每日 3 次能量盘生成(含主性格概要文字版)
   - 成长财富量级、少儿天赋解码、少儿职业方向 仅展示标题和付费解锁提示
 - 体验引导:
   - 体验后提示购买 C 端年费 ¥131 获得完整解读
@@ -230,7 +230,7 @@ AI解读是平台的核心价值。Phase 1 首发 4 个解读维度,后续阶
 | 能量师年费(种子价) | ¥1,314/年 | 首300人 | 首批种子能量师锁定优惠价 |
 | 能量师年费(标准价) | ¥1,986/年 | — | 正常价格 |
 | C端用户年费 | ¥131/年 | — | 普通用户订阅 |
-| 免费试用 | ¥0 | 每日3次 | 盘+主性格概要 |
+| 免费试用 | ¥0 | 每日3次 | 能量盘+主性格概要 |
 
 ### 6.2 分销规则
 
@@ -246,11 +246,11 @@ AI解读是平台的核心价值。Phase 1 首发 4 个解读维度,后续阶
 - B端:技术方固定 ¥998/人,运营方获得剩余(种子价¥1,314-¥998=¥316/人,标准价¥1,986-¥998=¥988/人),运营方从自身份额中支付 ¥500+¥100 佣金
 - C端 ¥131:技术方 40%(¥52.40)+ 运营方 15%(¥19.65)+ 能量师 40%(¥52.40)+ 上级 5%(¥6.55)
 
-### 6.4 三角形盘计算规则
+### 6.4 三角形能量盘计算规则
 
 **输入:** 出生年份(4位)、月份(2位)、日期(2位)
 
-盘计算采用 **30位系统**(A-X),由后端 `CalculatorService` 计算,前端 `calculator.js` 作为降级兜底。
+能量盘计算采用 **30位系统**(A-X),由后端 `CalculatorService` 计算,前端 `calculator.js` 作为降级兜底。
 
 #### 6.4.1 输入层(A-H)—— 生日原始数字
 
@@ -354,15 +354,15 @@ I ─────────── J  K ─────────── L
 
 | 指标 | 要求 |
 |------|------|
-| 盘生成 + AI解读 | ≤ 3 秒 |
+| 能量盘生成 + AI解读 | ≤ 3 秒 |
 | 页面首屏加载 | ≤ 2 秒(小程序) |
-| 盘图Canvas渲染 | ≤ 1 秒 |
+| 能量盘图Canvas渲染 | ≤ 1 秒 |
 | 并发用户 | 初期支持 100 人同时在线 |
 
 ### 7.2 安全性需求
 
 - 用户密码/登录信息加密存储
-- 盘数据(姓名+生日+AI解读)需做访问权限控制
+- 能量盘数据(姓名+生日+AI解读)需做访问权限控制
 - 能量师只能查看自己绑定的客户数据
 - 支付相关签名使用微信支付 SDK 规范
 - API 鉴权(JWT token 或 session)
@@ -379,7 +379,7 @@ I ─────────── J  K ─────────── L
 |---------|---------|
 | 用户账号 | 微信 openId + 用户信息 |
 | 能量师-客户绑定关系 | 关系表(能量师ID + 客户ID + 绑定时间) |
-| 命盘生成记录 | 每次命盘生成保存结果(含姓名+生日+解读),可追溯 |
+| 能量盘生成记录 | 每次能量盘生成保存结果(含姓名+生日+解读),可追溯 |
 | 佣金/分销数据 | 推荐关系链 + 佣金记录 + 提现记录 |
 | 支付流水 | 微信支付订单号 + 金额 + 状态 + 回调记录 |
 
@@ -392,7 +392,7 @@ I ─────────── J  K ─────────── L
 | 角色 | 人数 | 核心职责 |
 |------|------|---------|
 | 后端开发 | 1 | API + 数据库 + 支付对接 + 服务器部署 + 运维 |
-| 前端开发 | 2 | 微信小程序 + 管理后台 + Canvas 盘渲染 |
+| 前端开发 | 2 | 微信小程序 + 管理后台 + Canvas 能量盘渲染 |
 | AI 工程师 | 1 | Prompt 设计调优 + 模型选型 + Token 成本控制 |
 | 产品经理 | 1 | 需求定义 + 进度管理 + 跨团队协调 |
 
@@ -401,7 +401,7 @@ I ─────────── J  K ─────────── L
 | 周次 | 重点工作 |
 |------|---------|
 | W1-2 | 技术选型 + 架构设计 + 数据库设计 + 微信小程序框架搭建 |
-| W3-4 | 盘引擎 Canvas 开发 + 后端 API 框架 + 用户系统 |
+| W3-4 | 能量盘引擎 Canvas 开发 + 后端 API 框架 + 用户系统 |
 | W5-6 | AI Prompt 开发(4个解读维度)+ 后端解读API + 微信支付接入 |
 | W7-8 | CRM 基础 + 分销基础 + 联调测试 + Bug 修复 + 上线准备 |
 
@@ -413,7 +413,7 @@ I ─────────── J  K ─────────── L
 
 | 交付物 | 说明 |
 |--------|------|
-| 三角形盘引擎 | Canvas 可视化,3秒出图 |
+| 三角形能量盘引擎 | Canvas 可视化,3秒出图 |
 | AI 主性格解读 | 成人性格分析(完整版) |
 | AI 成长财富量级 | 成人财富潜力分析 |
 | AI 少儿天赋解码 | 少儿天赋潜能分析 |
@@ -427,11 +427,11 @@ I ─────────── J  K ─────────── L
 
 | 术语 | 说明 |
 |------|------|
-| 命盘(三角形命盘) | 基于数字能量学理论,通过姓名+生日计算生成的命盘图 |
+| 能量盘(三角形能量盘) | 基于数字能量学理论,通过姓名+生日计算生成的能量盘图 |
 | 五区 | 数字能量学三角形的五个区域:主性格区、父源区、母源区、左区、中区/右区 |
 | 能量师 | 数字心理学从业者,B端付费用户 |
-| 主性格 | 盘中最核心的数字,代表人的基本性格特质 |
-| 成长财富量级 | 基于盘数字分析财富潜力和模式的解读维度 |
+| 主性格 | 能量盘中最核心的数字,代表人的基本性格特质 |
+| 成长财富量级 | 基于能量盘数字分析财富潜力和模式的解读维度 |
 | 少儿天赋解码 | 针对少儿的天赋潜能分析 |
 | 少儿职业方向 | 针对少儿的职业发展方向推荐 |
 | CRM | 能量师-客户关系管理 |

+ 649 - 0
docs/withdrawal-design.md

@@ -0,0 +1,649 @@
+# 小程序提现机制设计(含税务优化)
+
+> **状态:** Draft v1  
+> **适用范围:** 超级会员、能量师(所有有分销佣金收益的用户角色)  
+> **提现方式:** 微信「企业付款到零钱」(原「企业红包」API)  
+> **税务处理:** 预扣代缴 + 年度汇总  
+
+---
+
+## 1. 整体链路
+
+```text
+用户申请提现
+    │
+    ▼
+后端校验(余额、身份、频率、首笔退费资格)
+    │
+    ▼
+创建提现记录 → 状态:QUEUED(排队中)
+    │
+    ▼
+前端提示:「申请已提交,预计今晚到账」
+    │
+    ▼
+┌─ 每日定时任务(23:30,微信日结前)────────────────────┐
+│                                                         │
+│  Step 1: 拉取当日所有 QUEUED 记录                        │
+│  Step 2: 检查微信商户 Master 余额                         │
+│  Step 3: 按优先级排序:                                  │
+│      ① 首笔退费(退款通道,扣退款余额)                    │
+│      ② 常规微信直付(≤¥800,免个税)                      │
+│      ③ 第三方通道(>¥800,代扣个税)                      │
+│  Step 4: 逐笔执行                                        │
+│      ├─ 足够余额 → 调用对应通道 API → SUCCESS             │
+│      └─ 余额不足 → 跳过,保持 QUEUED,次日重试            │
+│                                                         │
+│  Step 5: 更新微信 Master 余额缓存                         │
+│  Step 6: 推送通知(成功/失败)                            │
+└─────────────────────────────────────────────────────────┘
+    │
+    ▼
+超过 3 天未处理 → 告警运维 → 人工介入
+```
+
+---
+
+## 2. 佣金科目体系
+
+当前 4 条产品线 → 全部提取至**统一可提现余额**:
+
+| 佣金类型 | 税率级次 | 是否可提现 |
+|---------|---------|-----------|
+| B端佣金(能量师推荐,固定金额) | 劳务报酬 | ✅ |
+| C端佣金(40%+5%,百分比) | 劳务报酬 | ✅ |
+| 超级会员佣金(30%+5%,百分比) | 劳务报酬 | ✅ |
+| 人工方案佣金(平台留存后返还) | 劳务报酬 | ✅ |
+| 提现退还(失败回滚) | — | 退回可提现余额 |
+
+> **结论:** 所有分销佣金合并为一个「可提现余额」,不做科目隔离。
+
+---
+
+## 3. 提现规则(后端可配置)
+
+### 3.1 规则表(sys_config + withdraw_rules 表)
+
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `withdraw.min_amount` | **¥100** | 单次最低提现金额(分) |
+| `withdraw.max_amount_per_time` | ¥10,000 | 单次最高提现金额 |
+| `withdraw.max_per_week` | **1次** | 每人每周限提次数 |
+| `withdraw.service_fee_rate` | **0.6%** | 微信企业付款手续费(平台承担) |
+| `withdraw.week_reset_day` | **周一 00:00** | 周频次重置时间 |
+| `withdraw.min_balance_keep` | ¥0 | 提现后保留的最低余额 |
+| `withdraw.auto_approve` | true | 是否自动审核(≤¥500 免审) |
+| `withdraw.fail_limit_per_day` | **3次** | 日失败上限,超限冻结提现 24h |
+| `withdraw.commission_expiry_days` | 0(永不过期) | 佣金过期天数,0=永久有效 |
+| `withdraw.refund_period_days` | **30** | 首笔提现退费窗口期(付费后30天内) |
+| `withdraw.third_party_threshold` | **¥800** | 超过此金额使用第三方结算通道(分) |
+| `withdraw.third_party_channel` | `wechat_settle` | 第三方通道类型:wechat_settle / lianlian / huifu |
+| `withdraw.refund_reason_tpl` | `推广佣金退款-{user_id}-{order_no}` | 退费备注模板 |
+
+### 3.2 提现状态机
+
+```
+用户提交申请
+    │
+    ▼
+INIT → QUEUED(等待夜间批处理)
+    │
+    ▼ [定时任务 23:30 触发]
+BATCH_PROCESSING(正在处理)
+    │
+    ├─ 余额足够 → 通道调用
+    │     ├─ 退费(首笔)→ 微信退款 API → SUCCESS
+    │     ├─ 微信直付 → 企业付款 API → SUCCESS
+    │     └─ 第三方 → 渠道 API → SUCCESS
+    │
+    ├─ 余额不足 → 跳过,保持 QUEUED → 次日重试
+    │
+    └─ 通道报错 → FAILED(可重新发起)
+          │
+          └─ 超过 3 天未成功 → FROZEN(告警运维)
+```
+
+**状态说明:**
+
+| 状态 | 说明 | 可见用户 |
+|------|------|---------|
+| `QUEUED` | 提交成功,等待夜间批处理 | ✅ 显示「预计今晚到账」 |
+| `BATCH_PROCESSING` | 定时任务正在处理(通常 23:30-00:30) | ✅ 显示「处理中」 |
+| `SUCCESS` | 已到账 | ✅ 显示「已到账」+ 到账金额 |
+| `FAILED` | 通道失败(余额不足/网络错误) | ✅ 显示「失败」+ 原因 +「重新申请」按钮 |
+| `REJECTED` | 风控不通过 | ✅ 显示「未通过审核」+ 原因 |
+| `FROZEN` | 超过 3 天未处理,需人工介入 | ✅ 显示「请联系客服」 |
+
+### 3.3 夜间定时批处理任务
+
+所有提现(含退费、直付、第三方)**不实时调用微信 API**,而是由定时任务统一处理。
+
+**触发时机:** 每日 23:30(微信商户平台通常在 00:00 前完成日结,确保当日余额可 Master)
+
+**处理流程:**
+
+```java
+@Scheduled(cron = "0 30 23 * * ?") // 每日 23:30
+public void nightlyWithdrawBatch() {
+    // 1. 拉取当日 QUEUED 记录
+    List<WithdrawRecord> queue = recordRepo.findByStatusOrderByCreatedAt("QUEUED");
+    
+    // 2. 查询实时 Master 余额(调用微信「查询商户余额」API 或本地缓存)
+    long masterBalance = queryWechatMasterBalance();
+    long refundBalance = queryWechatRefundBalance();
+    
+    // 3. 按优先级排序
+    queue.sort(Comparator
+        .comparing((r) -> !r.isEligibleRefund())  // 退费优先
+        .thenComparing(r -> r.getAmountFen()));   // 小额优先(更容易成功)
+    
+    for (WithdrawRecord record : queue) {
+        // 4. 判断通道
+        WithdrawChannel channel = resolveChannel(record, masterBalance, refundBalance);
+        
+        if (channel == null) {
+            // 余额不足,跳过,等待下一批
+            record.setRetryCount(record.getRetryCount() + 1);
+            recordRepo.save(record);
+            continue;
+        }
+        
+        // 5. 预扣税务(非退费通道)
+        TaxResult tax = channel.isRefund() 
+            ? TaxResult.zero()  // 退费不免税
+            : TaxCalculator.calc(record.getAmountFen());
+        
+        // 6. 扣减冻结余额
+        walletService.debitFrozen(record.getUserId(), record.getAmountFen());
+        
+        // 7. 调用对应通道
+        record.setStatus("BATCH_PROCESSING");
+        recordRepo.save(record);
+        
+        try {
+            switch (channel) {
+                case WECHAT_REFUND -> executeRefund(record, refundBalance);
+                case WECHAT_TRANSFER -> executeWechatTransfer(record, masterBalance, tax);
+                case THIRD_PARTY -> executeThirdParty(record, tax);
+            }
+            record.setStatus("SUCCESS");
+            record.setProcessedAt(LocalDateTime.now());
+        } catch (InsufficientBalanceException e) {
+            // 余额幻觉(并发场景下余额被其他批次扣走)
+            walletService.releaseFrozen(record.getUserId(), record.getAmountFen());
+            record.setStatus("QUEUED");
+            record.setRetryCount(record.getRetryCount() + 1);
+        } catch (Exception e) {
+            record.setStatus("FAILED");
+            record.setStatusRemark(e.getMessage());
+            walletService.releaseFrozen(record.getUserId(), record.getAmountFen());
+        }
+        recordRepo.save(record);
+        
+        // 8. 更新本地余额缓存
+        masterBalance = queryWechatMasterBalance();
+        refundBalance = queryWechatRefundBalance();
+    }
+    
+    // 9. 推送通知(微信模板消息)
+    notifyBatchResults(queue);
+}
+```
+
+### 3.4 微信商户账户余额约束(关键前提)
+
+```
+用户支付 ¥1,314 → 微信商户账户 +¥1,314
+    │
+    ├─ 微信先收手续费 0.6%(约 ¥7.88)
+    │
+    └─ 微信商户账户实际可 Master 余额 ≈ ¥1,306.12
+         │
+         ├─ 企业付款提现给用户 → 从此余额扣款
+         │
+         └─ 退费(退款)→ 扣「退款余额」(独立于 Master 余额)
+```
+
+**核心影响:**
+
+| 场景 | 约束 | 系统处理 |
+|------|------|---------|
+| 商户 Master 余额充足 | 按正常流程处理 | 无需特殊处理 |
+| 商户 Master 余额不足 | 微信接口报错 `NOT_ENOUGH` | 前端提示「余额不足,暂无法提现」,并提供「预约提现」(余额到账后自动处理) |
+| 首笔退费(退款通道) | 走微信「退款」API,扣「退款余额」;退款余额为 0 时不可用 | 系统降级为:标准微信直付 + 预扣个税,用户不再享受首笔退费资格 |
+| 退款余额为 0 | 退费通道不可用 | 降级为标准提现,首笔退费资格作废 |
+
+**运维要求(平台侧):**
+
+1. **每日对账** — 与微信商户平台核对「可 Master 余额」,低于阈值(建议 ¥5,000)时告警运维
+2. **定期充值** — 平台运营从企业银行账户向微信商户账户充值(在微信商户平台操作)
+3. **退款余额独立监控** — 退款余额与 Master 余额分开追踪,各有各的余额上限
+4. **提现排队机制** — 余额不足时,用户申请进入排队队列,后台定时任务每 15 分钟重试,最长等待 24 小时
+
+**新增 sys_config 参数:**
+
+| 参数 | 默认值 | 说明 |
+|------|--------|------|
+| `withdraw.wechat_master_balance_alert` | `500000` | Master 余额告警阈值(分,¥5,000) |
+| `withdraw.queue_retry_minutes` | `15` | 排队重试间隔(分钟) |
+| `withdraw.queue_max_wait_minutes` | `1440` | 最大排队等待(分钟,24h) |
+| `withdraw.refund_balance_fallback` | `true` | 退款余额不足时是否降级为标准提现 |
+| `withdraw.auto_topup_threshold` | `100000` | Master 余额低于此值时触发告警通知运营充值(分,¥1,000) |
+
+---
+
+## 4. 税务方案
+
+### 4.1 中国个税框架(劳务报酬所得)
+
+根据《个人所得税法》,个人推广佣金属于 **「劳务报酬所得」**,适用比例税率,由支付方(平台)**预扣代缴**。
+
+**劳务报酬预扣率表:**
+
+| 每次收入(税后估计) |  taxable income 计算 | 税率 | 速算扣除 |
+|-------------------|-------------------|-----|---------|
+| ≤ ¥800 | 免征 | 0% | — |
+| ¥800 – ¥4,000 | (收入 – ¥800) × 20% | 20% | 0 |
+| ¥4,000 – ¥25,000 | 收入 × 80% × 20% – ¥1,050 | 20% | ¥1,050 |
+| ¥25,000 – ¥62,500 | 收入 × 80% × 30% – ¥4,050 | 30% | ¥4,050 |
+| > ¥62,500 | 收入 × 80% × 40% – ¥7,050 | 40% | ¥7,050 |
+
+### 4.2 预扣模式选择
+
+| 模式 | 描述 | 优劣 |
+|------|------|------|
+| **A:每次提现预扣(推荐)** | 每次发钱时直接按劳务报酬税率计算个税 | 合规,平台无连带责任;用户到手金额透明 |
+| **B:年度汇算** | 全年预扣,次年3-6月用户自行汇算 | 复杂,平台需提供年度明细 |
+
+**系统采用模式 A**(预扣代缴),并提供年度明细(模式 B 的简化版)。
+
+### 4.3 税务公式
+
+```python
+def calc_withholding_tax(amount_fen: int) -> dict:
+    amount_yuan = amount_fen / 100
+    
+    if amount_yuan <= 800:
+        tax_yuan = 0
+        taxable_yuan = 0
+        rate = 0
+    
+    if amount_yuan <= 4000:
+        taxable_yuan = amount_yuan - 800
+        tax_yuan = taxable_yuan * 0.20
+        rate = 0.20
+    
+    else:
+        taxable_yuan = amount_yuan * 0.80
+        if taxable_yuan <= 20000:
+            tax_yuan = taxable_yuan * 0.20 - 1050
+            rate = 0.20
+        elif taxable_yuan <= 50000:
+            tax_yuan = taxable_yuan * 0.30 - 4050
+            rate = 0.30
+        else:
+            tax_yuan = taxable_yuan * 0.40 - 7050
+            rate = 0.40
+    
+    return {
+        "gross_amount_fen": amount_fen,
+        "taxable_amount_fen": int(taxable_yuan * 100),
+        "tax_rate": rate,
+        "withholding_tax_fen": max(0, int(tax_yuan * 100)),
+        "net_amount_fen": amount_fen - max(0, int(tax_yuan * 100)),
+        "service_fee_fen": int(amount_fen * 0.006),  # 微信手续费
+    }
+```
+
+### 4.4 节税策略(系统内置 + 用户指导)
+
+**系统侧(自动):**
+1. **周限提策略** – 鼓励用户合并小额提现,减少单次税率浪费
+   - 逻辑:周免提额 = max(周已提, min_amount),剩余额度跨周不清零(30天 VIP)
+   
+2. **年累计预扣优化**(年度报表)  
+   - 年底自动计算用户累计应税收入
+   - 若已预扣税率「过高」(累计税款 > 汇算后应交),退还差额至余额
+   - 若「过低」(累计预扣 < 汇算后应交),在次年首次提现补扣
+
+3. **800元以下小额免收割策略**  
+   - 若用户账户余额 ≤ ¥1500,建议用户先不提现,累计到¥800+:
+   ```
+   建议小程序前端提示:
+   "当前提现 ¥550,扣除个税后仅到账 ¥440(低于免征额 ¥800)。
+   建议再积累 ¥300 以上佣金,可享受个税免征。" 
+   ```
+
+**用户侧(引导):**
+1. **发票代开**:年度提现超过 ¥30,000 的用户,引导至税务局代开发票,税率约 2.5%-3%(远低于劳务报酬最高 40%)
+2. **个体工商户注册**:高频提现用户(月均 > ¥5,000),建议注册个体户,经营所得税率 5%-10%
+3. **合规申报辅助**:前端提供「年度汇总下载」按钮(PDF 明细),用户可自行 H5 汇算
+
+---
+
+## 5. 数据库设计
+
+### 5.1 withdraw_records 表
+
+```sql
+CREATE TABLE `withdraw_records` (
+  `id`              BIGINT PRIMARY KEY AUTO_INCREMENT,
+  `user_id`         BIGINT NOT NULL,
+  `amount_fen`      INT NOT NULL COMMENT '申请提现金额(分)',
+  
+  -- 税务
+  `withholding_tax_fen` INT NOT NULL DEFAULT 0 COMMENT '预扣个税(分)',
+  `tax_rate`           DECIMAL(4,2) NOT NULL DEFAULT 0 COMMENT '适用税率',
+  `taxable_amount_fen` INT NOT NULL DEFAULT 0 COMMENT '应纳税所得额(分)',
+  
+  -- 微信
+  `service_fee_fen`    INT NOT NULL DEFAULT 0 COMMENT '微信手续费(分)',
+  `wechat_transfer_id` VARCHAR(64) COMMENT '微信企业付款单号',
+  `wechat_resp`        JSON COMMENT '微信返回原始响应',
+  
+  -- 风控
+  `status`             VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT 'PENDING/SUCCESS/FAILED',
+  `status_remark`      VARCHAR(256) COMMENT '状态说明(失败原因等)',
+  `retry_count`        INT NOT NULL DEFAULT 0,
+  `risk_pass`          TINYINT NOT NULL DEFAULT 0 COMMENT '风控是否通过',
+  `risk_reason`        VARCHAR(256) COMMENT '风控不通过原因',
+  
+  -- 审计
+  `year`              INT NOT NULL COMMENT '所属年度(汇算用)',
+  `tax_year_amount_fen` INT NOT NULL DEFAULT 0 COMMENT '该年度已提现总额(分)',
+  `tax_year_withheld_fen` INT NOT NULL DEFAULT 0 COMMENT '该年度已扣个税额(分)',
+  
+  `applied_at`        DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `processed_at`      DATETIME COMMENT '处理完成时间',
+  INDEX `idx_user_status` (`user_id`, `status`),
+  INDEX `idx_user_year` (`user_id`, `year`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+```
+
+### 5.2 user_wallet 表(余额快照)
+
+```sql
+CREATE TABLE `user_wallet` (
+  `user_id`           BIGINT PRIMARY KEY,
+  `available_balance_fen` INT NOT NULL DEFAULT 0 COMMENT '可提现余额',
+  `frozen_balance_fen`    INT NOT NULL DEFAULT 0 COMMENT '冻结中余额(提现申请后)',
+  `total_withdrawn_fen`   INT NOT NULL DEFAULT 0 COMMENT '累计已提现',
+  `total_withholding_fen` INT NOT NULL DEFAULT 0 COMMENT '累计已扣个税',
+  `annual_withdrawn_fen`  INT NOT NULL DEFAULT 0 COMMENT '本年度已提',
+  `annual_withholding_fen` INT NOT NULL DEFAULT 0 COMMENT '本年度已扣税',
+  `last_withdraw_at`      DATETIME COMMENT '上次提现时间',
+  `week_withdraw_count`   INT NOT NULL DEFAULT 0 COMMENT '本周次数',
+  `week_reset_at`         DATE COMMENT '周重置日',
+  `day_fail_count`        INT NOT NULL DEFAULT 0 COMMENT '今日失败次数',
+  `day_fail_date`         DATE COMMENT '失败计数日期',
+  `updated_at`            DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+```
+
+### 5.3 commission 表新增字段(可选)
+
+```sql
+ALTER TABLE `commissions` ADD COLUMN `wallet_locked` TINYINT NOT NULL DEFAULT 0 COMMENT '是否已入钱包锁';
+ALTER TABLE `commissions` ADD COLUMN `withdraw_record_id` BIGINT COMMENT '关联提现ID';
+```
+
+### 5.4 sys_config 税务参数
+
+```sql
+INSERT INTO sys_config (`key`, `value`, `desc`, `value_type`) VALUES
+('withdraw.min_amount',        '10000',   '最低提现金额(分)', 'amount'),
+('withdraw.max_amount_time',  '1000000', '单次最高提现(分)', 'amount'),
+('withdraw.max_per_week',     '1',       '每周限提次数', 'number'),
+('withdraw.auto_approve_limit', '50000', '免审阈值(分)', 'amount'),
+('withdraw.fail_limit_day',   '3',       '日失败上限', 'number'),
+('withdraw.fail_lock_hours',  '24',      '超限冻结小时', 'number'),
+('withdraw.service_fee_rate', '6',       '微信手续费万分比(6=0.06%)', 'percent'),
+('withdraw.week_reset_day',   '1',       '周重置日(0=周日)', 'number'),
+('withdraw.tax.labor_rate_1', '800',     '劳务报酬免征额(元)', 'amount'),
+('withdraw.tax.deduction_2',  '2000',    '$4,000档速算扣除(分,对应¥20+1050)', 'amount'),
+('withdraw.tax.deduction_3',  '40500',   '$25,000档速算扣除(分,对应¥20,000*3%-4050)', 'amount'),
+('withdraw.tax.deduction_4',  '70500',   '>$62,500档速算扣除(分)', 'amount'),
+('withdraw.annual_reconcile', '1',       '是否开启年度汇算', 'boolean');
+```
+
+---
+
+## 6. 后端 API 设计
+
+### 6.1 提现流程 API
+
+| 端点 | 方法 | 说明 | 权限 |
+|------|------|------|------|
+| `POST /api/withdraw/apply` | 申请提现 | 输入 amount_fen(可选,默认全部可提) | 已登录 |
+| `POST /api/withdraw/records` | 提现记录列表 | 分页,含状态+金额+到账时间 | 已登录 |
+| `GET /api/withdraw/detail/:id` | 提现详情 | 单条明细(含税务明细) | 本人 |
+| `GET /api/withdraw/summary` | 提现汇总 | 累计提现/累计个税/本年度汇总 | 已登录 |
+| `GET /api/withdraw/tax-preview` | 税务预览 | 输入金额 → 返回预计扣税+到手 | 已登录 |
+| `POST /api/withdraw/cancel/:id` | 撤销提现 | PENDING 状态可撤销,解冻金额 | 本人 |
+| `GET /api/withdraw/annual-report` | 年度明细 PDF | 下载含扣税明细的年度 PDF | 已登录 |
+
+### 6.2 提现申请 DTO
+
+```java
+// WithdrawApplyRequest.java
+@Data
+public class WithdrawApplyRequest {
+    @NotNull(message = "提现金额不能为空")
+    @Min(value = 10000, message = "最低提现 ¥100") // amount in fen
+    @Max(value = 1000000, message = "单次最高 ¥10,000")
+    private Integer amountFen;
+    
+    // Optional: override full withdrawal
+    private Boolean all = false;
+}
+
+// WithdrawApplyResponse.java
+@Data
+public class WithdrawApplyResponse {
+    private Long recordId;
+    private Integer grossAmountFen;
+    private Integer withholdingTaxFen;
+    private Integer serviceFeeFen;
+    private Integer netAmountFen; // 实际到账
+    private BigDecimal taxRate;
+    private String status; // PENDING
+    private String estimatedArrival; // 1-3工作日
+}
+```
+
+### 6.3 关键业务流程
+
+```java
+// WithdrawService.java - 核心流程
+
+@Transactional
+public WithdrawApplyResponse apply(Long userId, WithdrawApplyRequest req) {
+    // 1. 校验余额
+    Wallet wallet = walletRepo.findByUserId(userId)
+        .orElseThrow(() -> new BizException(404, "钱包不存在"));
+    
+    // 2. 校验周限次
+    if (wallet.getWeekWithdrawCount() >= getMaxPerWeek()) {
+        throw new BizException(400, "本周提现次数已用完");
+    }
+    
+    // 3. 风控校验
+    RiskResult risk = riskCheck(userId, req.getAmountFen());
+    if (!risk.passed()) {
+        return reject(risk);
+    }
+    
+    // 4. 冻结金额
+    int amount = req.getAll() ? wallet.getAvailableBalance() : req.getAmountFen();
+    if (wallet.getAvailableBalance() < amount) {
+        throw new BizException(400, "可提现余额不足");
+    }
+    wallet.freeze(amount);
+    walletRepo.save(wallet);
+    
+    // 5. 税务计算
+    TaxResult tax = TaxCalculator.calc(amount);
+    
+    // 6. 创建提现记录
+    WithdrawRecord record = new WithdrawRecord();
+    record.setUserId(userId);
+    record.setAmountFen(amount);
+    record.setWithholdingTaxFen(tax.getWithholding());
+    record.setTaxRate(tax.getRate());
+    record.setStatus("PENDING");
+    record.setYear(Year.now().getValue());
+    walletRepo.save(wallet);
+    
+    // 7. 已通过自动审核(免审):直接调用微信付款
+    if (shouldAutoApprove(amount)) {
+        processWechatPayment(userId, record, tax);
+    }
+    
+    return toResponse(record, tax);
+}
+```
+
+---
+
+## 7. 微信企业付款到零钱集成
+
+### 7.1 API 端点
+
+```
+POST https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
+```
+
+**必要参数:**
+- `mch_appid` — 小程序 AppID
+- `mchid` — 商户号
+- `partner_trade_no` — 商户订单号(唯一)
+- `openid` — 用户 openid
+- `check_name` — `NO_CHECK`(不校验真实姓名,按公众号绑定)
+- `amount` — 金额(分,**实际打款金额 = amount - 服务费**)
+- `desc` — 企业付款说明
+- `spbill_create_ip` — 服务器 IP
+
+**签名校验:** 使用商户 API 证书(apiclient_key.pem)双向证书签名
+
+### 7.2 成本结构
+
+| 费用项 | 承担方 | 费率 |
+|--------|--------|------|
+| 微信企业付款手续费 | **平台** | 0.6%(最低 ¥0.1) |
+| 个税(劳务报酬) | **从用户提现金额中扣除** | 累进 0%-40% |
+| 代开发票(可选) | 用户 | 约 2.5%-3% |
+
+### 7.3 安全设计
+
+```java
+// WithdrawSecurity.kt (概念)
+@Scheduled(fixedRate = 60000)
+fun watchPending() {
+    // 检查超过 5 分钟未处理的 PENDING 记录
+    // 超时 → 解冻 + 记录告警
+}
+
+@Scheduled(fixedRate = 86400000)
+func dailyReconcile() {
+    // 与微信账单对账,确保平台记录与微信到账一致
+}
+```
+
+---
+
+## 8. 提现流程前端
+
+### 8.1 提现页(client/pages/withdraw/index.vue)
+
+```
+┌─────────────────────────────┐
+│  ← 提现                     │
+│                             │
+│ 可提现余额                  │ 大字 + 闪烁动画
+│ ¥ 1,380.00                 │
+│ ─────────────────────────  │
+│ 输入提现金额                │
+│ ┌─────────────────────┐     │
+│ │ ¥ 500.00            │     │  数字键盘
+│ └─────────────────────┘     │
+│ 快捷金额: ¥100 ¥500 ¥全部   │
+│                             │
+│ ┌─────────────────────┐     │ 浅灰蓝卡片 F7F8FC
+│ │ 税务预览             │     │
+│ │ 提现金额    ¥ 500.00 │     │
+│ │ 预扣个税    ¥  30.00 │     │  20% 税率
+│ │ 微信手续费  ¥   3.00 │     │  0.6% 平台承担
+│ │ 实际到账    ¥ 467.00 │     │  大号强调
+│ └─────────────────────┘     │
+│                             │
+│ ⚠️ 提示:本次提现低于 ¥800   │
+│ 免征额,建议累计至 ¥800+    │
+│                             │
+│       [  确认提现  ]        │  深色品牌按钮
+│                             │
+│ 本周已提:0/1次 | 预计1-3日到账 │ 小字灰色
+└─────────────────────────────┘
+```
+
+### 8.2 提现记录页
+
+```
+┌─────────────────────────────┐
+│ 提现记录                    │
+├─────────────────────────────┤
+│ ┌─────────────────────┐     │
+│ │ 11月20日 15:30       │     │
+│ │ 申请 ¥500.00        │     │
+│ │ 个税 ¥30 + 到账 ¥467 │     │
+│ │ 状态:✅ 已到账       │     │
+│ └─────────────────────┘     │
+│ ┌─────────────────────┐     │
+│ │ 11月15日 09:00       │     │
+│ │ 申请 ¥200.00        │     │
+│ │ 个税 ¥0(免征)      │     │
+│ │ 状态:⏳ 处理中       │     │
+│ └─────────────────────┘     │
+│                             │
+│ [下载年度税务明细 PDF]       │
+└─────────────────────────────┘
+```
+
+---
+
+## 9. 关键字段参照表
+
+| 表名 | 关键字段 | 说明 |
+|------|---------|------|
+| `user_wallet` | available_balance_fen | 可提现余额 |
+| `user_wallet` | frozen_balance_fen | 申请中冻结余额 |
+| `withdraw_records` | status | INIT / PENDING / SUCCESS / FAILED |
+| `withdraw_records` | withholding_tax_fen | 预扣个税金额 |
+| `withdraw_records` | tax_rate | 适用税率(0.20 等)|
+| `withdraw_records` | wechat_transfer_id | 微信付款单号 |
+| `sys_config` | withdraw.* | 所有可配置参数 |
+
+---
+
+## 10. 税务合规备忘
+
+1. **企业必须代扣代缴** — 平台作为支付方,有法定义务预扣个税
+2. **年度结算报告** — 次年 6 月前,平台需向税局报送上年度支付给个人的劳务报酬总额
+3. **发票管理** — 个税由平台代扣时,用户可凭「扣税记录」凭证申请退税
+4. **联合稽查风险** — 若提现流水大(>¥100万/年),需考虑>
+                       在小程序有关税提示:
+                       "年度汇总可凭此明细至税务局"
+                       (不提供代开发票,只提供明细)
+5. **税率更新** — `sys_config` 支持快速更新税率,年审时直接在后台调整
+
+---
+
+## 11. 节税策略实施优先级
+
+| 优先级 | 策略 | 用户价值 | 系统改动 |
+|--------|------|---------|---------|
+| P0 | 预扣代缴 + 税务预览弹窗 | 透明化 | ✅ 已覆盖 |
+| P0 | ¥800免征额智能提示 | 直接省钱 | ✅ 前端提示 |
+| P1 | 年度汇算退补机制 | 合规+体验 | 需年审触发器 |
+| P2 | 小额合并提现建议 | 减少税率浪费 | 前端算法 |
+| P3 | 代开发票引导(>¥30,000/年) | 合法降税 | 静态链接 |
+| P3 | 个体户注册指引 | 长期节税 | 外部跳转 |

+ 12 - 12
docs/需求差异分析-客户1.0vs当前Phase1.md

@@ -15,9 +15,9 @@
 | 产品名称 | 数字心理学·全生命周期AI赋能系统 | 数字能量学智能体 | 🔴 大 |
 | 目标用户 | **C端大众**(家长/单身/职场/中老年) | **B端能量师**(从业者) | 🔴 极大 |
 | 1.0 定位 | 免费锁客版,公域引流,积累百万用户 | 能量师工具,快速变现 | 🔴 极大 |
-| 功能范围 | 少儿+成人两大板块,6大刚需领域 | 三角形盘+AI五区解读 | 🔴 极大 |
+| 功能范围 | 少儿+成人两大板块,6大刚需领域 | 三角形能量盘+AI五区解读 | 🔴 极大 |
 | 付费策略 | 1.0 完全免费,2.0 月/年卡 | 能量师 ¥398/年唯一付费方案 | 🟡 中 |
-| 1.0 免费额度 | 无限使用,零门槛 | 每日3次盘+1次解读 | 🟡 中 |
+| 1.0 免费额度 | 无限使用,零门槛 | 每日3次能量盘+1次解读 | 🟡 中 |
 | 商业模式 | C端订阅+B端年费+分销 | 单一能量师年费+两级分销 | 🔴 大 |
 | 分销体系 | 城市合伙人/渠道代理/讲师分销(三级,20-50%) | 能量师两级分销(30%+10%) | 🟡 中 |
 | 收入预期 | 短期 ¥3,000万/年,中期 ¥2亿+ | Phase 1 ¥4-8万 | 🔴 极大 |
@@ -31,7 +31,7 @@
 | 项目 | 客户要求 | 当前规划 | 分析 |
 |------|---------|---------|------|
 | 产品名称 | "数字心理学·全生命周期AI赋能系统" | "数字能量学智能体" | 客户名称强调"全生命周期",暗示覆盖儿童到老年;当前名称偏学术/工具化 |
-| Slogan | "解码生命数字,赋能亿万人生" | "3秒出盘 + AI自动解读" | 客户口号宏大、面向大众;当前口号务实、面向从业者 |
+| Slogan | "解码生命数字,赋能亿万人生" | "3秒出能量盘 + AI自动解读" | 客户口号宏大、面向大众;当前口号务实、面向从业者 |
 | 品牌调性 | 万亿赛道、行业标准制定者 | 小工具、快速上线 | 客户期望高举高打,当前策略低调务实 |
 
 **风险**:如果客户期望的是"全生命周期赋能系统"但交付的是"能量师小工具",会产生重大的期望落差。
@@ -76,7 +76,7 @@
 - 财富格局底层特质
 
 #### 当前 Phase 1 功能
-- 三角形盘生成(Canvas 可视化)
+- 三角形能量盘生成(Canvas 可视化)
 - AI 五区解读(主性格 + 父源区 + 母源区 + 左区 + 中区 + 右区)
 - 分享/导出功能
 
@@ -128,7 +128,7 @@
 
 | 用户 | 价格 | 核心权益 |
 |------|------|---------|
-| 普通用户 | ¥0 | 每日3次盘 + 1次主性格概要 |
+| 普通用户 | ¥0 | 每日3次能量盘 + 1次主性格概要 |
 | 能量师 | ¥398/年 | 无限解读 + PDF + 分销 |
 
 **核心差异:**
@@ -182,8 +182,8 @@
 
 #### 当前 Phase 1 交互模式
 
-- **表单式输入** → 盘展示 → 解读结果
-- **只有三角形盘解读一个入口**
+- **表单式输入** → 能量盘展示 → 解读结果
+- **只有三角形能量盘解读一个入口**
 - **每日次数限制**
 - **面向专业用户**(能量师可理解三角形布局)
 
@@ -217,11 +217,11 @@
 
 ---
 
-### 分歧 3:功能范围是"全生命周期"还是"盘解读"?
+### 分歧 3:功能范围是"全生命周期"还是"能量盘解读"?
 
 | 客户观点 | 当前规划观点 |
 |---------|------------|
-| 覆盖少儿+成人两大板块,6大刚需领域 | 仅三角形盘 + AI 五区解读 |
+| 覆盖少儿+成人两大板块,6大刚需领域 | 仅三角形能量盘 + AI 五区解读 |
 
 **影响**:按客户要求,需要开发少儿天赋分析、学业评估、健康提示、婚恋匹配、事业规划、财富分析共 6 套解读引擎。当前只有 1 套。
 
@@ -244,7 +244,7 @@
 | 维度 | 一致性 | 说明 |
 |------|-------|------|
 | 核心技术 | ✅ 一致 | 都是基于数字心理学/数字能量学的 AI 解读 |
-| 三角形命盘 | ✅ 一致 | 命盘计算是双方共同认可的核心能力 |
+| 三角形能量盘 | ✅ 一致 | 能量盘计算是双方共同认可的核心能力 |
 | AI 驱动 | ✅ 一致 | 都依赖 LLM 生成内容,非固定模板 |
 | 分销裂变 | ✅ 一致 | 都认可分销是增长引擎 |
 | 微信小程序 | ✅ 一致 | 都选择微信生态作为载体 |
@@ -267,8 +267,8 @@
 - [ ] 方案 B:免费试用 + 付费解锁 — 当前规划
 
 ### 问题 3:功能范围
-- [ ] 方案 A:只做盘解读(当前范围,6周上线)
-- [ ] 方案 B:盘 + 少儿天赋 + 学业评估(扩展,12周+)
+- [ ] 方案 A:只做能量盘解读(当前范围,6周上线)
+- [ ] 方案 B:能量盘 + 少儿天赋 + 学业评估(扩展,12周+)
 - [ ] 方案 C:全 6 大领域(客户完整要求,20周+)
 
 ### 问题 4:产品名称

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů