// api.dart import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:aslan/chatvibe_ui/components/at_tts.dart'; import 'package:aslan/chatvibe_core/utilities/at_room_utils.dart'; import 'package:aslan/chatvibe_data/sources/local/user_manager.dart'; import 'package:aslan/chatvibe_features/family/family_route.dart'; import 'package:aslan/chatvibe_features/auth/login_route.dart'; import 'package:aslan/chatvibe_managers/user_profile_manager.dart'; import 'package:aslan/chatvibe_ui/widgets/room/pwd/input_room_pwd_page.dart'; import 'package:provider/provider.dart'; import 'package:aslan/chatvibe_core/routes/at_fluro_navigator.dart'; import 'package:aslan/chatvibe_core/utilities/at_loading_manager.dart'; import 'package:aslan/main.dart'; import 'package:aslan/chatvibe_ui/widgets/room/redpack/room_redenvelope_rec_record_page.dart'; import 'package:aslan/chatvibe_data/sources/remote/net/network_client.dart'; import '../../../models/enum/at_erro_code.dart'; export 'package:dio/dio.dart'; _parseAndDecode(String response) => jsonDecode(response); parseJson(String text) => compute(_parseAndDecode, text); class BaseNetworkClient { final Dio dio; BaseNetworkClient() : dio = Dio() { _configureDio(); init(); } void _configureDio() { dio.transformer = BackgroundTransformer()..jsonDecodeCallback = parseJson; dio.options = BaseOptions( connectTimeout: const Duration(seconds: 12), receiveTimeout: const Duration(seconds: 15), contentType: 'application/json; charset=UTF-8', ); } void init() {} // 通用 GET 请求 Future get( String path, { Map? queryParams, required T Function(dynamic) fromJson, CancelToken? cancelToken, ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress, }) async { return _request( path, method: 'GET', queryParams: queryParams, fromJson: fromJson, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress, ); } // 通用 put 请求 Future put( String path, { dynamic data, Map? queryParams, required T Function(dynamic) fromJson, CancelToken? cancelToken, ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress, }) async { return _request( path, method: 'PUT', data: data, queryParams: queryParams, fromJson: fromJson, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress, ); } // 通用 POST 请求 Future post( String path, { dynamic data, Map? queryParams, required T Function(dynamic) fromJson, CancelToken? cancelToken, ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress, }) async { return _request( path, method: 'POST', data: data, queryParams: queryParams, fromJson: fromJson, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress, ); } // 通用 POST 请求 Future delete( String path, { dynamic data, Map? queryParams, required T Function(dynamic) fromJson, CancelToken? cancelToken, ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress, }) async { return _request( path, method: 'DELETE', data: data, queryParams: queryParams, fromJson: fromJson, cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress, ); } // 核心请求方法 Future _request( String path, { required String method, dynamic data, Map? queryParams, CancelToken? cancelToken, ProgressCallback? onSendProgress, ProgressCallback? onReceiveProgress, required T Function(dynamic) fromJson, }) async { try { final response = await dio.request( path, data: data, queryParameters: queryParams, options: Options(method: method), cancelToken: cancelToken, onSendProgress: onSendProgress, onReceiveProgress: onReceiveProgress, ); // 处理基础响应 final baseResponse = ResponseData.fromJson( response.data as Map, fromJsonT: fromJson, ); // 业务逻辑成功判断 if (baseResponse.success) { if (baseResponse.body != null) { return baseResponse.body!; } else { if (T == bool) return false as T; if (T == int) return 0 as T; if (T == String) return "" as T; ATLoadingManager.veilRoutine(); throw Exception('Response data is null'); } } else { // 业务逻辑错误 ATLoadingManager.veilRoutine(); throw DioException( requestOptions: response.requestOptions, response: response, error: '业务错误: ${baseResponse.errorMsg}', ); } } on DioException catch (e) { // 网络错误处理 throw _handleDioError(e); } catch (e) { ATLoadingManager.veilRoutine(); throw Exception('未知错误: $e'); } } // 错误处理 DioException _handleDioError(DioException e) { ATLoadingManager.veilRoutine(); switch (e.type) { case DioExceptionType.connectionTimeout: return DioException(requestOptions: e.requestOptions, error: '连接超时'); case DioExceptionType.sendTimeout: return DioException(requestOptions: e.requestOptions, error: '发送超时'); case DioExceptionType.receiveTimeout: return DioException(requestOptions: e.requestOptions, error: '接收超时'); case DioExceptionType.badResponse: var errorCode = e.response?.data["errorCode"]; var errorMsg = e.response?.data["errorMsg"]; if (errorCode == ATErroCode.userNotRegistered.code) { //用户还没有注册 ATTts.show("Please register an account first."); BuildContext? context = navigatorKey.currentContext; if (context != null) { ATNavigatorUtils.push( context, LoginRouter.editProfile, replace: false, ); } } else if (errorCode == ATErroCode.authUnauthorized.code) { //token过期 BuildContext? context = navigatorKey.currentContext; if (context != null) { if (!inLoginPage) { AccountStorage().logout(context); inLoginPage = true; } } } else if (errorCode == ATErroCode.passwordNotTrue.code) { //需要输入房间密码 String roomId = e.requestOptions.data["roomId"]; bool needOpenRedenvelope = e.requestOptions.data["needOpenRedenvelope"]; String redPackId = e.requestOptions.data["redPackId"]; SmartDialog.dismiss(tag: "showInputRoomPwd"); SmartDialog.show( tag: "showInputRoomPwd", alignment: Alignment.bottomCenter, animationType: SmartAnimationType.fade, builder: (_) { return InputRoomPwdPage( roomId, needOpenRedenvelope: needOpenRedenvelope, redPackId: redPackId, ); }, ); } else if (errorCode == ATErroCode.redPacketFinished.code) { //红包领完了直接跳到红包详情页面 String packetId = e.requestOptions.data["packetId"]; SmartDialog.dismiss(tag: "showRoomRedenvelopeList"); SmartDialog.show( tag: "showRoomRedenvelopeRec", alignment: Alignment.center, animationType: SmartAnimationType.fade, builder: (_) { return RoomRedenvelopeRecRecordPage(packetId); }, ); } else if (errorCode == ATErroCode.userJoinedFamily.code) { BuildContext? context = navigatorKey.currentContext; Provider.of( context!, listen: false, ).getMyUserInfo(needRefreshFamily: true).then((res) { navigatorKey.currentState?.popUntil( ModalRoute.withName(FamilyRoute.reqRecordFamily), ); }); } else { if (errorMsg.toString().endsWith("balance not made")) { BuildContext? context = navigatorKey.currentContext; if (context != null) { ATRoomUtils.goRechargeOperation(context); } } else { ATTts.show(errorMsg); } } return DioException( requestOptions: e.requestOptions, response: e.response, error: '服务器错误: ${e.response?.data["errorCode"]}', ); case DioExceptionType.cancel: return DioException(requestOptions: e.requestOptions, error: 'Cancel'); default: return DioException( requestOptions: e.requestOptions, error: 'Net fail', ); } } } class NotSuccessException implements Exception { final String message; NotSuccessException(this.message); factory NotSuccessException.fromRespData(ResponseData respData) { return NotSuccessException(respData.errorMsg ?? "操作失败"); } }