import 'package:dio/dio.dart'; import 'package:file_picker/file_picker.dart'; import 'fileUtils.dart'; const _show_debug_info = false; /// 上传状态枚举 enum UploadStatus { uploading, completed, failed, } /// 上传结果 class UploadResult { final UploadStatus status; final String? filePath; final double? progress; final int? errorCode; final String? errorReason; final T? returnData; bool get isCompleted => status == UploadStatus.completed; bool get isUploading => status == UploadStatus.uploading; bool get isFailed => status == UploadStatus.failed; /// ----- error code ----- static const int errorCodeError = -1; static const int errorCodeUserCancel = 1; static const int errorCodeFileIsNotExist = -2; /// ----- constructor ----- UploadResult({ required this.status, this.filePath, this.progress, this.errorCode, this.errorReason, this.returnData, }); factory UploadResult.uploading(double progress) { if (progress < 0) { progress = 0; } else if (progress > 1) { progress = 1; } return UploadResult( status: UploadStatus.uploading, progress: progress, ); } factory UploadResult.failed({ int errorCode = errorCodeError, String? errorReason, }) { return UploadResult( status: UploadStatus.failed, errorCode: errorCode, errorReason: errorReason, ); } factory UploadResult.completed({ required String filePath, T? returnData, }) { return UploadResult( status: UploadStatus.completed, filePath: filePath, progress: 1.0, returnData: returnData, ); } } /// ----------------------------------------------------------- /// HttpUploader /// class HttpUploader { //上传 static Future> upload({ required String receiverUrl, String? filePath, String? fileName, Map? headers, Map? extraData, void Function(UploadResult)? onProgress, }) async { // 选择文件 String selectedFilePath; if (filePath != null) { if (await isFileExists(filePath)) { selectedFilePath = filePath; } else { final result = UploadResult.failed( errorCode: UploadResult.errorCodeFileIsNotExist, errorReason: 'file is not exist', ); if (onProgress != null) { onProgress(result); } return result; } } else { FilePickerResult? result = await FilePicker.platform.pickFiles(); if (result == null) { final result = UploadResult.failed( errorCode: UploadResult.errorCodeUserCancel, errorReason: 'Selection canceled by user', ); if (onProgress != null) { onProgress(result); } return result; } PlatformFile file = result.files.first; selectedFilePath = file.path!; } FormData formData = FormData.fromMap({ 'file': await MultipartFile.fromFile(selectedFilePath, filename: fileName), ...?extraData, }); final dio = Dio(); try { if (_show_debug_info) { print('┌────────────────────────────────────────────────────────────────────────────────────────'); print('│ ⬆️ start upload file: $selectedFilePath'); print('│ toServer: $receiverUrl'); print('└────────────────────────────────────────────────────────────────────────────────────────'); } final response = await dio.post( receiverUrl, data: formData, options: Options( headers: headers, contentType: 'multipart/form-data', ), onSendProgress: (sent, total) { if (_show_debug_info) { print('upload: $sent / $total'); } if (onProgress != null) { final progress = total != 0 ? sent / total : 0.0; onProgress(UploadResult.uploading(progress)); } }, ); if (_show_debug_info) { print('$filePath 上传完成: $response'); } final result = UploadResult.completed( filePath: selectedFilePath, returnData: response.data, ); if (onProgress != null) { onProgress(result); } return result; } catch (e) { print('上传失败: $e'); final result = UploadResult.failed( errorReason: e.toString(), ); if (onProgress != null) { onProgress(result); } return result; } } }