import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; // 引入 kDebugMode 和 debugPrint import 'package:get/get.dart' hide FormData, MultipartFile; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:problem_check_system/core/extensions/http_response_extension.dart'; import 'package:problem_check_system/core/utils/constants/api_endpoints.dart'; import 'package:problem_check_system/data/models/image_metadata_model.dart'; import 'package:problem_check_system/data/models/image_status.dart'; import 'package:problem_check_system/data/providers/http_provider.dart'; class FileRepository { final HttpProvider _httpProvider = Get.find(); /// @param imageFilePath 要上传的本地图片文件。 /// @param cancelToken 用于取消上传任务的令牌。 /// @param onSendProgress 上传进度回调,提供已发送和总大小。 /// @return 上传成功后服务器返回的图片 URL。 Future uploadImage( String imageFilePath, { required CancelToken cancelToken, ProgressCallback? onSendProgress, }) async { try { // 1. 创建 FormData 对象,用于构建 multipart/form-data 请求体 final formData = FormData.fromMap({ // 'file': 这通常是后端接口定义的文件字段名 'file': await MultipartFile.fromFile( imageFilePath, filename: p.basename(imageFilePath), ), }); // 2. 使用 HttpProvider 的 post 方法发送请求 final response = await _httpProvider.post( ApiEndpoints.postUploadFile, data: formData, cancelToken: cancelToken, // 将取消令牌传递给 post 请求 onSendProgress: onSendProgress, // 将进度回调传递给 post 请求 ); // --- 在这里打印服务器的完整响应结构 (仅在调试模式下) --- if (kDebugMode) { debugPrint('服务器返回的状态码: ${response.statusCode}'); debugPrint('服务器返回的原始数据: ${response.data}'); } // 3. 处理响应,并返回图片 URL if (response.isSuccess) { final Map data = response.data; // 假设服务器返回的图片 URL 字段名为 'url' String imageUrl = data['fileName']; return imageUrl; } else { throw Exception('上传失败,状态码: ${response.statusCode}'); } } on DioException catch (e) { Get.log('图片上传发生未知错误: $e'); throw Exception('图片上传失败: ${e.message}'); } catch (e) { Get.log('图片上传发生未知错误: $e'); throw Exception('图片上传发生未知错误: $e'); } } // 新增的下载方法 Future downloadImage( String imageUrl, { CancelToken? cancelToken, void Function(int received, int total)? onReceiveProgress, }) async { final directory = await getApplicationDocumentsDirectory(); final imagesDir = Directory('${directory.path}/problem_images'); // 确保目录存在 if (!await imagesDir.exists()) { await imagesDir.create(recursive: true); } // 生成唯一的文件名 final String fileName = 'downloaded_${DateTime.now().millisecondsSinceEpoch}_${imageUrl.hashCode}${_getFileExtension(imageUrl)}'; final String imagePath = '${imagesDir.path}/$fileName'; try { // 下载图片 await _httpProvider.download( imageUrl, imagePath, cancelToken: cancelToken, onReceiveProgress: onReceiveProgress, ); // 返回图片元数据 return ImageMetadata( localPath: imagePath, remoteUrl: imageUrl, status: ImageStatus.synced, ); } catch (e) { // 清理可能创建的不完整文件 final file = File(imagePath); if (await file.exists()) { await file.delete(); } rethrow; } } // 批量下载方法 Future> downloadImages( List imageUrls, { CancelToken? cancelToken, void Function(int current, int total)? onProgress, }) async { final List results = []; int downloadedCount = 0; for (final imageUrl in imageUrls) { if (cancelToken?.isCancelled == true) { break; } try { final metadata = await downloadImage( imageUrl, cancelToken: cancelToken, onReceiveProgress: (received, total) { // 单个文件的进度可以在这里处理 }, ); results.add(metadata); // 更新总体进度 downloadedCount++; onProgress?.call(downloadedCount, imageUrls.length); } catch (e) { Get.log('Failed to download image $imageUrl: $e'); // 可以选择继续下载其他图片或抛出异常 } } return results; } // 辅助方法:获取文件扩展名 String _getFileExtension(String url) { try { final uri = Uri.parse(url); final pathSegments = uri.pathSegments; if (pathSegments.isNotEmpty) { final fileName = pathSegments.last; final dotIndex = fileName.lastIndexOf('.'); if (dotIndex != -1 && dotIndex < fileName.length - 1) { return fileName.substring(dotIndex); } } return '.jpg'; } catch (e) { return '.jpg'; } } }