// // AppServices.swift // suixinkan // // Created by Codex on 2026/6/26. // import Foundation @MainActor /// 全局依赖容器,集中提供 ViewModel 与 ViewController 所需的 API 和上下文。 final class AppServices { static let shared = AppServices() let session: SessionBundle let context: AppContextBundle let network: NetworkBundle let ui: UIFeedbackBundle let runtime: AppRuntimeBundle let appRouter = AppRouter() private let tokenStore: SessionTokenStore private let snapshotStore: AccountSnapshotStore // MARK: - 扁平访问(兼容现有调用方) var appSession: AppSession { session.appSession } var accountContext: AccountContext { context.accountContext } var permissionContext: PermissionContext { context.permissionContext } var scenicSpotContext: ScenicSpotContext { context.scenicSpotContext } var toastCenter: ToastCenter { ui.toastCenter } var globalLoading: GlobalLoadingCenter { ui.globalLoading } var scenicQueueRuntime: ScenicQueueRuntime { runtime.scenicQueueRuntime } var apiClient: APIClient { network.apiClient } var authAPI: AuthAPI { network.authAPI } var profileAPI: ProfileAPI { network.profileAPI } var uploadAPI: UploadAPI { network.uploadAPI } var ossUploadService: OSSUploadService { network.ossUploadService } var accountContextAPI: AccountContextAPI { network.accountContextAPI } var ordersAPI: OrdersAPI { network.ordersAPI } var statisticsAPI: StatisticsAPI { network.statisticsAPI } var paymentAPI: PaymentAPI { network.paymentAPI } var walletAPI: WalletAPI { network.walletAPI } var pushAPI: PushAPI { network.pushAPI } var scenicPermissionAPI: ScenicPermissionAPI { network.scenicPermissionAPI } var scenicSettlementAPI: ScenicSettlementAPI { network.scenicSettlementAPI } var messageCenterAPI: MessageCenterAPI { network.messageCenterAPI } var scenicQueueAPI: ScenicQueueAPI { network.scenicQueueAPI } var liveAPI: LiveAPI { network.liveAPI } var operatingAreaAPI: OperatingAreaAPI { network.operatingAreaAPI } var pilotCertificationAPI: PilotCertificationAPI { network.pilotCertificationAPI } var taskAPI: TaskAPI { network.taskAPI } var projectAPI: ProjectAPI { network.projectAPI } var scheduleAPI: ScheduleAPI { network.scheduleAPI } var inviteAPI: InviteAPI { network.inviteAPI } var assetsAPI: AssetsAPI { network.assetsAPI } var punchPointAPI: PunchPointAPI { network.punchPointAPI } var locationReportAPI: LocationReportAPI { network.locationReportAPI } var authSessionCoordinator: AuthSessionCoordinator { session.authSessionCoordinator } var sessionBootstrapper: SessionBootstrapper { session.sessionBootstrapper } /// 当前景区 ID。 var currentScenicId: Int? { accountContext.currentScenic?.id } /// 当前用户 staffId,用于钱包等接口。 var staffId: Int? { Int(accountContext.profile?.userId ?? "") } /// 当前用户 ID 字符串。 var userId: String? { accountContext.profile?.userId } /// 生产环境默认初始化。 private init() { let tokenStore = SessionTokenStore() let snapshotStore = AccountSnapshotStore() let preferencesStore = AppPreferencesStore() let apiClient = APIClient() self.tokenStore = tokenStore self.snapshotStore = snapshotStore context = AppContextBundle( accountContext: AccountContext(), permissionContext: PermissionContext(), scenicSpotContext: ScenicSpotContext() ) network = NetworkBundle(apiClient: apiClient) ui = UIFeedbackBundle( toastCenter: ToastCenter(), globalLoading: GlobalLoadingCenter() ) runtime = AppRuntimeBundle(scenicQueueRuntime: ScenicQueueRuntime()) session = SessionBundle( appSession: AppSession(), authSessionCoordinator: AuthSessionCoordinator( tokenStore: tokenStore, snapshotStore: snapshotStore, preferencesStore: preferencesStore ), sessionBootstrapper: SessionBootstrapper( tokenStore: tokenStore, snapshotStore: snapshotStore ) ) bindAuthTokenProvider() } /// 测试专用初始化,允许注入 mock `APIClient` 与存储替身。 init( apiClient: APIClient, tokenStore: SessionTokenStore = SessionTokenStore(), snapshotStore: AccountSnapshotStore = AccountSnapshotStore(), preferencesStore: AppPreferencesStore = AppPreferencesStore() ) { self.tokenStore = tokenStore self.snapshotStore = snapshotStore context = AppContextBundle( accountContext: AccountContext(), permissionContext: PermissionContext(), scenicSpotContext: ScenicSpotContext() ) network = NetworkBundle(apiClient: apiClient) ui = UIFeedbackBundle( toastCenter: ToastCenter(), globalLoading: GlobalLoadingCenter() ) runtime = AppRuntimeBundle(scenicQueueRuntime: ScenicQueueRuntime()) session = SessionBundle( appSession: AppSession(), authSessionCoordinator: AuthSessionCoordinator( tokenStore: tokenStore, snapshotStore: snapshotStore, preferencesStore: preferencesStore ), sessionBootstrapper: SessionBootstrapper( tokenStore: tokenStore, snapshotStore: snapshotStore ) ) bindAuthTokenProvider() } /// 绑定推送与 UIKit 导航。 func configurePushNotifications() { PushNotificationManager.shared.configure( api: pushAPI, session: appSession, router: appRouter ) } /// 将 `APIClient` 与当前 `AppSession` token 关联。 private func bindAuthTokenProvider() { apiClient.bindAuthTokenProvider { [unowned self] in appSession.token } } }