feat: 增加门店身份注销流程

This commit is contained in:
2026-08-31 09:43:14 +08:00
parent 396597a160
commit e529bb5942
35 changed files with 6062 additions and 45 deletions
+78 -13
View File
@@ -9,6 +9,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private var sessionExpiredDialog: SessionExpiredDialogViewController?
private var deregistrationCoordinator: StoreAccountDeregistrationRootCoordinator?
private var needsForegroundDeregistrationCheck = false
func scene(
_ scene: UIScene,
@@ -20,26 +22,39 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
AppNavigationBarAppearance.applyGlobalAppearance()
let window = UIWindow(windowScene: windowScene)
window.rootViewController = AppRouter.makeRootViewController()
window.makeKeyAndVisible()
window.rootViewController = UIViewController()
self.window = window
(UIApplication.shared.delegate as? AppDelegate)?.window = window
let appSession = AppStore.shared.session
deregistrationCoordinator = StoreAccountDeregistrationRootCoordinator(
window: window, session: appSession,
makeAPI: { identity in
StoreAccountDeregistrationAPI(client: NetworkServices.shared.apiClient, identity: identity) {
identity.matches(session: appSession)
}
},
makeSubmissionStore: { StoreAccountDeregistrationSubmissionStore(storeUserID: $0) },
makeBusinessRoot: { MainTabBarController() },
setBindingSuspended: { PushNotificationManager.shared.setAccountBindingSuspended($0) },
onBusinessResumed: {
PushNotificationManager.shared.handleLoginCompleted()
PushNotificationManager.shared.routePendingNotificationIfPossible()
}
)
PushNotificationManager.shared.attach(window: window)
registerNotifications()
if AppStore.shared.session.isLoggedIn {
DispatchQueue.main.async {
PushNotificationManager.shared.handleLoginCompleted()
}
}
refreshRootForCurrentSession()
window.makeKeyAndVisible()
if let response = connectionOptions.notificationResponse {
PushNotificationManager.shared.handleNotificationResponse(response)
}
}
func sceneDidDisconnect(_ scene: UIScene) {
deregistrationCoordinator?.cancelPendingCheck()
deregistrationCoordinator = nil
NotificationCenter.default.removeObserver(self)
if (UIApplication.shared.delegate as? AppDelegate)?.window === window {
(UIApplication.shared.delegate as? AppDelegate)?.window = nil
@@ -56,10 +71,26 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
func sceneDidBecomeActive(_ scene: UIScene) {
guard accessController == nil, deregistrationCoordinator?.isChecking != true else { return }
PushNotificationManager.shared.retryPendingRegistrationUpload()
}
func sceneDidEnterBackground(_ scene: UIScene) {
needsForegroundDeregistrationCheck = true
}
func sceneWillEnterForeground(_ scene: UIScene) {
guard needsForegroundDeregistrationCheck else { return }
needsForegroundDeregistrationCheck = false
guard sessionExpiredDialog == nil else { return }
deregistrationCoordinator?.resumeFromBackground()
}
private func registerNotifications() {
NotificationCenter.default.addObserver(
self, selector: #selector(handleStoreDeregistrationRestriction(_:)),
name: NotificationName.storeAccountDeregistrationRestricted, object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(handleSessionDidExpire),
@@ -90,6 +121,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
guard AppStore.shared.session.isLoggedIn else { return }
guard sessionExpiredDialog == nil else { return }
deregistrationCoordinator?.cancelPendingCheck()
GlobalLoadingManager.shared.hideAll()
let dialog = SessionExpiredDialogViewController { [weak self] in
self?.transitionToLogin()
@@ -104,8 +136,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
private func transitionToLogin() {
deregistrationCoordinator?.cancelPendingCheck()
sessionExpiredDialog = nil
PushNotificationManager.shared.handleLogout()
PushNotificationManager.shared.setAccountBindingSuspended(false)
AppStore.shared.logout()
AppRouter.setRoot(.login, on: window)
}
@@ -117,15 +151,46 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
@objc private func handleUserDidLogin() {
sessionExpiredDialog?.dismiss(animated: false)
sessionExpiredDialog = nil
AppRouter.setRoot(.mainTab, on: window)
DispatchQueue.main.async {
PushNotificationManager.shared.handleLoginCompleted()
PushNotificationManager.shared.routePendingNotificationIfPossible()
if AppStore.shared.session.isLoggedIn, AppStore.shared.session.accountType == .storeUser {
deregistrationCoordinator?.check()
} else {
refreshRootForCurrentSession()
}
}
@objc private func handleAccountDidSwitch() {
PushNotificationManager.shared.handleAccountSwitched()
if AppStore.shared.session.accountType == .storeUser {
refreshRootForCurrentSession()
} else {
deregistrationCoordinator?.cancelPendingCheck()
PushNotificationManager.shared.setAccountBindingSuspended(false)
PushNotificationManager.shared.handleAccountSwitched()
}
}
/// 仅检查真实根控制器,避免被旧的异步查询或页面导航状态误判。
private var accessController: StoreAccountDeregistrationAccessViewController? {
deregistrationCoordinator?.accessController
}
/// 冷启动和切换身份使用已有会话,不主动查询注销状态;新登录由独立入口核验。
private func refreshRootForCurrentSession() {
let session = AppStore.shared.session
guard session.isLoggedIn else {
deregistrationCoordinator?.cancelPendingCheck()
PushNotificationManager.shared.setAccountBindingSuspended(false)
AppRouter.setRoot(.login, on: window, animated: false)
return
}
deregistrationCoordinator?.restoreSession()
}
/// 150015 只限制原请求对应的当前门店身份;旧 Token 响应不会影响新身份。
@objc private func handleStoreDeregistrationRestriction(_ notification: Notification) {
let token = notification.userInfo?[NotificationUserInfoKey.deregistrationRequestToken] as? String
let session = AppStore.shared.session
guard StoreAccountDeregistrationAccessViewModel.restrictionApplies(requestToken: token, session: session) else { return }
deregistrationCoordinator?.recordRestriction(requestToken: token)
}
private func topViewController(from viewController: UIViewController?) -> UIViewController? {