feat: 添加云盘与消息中心功能
This commit is contained in:
682
应用启动流程与接口数据存储梳理.md
Normal file
682
应用启动流程与接口数据存储梳理.md
Normal file
@ -0,0 +1,682 @@
|
||||
# 应用启动流程与接口数据存储梳理
|
||||
|
||||
本文按当前 iOS 工程代码梳理应用从冷启动到各首屏展示期间发生的初始化、接口调用顺序,以及接口数据和本地状态的存储方式。范围仅覆盖当前 iOS 实现,不额外补充 Android 中存在但 iOS 尚未接入的能力。
|
||||
|
||||
## 1. 冷启动立即发生
|
||||
|
||||
冷启动入口在 `AppDelegate.application(_:didFinishLaunchingWithOptions:)`。
|
||||
|
||||
1. 调用 `UmengBootstrap.configureIfNeeded()`。
|
||||
- 友盟初始化受 `AppStore.shared.privacyAgreementAccepted` 控制。
|
||||
- 未同意隐私协议时直接返回,不初始化 SDK。
|
||||
2. 调用 `WeChatManager.shared.registerIfNeeded()`。
|
||||
- 校验 Universal Link。
|
||||
- 调用微信 SDK `WXApi.registerApp` 注册 AppID。
|
||||
3. 若 `AppStore.shared.privacyAgreementAccepted == true` 且 `AppStore.shared.token` 非空,则调用 `AMapBootstrap.configureIfNeeded()`。
|
||||
- 写入高德隐私合规状态。
|
||||
- 设置 `AMapServices.shared().apiKey` 和 HTTPS。
|
||||
4. 此阶段不直接调用任何业务后端接口。
|
||||
|
||||
随后系统进入 `SceneDelegate.scene(_:willConnectTo:options:)`。
|
||||
|
||||
1. 调用 `AppNavigationBarAppearance.applyGlobalAppearance()` 设置全局导航栏样式。
|
||||
2. 创建 `UIWindow`。
|
||||
3. 设置 `window.rootViewController = AppRouter.makeRootViewController()`。
|
||||
4. `AppRouter` 通过 `AppStore.shared.isLoggedIn` 判断根页面:
|
||||
- token 非空:进入 `MainTabBarController`。
|
||||
- token 为空:进入 `UINavigationController(rootViewController: LoginViewController())`。
|
||||
5. 注册全局通知:
|
||||
- `sessionDidExpire`:清除登录态并切回登录页。
|
||||
- `userDidLogout`:清除登录态并切回登录页。
|
||||
- `userDidLogin`:切到主 Tab。
|
||||
|
||||
## 2. 网络依赖初始化
|
||||
|
||||
`NetworkServices.shared` 是全局网络依赖容器,不在 `AppDelegate` 中主动创建,而是在页面或 Tab 首次访问业务 API 时懒加载。
|
||||
|
||||
初始化顺序如下:
|
||||
|
||||
1. 创建 `APIClient(environment: .current)`。
|
||||
2. 用同一个 `APIClient` 创建各业务 API:
|
||||
- `AuthAPI`
|
||||
- `ProfileAPI`
|
||||
- `StatisticsAPI`
|
||||
- `OrderAPI`
|
||||
- `HomeAPI`
|
||||
- 以及其他业务模块 API。
|
||||
3. 创建 `OSSUploadService(configService: uploadAPI)`。
|
||||
4. 调用 `client.bindAuthTokenProvider`,从 `AppStore.shared.token` 读取 token。
|
||||
|
||||
`APIClient` 的公共请求规则:
|
||||
|
||||
- `APIEnvironment.current`
|
||||
- Debug:`https://api-test.zhifly.cn`
|
||||
- Release:`https://api.zhifly.cn`
|
||||
- 每个请求默认写入 Header:
|
||||
- `Content-Type: application/json`
|
||||
- `Accept: application/json`
|
||||
- `X-APP-VERSION`
|
||||
- `X-OS-TYPE: iOS`
|
||||
- token 非空时写入 `token`
|
||||
- 响应通过 `APIEnvelope` 解包。
|
||||
- 成功业务码:`100000`
|
||||
- 非成功业务码抛出 `APIError.serverCode`
|
||||
- 认证失效时广播 `sessionDidExpire`,由 `SceneDelegate` 清会话并回登录页。
|
||||
|
||||
## 3. 未登录启动与登录流程
|
||||
|
||||
未登录时根页面为登录页。
|
||||
|
||||
### 3.1 登录页展示前
|
||||
|
||||
`LoginViewController.setupUI` 会调用 `viewModel.applyStoredPreferences()`,从 `AppStore` 读取:
|
||||
|
||||
- `lastLoginUsername`
|
||||
- `privacyAgreementAccepted`
|
||||
|
||||
这一步只恢复本地表单状态,不调用后端接口。
|
||||
|
||||
### 3.2 登录页出现后
|
||||
|
||||
`LoginViewController.viewDidAppear` 调用:
|
||||
|
||||
```text
|
||||
GET /api/app/config
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
LoginViewController.viewDidAppear
|
||||
-> LoginViewModel.loadAppConfig(authAPI:)
|
||||
-> AuthAPI.getAppConfig()
|
||||
```
|
||||
|
||||
用途:
|
||||
|
||||
- 读取 App 配置。
|
||||
- 当前只使用 `enableRegister` 控制验证码登录/注册入口显隐。
|
||||
- 配置加载失败会静默忽略,不影响密码登录。
|
||||
- 该结果只保存在 `LoginViewModel.enableRegister` 内存态,不写入 `AppStore`。
|
||||
|
||||
### 3.3 点击登录后的接口顺序
|
||||
|
||||
用户点击登录按钮后,先做本地校验:
|
||||
|
||||
- 手机号必须是 11 位且以 `1` 开头。
|
||||
- 密码不能为空。
|
||||
- 必须勾选隐私协议。
|
||||
|
||||
校验通过后发起登录:
|
||||
|
||||
```text
|
||||
POST /api/app/v9/login
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
LoginViewController.performLogin()
|
||||
-> LoginViewModel.login(authAPI:)
|
||||
-> AuthAPI.login(username:password:)
|
||||
```
|
||||
|
||||
返回数据包含临时 token 和可选账号列表。随后根据账号数量分流:
|
||||
|
||||
- 只有一个账号:立即调用 `set-user` 换正式 token。
|
||||
- 多个账号:展示账号选择弹窗,用户确认后再调用 `set-user`。
|
||||
|
||||
正式账号选择接口:
|
||||
|
||||
```text
|
||||
POST /api/app/v9/set-user
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
单账号:
|
||||
LoginViewModel.resolveLoginResponse(...)
|
||||
-> AuthAPI.setUser(..., tokenOverride: 临时 token)
|
||||
|
||||
多账号:
|
||||
LoginViewController.selectAccount(_:)
|
||||
-> LoginViewModel.selectAccount(_:authAPI:)
|
||||
-> AuthAPI.setUser(..., tokenOverride: 临时 token)
|
||||
```
|
||||
|
||||
### 3.4 登录完成后的存储与跳转
|
||||
|
||||
登录完成调用:
|
||||
|
||||
```text
|
||||
AuthSessionHelper.completeLogin(...)
|
||||
```
|
||||
|
||||
写入 `AppStore` 的内容:
|
||||
|
||||
- `token`
|
||||
- `lastLoginUsername`
|
||||
- `privacyAgreementAccepted`
|
||||
- `userId`
|
||||
- `userName`
|
||||
- `realName`
|
||||
- `avatar`
|
||||
- `phone`
|
||||
- `accountType`
|
||||
- `accountDisplayName`
|
||||
- `roleCode`
|
||||
- `roleName`
|
||||
- `currentScenicId`
|
||||
- `currentScenicName`
|
||||
- `currentStoreId`
|
||||
|
||||
其中账号上下文来自 `AccountSwitchAccount`、`V9ScenicUser` 或 `V9StoreUser`。
|
||||
|
||||
如果用户已同意隐私协议,还会再次触发:
|
||||
|
||||
- `AMapBootstrap.configureIfNeeded()`
|
||||
- `UmengBootstrap.configureIfNeeded()`
|
||||
|
||||
最后发送:
|
||||
|
||||
```text
|
||||
NotificationName.userDidLogin
|
||||
```
|
||||
|
||||
`SceneDelegate.handleUserDidLogin()` 收到通知后调用:
|
||||
|
||||
```text
|
||||
AppRouter.setRoot(.mainTab, on: window)
|
||||
```
|
||||
|
||||
根页面切换到主 Tab。
|
||||
|
||||
## 4. 已登录启动与默认首页首次展示
|
||||
|
||||
已登录时,`AppRouter.makeRootViewController()` 创建 `MainTabBarController`。
|
||||
|
||||
### 4.1 主 Tab 创建
|
||||
|
||||
`MainTabBarController.viewDidLoad` 顺序:
|
||||
|
||||
1. 设置 `delegate`。
|
||||
2. 配置 TabBar 外观。
|
||||
3. 调用 `configureTabs()` 创建五个 Tab slot:
|
||||
- 首页:`HomeViewController`
|
||||
- 订单:`OrdersViewController`
|
||||
- 中间扫码占位页
|
||||
- 数据:`StatisticsViewController`
|
||||
- 我的:`ProfileViewController`
|
||||
4. 绑定订单角标 ViewModel。
|
||||
5. 绑定扫码处理器。
|
||||
6. 调用 `badgeViewModel.refreshPendingWriteOffCount()`。
|
||||
|
||||
注意:`MainTabBadgeViewModel.refreshPendingWriteOffCount()` 当前仅执行:
|
||||
|
||||
```text
|
||||
pendingWriteOffCount = nil
|
||||
```
|
||||
|
||||
代码注释标明“接口未接入前保持为空”,因此这里不记录为真实后端接口调用。
|
||||
|
||||
### 4.2 默认首页首次出现
|
||||
|
||||
默认选中首页。`HomeViewController.viewDidAppear` 首次出现时调用:
|
||||
|
||||
```text
|
||||
initializeHome()
|
||||
```
|
||||
|
||||
调用顺序:
|
||||
|
||||
1. 展示全局 loading。
|
||||
2. `HomeViewModel.initialize(api:)`
|
||||
3. 隐藏 loading。
|
||||
4. 刷新首页 UI。
|
||||
5. 延迟评估弹窗。
|
||||
|
||||
`HomeViewModel.initialize(api:)` 内部顺序:
|
||||
|
||||
1. `locationStateStore.restoreStateIfNeeded()`
|
||||
- 从 `AppStore` 恢复在线状态、上次位置上报时间、提醒分钟数。
|
||||
- 如果上次在线状态已过期,会清除在线状态和上次上报时间。
|
||||
- 不调用后端接口。
|
||||
2. `refreshLocalDisplayState()`
|
||||
- 从 `AppStore` 读取当前景区、当前角色。
|
||||
- 无有效景区时清空 `currentScenicId/currentScenicName`。
|
||||
3. 强制调用 `loadPermissions(api:force: true)`。
|
||||
|
||||
权限接口:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/role-permission
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
HomeViewModel.initialize(api:)
|
||||
-> HomeViewModel.loadPermissions(api:force: true)
|
||||
-> HomeAPI.rolePermissions()
|
||||
```
|
||||
|
||||
权限返回后的存储:
|
||||
|
||||
- 完整角色权限列表:`AppStore.saveRolePermissionList(_:)`
|
||||
- 当前匹配角色的景区列表:`AppStore.saveRoleScenicList(_:)`
|
||||
- 当前匹配角色的扁平权限:`AppStore.savePermissionItems(_:)`
|
||||
- 匹配角色名:必要时写入 `AppStore.roleName`
|
||||
|
||||
这些权限数据都按账号作用域 key 写入 `UserDefaults`,值为 JSON Data。
|
||||
|
||||
随后首页重建常用应用:
|
||||
|
||||
- 从 `AppStore.permissionItems()` 读取权限。
|
||||
- `HomeMenuCatalog.visibleMenus(from:)` 生成可见菜单。
|
||||
- `HomeCommonMenuStore` 读取或写入常用应用 URI。
|
||||
- 常用应用 key 由 `accountScope + roleCode` 组成。
|
||||
|
||||
### 4.3 首页门店接口
|
||||
|
||||
权限加载完成后会调用:
|
||||
|
||||
```text
|
||||
HomeViewModel.loadStoreListIfNeeded(api:)
|
||||
```
|
||||
|
||||
只有同时满足以下条件才会请求门店:
|
||||
|
||||
- 当前角色为 `storeAdmin`
|
||||
- `AppStore.currentScenicId > 0`
|
||||
|
||||
接口:
|
||||
|
||||
```text
|
||||
GET /api/app/store/all
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
HomeViewModel.loadStoreListIfNeeded(api:)
|
||||
-> HomeAPI.storeList()
|
||||
```
|
||||
|
||||
返回后的处理:
|
||||
|
||||
- 根据 `currentScenicId` 和已保存的 `currentStoreId` 匹配当前门店。
|
||||
- 匹配结果保存在 `HomeViewModel.storeItem`。
|
||||
- 若匹配到门店,写入 `AppStore.currentStoreId`。
|
||||
- 门店列表本身不持久化。
|
||||
|
||||
### 4.4 首页弹窗评估与位置详情接口
|
||||
|
||||
首页 UI 刷新后调用:
|
||||
|
||||
```text
|
||||
evaluateDialogsWithDelay()
|
||||
-> HomeViewModel.evaluateDialogs(api:)
|
||||
```
|
||||
|
||||
弹窗优先级:
|
||||
|
||||
1. 权限弹窗。
|
||||
2. 景区弹窗。
|
||||
3. 位置超时弹窗。
|
||||
|
||||
如果不需要权限弹窗、不需要景区弹窗、不是简化顶部角色,并且本地设置了位置提醒分钟数,则可能调用位置详情接口:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/photog/loacation/detail?staff_id=...
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
HomeViewModel.evaluateDialogs(api:)
|
||||
-> HomeViewModel.checkLocationTimeout(api:)
|
||||
-> HomeAPI.locationDetail(staffId:)
|
||||
```
|
||||
|
||||
返回后的处理:
|
||||
|
||||
- 只用于判断是否展示位置超时提醒。
|
||||
- 结果不写入 `AppStore`。
|
||||
- 弹窗状态保存在 `HomeViewModel.showLocationTimeoutDialog` 等内存属性中。
|
||||
|
||||
## 5. 其他 Tab 首次展示时的接口
|
||||
|
||||
其他 Tab 的根控制器会在 `MainTabBarController.configureTabs()` 时创建,但各自的数据接口通常在首次展示时才调用。
|
||||
|
||||
### 5.1 订单 Tab
|
||||
|
||||
`OrdersViewController.viewDidAppear` 首次出现时调用:
|
||||
|
||||
```text
|
||||
initializeList()
|
||||
```
|
||||
|
||||
按当前角色选择接口。
|
||||
|
||||
摄影师:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/photog/order/listv2
|
||||
```
|
||||
|
||||
景区管理员:
|
||||
|
||||
```text
|
||||
GET /api/app/scenic-admin/order/list
|
||||
```
|
||||
|
||||
门店管理员:
|
||||
|
||||
```text
|
||||
GET /api/app/store/order/list
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
OrdersViewController.initializeList()
|
||||
-> OrderListViewModel.refreshOrderList(api:)
|
||||
-> OrderAPI.photographerOrderList(...) 或 OrderAPI.scenicAdminOrderList(...)
|
||||
|
||||
或
|
||||
|
||||
OrdersViewController.initializeList()
|
||||
-> DepositOrderListViewModel.refreshOrderList(api:)
|
||||
-> OrderAPI.storeOrderList(...)
|
||||
```
|
||||
|
||||
数据存储:
|
||||
|
||||
- 摄影师/景区管理员订单列表保存在 `OrderListViewModel.orderList`。
|
||||
- 门店管理员订单列表保存在 `DepositOrderListViewModel.orderList`。
|
||||
- 分页状态、筛选状态、搜索状态都保存在对应 ViewModel 内存属性中。
|
||||
- 首屏订单列表不写入 `AppStore`。
|
||||
|
||||
### 5.2 数据 Tab
|
||||
|
||||
`StatisticsViewController.viewDidAppear` 首次出现时调用:
|
||||
|
||||
```text
|
||||
initializeStatistics()
|
||||
-> StatisticsViewModel.initStatistics(api:)
|
||||
```
|
||||
|
||||
内部顺序:
|
||||
|
||||
1. 加载汇总数据。
|
||||
2. 设置日明细日期范围为今日并刷新列表。
|
||||
|
||||
摄影师汇总:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/photog/analyse/user
|
||||
```
|
||||
|
||||
摄影师日明细:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/photog/analyse/user/daily
|
||||
```
|
||||
|
||||
景区管理员汇总:
|
||||
|
||||
```text
|
||||
GET /api/app/scenic-admin/analyse
|
||||
```
|
||||
|
||||
景区管理员日明细:
|
||||
|
||||
```text
|
||||
GET /api/app/scenic-admin/analyse/daily
|
||||
```
|
||||
|
||||
门店管理员汇总:
|
||||
|
||||
```text
|
||||
GET /api/app/store/analyse
|
||||
```
|
||||
|
||||
门店管理员日明细:
|
||||
|
||||
```text
|
||||
GET /api/app/store/analyse/daily
|
||||
```
|
||||
|
||||
数据存储:
|
||||
|
||||
- 汇总数据保存在 `StatisticsViewModel.statistics`。
|
||||
- 日明细列表保存在 `StatisticsViewModel.statisticsList`。
|
||||
- 当前周期、日期范围、分页状态保存在 `StatisticsViewModel` 内存属性中。
|
||||
- 统计数据不写入 `AppStore`。
|
||||
|
||||
### 5.3 我的 Tab
|
||||
|
||||
`ProfileViewController.viewWillAppear` 每次出现都会调用:
|
||||
|
||||
```text
|
||||
reloadProfile(showGlobalLoading:)
|
||||
-> ProfileViewModel.reload(api:)
|
||||
```
|
||||
|
||||
第一步固定调用用户资料接口:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/userinfo
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
ProfileViewModel.reload(api:)
|
||||
-> ProfileAPI.userInfo()
|
||||
```
|
||||
|
||||
返回后的处理:
|
||||
|
||||
- 保存在 `ProfileViewModel.userInfo`。
|
||||
- 调用 `AppStore.applyUserInfo(_:)` 回写展示字段:
|
||||
- `userName`
|
||||
- `realName`
|
||||
- `avatar`
|
||||
- `phone`
|
||||
- `roleName`,仅在本地为空时由 `applyUserInfo` 写入;随后 `ProfileViewModel.reload` 也会在接口 `roleName` 非空时写入。
|
||||
|
||||
如果当前为摄影师角色,则并发调用:
|
||||
|
||||
```text
|
||||
GET /api/yf-handset-app/photog/real-name/info
|
||||
GET /api/yf-handset-app/photog/wallet/bank-card/info
|
||||
```
|
||||
|
||||
调用链:
|
||||
|
||||
```text
|
||||
async let realName = api.realNameInfo()
|
||||
async let bankCard = api.bankCardInfo()
|
||||
```
|
||||
|
||||
返回后的处理:
|
||||
|
||||
- 实名信息保存在 `ProfileViewModel.realNameInfo`。
|
||||
- 银行卡信息保存在 `ProfileViewModel.bankCardInfo`。
|
||||
- 这两个结果不写入 `AppStore`。
|
||||
|
||||
## 6. 数据存储总览
|
||||
|
||||
### 6.1 AppStore / UserDefaults
|
||||
|
||||
`AppStore` 是本地会话和业务快照的统一入口,底层使用 `UserDefaults`。
|
||||
|
||||
非账号作用域的主要 key:
|
||||
|
||||
- `key_in_token`
|
||||
- `key_last_login_username`
|
||||
- `key_privacy_agreement_accepted`
|
||||
- `key_in_user_id`
|
||||
- `key_in_user_name`
|
||||
- `key_in_real_name`
|
||||
- `key_in_avatar`
|
||||
- `key_in_phone`
|
||||
- `key_in_account_type`
|
||||
- `key_in_account_display_name`
|
||||
- `key_in_role_code`
|
||||
- `key_in_role_name`
|
||||
- `key_in_current_scenic_id`
|
||||
- `key_in_current_scenic_name`
|
||||
- `key_in_current_store_id`
|
||||
|
||||
账号作用域由 `accountCachePrefix` 生成:
|
||||
|
||||
```text
|
||||
userId_accountType
|
||||
```
|
||||
|
||||
如果没有 userId,则使用 `guest`。账号作用域 key 用于存储:
|
||||
|
||||
- 旧版角色 ID:`key_in_role_id`
|
||||
- 完整 role-permission 列表:`key_role_permission_list`
|
||||
- 当前角色扁平权限:`key_in_permission`
|
||||
- 当前角色可选景区列表:`key_current_role_scenic_list`
|
||||
- 在线状态:`key_online_status`
|
||||
- 上次位置上报时间:`key_last_location_report_time`
|
||||
- 位置提醒分钟数:`key_location_reminder_minutes`
|
||||
- 收款到账语音播报开关:`key_is_open_receive_voice`
|
||||
- 排队叫号相关本地设置。
|
||||
|
||||
权限和景区列表以 JSON Data 写入 `UserDefaults`:
|
||||
|
||||
- `saveRolePermissionList(_:)`
|
||||
- `savePermissionItems(_:)`
|
||||
- `saveRoleScenicList(_:)`
|
||||
|
||||
### 6.2 HomeCommonMenuStore
|
||||
|
||||
首页常用应用由 `HomeCommonMenuStore` 单独管理,底层也是 `UserDefaults`。
|
||||
|
||||
存储 key:
|
||||
|
||||
```text
|
||||
{accountScope}_role_{roleCode}_common_uris
|
||||
```
|
||||
|
||||
值为 URI 字符串数组。
|
||||
|
||||
首次有权限但没有常用应用记录时,会从权限列表生成最多 4 个默认常用入口并写入本地。
|
||||
|
||||
### 6.3 HomeLocationStateStore
|
||||
|
||||
`HomeLocationStateStore` 负责首页在线状态和 2 小时位置上报倒计时。
|
||||
|
||||
持久化到 `AppStore` 的字段:
|
||||
|
||||
- `onlineStatus`
|
||||
- `lastLocationReportTime`
|
||||
- `locationReminderMinutes`
|
||||
|
||||
内存态字段:
|
||||
|
||||
- `isOnline`
|
||||
- `elapsedSeconds`
|
||||
- `nextReportCountdownSeconds`
|
||||
- `reminderMinutes`
|
||||
- 倒计时 `Task`
|
||||
|
||||
启动恢复逻辑:
|
||||
|
||||
- 如果本地 `onlineStatus == false`,停止倒计时。
|
||||
- 如果没有 `lastLocationReportTime`,清除在线状态。
|
||||
- 如果距离上次上报已超过 2 小时,清除在线状态和上次上报时间。
|
||||
- 否则恢复倒计时。
|
||||
|
||||
### 6.4 ViewModel 内存态
|
||||
|
||||
多数页面接口结果只保存在 ViewModel 内存属性中,不持久化。
|
||||
|
||||
典型示例:
|
||||
|
||||
- 登录配置:`LoginViewModel.enableRegister`
|
||||
- 首页门店卡片:`HomeViewModel.storeItem`
|
||||
- 首页弹窗状态:`HomeViewModel.showPermissionDialog`、`showScenicDialog`、`showLocationTimeoutDialog`
|
||||
- 订单列表:`OrderListViewModel.orderList`、`DepositOrderListViewModel.orderList`
|
||||
- 数据统计:`StatisticsViewModel.statistics`、`statisticsList`
|
||||
- 我的页面实名/银行卡状态:`ProfileViewModel.realNameInfo`、`bankCardInfo`
|
||||
|
||||
例外是明确调用 `AppStore` 的数据:
|
||||
|
||||
- 登录 token 与账号上下文。
|
||||
- 用户资料展示字段。
|
||||
- 权限、景区、角色相关快照。
|
||||
- 门店当前 ID。
|
||||
- 位置在线状态与倒计时锚点。
|
||||
|
||||
## 7. 启动接口顺序速查
|
||||
|
||||
### 7.1 未登录冷启动
|
||||
|
||||
```text
|
||||
AppDelegate.didFinishLaunching
|
||||
-> 友盟/微信/高德 SDK 条件初始化
|
||||
-> SceneDelegate.willConnect
|
||||
-> AppRouter.makeRootViewController()
|
||||
-> LoginViewController.setupUI
|
||||
-> LoginViewController.viewDidAppear
|
||||
-> GET /api/app/config
|
||||
```
|
||||
|
||||
点击登录后:
|
||||
|
||||
```text
|
||||
POST /api/app/v9/login
|
||||
-> POST /api/app/v9/set-user
|
||||
-> AppStore 写入登录态和账号上下文
|
||||
-> userDidLogin
|
||||
-> AppRouter.setRoot(.mainTab)
|
||||
```
|
||||
|
||||
### 7.2 已登录冷启动默认首页
|
||||
|
||||
```text
|
||||
AppDelegate.didFinishLaunching
|
||||
-> 友盟/微信/高德 SDK 条件初始化
|
||||
-> SceneDelegate.willConnect
|
||||
-> AppRouter.makeRootViewController()
|
||||
-> MainTabBarController.viewDidLoad
|
||||
-> HomeViewController.viewDidAppear
|
||||
-> HomeLocationStateStore.restoreStateIfNeeded()
|
||||
-> GET /api/yf-handset-app/role-permission
|
||||
-> 条件满足时 GET /api/app/store/all
|
||||
-> 条件满足时 GET /api/yf-handset-app/photog/loacation/detail?staff_id=...
|
||||
```
|
||||
|
||||
### 7.3 用户首次切到订单 Tab
|
||||
|
||||
```text
|
||||
OrdersViewController.viewDidAppear
|
||||
-> 摄影师 GET /api/yf-handset-app/photog/order/listv2
|
||||
或 景区管理员 GET /api/app/scenic-admin/order/list
|
||||
或 门店管理员 GET /api/app/store/order/list
|
||||
```
|
||||
|
||||
### 7.4 用户首次切到数据 Tab
|
||||
|
||||
```text
|
||||
StatisticsViewController.viewDidAppear
|
||||
-> 按角色 GET 汇总接口
|
||||
-> 按角色 GET 日明细接口
|
||||
```
|
||||
|
||||
### 7.5 用户切到我的 Tab
|
||||
|
||||
```text
|
||||
ProfileViewController.viewWillAppear
|
||||
-> GET /api/yf-handset-app/userinfo
|
||||
-> 摄影师角色并发:
|
||||
GET /api/yf-handset-app/photog/real-name/info
|
||||
GET /api/yf-handset-app/photog/wallet/bank-card/info
|
||||
```
|
||||
Reference in New Issue
Block a user