# Profile 模块业务逻辑 ## 模块职责 Profile 模块负责“我的/个人信息”页面及其二级页面,包括用户资料展示、昵称编辑、账号切换、密码修改、实名认证、系统设置、协议页和退出登录。 首页“空间设置”入口对应的是摄影师当前景区下的个人空间配置,已拆到 `ProfileSpace` 模块;`Profile` 模块只保留账号级个人资料能力。 该模块聚焦个人资料业务: - 拉取用户基础资料。 - 拉取实名认证信息。 - 展示头像、昵称、UID、手机号、账号状态和实名认证状态。 - 修改昵称和头像。 - 修改密码。 - 切换当前景区/门店业务账号。 - 提交实名认证基础资料。 - 展示系统设置、版本号、下载链接和协议 H5 页面。 - 退出登录入口。 登录态清理和缓存清理由 App 模块的 `AuthSessionCoordinator` 统一处理。 DEBUG 构建下,“我的”列表会额外展示“首页调试”入口,进入 `DebugHomeMenuPreviewView` 后可查看并跳转所有已知首页菜单,不读取角色权限。该入口只用于迁移预览和调试,不进入 Release 包。 ## 核心对象 - `ProfileView`:个人信息页 UI,负责展示资料、编辑入口、密码弹窗和退出确认。 - `ProfileViewModel`:维护资料加载状态、编辑状态、保存状态和展示文案。 - `ProfileRoute`:个人中心二级页面路由。 - `AccountSwitchView` / `AccountSwitchViewModel`:账号切换页面和状态逻辑。 - `RealNameAuthView` / `RealNameAuthViewModel`:实名认证页面和表单逻辑。 - `SettingsCenterView` / `AgreementView`:设置中心和协议 H5 页面。 - `DebugHomeMenuPreviewView`:DEBUG 专用首页菜单预览页,不参与正式业务流程。 - `ProfileAPI`:封装用户资料、实名认证和资料更新接口。 - `OSSUploadService`:上传头像和实名认证证件图片,返回可提交给业务接口的 OSS URL。 - `UserInfoResponse`:用户基础资料。 - `RealNameInfoResponse` / `RealNameInfo`:实名认证信息。 - `UpdateInfoRequest`:昵称、密码或头像更新请求体。 - `RealNameAuthRequest`:实名认证提交请求体。 `basic_info` 首页权限入口继续进入 `ProfileView`;`space_settings` 进入 `ProfileSpaceView`,两者不共用页面状态。 ## 加载流程 1. `ProfileView.task` 进入页面时调用 `reloadProfile()`。 2. 下拉刷新时同样调用 `reloadProfile()`,成功后不展示 Toast。 3. `ProfileViewModel.reload` 并发请求: - `ProfileAPI.userInfo` - `ProfileAPI.realNameInfo` 4. 请求成功后更新 `userInfo` 和 `realNameInfo`。 5. `ProfileView` 将最新 `userInfo` 交给 `AuthSessionCoordinator.refreshCachedProfile`。 6. 协调器更新 `AccountContext.profile`,并同步刷新账号快照。 ## 资料编辑流程 1. 用户点击编辑按钮。 2. `ProfileViewModel.beginEditing` 进入编辑状态,并把当前昵称写入编辑框。 3. 用户点击头像时通过 `PhotosPicker` 选择本地图片。 4. `AvatarImageProcessor` 将头像压缩为 JPEG,并暂存在内存中。 5. 用户提交后,`ProfileViewModel.saveProfile` 校验昵称非空。 6. 头像变化时先调用 `OSSUploadService.uploadUserAvatar` 上传到 OSS。 7. 头像上传成功后调用 `ProfileAPI.updateUserAvatarURL` 回写头像 URL。 8. 昵称变化时调用 `ProfileAPI.updateUserInfo(nickname:)`。 9. 接口成功后本地更新 `userInfo.nickname` 和 `userInfo.avatar`。 10. `ProfileView` 刷新全局账号资料和账号快照。 ## 密码修改流程 1. 用户打开 `PasswordUpdateSheet`。 2. 输入新密码并点击完成。 3. `ProfileViewModel.updatePassword` 校验密码至少 6 位。 4. 校验通过后调用 `ProfileAPI.updateUserInfo(password:)`。 5. 成功后关闭弹窗并展示 Toast。 密码不会写入本地缓存。 ## 账号切换流程 1. 用户点击“当前账号”进入 `AccountSwitchView`。 2. `AccountSwitchViewModel.load` 调用 `ProfileAPI.switchableAccounts`,读取 `/api/app/v9/accounts`。 3. 页面展示景区账号和门店账号,优先选中后端标记的当前账号,否则选中第一项。 4. 用户确认后调用 `AuthAPI.setUser`,使用 `AccountSwitchAccount.toSetUserRequest()` 生成请求体。 5. 切换成功后调用 `AuthSessionCoordinator.completeLogin`,重新写入正式 token、账号快照、权限、景区和门店上下文。 6. `AppRouter.reset()` 清空旧路由栈并回到首页。 ## 实名认证流程 1. 用户点击“认证状态”进入 `RealNameAuthView`。 2. `RealNameAuthViewModel.load` 调用 `ProfileAPI.realNameInfo` 并回填姓名、身份证号、证件有效期、图片 URL 和审核状态。 3. 用户可发送短信验证码,接口为 `/api/yf-handset-app/photog/real-name/sms-verify-code`。 4. 用户通过图片卡片选择身份证人像面和国徽面。 5. `RealNameImageProcessor` 将证件图片压缩为 JPEG,并暂存在内存中。 6. 提交前校验姓名、身份证号、短信验证码、证件图片和有效期。 7. 校验通过后先调用 `OSSUploadService.uploadRealNameImage` 上传证件图片。 8. 上传成功后把 OSS URL 写入 `RealNameAuthRequest.frontUrl/backUrl`。 9. 调用 `/api/yf-handset-app/photog/real-name/submit` 提交实名资料。 10. 提交成功后重新加载实名认证信息。 证件图片的原始 Data、压缩 Data 和上传进度只保存在内存中,不写入本地缓存。 ## 设置和协议流程 1. 用户点击“系统设置”进入 `SettingsCenterView`。 2. 设置中心展示关于我们、系统版本、App 下载链接、用户协议和隐私政策。 3. App 下载点击后复制 `/h5/app/download` 链接到剪贴板。 4. 协议页使用 `AgreementView` 加载 `APIEnvironment.current.baseURL` 下的 H5 页面。 ## 退出登录流程 1. 用户点击退出登录。 2. `ProfileView` 展示确认弹窗。 3. 用户确认后调用 `AuthSessionCoordinator.logout`。 4. 协调器清空正式 token、账号快照、账号上下文、路由栈和 Toast。 5. `AppSession` 切换为 `loggedOut`,根视图回到登录页。 6. 上次手机号和协议状态等非敏感偏好保留。 ## 状态展示规则 - 进入个人信息页时,先用 `AccountContext` 中已恢复的本地缓存(`AccountSnapshot`)预填充昵称、手机号和头像;接口返回后再替换为最新数据。 - 昵称为空时展示“未设置昵称”。 - 真实姓名、手机号和账号状态为空时展示 `--`。 - 实名认证状态: - `auditStatus == 2`:已实名认证。 - `auditStatus == 3`:审核不通过。 - 其他状态:审核中。 - 无实名认证信息时:点击去实名认证。 - 账号切换失败只展示 Toast,不清空登录态。 - 实名认证失败只影响实名认证页面,不影响登录态和账号上下文。