# 团队层级树与推荐关系可视化设计 **版本:** v1.0 **日期:** 2026-09-09 **状态:** 待审查 **关联需求:** 用户需求记录 --- ## 一、概述 **用户故事:** > 作为家长用户,我想在「我的」页面查看我的推荐人、分享人数、团队层级树(从下往上生长)、团队总消费额、直推成员的消费额和我获得的 CF 值,以便直观了解我的推广成果与团队结构。 **核心目标:** 1. 去掉富页面的推荐码展示 2. 我的页面新增「我的推荐人」卡片 3. 我的页面新增「团队层级」入口,跳转独立树形页面(从下往上生长) 4. 树形页面展示:团队总消费额(默认 3 级,后台可配)、直推成员列表含消费额+我获得的 CF 值 5. 后端新增/扩展接口支撑上述功能 --- ## 二、验收标准 ### 2.1 富页面 - [ ] 删除「我的邀请码」横条(`referral-code-bar` 区块) - [ ] 保留「邀请人数」显示 ### 2.2 我的页面 - [ ] 新增「我的推荐人」卡片(显示推荐人昵称、头像、邀请码、绑定时间) - [ ] 新增「团队层级」入口按钮,点击跳转树形页面 - [ ] 保留现有「推广收益」成就卡片 ### 2.3 团队层级树页面(新建 `/pages/profile/team-tree`) - [ ] 树形结构从下往上生长(根节点在底部,分支向上延伸) - [ ] 顶部展示:团队总消费额(默认统计 3 级)、团队人数 - [ ] 支持折叠/展开每个节点 - [ ] 每个节点显示:头像、昵称、层级标识(L1/L2/L3)、消费额、我的 CF 获得 - [ ] 点击成员可查看详情(预留) ### 2.4 后端接口 - [ ] `POST /api/commission/team/list` 扩展:返回中每个成员新增 `memberConsumption`、`myCfEarnedFromMember` - [ ] `POST /api/commission/team/consumption` 新增:团队总消费额分级汇总 - [ ] `POST /api/commission/my-referrer` 新增:获取我的推荐人信息 - [ ] `POST /api/commission/team/tree` 新增:团队树形扁平数据(含层级、父子关系) ### 2.5 配置化 - [ ] 后台可配置团队消费统计最大层级(默认 3 级) --- ## 三、技术方案 ### 3.1 数据模型关系 | 表 | 关键字段 | 用途 | |---|---|---| | `users` | `id`, `referrerId`, `referralCode`, `nickname`, `avatar`, `created_at` | 用户与推荐关系 | | `referral_tree` | `parentId`, `childId`, `level`, `path` | 物化全层级推荐树 | | `product_orders` | `buyerId`, `totalAmount`, `status`, `fulfillStatus`, `paidAt` | 消费订单(fulfillStatus=completed 表示已完成履约) | | `commission_records` | `referrerId`, `buyerId`, `commissionAmount`, `level`, `status` | 佣金记录(L1/L2;status=settled/cancelled) | | `user_platform_balance` | `userId`, `totalEarned`, `available`, `frozen`, `withdrawn` | CF 值钱包(现有,本需求不直接读) | | `cf_rate_tier` | `minTeamSize`, `ratePercent`, `enabled` | 返佣阶梯(现有,复用其 maxLevel 配置) | > 注:`referral_tree.level` = 代际差(1=直推,2=间推...);`commission_records.level` = 1/2(仅 L1/L2 结算佣金);订单完成以 `fulfillStatus = 'completed'` 为准。 ### 3.2 后端接口设计 #### 3.2.1 扩展 `/api/commission/team/list` **请求:** `{ page, size, level }`(level: ALL/L1/L2) **响应扩展字段:** ```json { "records": [ { "userId": 123, "nickname": "用户名", "avatarUrl": "https://...", "createdAt": "2026-01-01", "orderCount": 5, "commissionEarned": 15000, "memberConsumption": 32000, // 新增:该成员 completed 订单总额 "myCfEarnedFromMember": 9600 // 新增:我从该成员消费获得的 CF(佣金)总额 } ], "total": 10, "page": 1, "size": 20 } ``` **实现逻辑:** - `memberConsumption`:查 `product_orders` 表 `buyerId = 该成员` 且 `fulfillStatus = 'completed'` 的 `totalAmount` 总和(仅统计已完成履约的订单) - `myCfEarnedFromMember`:查 `commission_records` 表 `referrerId = 我` 且 `buyerId = 该成员` 且 `status != 'cancelled'` 的 `commissionAmount` 总和(含 settled + pending) #### 3.2.2 新增 `/api/commission/team/consumption` **请求:** `{ maxLevel: 3 }`(默认 3,可选) **响应:** ```json { "totalConsumption": 125000, "levelBreakdown": [ { "level": 1, "memberCount": 5, "consumption": 80000 }, { "level": 2, "memberCount": 12, "consumption": 35000 }, { "level": 3, "memberCount": 8, "consumption": 10000 } ], "totalMembers": 25, "maxLevel": 3 } ``` **实现逻辑:** 1. 查 `referral_tree` 表 `parentId = 我` 且 `level <= maxLevel` 的所有 `childId` 2. 按 `level` 分组统计 `memberCount` 3. 查这些 `childId` 的 `product_orders`(`fulfillStatus = 'completed'`)`totalAmount` 总和,按 `level` 汇总 **配置化:** - 读取 `cf_rate_tier` 表中 `enabled=1` 的记录,或新增 `commission_config` 表存储 `team_consumption_max_level`(默认 3) - 后端管理接口:`POST /api/admin/cf-rate-tier/setting`(扩展现有)或新增 #### 3.2.3 新增 `/api/commission/my-referrer` **请求:** 空 **响应:** ```json { "referrerId": 456, "nickname": "推荐人昵称", "avatar": "https://...", "referralCode": "ABC123XY", "bindTime": "2026-01-15 10:30:00" } ``` **实现逻辑:** - 查 `users` 表 `id = 当前用户.referrerId` - 若 `referrerId` 为空,返回 `{ hasReferrer: false }` #### 3.2.4 新增 `/api/commission/team/tree` **请求:** `{ maxLevel: 3 }`(默认 3) **响应:** ```json { "nodes": [ { "userId": 101, "nickname": "直推A", "avatar": "https://...", "level": 1, "parentId": 100, "referrerId": 100, "memberConsumption": 32000, "myCfEarnedFromMember": 9600 }, { "userId": 102, "nickname": "间推B", "avatar": "https://...", "level": 2, "parentId": 101, "referrerId": 101, "memberConsumption": 8000, "myCfEarnedFromMember": 2400 }, { "userId": 103, "nickname": "直推C", "avatar": "https://...", "level": 1, "parentId": 100, "referrerId": 100, "memberConsumption": 15000, "myCfEarnedFromMember": 4500 } ], "totalMembers": 3, "maxLevel": 3 } ``` > **说明:** `nodes` 数组**不包含根节点("我")**——仅包含 team 成员(level >= 1);根节点仅用于前端统计/上下文。每个节点已包含 `memberConsumption`(该成员自身已完成履约订单总额)和 `myCfEarnedFromMember`(我从该成员消费获得的 CF 总额)。前端按 `parentId` 递归构建树,`level` 用于层级标签与缩进。 --- ### 3.3 前端改动清单 | 文件 | 变更类型 | 详情 | |---|---|---| | `pages/wealth/index.vue` | 删除 | 移除 `referral-code-bar`(第 161-165 行) | | `pages/profile-main/profile.vue` | 新增 | 1.「我的推荐人」卡片
2.「团队层级」入口按钮 → `navigateTo('/pages/profile/team-tree')` | | `pages/profile/team-tree.vue` | **新建** | 树形页面:
- 顶部统计卡(总消费、人数)
- 树形组件(从下往上生长,flex column-reverse + 递归)
- 节点组件:头像、昵称、层级标签、消费额、我的 CF 获得
- 折叠/展开交互 | | `utils/api.js` | 新增 | `getTeamConsumption(maxLevel)`、`getMyReferrer()`、`getTeamTree(maxLevel)`、`getTeamList` 扩展字段 | | `pages.json` | 注册 | 新增 `pages/profile/team-tree` 页面 | **树形 UI 实现思路(从下往上生长):** ```vue {{ node.nickname }} L{{ node.level }} 消费: ¥{{ (node.memberConsumption/100).toFixed(2) }} 我得CF: ¥{{ (node.myCfEarnedFromMember/100).toFixed(2) }} ``` --- ### 3.4 后端实现要点 **新增 Service 方法(`CommissionService`):** ```java // 1. 团队消费统计 public Map getTeamConsumption(Long userId, Integer maxLevel) // 2. 我的推荐人 public Map getMyReferrer(Long userId) // 3. 团队树形数据 public Map getTeamTree(Long userId, Integer maxLevel) // 4. 扩展 getTeamList:查询 memberConsumption、myCfEarnedFromMember ``` **依赖注入需补充:** - `ProductOrderMapper` - `ReferralTreeMapper` - `UserPlatformBalanceMapper`(如需) **新增 Controller 方法(`CommissionController`):** ```java @PostMapping("/team/consumption") public Result> teamConsumption(@RequestAttribute("userId") Long userId, @RequestBody Map params) @PostMapping("/my-referrer") public Result> myReferrer(@RequestAttribute("userId") Long userId) @PostMapping("/team/tree") public Result> teamTree(@RequestAttribute("userId") Long userId, @RequestBody Map params) ``` --- ## 四、API 设计汇总 | 接口 | 方法 | 请求体 | 响应关键字段 | 备注 | |---|---|---|---|---| | `/api/commission/team/list` | POST | `{page,size,level}` | `records[].memberConsumption`, `records[].myCfEarnedFromMember` | 扩展现有 | | `/api/commission/team/consumption` | POST | `{maxLevel}` | `totalConsumption`, `levelBreakdown[]`, `totalMembers` | 新增 | | `/api/commission/my-referrer` | POST | `{}` | `referrerId`, `nickname`, `avatar`, `referralCode`, `bindTime` | 新增 | | `/api/commission/team/tree` | POST | `{maxLevel}` | `nodes[]`, `totalMembers` | 新增 | --- ## 五、配置项 | 配置键 | 默认值 | 说明 | 维护位置 | |---|---|---|---| | `team_consumption_max_level` | 3 | 团队消费统计最大层级 | 后台管理 - CF返佣阶梯配置扩展 | > 建议复用 `AdminCfRateTierController` 新增设置接口,或新增 `CommissionConfigController` --- ## 六、边界情况处理 | 场景 | 处理 | |---|---| | 用户无推荐人(`referrerId` 为空) | 我的推荐人卡片显示"暂无推荐人",不显示邀请码 | | 团队成员无消费订单 | 消费额显示 0,CF 获得显示 0 | | `maxLevel` 超过实际层级 | 按实际最大层级统计 | | `referral_tree` 数据不一致 | 以 `users.referrerId` 为准,`referral_tree` 为辅助加速查询 | | 订单状态:仅统计已完成履约 | 高 | 严格筛选 `fulfillStatus = 'completed'`(排除 pending/confirmed_by_vendor/received_by_user) | --- ## 七、测试用例 | 用例 | 输入 | 预期输出 | |---|---|---| | 无推荐人用户访问我的页面 | 登录用户,referrerId=null | 推荐人卡片显示"暂无推荐人" | | 有推荐人用户访问我的页面 | 登录用户,referrerId=456 | 显示推荐人昵称、头像、邀请码、绑定时间 | | 空团队访问树形页面 | 无下级 | 仅显示根节点(自己),统计为 0 | | 3层团队消费统计 | maxLevel=3 | 正确汇总 L1/L2/L3 消费额 | | 直推成员列表 | level=L1 | 每行含 memberConsumption、myCfEarnedFromMember | | 折叠/展开交互 | 点击节点图标 | 子节点显示/隐藏,连接线正确 | --- ## 八、关联文档 - `docs/superpowers/api/API_REFERENCE.md` - 接口参考(新增接口需同步记录) - `cfc-backend/AGENTS.md` - 后端规范 - `cfc-frontend/AGENTS.md` - 前端规范 --- ## 九、实施顺序建议 1. **后端先行**(1-2 天): - 新增 3 个接口 + 扩展 1 个接口 - 单元测试验证查询逻辑 - 更新 `API_REFERENCE.md` 2. **前端并行**(1-2 天): - 删除富页面推荐码 - 我的页面新增推荐人卡片 + 团队入口 - 新建 team-tree 页面(树形组件复用/新建) - 接入 API 3. **配置化**(0.5 天): - 后台 CF 阶梯配置页扩展 `maxLevel` 字段 - 接口读取配置 4. **联调验证**(0.5 天): - 真实数据跑通 - 边界情况验证 --- ## 十、风险与对策 | 风险 | 等级 | 对策 | |---|---|---| | `referral_tree` 数据量大,树形查询慢 | 中 | 限制 `maxLevel`≤5,加索引 `idx_parent_level(parentId, level)` | | 消费额统计包含退款订单 | 高 | 严格筛选 `fulfillStatus = 'completed'`(仅统计已完成履约的订单,排除未结算/退货状态) | | 树形 UI 在小程序渲染卡顿 | 低 | 虚拟列表/分页加载,层级>3 懒加载 | | 后台配置未生效(缓存) | 低 | 配置读取走 Redis,更新后清理 | --- **文档结束**