172 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:io';
 | ||
| import 'dart:ui';
 | ||
| import 'package:dio/dio.dart';
 | ||
| import 'package:qhd_prevention/customWidget/toast_util.dart';
 | ||
| import 'package:qhd_prevention/tools/tools.dart';
 | ||
| 
 | ||
| /// 全局接口异常
 | ||
| class ApiException implements Exception {
 | ||
|   final String result;
 | ||
|   final String message;
 | ||
|   ApiException(this.result, this.message);
 | ||
| 
 | ||
|   @override
 | ||
|   String toString() => 'ApiException($result): $message';
 | ||
| }
 | ||
| 
 | ||
| /// HTTP 方法枚举
 | ||
| enum Method { get, post, put, delete }
 | ||
| 
 | ||
| /// HTTP 管理器 单例
 | ||
| class HttpManager {
 | ||
|   HttpManager._internal() {
 | ||
|     _dio = Dio(BaseOptions(
 | ||
|       connectTimeout: const Duration(milliseconds: 20000),
 | ||
|       receiveTimeout: const Duration(milliseconds: 20000),
 | ||
|       headers: {
 | ||
|         'Content-Type': Headers.formUrlEncodedContentType,
 | ||
|       },
 | ||
|     ));
 | ||
|     _initInterceptors();
 | ||
|   }
 | ||
| 
 | ||
|   static final HttpManager _instance = HttpManager._internal();
 | ||
|   factory HttpManager() => _instance;
 | ||
|   late final Dio _dio;
 | ||
| 
 | ||
|   // 添加401处理回调
 | ||
|   static VoidCallback? onUnauthorized;
 | ||
| 
 | ||
|   void _initInterceptors() {
 | ||
|     _dio.interceptors
 | ||
|       ..add(LogInterceptor(request: true, responseBody: true, error: true))
 | ||
|       ..add(InterceptorsWrapper(onError: (err, handler) {
 | ||
|         // TODO 暂不处理
 | ||
|         // 捕获401错误
 | ||
|         if (err.response?.statusCode == 401) {
 | ||
|           // 触发全局登出回调
 | ||
|           onUnauthorized?.call();
 | ||
|           // 创建自定义异常
 | ||
|           final apiException = ApiException(
 | ||
|               '提示',
 | ||
|               '您的账号已在其他设备登录,已自动下线'
 | ||
|           );
 | ||
|           // 直接抛出业务异常,跳过后续错误处理
 | ||
|           return handler.reject(
 | ||
|             DioException(
 | ||
|               requestOptions: err.requestOptions,
 | ||
|               error: apiException,
 | ||
|               response: err.response,
 | ||
|               type: DioExceptionType.badResponse,
 | ||
|             ),
 | ||
|           );
 | ||
|         }
 | ||
|         handler.next(err);
 | ||
|       }));
 | ||
|   }
 | ||
| 
 | ||
|   /// 通用请求方法,返回完整后台 JSON
 | ||
|   Future<Map<String, dynamic>> request(
 | ||
|       String baseUrl,
 | ||
|       String path, {
 | ||
|         Method method = Method.post,
 | ||
|         Map<String, dynamic>? data,
 | ||
|         Map<String, dynamic>? params,
 | ||
|         CancelToken? cancelToken,
 | ||
|         bool withToken = false, //  新增可选参数,默认 false
 | ||
|       }) async {
 | ||
|     Response resp;
 | ||
|     final url = baseUrl + path;
 | ||
| 
 | ||
|     // 动态 headers
 | ||
|     final headers = {
 | ||
|       'Content-Type': Headers.formUrlEncodedContentType,
 | ||
|     };
 | ||
|     if (withToken) {
 | ||
|       final token = SessionService.instance.studyToken;
 | ||
|       if (token != null && token.isNotEmpty) {
 | ||
|         headers['Token'] = token;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     final options = Options(
 | ||
|       method: method.name.toUpperCase(),
 | ||
|       contentType: Headers.formUrlEncodedContentType,
 | ||
|       headers: headers,
 | ||
|     );
 | ||
| 
 | ||
|     try {
 | ||
|       switch (method) {
 | ||
|         case Method.get:
 | ||
|           resp = await _dio.get(url,
 | ||
|               queryParameters: {...?params, ...?data},
 | ||
|               cancelToken: cancelToken,
 | ||
|               options: options);
 | ||
|           break;
 | ||
|         case Method.post:
 | ||
|           resp = await _dio.post(url,
 | ||
|               data: data,
 | ||
|               queryParameters: params,
 | ||
|               cancelToken: cancelToken,
 | ||
|               options: options);
 | ||
|           break;
 | ||
|         case Method.put:
 | ||
|           resp = await _dio.put(url,
 | ||
|               data: data,
 | ||
|               queryParameters: params,
 | ||
|               cancelToken: cancelToken,
 | ||
|               options: options);
 | ||
|           break;
 | ||
|         case Method.delete:
 | ||
|           resp = await _dio.delete(url,
 | ||
|               queryParameters: params,
 | ||
|               cancelToken: cancelToken,
 | ||
|               options: options);
 | ||
|           break;
 | ||
|       }
 | ||
|     } on DioException catch (e) {
 | ||
|       if (e.error is ApiException) throw e.error as ApiException;
 | ||
|       throw ApiException('network_error', e.message ?? e.toString());
 | ||
|     }
 | ||
| 
 | ||
|     final json = resp.data is Map<String, dynamic>
 | ||
|         ? resp.data as Map<String, dynamic>
 | ||
|         : <String, dynamic>{};
 | ||
|     return json;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| /// 上传图片扩展
 | ||
| extension HttpManagerUpload on HttpManager {
 | ||
|   Future<Map<String, dynamic>> uploadFaceImage({
 | ||
|     required String baseUrl,
 | ||
|     required String path,
 | ||
|     required Map<String, dynamic> fromData,
 | ||
|     CancelToken? cancelToken,
 | ||
|   }) async {
 | ||
|     final form = FormData.fromMap(fromData);
 | ||
|     try {
 | ||
|       final resp = await _dio.post(
 | ||
|         baseUrl + path,
 | ||
|         data: form,
 | ||
|         cancelToken: cancelToken,
 | ||
|         options: Options(
 | ||
|           method: Method.post.name.toUpperCase(),
 | ||
|           contentType: 'multipart/form-data',
 | ||
|         ),
 | ||
|       );
 | ||
|       final json = resp.data is Map<String, dynamic>
 | ||
|           ? resp.data as Map<String, dynamic>
 | ||
|           : <String, dynamic>{};
 | ||
| 
 | ||
|       return json;
 | ||
|     } on DioException catch (e) {
 | ||
|       // 如果已经是ApiException类型(401转换的)
 | ||
|       if (e.error is ApiException) {
 | ||
|         throw e.error as ApiException;
 | ||
|       }
 | ||
|       return {'network_error': e.message ?? e.toString()};
 | ||
|       throw ApiException('network_error', e.message ?? e.toString());
 | ||
|     }
 | ||
|   }
 | ||
| } |