From a7fb6e5ff3dd9a1ad2385cd5cc6e98eea64e12e1 Mon Sep 17 00:00:00 2001 From: MingNian <1281442923@qq.com> Date: Sun, 21 Jun 2026 23:32:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=90=AF=E5=8A=A8=E9=A1=B5=E9=81=AE?= =?UTF-8?q?=E4=BD=8F=E7=99=BB=E5=BD=95/=E9=A6=96=E9=A1=B5=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E6=80=81=EF=BC=8C=E6=B6=88=E9=99=A4=E6=B7=B1=E8=89=B2?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E9=BB=91=E9=97=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 SplashPage + appReadyProvider/_BootGate:启动闸门将启动页覆盖在最上层, 直到 auth 判定完成且今日健康卡数据就绪,遮住登录页闪现与首页对话流初始态 - auth 初始状态改为 isLoading=true,无 token 时再置 false - values-night/styles.xml 改为亮色白底,消除深色模式下 Flutter 初始化期间的黑色窗口背景 - 带 8 秒安全兜底,避免离线时卡在启动页 --- .../app/src/main/res/values-night/styles.xml | 17 ++--- health_app/lib/app.dart | 64 ++++++++++++++++++- health_app/lib/pages/splash_page.dart | 20 ++++++ health_app/lib/providers/auth_provider.dart | 9 ++- 4 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 health_app/lib/pages/splash_page.dart diff --git a/health_app/android/app/src/main/res/values-night/styles.xml b/health_app/android/app/src/main/res/values-night/styles.xml index 06952be..51b3023 100644 --- a/health_app/android/app/src/main/res/values-night/styles.xml +++ b/health_app/android/app/src/main/res/values-night/styles.xml @@ -1,18 +1,11 @@ - - - - diff --git a/health_app/lib/app.dart b/health_app/lib/app.dart index c15495a..6fb6537 100644 --- a/health_app/lib/app.dart +++ b/health_app/lib/app.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -5,7 +6,9 @@ import 'package:shadcn_ui/shadcn_ui.dart'; import 'core/app_router.dart'; import 'core/app_theme.dart'; import 'core/navigation_provider.dart'; +import 'pages/splash_page.dart'; import 'providers/auth_provider.dart'; +import 'providers/data_providers.dart'; /// 健康管家 App 根组件 class HealthApp extends ConsumerWidget { @@ -25,9 +28,64 @@ class HealthApp extends ConsumerWidget { supportedLocales: const [Locale('zh', 'CN'), Locale('zh')], locale: const Locale('zh'), home: const _RootNavigator(), - // 注入 ShadTheme,让所有页面都能用 shadcn 组件 - builder: (context, child) => - ShadTheme(data: AppTheme.shadTheme, child: child!), + // 注入 ShadTheme + 启动闸门:Splash 盖在最上层,直到首页今日健康卡数据就绪 + builder: (context, child) => ShadTheme( + data: AppTheme.shadTheme, + child: _BootGate(child: child!), + ), + ); + } +} + +/// 启动是否就绪:auth 判定完成,且(已登录的普通用户)今日健康卡数据已到位。 +/// 未登录或医生/管理员无需等待健康卡。 +final appReadyProvider = Provider((ref) { + final auth = ref.watch(authProvider); + if (auth.isLoading) return false; // 还在判登录态 → 继续盖 Splash + if (!auth.isLoggedIn) return true; // 未登录 → 就绪,露出登录页 + final role = auth.user?.role ?? 'User'; + if (role != 'User') return true; // 医生/管理员首页不依赖今日健康卡 + // 普通用户:等今日健康卡片数据(成功或失败都算就绪,避免卡死) + final health = ref.watch(latestHealthProvider); + return health.hasValue || health.hasError; +}); + +/// 启动闸门——就绪前在最上层覆盖 Splash,盖住登录页闪现与首页对话流初始态。 +/// 带 8 秒安全兜底,避免离线时数据永不返回导致卡在启动页。 +class _BootGate extends ConsumerStatefulWidget { + final Widget child; + const _BootGate({required this.child}); + + @override + ConsumerState<_BootGate> createState() => _BootGateState(); +} + +class _BootGateState extends ConsumerState<_BootGate> { + bool _timedOut = false; + Timer? _timer; + + @override + void initState() { + super.initState(); + _timer = Timer(const Duration(seconds: 8), () { + if (mounted) setState(() => _timedOut = true); + }); + } + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final ready = ref.watch(appReadyProvider) || _timedOut; + return Stack( + children: [ + widget.child, + if (!ready) const Positioned.fill(child: SplashPage()), + ], ); } } diff --git a/health_app/lib/pages/splash_page.dart b/health_app/lib/pages/splash_page.dart new file mode 100644 index 0000000..4ebee25 --- /dev/null +++ b/health_app/lib/pages/splash_page.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +/// 启动页——盖在整个 App 最上层,直到「今日健康卡片」数据就绪后才撤掉, +/// 用于遮住启动期间的登录页闪现与首页对话流初始态。始终亮色白底。 +class SplashPage extends StatelessWidget { + const SplashPage({super.key}); + + @override + Widget build(BuildContext context) { + return const ColoredBox( + color: Colors.white, + child: Center( + child: Image( + image: AssetImage('assets/branding/health_splash_master.png'), + fit: BoxFit.contain, + ), + ), + ); + } +} diff --git a/health_app/lib/providers/auth_provider.dart b/health_app/lib/providers/auth_provider.dart index ca2ae17..4c1163e 100644 --- a/health_app/lib/providers/auth_provider.dart +++ b/health_app/lib/providers/auth_provider.dart @@ -35,13 +35,18 @@ class AuthNotifier extends Notifier { @override AuthState build() { _checkAuth(); - return const AuthState(isLoggedIn: false, isLoading: false); + // 初始为"加载中",让启动闸门显示 Splash 盖住登录页/首页初始态 + return const AuthState(isLoggedIn: false, isLoading: true); } Future _checkAuth() async { final db = ref.read(localDbProvider); final refresh = await db.read('refresh_token'); - if (refresh == null) return; // 无token,保持 isLoggedIn: false + if (refresh == null) { + // 无 token:判定完成、未登录 + state = const AuthState(isLoggedIn: false, isLoading: false); + return; + } state = const AuthState(isLoading: true); try {