Initial commit

This commit is contained in:
2026-06-22 11:28:01 +08:00
commit ace9c94359
84 changed files with 8899 additions and 0 deletions

View File

@ -0,0 +1,63 @@
# Auth 模块业务逻辑
## 模块职责
Auth 模块负责登录页、手机号密码登录、多账号选择和账号选择后的正式登录确认。
该模块只处理登录流程本身:
- 表单输入、校验和协议确认。
- 调用 v9 登录接口获取临时 token 和账号列表。
- 单账号时自动调用 set-user。
- 多账号时展示账号选择页。
- 选择账号后调用 set-user 换取正式 token。
正式 token 存储、账号快照和全局登录态写入由 App 模块的 `AuthSessionCoordinator` 统一处理。
## 核心对象
- `LoginView`:登录页 UI展示手机号、密码、协议确认和登录按钮。
- `AccountSelectionView`:多账号选择弹窗,展示景区账号和门店账号。
- `LoginViewModel`:维护表单状态、校验状态、登录请求状态和多账号选择状态。
- `AuthAPI`:封装 `/api/app/v9/login``/api/app/v9/set-user`
- `LoginRequest`:登录请求体。
- `SetUserRequest`:账号选择请求体。
- `V9AuthResponse`v9 登录和 set-user 响应。
- `V9ScenicUser` / `V9StoreUser`:后端返回的景区账号和门店账号。
- `AccountSwitchAccount`:统一后的可选择账号模型。
## 登录流程
1. 用户输入手机号和密码。
2. `LoginViewModel.validateForLogin` 校验手机号、密码和协议勾选状态。
3. 未勾选协议时,`LoginView` 弹出协议确认 Sheet。
4. 校验通过后,`LoginViewModel.login` 调用 `AuthAPI.login`
5. 登录接口返回临时 token 和可用账号列表。
6. `LoginViewModel` 过滤掉业务账号 ID 无效的账号。
7. 没有可用账号时抛出 `LoginFlowError.noAvailableAccount`
8. 只有一个账号时,自动调用 `AuthAPI.setUser`,并返回 `.completed`
9. 多个账号时,保存 `AccountSelectionPayload`,并返回 `.needsAccountSelection`
10. `LoginView` 展示 `AccountSelectionView`
11. 用户确认账号后,`LoginViewModel.selectAccount` 使用临时 token 调用 set-user。
12. set-user 返回正式 token 后,`LoginView` 调用 `AuthSessionCoordinator.completeLogin` 写入 token并同步用户资料、角色权限、景区和门店。
## 账号模型转换
后端景区账号和门店账号字段不完全一致,统一转换为 `AccountSwitchAccount`
- 景区账号通过 `ssUserId``scenicUserId``userId``id` 兜底生成业务账号 ID。
- 门店账号通过 `storeUserId``userId``id` 兜底生成业务账号 ID。
- `AccountSwitchAccount.toSetUserRequest` 根据账号类型生成 `store_user_id``ss_user_id`
`V9AuthResponse` 还会派生:
- `accounts`:合并后的账号选择列表。
- `primaryProfile`:登录后用于全局展示的账号资料。
- `scenicScopes`:当前账号可用景区作用域。
- `storeScopes`:当前账号可用门店作用域。
## 缓存规则
Auth 模块不直接写缓存。登录成功后的缓存由 `AuthSessionCoordinator` 负责:
- 正式 token 写 Keychain。
- 上次手机号和协议状态写 UserDefaults。
- 账号资料、当前角色和业务作用域写入账号快照。
临时 token 只存在于 `AccountSelectionPayload`,不落盘。