Kaynağa Gözat

feat: 注册零填写设计规格(注册直接进首页+接收家庭邀请独立页+功能→信息字段映射表+添加成员手机号→邀请加入)

E2E Test Bot 19 saat önce
ebeveyn
işleme
9620e46798

+ 4 - 3
docs/superpowers/PROJECT-OVERVIEW.md

@@ -1,8 +1,8 @@
 # 浠艾福 项目全景 — 阶段性需求与设计汇总
 
-**文档版本:** v2.12
-**日期:** 2026-09-19
-**状态:** 已确认(v2.1 Phase 2-4 全栈完成)+ 虚拟支付改造(Tasks 1-12 已完成,退款闭环实施中)+ 新用户注册引导(12 Tasks 全栈完成)+ 家庭成员关系条增强(✅ 已实施)+ TabBar 重构(✅ 4Tab + 中间⭐扇形菜单,设计已对齐实现)+ **LIFETIME 终身会员(✅ 11 Tasks 全栈完成)** + **健康数据中心(✅ 全栈完成)** + **SKU 价格单位统一分 + 规格选择响应式修复(✅ 7 Tasks 全栈完成)** + **AI健康教练人格分化与管家自助选择(✅ 11 Tasks 全栈完成)** + **优惠券全链路改为家庭维度(待实施)** + **关系三图重构(关键人拓展章鱼图/珍珠图/能力图,设计规格已完成)**
+**文档版本:** v2.13
+**日期:** 2026-09-28
+**状态:** 已确认(v2.1 Phase 2-4 全栈完成)+ 虚拟支付改造(Tasks 1-12 已完成,退款闭环实施中)+ 新用户注册引导(12 Tasks 全栈完成)+ 家庭成员关系条增强(✅ 已实施)+ TabBar 重构(✅ 4Tab + 中间⭐扇形菜单,设计已对齐实现)+ **LIFETIME 终身会员(✅ 11 Tasks 全栈完成)** + **健康数据中心(✅ 全栈完成)** + **SKU 价格单位统一分 + 规格选择响应式修复(✅ 7 Tasks 全栈完成)** + **AI健康教练人格分化与管家自助选择(✅ 11 Tasks 全栈完成)** + **优惠券全链路改为家庭维度(待实施)** + **关系三图重构(关键人拓展章鱼图/珍珠图/能力图,设计规格已完成)** + **注册零填写+信息按需补充(🟡 设计稿:注册直接进首页 + 接受邀请独立页真实姓名/家庭身份必填 + 功能→信息字段映射表 + 添加成员手机号冲突邀请加入)**
 **维护:** 所有需求变更需更新本文档
 
 ---
@@ -350,6 +350,7 @@
 | `2026-07-31-compare-table-mobile-redesign.md` | 🟡 设计稿 | 四大饮水方案对比 — 移动端轮播式重设计 |
 | `2026-08-02-virtual-payment-design.md` | 🟢 已实施(offerId/签名按官方 signData 修正) | 小程序虚拟支付合规接入(测评/会员/订阅)|
 | `2026-08-04-registration-profile-backfill-design.md` | 🟡 设计稿 | 新用户注册引导 + 个人信息按需补充/回写 |
+| `2026-09-28-registration-zero-fill-design.md` | 🟡 设计稿(待确认) | 注册零填写:登录直接进首页 + 接受家庭邀请独立页(真实姓名+家庭身份必填)+ 功能→信息字段映射表 + 添加成员手机号冲突→邀请加入 |
 | `2026-08-04-report-confirm-member-selector-design.md` | 🟡 设计稿 | 健康报告确认页被检测人选择面板整合(基本信息内选/添被检人) |
 | `2026-08-04-family-challenge-custom.md` | 🟢 已实施 | 家庭挑战自定义管理(创建/编辑/删除/模板) |
 | `2026-08-05-inventory-management-design.md` | 🟡 设计稿 | 库存管理(入库单+流水+盘点+预警+套餐拆库存) |

+ 208 - 0
docs/superpowers/specs/2026-09-28-registration-zero-fill-design.md

