فهرست منبع

增加无网络状态拦截器。

PC\19500 2 هفته پیش
والد
کامیت
7fa6d69c90

+ 3 - 0
lib/app/router.dart

@@ -6,8 +6,11 @@ import '../features/auth/presentation/login_page.dart';
 import '../features/MediaTestPage/presentation/media_test_page.dart';
 import '../features/MediaTestPage/presentation/media_test_page.dart';
 import '../core/network/pages/no_network_page.dart';
 import '../core/network/pages/no_network_page.dart';
 
 
+final rootNavigatorKey = GlobalKey<NavigatorState>();
+
 class AppRouter {
 class AppRouter {
   static final router = GoRouter(
   static final router = GoRouter(
+    navigatorKey: rootNavigatorKey,
     routes: [
     routes: [
       GoRoute(
       GoRoute(
         path: '/',
         path: '/',

+ 3 - 0
lib/core/network/dio_client.dart

@@ -3,6 +3,7 @@ import 'package:sino_med_cloud/core/constants/api_constants.dart';
 import 'package:sino_med_cloud/core/network/interceptors/auth_interceptor.dart';
 import 'package:sino_med_cloud/core/network/interceptors/auth_interceptor.dart';
 import 'package:sino_med_cloud/core/network/interceptors/error_interceptor.dart';
 import 'package:sino_med_cloud/core/network/interceptors/error_interceptor.dart';
 import 'package:sino_med_cloud/core/network/interceptors/log_interceptor.dart';
 import 'package:sino_med_cloud/core/network/interceptors/log_interceptor.dart';
+import 'package:sino_med_cloud/core/network/interceptors/network_interceptor.dart';
 import 'package:sino_med_cloud/core/utils/logger.dart';
 import 'package:sino_med_cloud/core/utils/logger.dart';
 import 'package:sino_med_cloud/base/common_response.dart';
 import 'package:sino_med_cloud/base/common_response.dart';
 
 
@@ -32,6 +33,7 @@ class DioClient {
       AuthInterceptor(), // 认证拦截器
       AuthInterceptor(), // 认证拦截器
       LogInterceptor(), // 日志拦截器
       LogInterceptor(), // 日志拦截器
       ErrorInterceptor(), // 错误拦截器
       ErrorInterceptor(), // 错误拦截器
+      NetworkInterceptor(), // 网络状态拦截器(在最后检查,确保异常能被 ErrorInterceptor 捕获)
     ]);
     ]);
 
 
     AppLogger.d('DioClient - Dio 实例初始化完成,拦截器数量: ${dio.interceptors.length}');
     AppLogger.d('DioClient - Dio 实例初始化完成,拦截器数量: ${dio.interceptors.length}');
@@ -48,6 +50,7 @@ class DioClient {
       AuthInterceptor(),
       AuthInterceptor(),
       LogInterceptor(),
       LogInterceptor(),
       ErrorInterceptor(),
       ErrorInterceptor(),
+      NetworkInterceptor(),
     ]);
     ]);
   }
   }
 
 

+ 31 - 0
lib/core/network/exceptions/no_network_exception.dart

@@ -0,0 +1,31 @@
+import 'package:sino_med_cloud/app/router.dart';
+import 'package:sino_med_cloud/l10n/app_localizations.dart';
+
+/// 无网络连接异常
+class NoNetworkException implements Exception {
+  final String? _message;
+
+  NoNetworkException([this._message]);
+
+  @override
+  String toString() {
+    if (_message != null) return _message!;
+
+    // 尝试获取本地化消息
+    // 注意:需要确保 rootNavigatorKey 已绑定且 AppLocalizations 已初始化
+    try {
+      final context = rootNavigatorKey.currentContext;
+      if (context != null) {
+        final l10n = AppLocalizations.of(context);
+        if (l10n != null) {
+          return l10n.networkErrorCheckSettings;
+        }
+      }
+    } catch (_) {
+      // 忽略任何获取 Context 或 Localizations 过程中的错误
+    }
+
+    // 默认回退文案
+    return '当前无网络连接,请检查网络设置';
+  }
+}

+ 15 - 5
lib/core/network/interceptors/error_interceptor.dart

@@ -1,5 +1,6 @@
 import 'package:dio/dio.dart';
 import 'package:dio/dio.dart';
 import 'package:sino_med_cloud/core/constants/app_constants.dart';
 import 'package:sino_med_cloud/core/constants/app_constants.dart';
