一次大的提交
This commit is contained in:
@@ -1,19 +1,179 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:fpdart/fpdart.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../../../../../../core/consts/http_api_consts.dart';
|
||||
import '../../../../../../core/error/failure.dart';
|
||||
import '../../../../../../core/app/app_user_cubit.dart';
|
||||
import '../models/report_model.dart';
|
||||
import 'report_remote_datasource.dart';
|
||||
|
||||
/// 上报远程数据源实现(模拟接口请求)
|
||||
/// 上报远程数据源实现
|
||||
class ReportRemoteDataSourceImpl implements ReportRemoteDataSource {
|
||||
@override
|
||||
Future<Either<Failure, bool>> submitReport(ReportModel report) async {
|
||||
// 模拟网络请求延迟
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
print('========================================');
|
||||
print('[上报工单] 开始提交');
|
||||
print('[上报工单] 请求URL: ${HttpApiConsts.workOrderAdd}');
|
||||
print('[上报工单] 请求方法: POST (multipart/form-data)');
|
||||
try {
|
||||
// 1. 构造 workOrder JSON(直接映射 IOTWorkOrder 实体)
|
||||
print('[上报工单] 入参: siteId=${report.siteId}, siteName=${report.siteName}, reportType=${report.reportType}');
|
||||
print('[上报工单] 入参: deviceId=${report.deviceId}, deviceName=${report.deviceName}');
|
||||
print('[上报工单] 入参: description=${report.description}, problemLevel=${report.problemLevel}');
|
||||
print('[上报工单] 入参: mediaUrls数量=${report.mediaUrls?.length ?? 0}');
|
||||
final workOrder = <String, dynamic>{
|
||||
'siteId': report.siteId,
|
||||
'siteName': report.siteName ?? '',
|
||||
'sourceType': 6, // 6=人工创建
|
||||
'orderType': report.reportType ?? '',
|
||||
'deviceId': report.deviceId ?? '',
|
||||
'deviceName': report.deviceName ?? '',
|
||||
'taskDescription': report.description ?? '',
|
||||
'priorityLevel': report.problemLevel ?? 'INFO',
|
||||
'orderTitle': '${report.reportType ?? '上报'} - ${report.deviceName ?? ''}',
|
||||
'orderStatus': 1, // 1=待处理
|
||||
'imgUrl': <String>[],
|
||||
'videoUrl': <String>[],
|
||||
};
|
||||
final workOrderJson = jsonEncode(workOrder);
|
||||
print('[上报工单] workOrder JSON: $workOrderJson');
|
||||
|
||||
// 模拟成功返回
|
||||
return right(true);
|
||||
// 2. 分离图片和视频
|
||||
final imagePaths = <String>[];
|
||||
final videoPaths = <String>[];
|
||||
final imageExts = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'];
|
||||
final videoExts = ['mp4', 'mov', 'avi', 'mkv', 'wmv', 'flv', '3gp'];
|
||||
|
||||
// 模拟失败情况(取消注释以测试错误处理)
|
||||
// return left(ServerFailure('提交失败,请重试'));
|
||||
if (report.mediaUrls != null) {
|
||||
for (final path in report.mediaUrls!) {
|
||||
final ext = path.split('.').last.toLowerCase();
|
||||
if (videoExts.contains(ext)) {
|
||||
videoPaths.add(path);
|
||||
print('[上报工单] 识别为视频: $path');
|
||||
} else {
|
||||
imagePaths.add(path);
|
||||
print('[上报工单] 识别为图片: $path');
|
||||
}
|
||||
}
|
||||
}
|
||||
print('[上报工单] 图片: ${imagePaths.length}个, 视频: ${videoPaths.length}个');
|
||||
|
||||
// 3. 创建 multipart 请求
|
||||
final request = http.MultipartRequest(
|
||||
'POST',
|
||||
Uri.parse(HttpApiConsts.workOrderAdd),
|
||||
);
|
||||
|
||||
// 4. 添加 Authorization 认证头
|
||||
final userToken = GetIt.I<AppUserCubit>().state.user?.token;
|
||||
if (userToken != null) {
|
||||
request.headers['Authorization'] = 'Bearer $userToken';
|
||||
print('[上报工单] Authorization token: ${userToken.substring(0, userToken.length > 20 ? 20 : userToken.length)}...');
|
||||
} else {
|
||||
print('[上报工单] WARNING: Token为空');
|
||||
}
|
||||
|
||||
// 5. 处理图片文件(后端要求 file 字段必须存在)
|
||||
if (imagePaths.isNotEmpty) {
|
||||
final firstImage = imagePaths.first;
|
||||
final file = File(firstImage);
|
||||
if (await file.exists()) {
|
||||
final bytes = await file.readAsBytes();
|
||||
print('[上报工单] 上传图片: $firstImage, 大小: ${bytes.length} bytes');
|
||||
request.files.add(http.MultipartFile.fromBytes(
|
||||
'file',
|
||||
bytes,
|
||||
filename: firstImage.split('/').last,
|
||||
contentType: http.MediaType('image', 'jpeg'),
|
||||
));
|
||||
} else {
|
||||
print('[上报工单] WARNING: 图片文件不存在: $firstImage');
|
||||
}
|
||||
} else {
|
||||
print('[上报工单] 无图片,使用空文件占位');
|
||||
request.files.add(http.MultipartFile.fromBytes(
|
||||
'file',
|
||||
<int>[],
|
||||
filename: 'empty.jpg',
|
||||
contentType: http.MediaType('image', 'jpeg'),
|
||||
));
|
||||
}
|
||||
|
||||
// 6. 处理视频文件(后端要求 video 字段必须存在)
|
||||
if (videoPaths.isNotEmpty) {
|
||||
final firstVideo = videoPaths.first;
|
||||
final file = File(firstVideo);
|
||||
if (await file.exists()) {
|
||||
final bytes = await file.readAsBytes();
|
||||
print('[上报工单] 上传视频: $firstVideo, 大小: ${bytes.length} bytes');
|
||||
request.files.add(http.MultipartFile.fromBytes(
|
||||
'video',
|
||||
bytes,
|
||||
filename: firstVideo.split('/').last,
|
||||
contentType: http.MediaType('video', 'mp4'),
|
||||
));
|
||||
} else {
|
||||
print('[上报工单] WARNING: 视频文件不存在: $firstVideo');
|
||||
}
|
||||
} else {
|
||||
print('[上报工单] 无视频,使用空文件占位');
|
||||
request.files.add(http.MultipartFile.fromBytes(
|
||||
'video',
|
||||
<int>[],
|
||||
filename: 'empty.mp4',
|
||||
contentType: http.MediaType('video', 'mp4'),
|
||||
));
|
||||
}
|
||||
|
||||
// 7. 添加 workOrder JSON(对应前端 new Blob,filename 为空字符串)
|
||||
print('[上报工单] workOrder JSON长度: ${workOrderJson.length} chars');
|
||||
request.files.add(http.MultipartFile.fromBytes(
|
||||
'workOrder',
|
||||
utf8.encode(workOrderJson),
|
||||
filename: '',
|
||||
contentType: http.MediaType('application', 'json'),
|
||||
));
|
||||
|
||||
print('[上报工单] 请求字段: ${request.fields.keys.toList()}');
|
||||
print('[上报工单] 文件字段: ${request.files.map((f) => f.field).toList()}');
|
||||
print('[上报工单] 开始发送请求...');
|
||||
|
||||
// 8. 发送请求
|
||||
final http.StreamedResponse response = await request.send();
|
||||
final String responseBody = await response.stream.bytesToString();
|
||||
|
||||
print('[上报工单] 响应状态码: ${response.statusCode}');
|
||||
print('[上报工单] 响应头: ${response.headers}');
|
||||
print('[上报工单] 响应体: $responseBody');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final respJson = jsonDecode(responseBody) as Map<String, dynamic>;
|
||||
final code = respJson['code'];
|
||||
print('[上报工单] 业务code: $code');
|
||||
if (code != null && code.toString() == '200') {
|
||||
print('[上报工单] 提交成功');
|
||||
print('========================================');
|
||||
return right(true);
|
||||
} else {
|
||||
final msg = respJson['msg'] ?? respJson['message'] ?? '提交失败';
|
||||
print('[上报工单] 业务失败: $msg');
|
||||
print('========================================');
|
||||
return left(Failure(msg.toString()));
|
||||
}
|
||||
} else {
|
||||
print('[上报工单] HTTP错误: ${response.statusCode}');
|
||||
print('========================================');
|
||||
return left(Failure('服务器错误: HTTP ${response.statusCode}, 响应: $responseBody'));
|
||||
}
|
||||
} catch (e) {
|
||||
print('[上报工单] 异常: $e');
|
||||
print('[上报工单] 异常类型: ${e.runtimeType}');
|
||||
print('========================================');
|
||||
return left(Failure('提交失败: $e'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user