@@ -0,0 +1,208 @@
+# 规格文档:注册零填写 + 信息按需补充
+
+**日期:** 2026-09-28
+**状态:** 设计稿
+**前置文档:**
+- `2026-08-04-registration-profile-backfill-design.md`(注册引导 + 按需补充回写,本设计继承其回写机制)
+- `2026-08-04-registration-profile-backfill.md`(对应实施计划)
+
+---
+
+## 1. 概述
+
+**核心诉求:取消用户注册时的信息填写步骤,注册成功直接进首页;所有个人信息在功能实际需要时补充。**
+
+用户原话:「取消用户注册时填写信息一项,所有信息都在需要时补充,各个功能要列出要使用的信息。」
+
+三个目标:
+
+1. **注册零填写**:可登录用户手机号登录即注册,登录成功直接进首页,不跳任何信息填写页
+2. **功能→信息映射**:每个功能列出其使用的用户信息字段,缺失时在功能内就地补充并自动回写
+3. **接受邀请必填**:接受家庭邀请时,真实姓名 + 家庭身份必填(仅此场景强制)
+
+## 2. 角色模型(统一口径)
+
+系统角色分三大类(不区分"家长/孩子"语义,新功能禁止引入孩子概念):
+
+| 角色类别 | 说明 | 注册/创建方式 |
+|---------|------|--------------|
+| **可登录用户** | 手机号+微信注册,可登录小程序 | 注册零填写,登录即注册,直接进首页 |
+| **服务用户** | 成长规划师等,需资质审核 | 独立注册流程 `pages/guide/register`(证书/照片/身份证,本方案不改动) |
+| **不可登录用户** | 无登录账号,由家庭管理员创建 | 家庭成员管理页添加(`pages/family/add-member`),填昵称/辈分/性别/生日等 |
+
+**数据归属**:可登录用户信息存 `users` 表;不可登录用户信息存 `family_members` 表;同一家庭的可登录用户可代管不可登录用户数据。
+
+## 3. 现状分析
+
+| 项目 | 现状 | 问题 |
+|------|------|------|
+| 注册流程 | 登录成功 → `needsRoleSelect=true`(新用户)→ 跳 `user-edit?autoParent=true` 全字段表单 | **强制填写,与"注册零填写"诉求冲突** |
+| 默认昵称 | 后端注册时已设默认(`用户+手机尾号` / `微信用户`),不依赖前端 | ✅ 可复用 |
+| 接受邀请 | `join.vue` → 已登录用户跳 `user-edit?autoParent=true`(全字段 + 家庭身份下拉) | 全字段表单过重,且家庭身份非必填 |
+| 添加成员 | `add-member.vue` 填手机号时提示「若手机号已注册,将自动关联该账号」 | 需求改为「提示是否邀请加入」 |
+| 按需回写 | `profile-field-usage.js` + `profile-backfill.js` + 后端 backfill 接口已就绪;仅活动报名接入 | 映射表不完整,各功能未接入 |
+
+## 4. 设计决策记录
+
+| # | 决策 | 结论 |
+|---|------|------|
+| 1 | 注册后是否填写 | **完全零填写,登录成功直接进首页**(头像/昵称均不填,昵称用后端默认) |
+| 2 | 角色注册 | 可登录用户默认直接进首页;服务用户保留独立注册流程;不可登录用户由家庭管理员添加 |
+| 3 | 接受家庭邀请 | **新增独立页面**(内容与 user-edit 相同),真实姓名 + 家庭身份必填,其余选填 |
+| 4 | 功能→信息映射 | 更新 `profile-field-usage.js` 建立完整映射(本次仅出文档,各功能后续逐个接入) |
+| 5 | 添加成员手机号冲突 | 手机号已被注册 → 提示「是否邀请该用户加入家庭」 |
+| 6 | `needsRoleSelect` | 后端字段保留,前端不再消费(登录不再跳转) |
+| 7 | `user-edit.vue` | 保留「个人中心编辑资料」用途,`autoParent=true` 新用户流程停用 |
+
+## 5. 详细设计
+
+### 5.1 注册零填写(可登录用户)
+
+**文件:** `pages/login/login.vue`
+
+`completeLogin()`(L177-178)改造:
+
+```
+当前:
+  if (data.needsRoleSelect || hasPendingFamilyInvite) {
+    uni.redirectTo('/pages/user-edit/user-edit?...&autoParent=true')
+  } else {
+    self.handlePostLoginRouting()
+  }
+
+改为:
+  // 注册零填写:needsRoleSelect 不再触发跳转
+  // 家庭邀请衔接:有 pendingFamilyInviteCode → 直接进 join-form 填真实姓名+家庭身份
+  var pendingInvite = uni.getStorageSync('pendingFamilyInviteCode')
+  if (pendingInvite) {
+    uni.redirectTo({ url: '/pages/invite/join-form?familyInviteCode=' + encodeURIComponent(pendingInvite) })
+  } else {
+    self.handlePostLoginRouting()
+  }
+```
+
+- 新用户(`needsRoleSelect=true`)**不再跳 user-edit**,登录成功直接进首页(后端默认昵称兜底)
+- 未登录用户点家庭邀请链接 → join.vue 引导登录 → 登录成功 → 直接进 **join-form**(衔接闭环)
+- 后端 `needsRoleSelect` 字段保留在 `LoginResultDTO`,前端不再消费
+
+**文件:** `pages/user-edit/user-edit.vue`
+
+- `isNewUserFlow`(`autoParent=true` 分支)停用:`onLoad` 不再处理 `autoParent=true` / `needsRoleSelect=true` 参数,统一走普通编辑模式
+- `confirmRole` / `selectRole` / 角色选择区:仅保留非新用户进入时的行为(实际个人中心编辑不涉及角色选择,相关区块可清理或保留不显示)
+- 家庭邀请相关(`hasPendingFamilyInvite` / `familyRole` 区块 / `requestJoinByCode`)逻辑迁移至新页面 5.2
+- 保留:头像/昵称/真实姓名/性别/生日/出生时辰/民族/血型/学历/婚姻/地区/兴趣/饮食偏好 全字段编辑(个人中心入口)
+
+### 5.2 接受家庭邀请简化表单(新页面)
+
+**新增文件:** `pages/invite/join-form.vue`(注册到 `pages.json` 的 `pages/invite` 分包)
+
+**页面内容:** 字段与 `user-edit.vue` 编辑模式相同,但仅强制两项:
+
+| 字段 | 必填 | 说明 |
+|------|:----:|------|
+| **真实姓名** | ✅ | 家庭管理员据此识别申请人 |
+| **家庭身份** | ✅ | 爸爸/妈妈/爷爷/奶奶/姥爷/姥姥/其他(复用 `familyRoleOptions`) |
+| 昵称 | 选填 | 为空时前端用默认(`用户+手机尾号`),不强制触发后端重算 |
+| 头像/性别/生日/其他 | 选填 | 可顺手填,不填不影响加入申请 |
+
+**交互流程:**
+
+```
+join.vue(已登录、不在目标家庭)
+  → goJoinForm() 跳 /pages/invite/join-form?familyInviteCode=xxx
+  → 填写真实姓名 + 家庭身份(其余选填)
+  → 保存:updateUserInfo(realName, nickname, avatar, ...)(可选字段透传)
+         + requestJoinByCode(inviteCode, familyRole) 提交加入申请
+  → 成功 toast「加入家庭申请已提交,等待管理员审批」→ goHome
+
+join.vue(未登录)
+  → goLogin → 登录成功后 login.vue completeLogin 检测到 pendingFamilyInviteCode
+         → 跳 join-form(衔接闭环)
+```
+
+**`join.vue` 改造(L261-284):**
+
+- `goUserEdit()` 改为 `goJoinForm()`:跳 `/pages/invite/join-form?familyInviteCode=...&token=...&userId=...`
+- `goNext()` 未登录分支(L274-278)保持不变:调 `goLogin()`;登录后由 login.vue 完成衔接(见上面流程)
+- 复制 `user-edit.vue` 的 `requestJoinByCode` 调用逻辑到新页面(`user-edit.vue` 中 L754-768 相关逻辑迁移)
+
+**`user-edit.vue` 家庭邀请逻辑清理:**
+- `hasPendingFamilyInvite` 计算属性移除(已无引用)
+- `familyRole` form 字段、L48-57 家庭身份区块移除
+- L754-768 保存时提交加入申请逻辑移除(迁移至 join-form)
+
+### 5.3 功能→信息字段映射表(文档 + 配置更新)
+
+**新增/更新:** `cfc-frontend/utils/profile-field-usage.js`
+
+完整映射(基于全前端探查):
+
+| 字段 | 功能场景 | 页面 | 字段去向 | 现状 |
+|------|---------|------|---------|------|
+| **realName 真实姓名** | 活动报名 | activity-detail | user/member | 手动填,未回写 |
+| | 接受家庭邀请 | invite/join-form | user | **本次新增必填** |
+| | 创建联系人 | ContactImport | 独立实体 | 自填 |
+| **phone 手机号** | 活动报名 | activity-detail | user/member | ✅ 已回写 |
+| | 添加成员关联账号 | add-member | member | 本次改「邀请加入」提示 |
+| **birthday 生日** | 家庭天盘 | tianpan/* | user/member | 后端计算生肖/五行/生命数字,前端缺失无引导 |
+| | 测评年龄计算 | assessment/* | member | 后端计算,前端缺失无引导 |
+| | 健康报告匹配 | health/report-* | member | 报告页自填(newMember) |
+| | 饮食推荐 | nutrition-profile | member | 后端计算 |
+| **birthHour 出生时辰** | 家庭天盘 | tianpan/* | user/member | 后端计算 |
+| **gender 性别** | 家庭天盘 | tianpan/* | user/member | 后端计算 |
+| | 测评维度计算 | assessment/* | member | 后端计算 |
+| | 健康报告匹配 | health/report-* | member | 报告页自填 |
+| **dietPreferences 饮食偏好** | 饮食推荐 | nutrition-profile | user/member | 后端计算 |
+| **address 地区** | 收货地址(独立地址簿) | shop/* | 独立实体 | 不走个人信息 |
+| | 活动地点 | activity-detail | user | 低优先级 |
+| **avatar/nickname** | 全局展示(家庭成员列表/评论/推荐人) | 各页 | user/member | 后端默认昵称兜底 |
+
+**约定:** 功能页接入时在 `scenes` 中登记本场景;回写前校验字段属于本场景(`profile-backfill.js` 已实现该机制);回写白名单沿用后端 6 字段(phone/gender/birthday/birthHour/dietPreferences/address)+ realName(本次新增,后端白名单同步加)。
+
+**后端回写白名单扩展:** `UserService.backfillProfile()` 的 `USER_BACKFILL_WHITELIST` 增加 `"realName"`(`MEMBER_BACKFILL_WHITELIST` 同步确认 family_members 是否有 realName 列;无则维持 phone/gender/birthday/birthHour)。
+
+> 各功能页「缺失即就地补充 + 回写」的接入不在本次范围,按映射表后续逐个排期实施(P2+)。
+
+### 5.4 添加成员手机号冲突 → 邀请加入
+
+**文件:** `pages/family/add-member.vue`
+
+- L78-80 提示文案:「填写手机号可关联已有账号 / 若手机号已注册,将自动关联该账号」→ 改为「填写手机号可在已注册时邀请加入」
+- 提交时(`doSubmit`)若填了手机号:调后端查询该手机号是否已被注册(新增或复用接口,如 `POST /api/user/check-phone-exists`)
+  - 已注册 → 弹确认「该手机号已被注册,是否邀请该用户加入家庭?」→ 确认 → 跳转邀请流程(携带手机号/邀请码);取消 → 继续以不可登录用户身份添加(不关联账号)
+  - 未注册 → 正常添加
+- 后端新增接口需确认是否已有类似能力(`FamilyMemberService` / `UserService` 查询 phone)
+
+## 6. 实施范围
+
+| 阶段 | 内容 | 说明 |
+|------|------|------|
+| **P0(本次)** | 注册零填写(login.vue)+ user-edit 新用户流程停用 + join-form 新页面 + join.vue 衔接 + 映射表更新 + add-member 手机号冲突提示 | 可单独上线 |
+| **P2+(后续逐个接入)** | 天盘/测评/健康报告/饮食推荐等页面的「缺失就地补充 + 回写」接入 | 按映射表排期 |
+
+## 7. 验收标准
+
+- [ ] 新用户手机号登录 → 登录成功 → **直接进首页**,不出现任何信息填写页
+- [ ] `user-edit` 不再接受 `autoParent=true` 新用户流程参数(个人中心编辑资料正常)
+- [ ] 接受家庭邀请(join.vue 已登录场景)→ 跳 `join-form`:真实姓名 + 家庭身份必填,其余选填;提交后调 `requestJoinByCode` 等待管理员审批
+- [ ] `profile-field-usage.js` 映射表完整(真实姓名/手机号/生日/出生时辰/性别/饮食偏好/地区 + 各自场景)
+- [ ] 后端 backfill 白名单增加 `realName`(若 member 表无 realName 列则确认边界)
+- [ ] add-member 填已注册手机号 → 提示「邀请加入」,确认后走邀请流程
+- [ ] `mvn clean compile` 通过;前端语法/结构校验通过
+- [ ] 不破坏:服务用户注册流程、个人中心编辑、现有活动报名回写
+
+## 8. 实现决策(已完成评估)
+
+| # | 项 | 决策 |
+|---|----|------|
+| 1 | 手机号已注册查询接口 | 复用现有 `POST /api/auth/check-phone`(前端已封装 `checkPhone(phone)` in api.js L344) |
+| 2 | member 表 realName 列 | `family_members` 无 real_name 列(仅 nickname/phone/gender/birthday/birthHour 等);**realName 只加进 USER 回写白名单**(member 白名单维持 phone/gender/birthday/birthHour 4 字段) |
+| 3 | join-form 与 user-edit 字段共用 | 本期直接新建,不抽公共组件;二期优化时考虑复用 |
+
+## 9. 文档索引更新
+
+本设计同步更新 `docs/superpowers/PROJECT-OVERVIEW.md` v2.13(2026-09-28)。
+
+## 10. 待实施
+
+详见 `docs/superpowers/plans/2026-09-28-registration-zero-fill.md`(编写中)。