+import '../exceptions/no_network_exception.dart';
 
 
 /// 错误拦截器 - 统一处理错误响应
 /// 错误拦截器 - 统一处理错误响应
 class ErrorInterceptor extends Interceptor {
 class ErrorInterceptor extends Interceptor {
@@ -73,11 +74,20 @@ class ErrorInterceptor extends Interceptor {
         break;
         break;
 
 
       case DioExceptionType.connectionError:
       case DioExceptionType.connectionError:
-        dioException = DioException(
-          requestOptions: err.requestOptions,
-          error: '网络连接失败,请检查网络设置',
-          type: err.type,
-        );
+        // 如果是无网络异常,保留原始异常信息
+        if (err.error is NoNetworkException) {
+          dioException = DioException(
+            requestOptions: err.requestOptions,
+            error: err.error, // 保留 NoNetworkException 对象
+            type: err.type,
+          );
+        } else {
+          dioException = DioException(
+            requestOptions: err.requestOptions,
+            error: '网络连接失败,请检查网络设置',
+            type: err.type,
+          );
+        }
         break;
         break;
 
 
       default:
       default:

+ 42 - 0
lib/core/network/interceptors/network_interceptor.dart

@@ -0,0 +1,42 @@
+import 'package:connectivity_plus/connectivity_plus.dart';
+import 'package:dio/dio.dart';
+import '../exceptions/no_network_exception.dart';
+
+/// 网络状态拦截器
+/// 
+/// 在发送请求前检查网络连接状态,如果没有网络则抛出 [NoNetworkException]
+class NetworkInterceptor extends Interceptor {
+  @override
+  Future<void> onRequest(
+    RequestOptions options,
+    RequestInterceptorHandler handler,
+  ) async {
+    // 检查网络连接
+    final connectivityResult = await Connectivity().checkConnectivity();
+    
+    // 检查是否有可用网络 (WiFi 或 Mobile)
+    // ConnectivityResult 包含 none 表示无网络
+    // 实际上只要列表中包含 mobile 或 wifi 就认为有网
+    final bool hasNetwork = connectivityResult.any(
+      (result) => result == ConnectivityResult.mobile || result == ConnectivityResult.wifi
+    );
+
+    // 如果没有网络(或者是其他未处理的类型且不是 wifi/mobile,严格来说应该根据业务需求。
+    // 这里简单起见,如果没有 wifi 且没有 mobile,就认为无网,或者如果只包含 none)
+    // 更准确的逻辑:如果 connectivityResult 包含 none 且不包含 mobile/wifi (实际上 none 不会和 mobile/wifi 共存)
+    
+    // 简单判断:只要不包含 mobile 和 wifi
+    if (!hasNetwork) {
+      return handler.reject(
+        DioException(
+          requestOptions: options,
+          error: NoNetworkException(),
+          type: DioExceptionType.connectionError,
+        ),
+      );
+    }
+    
+    super.onRequest(options, handler);
+  }
+}
+

+ 6 - 0
lib/l10n/app_localizations.dart

@@ -609,6 +609,12 @@ abstract class AppLocalizations {
   /// In zh, this message translates to:
   /// In zh, this message translates to:
   /// **'加载失败'**
   /// **'加载失败'**
   String get loadFailed;
   String get loadFailed;
+
+  /// 无网络连接错误提示(检查设置)
+  ///
+  /// In zh, this message translates to:
+  /// **'当前无网络连接,请检查网络设置'**
+  String get networkErrorCheckSettings;
 }
 }
 
 
 class _AppLocalizationsDelegate
 class _AppLocalizationsDelegate

+ 3 - 0
lib/l10n/app_localizations_zh.dart

@@ -269,4 +269,7 @@ class AppLocalizationsZh extends AppLocalizations {
 
 
   @override
   @override
   String get loadFailed => '加载失败';
   String get loadFailed => '加载失败';
+
+  @override
+  String get networkErrorCheckSettings => '当前无网络连接,请检查网络设置';
 }
 }

+ 4 - 0
lib/l10n/app_zh.arb

@@ -353,6 +353,10 @@
   "loadFailed": "加载失败",
   "loadFailed": "加载失败",
   "@loadFailed": {
   "@loadFailed": {
     "description": "加载失败提示"
     "description": "加载失败提示"
+  },
+  "networkErrorCheckSettings": "当前无网络连接,请检查网络设置",
+  "@networkErrorCheckSettings": {
+    "description": "无网络连接错误提示(检查设置)"
   }
   }
 }
 }