import 'dart:io'; import 'dart:ui'; import 'package:dio/dio.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 ,patch} /// HTTP 管理器 单例 class HttpManager { HttpManager._internal() { _dio = Dio(BaseOptions( connectTimeout: const Duration(milliseconds: 10000), receiveTimeout: const Duration(milliseconds: 10000), headers: { 'Content-Type': Headers.jsonContentType, }, )); _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( onRequest: (RequestOptions options, RequestInterceptorHandler handler) { // 在请求头中添加Token String? token=SessionService.instance.token; options.headers['token'] = '${SessionService.instance.token}'; return handler.next(options); }, 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> request( String baseUrl, String path, { Method method = Method.post, Map? data, Map? params, CancelToken? cancelToken, String headerType=Headers.formUrlEncodedContentType, }) async { Response resp; final url = baseUrl + path; try { switch (method) { case Method.get: final queryParameters = {}; if (params != null && params.isNotEmpty) queryParameters.addAll(params); if (data != null && data.isNotEmpty) queryParameters.addAll(data); resp = await _dio.get( url, queryParameters: queryParameters, cancelToken: cancelToken, options: Options( method: method.name.toUpperCase(), contentType: Headers.formUrlEncodedContentType, ), ); break; case Method.put: resp = await _dio.put( url, data: data, queryParameters: params, cancelToken: cancelToken, options: Options( method: method.name.toUpperCase(), contentType: Headers.jsonContentType, ), ); break; case Method.delete: resp = await _dio.delete( url, queryParameters: params, cancelToken: cancelToken, options: Options( method: method.name.toUpperCase(), contentType: Headers.jsonContentType, ), ); break; case Method.patch: resp = await _dio.patch( url, data: data, queryParameters: params, cancelToken: cancelToken, options:Options( method: method.name.toUpperCase(), contentType:Headers.jsonContentType, ), ); break; case Method.post: resp = await _dio.post( url, data: data, queryParameters: params, cancelToken: cancelToken, options:Options( method: method.name.toUpperCase(), contentType:Headers.jsonContentType, ), ); } } on DioException catch (e) { // 如果已经是ApiException类型(401转换的) if (e.error is ApiException) { throw e.error as ApiException; } // 其他网络错误 throw ApiException('network_error', e.message ?? e.toString()); } // 解析返回 JSON final json = resp.data is Map ? resp.data as Map : {}; final result = json['result'] as String?; final msg = json['msg'] as String? ?? json['message'] as String? ?? ''; if (result != 'success') { // 非 success 都抛异常 throw ApiException(result ?? 'unknown', msg); } return json; } } /// 上传图片扩展 extension HttpManagerUpload on HttpManager { Future> uploadFileImage({ required String baseUrl, required String path, required Map 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 ? resp.data as Map : {}; return json; } on DioException catch (e) { // 如果已经是ApiException类型(401转换的) if (e.error is ApiException) { throw e.error as ApiException; } throw ApiException('network_error', e.message ?? e.toString()); } } }