QinGang_interested/lib/services/upload_file_service.dart

158 lines
5.0 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// upload_file_service.dart
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:image_picker/image_picker.dart';
/// 上传结果 - 简单包装
class UploadResult {
final String? filePath;
final String? id;
UploadResult({this.filePath, this.id});
}
/// 可接受的上传文件项:支持 File、XFile或已有的 filePath表示无需重新上传
class UploadFileItem {
final File? file;
final XFile? xfile;
final String? filePath; // 已有文件的返回路径(老文件)
UploadFileItem({this.file, this.xfile, this.filePath});
}
/// UploadFileService: 可被 Provider/Consumer 或直接持有
class UploadFileService extends ChangeNotifier {
final Dio dio;
final Map<String, String> uploadPathEnum; // 对应 UPLOAD_FILE_PATH_ENUM
final Set<String> uploadTypeEnum; // 对应 UPLOAD_FILE_TYPE_ENUM 的取值集合
bool _loading = false;
bool get loading => _loading;
UploadFileService({
Dio? dioInstance,
required this.uploadPathEnum,
required this.uploadTypeEnum,
}) : dio = dioInstance ?? Dio();
void _setLoading(bool v) {
_loading = v;
notifyListeners();
}
/// options:
/// - files: List<UploadFileItem>
/// - single: bool (default true)
/// - params: Map<String, dynamic> (must contain 'type')
///
/// 返回 UploadResult
/// - single: 返回 filePath 字段
/// - batch(single==false): 返回 id 字段(对应 foreignKey
Future<UploadResult> uploadFile({
required List<UploadFileItem>? files,
bool single = true,
required Map<String, dynamic>? params,
}) async {
if (params == null) {
throw ArgumentError('请传入 options.params');
}
final type = params['type'];
if (type == null) {
throw ArgumentError('请传入 options.params.type');
}
if (!uploadTypeEnum.contains(type)) {
throw ArgumentError('传入的 type 不在 UPLOAD_FILE_TYPE_ENUM 中');
}
final path = uploadPathEnum[type];
if (path == null || path.isEmpty) {
throw ArgumentError('未找到 type $type 对应的 path');
}
if (!single && (params['foreignKey'] == null)) {
throw ArgumentError('single 为 false 时options.params.foreignKey 必需');
}
_setLoading(true);
try {
final fileItems = files ?? [];
// 如果没有文件则直接返回(与原逻辑一致)
if (fileItems.isEmpty) {
return single
? UploadResult(filePath: '')
: UploadResult(id: '');
}
// 检查是否有真正需要上传的文件File 或 XFile
final needUpload = fileItems.where((it) => it.file != null || it.xfile != null).toList();
// 如果没有实际要上传的文件返回老文件files[0].filePath 或 params.foreignKey
if (needUpload.isEmpty) {
_setLoading(false);
return single
? UploadResult(filePath: fileItems[0].filePath ?? '')
: UploadResult(id: params['foreignKey']?.toString() ?? '');
}
// 构建 FormData
final formData = FormData();
// 添加文件字段 - 同名 "files"(与后端约定)
for (final it in needUpload) {
String filePath;
if (it.file != null) {
filePath = it.file!.path;
} else if (it.xfile != null) {
// XFile.path 在 web 上不是本地文件(注意),这里只为移动端/桌面可用
filePath = it.xfile!.path;
} else {
continue;
}
final filename = filePath.split(Platform.pathSeparator).last;
final multipart = await MultipartFile.fromFile(filePath, filename: filename);
formData.files.add(MapEntry('files', multipart));
}
// 添加 params 字段(全部作为字符串)
params.forEach((k, v) {
if (v == null) return;
formData.fields.add(MapEntry(k, v.toString()));
});
// 添加 path 字段
formData.fields.add(MapEntry('path', path));
// 选择 URL单文件/批量
final url = single ? '/basicInfo/imgFiles/save' : '/basicInfo/imgFiles/batchSave';
final response = await dio.post(
url,
data: formData,
options: Options(
contentType: 'multipart/form-data',
// 如果需要加额外 headers 可以在这里传入
),
);
// 解析响应(假定后端返回结构与原 JS 一致res.data.filePath / res.data.foreignKey
final resData = response.data;
if (single) {
final String? returnedPath = (resData is Map && resData['filePath'] != null)
? resData['filePath'].toString()
: null;
return UploadResult(filePath: returnedPath);
} else {
final String? foreignKey = (resData is Map && resData['foreignKey'] != null)
? resData['foreignKey'].toString()
: null;
return UploadResult(id: foreignKey);
}
} catch (e) {
// 将错误上抛,调用方可 catch
rethrow;
} finally {
_setLoading(false);
}
}
}