fix(mobile-app): 修复账号切换后自动退出登录的问题

根因:ref.invalidate(authProvider) 销毁旧 AuthNotifier 后,新实例的构造函数
仅设置 AuthState(status: AuthStatus.initial),从不自动调用 checkAuthStatus()
从 SecureStorage 重新加载认证数据。导致 auth 状态停留在 initial(未认证),
依赖 auth 状态的组件误判为"未登录",触发页面跳转到登录页。

修复:
- account_switch_page: invalidate 后立即调用 loadAuthState() 从 storage
  读取新账号数据,确保 auth 状态为 authenticated 后再导航
- account_switch_page: 切换后重置 ApiClient 的 tokenExpired 标记,防止
  旧会话的 401 状态阻塞新账号的请求
- app.dart: _handleTokenExpired() 增加醒目日志和调用栈打印,便于排查
  切换期间是否有 token 过期事件被误触发

切换流程更新为 6 步:
[1/6] switchToAccount() - 保存旧账号、清空、恢复新账号 storage
[2/6] onBeforeRestore - 停止所有定时器
[3/6] invalidate Provider - 销毁旧 Provider 实例
[4/6] loadAuthState() - 从 storage 加载新账号 auth 状态 ← 新增关键步骤
[5/6] 恢复遥测上传
[6/6] 导航到 ranking 页面

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-02-26 11:39:31 -08:00
parent 83ba9b7d54
commit 12004d1c2e
2 changed files with 23 additions and 8 deletions

View File

@ -52,7 +52,10 @@ class _AppState extends ConsumerState<App> {
/// token
Future<void> _handleTokenExpired(String? message) async {
debugPrint('[App] Token expired, navigating to login page');
debugPrint('[App] !!!! Token expired 事件触发,即将跳转登录页面 !!!!');
debugPrint('[App] Token expired message: $message');
// 便 token
debugPrint('[App] Token expired stack: ${StackTrace.current}');
//
final multiAccountService = ref.read(multiAccountServiceProvider);

View File

@ -76,14 +76,14 @@ class _AccountSwitchPageState extends ConsumerState<AccountSwitchPage> {
// switchToAccount() saveCurrentAccountData()
// onBeforeRestore: storage API
// Provider invalidate switchToAccount storage
debugPrint('$_tag [1/5] 调用 switchToAccount()...');
debugPrint('$_tag [1/6] 调用 switchToAccount()...');
final success = await multiAccountService.switchToAccount(
account.userSerialNum,
onBeforeRestore: () async {
// ===== =====
// storage clear restore
// userSerialNum + token
debugPrint('$_tag [2/5] onBeforeRestore - 停止全部定时器...');
debugPrint('$_tag [2/6] onBeforeRestore - 停止全部定时器...');
ref.read(walletStatusProvider.notifier).stopPolling();
debugPrint('$_tag ✓ walletStatusProvider 轮询已停止');
ref.read(pendingActionPollingServiceProvider).stop();
@ -97,7 +97,7 @@ class _AccountSwitchPageState extends ConsumerState<AccountSwitchPage> {
await TelemetryService().pauseForLogout();
debugPrint('$_tag ✓ TelemetryService 已暂停');
}
debugPrint('$_tag [2/5] onBeforeRestore - 定时器全部停止');
debugPrint('$_tag [2/6] onBeforeRestore - 定时器全部停止');
},
);
@ -105,7 +105,7 @@ class _AccountSwitchPageState extends ConsumerState<AccountSwitchPage> {
// ===== invalidate Provider storage =====
// switchToAccount storage
// Provider
debugPrint('$_tag [3/5] switchToAccount 成功invalidate Provider...');
debugPrint('$_tag [3/6] switchToAccount 成功invalidate Provider...');
ref.invalidate(authProvider);
debugPrint('$_tag ✓ authProvider invalidated');
ref.invalidate(walletStatusProvider);
@ -113,15 +113,27 @@ class _AccountSwitchPageState extends ConsumerState<AccountSwitchPage> {
ref.invalidate(notificationBadgeProvider);
debugPrint('$_tag ✓ notificationBadgeProvider invalidated将重建并自动重启定时器');
// ===== auth SecureStorage =====
// invalidate AuthNotifier AuthStatus.initial
// loadAuthState() storage auth initial
// auth
debugPrint('$_tag [4/6] 重新加载 auth 状态(从 storage 读取新账号数据)...');
await ref.read(authProvider.notifier).loadAuthState();
final newAuthState = ref.read(authProvider);
debugPrint('$_tag ✓ auth 状态已加载: status=${newAuthState.status}, userSerialNum=${newAuthState.userSerialNum}');
// ApiClient token
ref.read(apiClientProvider).resetTokenExpiredFlag();
debugPrint('$_tag ✓ ApiClient tokenExpired 标记已重置');
// ===== =====
debugPrint('$_tag [4/5] 恢复遥测上传...');
debugPrint('$_tag [5/6] 恢复遥测上传...');
if (TelemetryService().isInitialized) {
TelemetryService().resumeAfterLogin();
debugPrint('$_tag ✓ TelemetryService 已恢复');
}
//
debugPrint('$_tag [5/5] 导航到 ranking 页面');
debugPrint('$_tag [6/6] 导航到 ranking 页面');
debugPrint('$_tag ========== 切换账号完成 ==========');
context.go(RoutePaths.ranking);
} else if (mounted) {
@ -159,7 +171,7 @@ class _AccountSwitchPageState extends ConsumerState<AccountSwitchPage> {
await multiAccountService.saveCurrentAccountData();
// ===== 1. =====
debugPrint('$_tag [2/5] 停止定时器...');
debugPrint('$_tag [2/6] 停止定时器...');
ref.read(walletStatusProvider.notifier).stopPolling();
debugPrint('$_tag ✓ walletStatusProvider 轮询已停止');
ref.read(pendingActionPollingServiceProvider).stop();