|
@@ -0,0 +1,87 @@
|
|
|
|
|
+# 财富中心成员贡献榜:管理员身份口径统一 + 池权限可切换 — 需求变更说明(2026-11-07)
|
|
|
|
|
+
|
|
|
|
|
+> **版本:** v1.0(主理人裁定,以 role 为准)
|
|
|
|
|
+> **来源:** 用户 2026-11-07 需求(3 条)
|
|
|
|
|
+> **状态:** 现状核查完成 → 需求变更锁定(待入池/派发)
|
|
|
|
|
+> **关联台账:** `docs/superpowers/specs/2026-11-07-family-earnings-admin-role.md`(实现任务书)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 一、需求清单(原话)
|
|
|
|
|
+
|
|
|
|
|
+1. 财富中心成员贡献榜中显示的**管理员与实际身份不一致**。
|
|
|
|
|
+2. `earnings/admin/toggle-member` 接口报**无权限操作**,不知道有什么用。
|
|
|
|
|
+3. 成员贡献榜每个人都写的**「池关闭」**,不知道有什么用。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 二、现状与根因(cfclub @ b4cc6b791)
|
|
|
|
|
+
|
|
|
|
|
+### 页面与接口
|
|
|
|
|
+- **前端**:`cfc-frontend/pages/promotion/index.vue`(990 行)——家庭公共收益总览 + 成员贡献榜;调 `/api/earnings/*`
|
|
|
|
|
+- **后端**:`FamilyEarningsController`(`/api/earnings`)+ `FamilyEarningsService`
|
|
|
|
|
+
|
|
|
|
|
+### 根因 1 · 管理员身份双口径割裂
|
|
|
|
|
+| 处 | 口径 |
|
|
|
|
|
+|----|------|
|
|
|
|
|
+| 前端 `isAdmin`(promotion/index.vue L228-232) | `role === 'parent' \|\| role === 'teacher'`(**登录角色**) |
|
|
|
|
|
+| 前端贡献榜 `m.isAdmin` 标签(L56) | 来自后端 DTO |
|
|
|
|
|
+| 后端 `FamilyEarningsService.getMemberContributions` L75 | `user.getIsFamilyAdmin()`(**`is_family_admin` 字段**) |
|
|
|
|
|
+| 后端 `FamilyEarningsController.isFamilyAdmin` L131-134 | 仅 `user.getIsFamilyAdmin()` |
|
|
|
|
|
+
|
|
|
|
|
+→ 一个 `role='parent'` 但 `is_family_admin=0` 的用户:前端显示管理员(有操作按钮),贡献榜标签却不是管理员(或反之)。**`is_family_admin` 只在建家庭/接邀请/转让时设置**(`FamilyInvitationService` L180/260/299/308),普通家长加入已有家庭后默认 0。
|
|
|
|
|
+
|
|
|
|
|
+### 根因 2 · toggle-member 无权限
|
|
|
|
|
+- 前端显示 switch(L66):`isAdmin && !m.isAdmin`(`isAdmin`=role 判定)
|
|
|
|
|
+- 后端鉴权(Controller L88):`isFamilyAdmin(adminId)` 只查 `is_family_admin` 字段
|
|
|
|
|
+- → 家长角色(前端认为有权限)但 `is_family_admin=0` → 后端拒绝「无权限操作」。**同一人前端看有权限、后端看无权限**。
|
|
|
|
|
+
|
|
|
|
|
+### 根因 3 · 全员「池关闭」
|
|
|
|
|
+- `FamilyEarningsService.getMemberContributions` L94:查不到 `family_earnings_member` 记录时默认 `canUseFamilyBalance=false`(显示「池关闭」)
|
|
|
|
|
+- 该记录仅在 `distribute`(L206)/`toggleMemberAccess`(L298)时创建 → 正常家庭从未分配过就全员「池关闭」
|
|
|
|
|
+- **「池」语义**:家庭公共收益池(family_earnings 总账),`canUseFamilyBalance` 控制成员能否动用家庭公共余额。默认关闭是安全设计,管理员开启后成员才可用。用户"不知道有什么用"——功能存在但被权限问题挡住无法切换(根因 2),需在权限修复后**可正常切换**并**补一句说明文案**。
|
|
|
|
|
+
|
|
|
|
|
+### 参考实现(role 口径的正确范例)
|
|
|
|
|
+- `ReportMemberPermissionService.isFamilyAdmin`(L61-79):三口径(family.creator_id / users.is_family_admin / family_members.is_admin)——**这是其他模块的正确做法**,财富中心只判了其中一个,故割裂。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 三、需求变更定义(目标态,以 role 为准)
|
|
|
|
|
+
|
|
|
|
|
+### 变更 F1 · 管理员身份统一为 role 口径(后端与前端对齐)
|
|
|
|
|
+- **后端** `FamilyEarningsService.getMemberContributions`(L75):`dto.setIsAdmin(...)` 改为**角色判定** `role ∈ {'parent','teacher'}`(`user.getRole()`),与前端 `isAdmin` computed 完全一致。
|
|
|
|
|
+- **后端** `FamilyEarningsController.isFamilyAdmin`(L131-134):同样改为角色判定 `role ∈ {'parent','teacher'}`(读 `User.getRole()`)。
|
|
|
|
|
+- 贡献榜「管理员」标签、管理员按钮、switch 显示条件、后端鉴权——**四者统一为 role 口径**。
|
|
|
|
|
+- 参考:`User.getRole()` 返回 `String`(ENUM parent/child/teacher,SchemaSyncHandler L71)。**判定函数**:`role != null && ("parent".equals(role) || "teacher".equals(role))`。
|
|
|
|
|
+
|
|
|
|
|
+### 变更 F2 · 池权限可正常切换 + 语义说明
|
|
|
|
|
+- 权限修复后(F1),管理员点击 switch → `toggleMemberAccess` 正常执行(创建/更新 `family_earnings_member.can_use_family_balance`),不再报「无权限操作」。
|
|
|
|
|
+- **前端**贡献榜区块(members-card)补一句说明文案:`池可用 = 该成员可使用家庭公共收益余额;池关闭 = 不可用,由管理员开启`(放 members-header 下或 member-list 上方,小字灰色,`$app-text-subtle`)。
|
|
|
|
|
+- **不改默认值**:`canUseFamilyBalance=false`(池关闭)是安全默认,保留;修复权限后管理员可正常开启,无"永远关着"问题。
|
|
|
|
|
+- **验收口径**:家长角色管理员对贡献榜成员点击 switch 不再报「无权限操作」;切换后「池可用/池关闭」状态正确刷新;贡献榜管理员标签与前端角色一致。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 四、TDD 入池
|
|
|
|
|
+
|
|
|
|
|
+| 能力键 | 变更 | requirement 溯源 | design 溯源 |
|
|
|
|
|
+|--------|------|-----------------|------------|
|
|
|
|
|
+| `family.earnings.admin.role` | F1 | 本文档需求 1+2 | `FamilyEarningsController.isFamilyAdmin`(role 判定)+ `FamilyEarningsService.getMemberContributions`(isAdmin 由 role 判定) |
|
|
|
|
|
+| `family.earnings.pool.toggle` | F2 | 本文档需求 2+3 | `FamilyEarningsService.toggleMemberAccess`(已合入)+ `promotion/index.vue` switch |
|
|
|
|
|
+
|
|
|
|
|
+> RED 契约以「已合入 origin/cfclub 的 `FamilyEarningsController` 契约」为准(`/api/earnings/admin/toggle-member` 入参 `{userId, enabled}`)。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 五、风险与注意事项(主理人核实)
|
|
|
|
|
+
|
|
|
|
|
+1. **`is_family_admin` 字段保留**:仅改为「不再作为财富中心鉴权依据」,字段本身不动(其他模块 `ReportMemberPermissionService` 仍用,勿删)。
|
|
|
|
|
+2. **role 判定边界**:`teacher` 也视为管理员(与前端 `isAdmin` 一致)——若产品只想要家长,需另行确认,勿擅自改。
|
|
|
|
|
+3. **不改 `ReportMemberPermissionService`**:那是正确的三口径实现,本任务只对齐财富中心的两个判定点。
|
|
|
|
|
+4. **默认池关闭保留**:是安全设计,本任务不改为默认开启;只保证「可切换」+「语义可读」。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 六、关联记录
|
|
|
|
|
+
|
|
|
|
|
+- 现状核查完成;任务书待入 cfclub 后派发 lan-204。
|