# 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`,不落盘。