# 会员中心重设计 + 用户管理会员功能扩展 设计文档 日期:2026-08-30 分支:cfclub ## 背景与目标 ### 现状问题 1. `MembershipCenter.vue`(525行)功能混杂:统计卡片 + 等级配置表 + 升级记录表 + 会员维护卡片挤在一个长页面,体验差。 2. `Users.vue`(436行)操作列只有「编辑」「更多」,无法直接修改用户会员等级/推荐人,需跳转会员中心。 3. 后台改会员等级**不送优惠券**,而小程序端用户购买会员会送 JOIN 赠券——行为不一致。 ### 本次目标 1. **重设计会员中心**:统计卡 + 3 个 Tab 页签(等级配置 / 升级记录 / 会员维护),职责清晰、界面专业。 2. **用户管理增加会员功能**:操作列新增「会员信息」按钮,弹窗改会员等级 + 推荐人。 3. **后台改等级自动送券**:复用 `CouponService.grantJoinCoupons`,与小程序购买一致。 ## 涉及文件 | 文件 | 改动 | |------|------| | `cfc-web/src/views/admin/MembershipCenter.vue` | 重构:统计卡 + Tab 页签 | | `cfc-web/src/views/Users.vue` | 新增「会员信息」按钮 + 弹窗 | | `cfc-backend/.../controller/admin/AdminController.java` | 注入 CouponService,改等级后送券 | | `cfc-web/src/api/admin.js` | 无需新增 API(复用现有) | ## 后端接口(已有,复用) - `POST /api/admin/membership/levels` — 等级列表(5个:FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME) - `POST /api/admin/membership/overview` — 统计 - `POST /api/admin/membership/upgrade-records` — 升级记录(分页) - `POST /api/admin/membership/user-update` — 改 memberLevel + referrerId - `POST /api/admin/user/search` — 用户搜索 ## 一、会员中心重设计(MembershipCenter.vue) ### 页面结构:统计卡 + 3 个 Tab 页签 ``` ┌──────────────────────────────────────────────┐ │ 统计卡 ×5(带图标+渐变底色) │ │ 免费用户 / FAMILY会员 / PROVIDER会员 / │ │ 本月新增 / 终身会员 │ ├──────────────────────────────────────────────┤ │ 【会员等级配置】 【升级记录】 【会员维护】 │ ├──────────────────────────────────────────────┤ │ Tab 内容区 │ └──────────────────────────────────────────────┘ ``` ### Tab1:会员等级配置 - 等级表格:id / levelCode / levelName / 描述 / 价格 / 孩子上限 / 每日任务 / AI审核 / 优先客服 / 操作 - 操作列:**编辑**(编辑弹窗)+ **更多**(权限详情弹窗) - 编辑弹窗:输入名称/描述/价格/各权限开关,保存刷新 - 权限详情弹窗:展示 features 权限说明 ### Tab2:升级记录 - 顶部可选筛选:按「到等级」筛选(全部/FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME) - 升级记录表:ID / 用户 / 从等级 / 到等级 / 升级方式 / 订单ID / 到期时间 / 创建时间 - 分页(默认10条) ### Tab3:会员维护(核心操作) - 搜索区:手机号/昵称/用户ID + 搜索按钮 - 结果表:ID / 昵称 / 手机号 / 当前等级(Tag) / 推荐人ID / 到期时间 / 操作 - 操作列:**修改会员信息** - 修改弹窗: - 用户信息只读(昵称/手机号/当前等级) - 会员等级下拉(FREE/FAMILY/PROVIDER/PREMIUM/LIFETIME) - 推荐人ID 输入框(留空不变/填0清除/填ID设定) - 保存 → 刷新表格+统计 ### 交互设计 - 统计卡点击 → 跳对应 Tab 筛选状态 - 弹窗用 `v-if` 懒渲染(避免空数据抛错,参考 `safeLevels` 防御) ## 二、用户管理增加「会员信息」(Users.vue) ### 操作列新增按钮 ``` [编辑] [会员信息] [更多▼] ``` ### 「会员信息」弹窗 | 字段 | 类型 | |------|------| | 用户昵称 | 只读 | | 手机号 | 只读 | | 当前会员等级 | 下拉(带Tag区分默认值) | | 推荐人ID | 输入框(留空不变/填0清除/填ID设定) | | 到期时间 | 可选日期(非LIFETIME时显示) | - 保存调用 `/api/admin/membership/user-update` - 成功后刷新用户列表 + Toast ## 三、后台改等级自动送券(后端) ### 改动点:`AdminController.updateMembershipUser` 1. 注入 `@Resource CouponService couponService;`(需 import `com.etotem.cfc.service.CouponService`) 2. 在等级实际变化(`newLevel != null && !oldLevel.equals(newLevel)`)且写入升级记录后,追加送券: ```java // 等级变化后,按新等级发放 JOIN 会员券(与小程序购买会员一致,幂等) try { couponService.grantJoinCoupons(targetUserId, newLevel, "admin:" + adminUserId); } catch (Exception e) { log.error("后台改等级发放JOIN会员券异常: userId={}, levelCode={}", targetUserId, newLevel, e); } ``` ### 复用逻辑 `CouponService.grantJoinCoupons` - 查找 `grant_type=JOIN` 且 `grant_level_code=levelCode` 的 ACTIVE 券模板 - 通过 `grant(userId, couponId, "JOIN", "JOIN", source)` 发放 - **幂等**:`uk_grant (user_id, coupon_id, grant_type, period)` 唯一键防重 → 同一等级券不重复发放 ### 关键行为矩阵 | 场景 | 是否送券 | |------|---------| | FREE → FAMILY | ✅ 送 FAMILY JOIN 券 | | FAMILY → LIFETIME | ✅ 送 LIFETIME JOIN 券(如有模板) | | 只改推荐人(等级不变) | ❌ 不送 | | 重复保存相同等级 | ❌ 不送(幂等) | ### 注意事项 - 送券失败仅打日志不影响等级更新(与 MembershipService 一致) - `upgradeType="admin"` 升级记录已存在,送券在其后执行 - source 用 `"admin:" + adminUserId` 标识后台来源 ## 验证 - 后端:`cd cfc-backend && mvn clean compile`(唯一验证方式) - 前端:`cd cfc-web && npm run serve -- --port 8083` - 手工验证:后台改一个用户等级 → 检查该用户是否收到对应 JOIN 券(member_upgrade_records 有记录 + user_coupon 新增)