Bladeren bron

手机密码登录存储登录信息。

PC\19500 3 weken geleden
bovenliggende
commit
acbe2994be

+ 10 - 13
lib/core/network/dio_client.dart

@@ -1,8 +1,8 @@
-import 'package:dio/dio.dart';
-import 'package:pretty_dio_logger/pretty_dio_logger.dart';
+import 'package:dio/dio.dart' hide LogInterceptor;
 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/error_interceptor.dart';
+import 'package:sino_med_cloud/core/network/interceptors/log_interceptor.dart';
 
 /// Dio 客户端 - 统一网络请求管理
 class DioClient {
@@ -20,21 +20,18 @@ class DioClient {
 
   static Dio get dio {
     // 确保拦截器只添加一次
+    // 拦截器执行顺序:按添加顺序执行
+    // 1. AuthInterceptor - 在请求前添加 Token
+    // 2. LogInterceptor - 记录请求和响应日志
+    // 3. ErrorInterceptor - 统一处理错误
     if (_dio.interceptors.isEmpty) {
       _dio.interceptors.addAll([
-        AuthInterceptor(), // 认证拦截器(添加 Token)
+        AuthInterceptor(), // 认证拦截器(自动添加 Token)
+        LogInterceptor(), // 日志拦截器(使用 AppLogger 记录日志)
         ErrorInterceptor(), // 错误拦截器(统一错误处理)
-        PrettyDioLogger( // 日志拦截器(美化输出)
-          requestHeader: true,
-          requestBody: true,
-          responseBody: true,
-          responseHeader: false,
-          error: true,
-          compact: true,
-        ),
-        // 如果需要自定义日志,可以使用 LogInterceptor 替代 PrettyDioLogger
-        // LogInterceptor(),
       ]);
+      // 调试:确认拦截器已添加
+      assert(_dio.interceptors.length == 3, '拦截器应该添加3个');
     }
     return _dio;
   }

+ 12 - 3
lib/core/network/interceptors/log_interceptor.dart

@@ -21,14 +21,21 @@ class LogInterceptor extends Interceptor {
   @override
   void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
     AppLogger.d('┌─────────────────────────────────────────────────────────────');
-    AppLogger.d('│ Request: ${options.method} ${options.uri}');
+    AppLogger.d('│ 📤 HTTP Request');
+    AppLogger.d('│ Method: ${options.method}');
+    AppLogger.d('│ URL: ${options.uri}');
     
     if (requestHeader && options.headers.isNotEmpty) {
       AppLogger.d('│ Headers:');
       options.headers.forEach((key, value) {
         // 隐藏敏感信息
         if (key.toLowerCase() == 'authorization') {
-          AppLogger.d('│   $key: ${value.toString().substring(0, 20)}...');
+          final authValue = value.toString();
+          if (authValue.length > 20) {
+            AppLogger.d('│   $key: ${authValue.substring(0, 20)}...');
+          } else {
+            AppLogger.d('│   $key: $authValue');
+          }
         } else {
           AppLogger.d('│   $key: $value');
         }
@@ -47,7 +54,9 @@ class LogInterceptor extends Interceptor {
   @override
   void onResponse(Response response, ResponseInterceptorHandler handler) {
     AppLogger.d('┌─────────────────────────────────────────────────────────────');
-    AppLogger.d('│ Response: ${response.statusCode} ${response.requestOptions.uri}');
+    AppLogger.d('│ 📥 HTTP Response');
+    AppLogger.d('│ Status Code: ${response.statusCode}');
+    AppLogger.d('│ URL: ${response.requestOptions.uri}');
     
     if (responseHeader && response.headers.map.isNotEmpty) {
       AppLogger.d('│ Headers:');

+ 56 - 4
lib/core/storage/local_storage.dart

@@ -1,3 +1,4 @@
+import 'dart:convert';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'package:sino_med_cloud/core/constants/app_constants.dart';
 
@@ -78,6 +79,57 @@ class LocalStorage {
     return prefs.getStringList(key);
   }
 
+  // ==================== Map 操作 ====================
+
+  /// 保存键值对(Map)
+  /// 
+  /// [key] 存储的键
+  /// [value] 要保存的 Map 对象
+  /// 
+  /// 返回保存是否成功
+  /// 
+  /// 示例:
+  /// ```dart
+  /// await LocalStorage.setMap('user', {'name': 'John', 'age': 30});
+  /// ```
+  static Future<bool> setMap(String key, Map<String, dynamic> value) async {
+    try {
+      // 将 Map 转换为 JSON 字符串保存
+      final jsonString = jsonEncode(value);
+      return await prefs.setString(key, jsonString);
+    } catch (e) {
+      // 如果转换失败,返回 false
+      return false;
+    }
+  }
+
+  /// 获取键值对(Map)
+  /// 
+  /// [key] 存储的键
+  /// [defaultValue] 默认值(可选)
+  /// 
+  /// 返回 Map 对象,如果不存在或解析失败则返回 null 或默认值
+  /// 
+  /// 示例:
+  /// ```dart
+  /// final user = LocalStorage.getMap('user');
+  /// // 返回:{'name': 'John', 'age': 30}
+  /// ```
+  static Map<String, dynamic>? getMap(String key, {Map<String, dynamic>? defaultValue}) {
+    try {
+      final jsonString = prefs.getString(key);
+      if (jsonString == null) {
+        return defaultValue;
+      }
+      // 将 JSON 字符串解析为 Map
+      final decoded = jsonDecode(jsonString) as Map<String, dynamic>;
+      return decoded;
+    } catch (e) {
+      // 如果解析失败,返回默认值或 null
+      return defaultValue;
+    }
+  }
+
   // ==================== 通用操作 ====================
 
   /// 删除指定 key
@@ -118,13 +170,13 @@ class LocalStorage {
   }
 
   /// 保存用户信息(JSON 字符串)
-  static Future<bool> saveUserInfo(String userInfo) async {
-    return await setString(AppConstants.keyUserInfo, userInfo);
+  static Future<bool> saveUserInfo(Map<String, dynamic> userInfo) async {
+    return await setMap(AppConstants.keyUserInfo, userInfo);
   }
 
   /// 获取用户信息
-  static String? getUserInfo() {
-    return getString(AppConstants.keyUserInfo);
+  static Map<String, dynamic>? getUserInfo() {
+    return getMap(AppConstants.keyUserInfo);
   }
 
   /// 删除用户信息

+ 1 - 0
lib/core/utils/logger.dart

@@ -24,6 +24,7 @@ class AppLogger {
 
   static logger_package.Logger get _instance {
     _logger ??= logger_package.Logger(
+      level: logger_package.Level.debug, // 设置日志级别为 debug,确保所有日志都能输出
       printer: logger_package.PrettyPrinter(
         methodCount: 2,
         errorMethodCount: 8,

+ 32 - 21
lib/features/auth/presentation/login_page.dart

@@ -1,15 +1,16 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:go_router/go_router.dart';
+import 'package:path/path.dart' as path;
 import 'package:sino_med_cloud/l10n/app_localizations.dart';
 import 'package:sino_med_cloud/core/constants/app_constants.dart';
 import '../../../core/constants/api_constants.dart';
 import '../../../core/network/dio_client.dart';
+import '../../../core/storage/local_storage.dart';
 import '../../../core/utils/logger.dart';
 import '../../../core/utils/crypto_utils.dart';
 import 'login_provider.dart';
 import 'package:dio/dio.dart';
-import 'package:path/path.dart' as path;
 
 class LoginPage extends ConsumerStatefulWidget {
   const LoginPage({super.key});
@@ -107,38 +108,48 @@ class _LoginPageState extends ConsumerState<LoginPage>
 
   // 密码登录
   void _handlePasswordLogin() async {
-    // 当前手机号及密码的格式已经验证过
-    if (_passwordFormKey.currentState!.validate()) {
-      final phoneNumber = ref.watch(passwordLoginPhoneProvider);
-      final password = ref.watch(passwordLoginPasswordProvider);
-
-      // 对密码进行 MD5 加密
-      final encryptedPassword = CryptoUtils.md5(password);
+    try {
+      // 当前手机号及密码的格式已经验证过
+      if (_passwordFormKey.currentState!.validate()) {
+        final phoneNumber = ref.watch(passwordLoginPhoneProvider);
+        final password = ref.watch(passwordLoginPasswordProvider);
 
-      final parame =  {
-        "mobile": phoneNumber,
-        "login_system": _loginSystem,
-        // "password": '6730d7b53ea42d2b0b88ae6ba590812b',
-        "password": encryptedPassword,
-        "login_type": _loginType
-      };
-      AppLogger.d('登录请求参数parame: $parame');
+        // 对密码进行 MD5 加密
+        final encryptedPassword = CryptoUtils.md5(password);
 
-      Response response = await DioClient.post<Map<String, dynamic>>(
-        path.join(ApiConstants.baseUrl, ApiConstants.login),
-        data: parame,
-      );
-      if (response.statusCode == 200) {
+        final parame = {
+          "mobile": phoneNumber,
+          "login_system": _loginSystem,
+          "password": encryptedPassword,
+          "login_type": _loginType
+        };
+        AppLogger.d('登录请求参数parame: $parame');
+        Response response = await DioClient.post<Map<String, dynamic>>(
+          path.join(ApiConstants.baseUrl, ApiConstants.login),
+          data: parame,
+        );
+        if (response.statusCode == 200) {
           final data = response.data;
           if (data['code'] == 20000) {
             AppLogger.d('登录成功: $data');
+            final jsonData = data['data'];
+            final accessToken = jsonData['access_token'];
+            final userInfo = jsonData['user_info'];
+            LocalStorage.saveToken(accessToken);
+            LocalStorage.saveUserInfo(userInfo);
             if (mounted) {
               context.replace('/mainTab');
             }
           } else {
             AppLogger.d('登录失败: $data');
           }
+        } else {
+          AppLogger.d('密码登录请求错误: ${response.statusCode}, ${response.statusMessage}');
+        }
       }
+    } catch (e) {
+      AppLogger.e('密码登录错误:handlePasswordLogin', e);
+      rethrow;
     }
   }