# 规格文档:注册零填写 + 信息按需补充 **日期:** 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`(编写中)。