家庭管理(上)
301. 家庭创建/加入:Repository + Service + Step 2 UI
日期: 2026-05-20 关联开发任务: 阶段 3 任务 3.1 创建/加入家庭 关联设计文档: 004.数据库设计文档 §4.2-4.3、003.详细设计文档 §2 界面二
一、问题/需求
注册流程的 Step 2 是家庭关系绑定——用户必须创建新家庭或通过 6 位邀请码加入已有家庭才能完成注册。需要从数据层到 UI 层完整实现这个流程。
二、思路
- 数据层先行:Family + FamilyMember 两个 Repository,遵循 UserRepository 模板
- Service 编排:FamilyService 负责 createFamily(生成邀请码 + 设户主)和 joinFamily(验证邀请码)
- Step 2 UI:独立 FamilySetupPage,创建/加入两个按钮,加入用底部 Drawer 抽屉
- 注册流程串联:RegisterWindow 用 StackView 管理 Step1→Step2,Step1 先调用 AuthService.registerUser() 拿到 userId,再传给 Step2
三、逻辑推导
3.1 注册顺序
Step 1 (RegisterPage)
├── 填表 → 校验 → AuthService.registerUser()
├── 拿到 userId → push Step 2
└── ❌ 不能在 Step 2 后才注册——因为 FamilyService 需要 userId
Step 2 (FamilySetupPage)
├── 创建家庭 → FamilyService.createFamily(userId)
└── 加入家庭 → FamilyService.joinFamily(userId, inviteCode)
3.2 邀请码策略
- 6 位字母数字(排除 I/O/0/1 易混淆字符)
- 用
QRandomGenerator::global()生成 - 不设过期(
invite_code_expires_at = NULL) - 唯一性由
family_repository.getByInviteCode()调用方自行保证重试(当前概率足够低,暂不做)
四、实施方案
文件清单
src/data/family_entity.h ← Family + FamilyMember 实体
src/data/family_repository.h/.cpp ← Family CRUD + getByInviteCode
src/data/family_member_repository.h/.cpp ← 成员 add/remove/query
src/core/family_service.h/.cpp ← createFamily / joinFamily
src/ui/qml/FamilySetupPage.qml ← Step 2 UI
src/ui/qml/RegisterWindow.qml ← StackView 串联两步骤
依赖注入链
main.cpp
├── FamilyRepository(&app)
├── FamilyMemberRepository(&app)
└── FamilyService(familyRepo, memberRepo, &app)
└── setContextProperty("familyService")
五、踩坑
| 现象 | 根因 | 修复 |
|---|---|---|
FamilySetupPage 中 session.userId 为空 | 注册未完成前 session 未设置 | 改用 RegisterWindow.registeredUserId 属性传递 |
| 两个步骤 UI 大小不一致 | RegisterWindow 固定 420×680,Page 内部用 anchors 自适应 | 统一窗口尺寸 |
| Drawer 挡住主按钮 | Drawer 高度 260,edge: Qt.BottomEdge | 正常 |
六、验证
| 验证项 | 结果 |
|---|---|
| 注册→创建家庭→数据库写入 families + family_members | ✅ |
| 邀请码 6 位大写字母数字 | ✅ |
| 户主 role=owner | ✅ |
| 邀请码无效 → “邀请码无效,请核对后重试” | ✅ |
| 重复加入 → “你已经是该家庭的成员” | ✅ |