集成接口 开始执行任务的领域层和数据层和UI层的开发啊(待测试)

集成功能 暂停 取消功能 恢复功能的接口的领域层和数据层的开发 下一步待集成到页面上
优化功能,优化了接口异常和未知异常对页面渲染的影响对用户的体验的不好情况。具体通过弹窗友好提示!
优化更新了tcp指示灯点击出现机器状态中添加选中设备的编号 方便用户使用的明白明了!。
优化更新关闭了tcp重连操作内链条中的获取用户设备和切换设备操作项。
调整了获取无人机状态信息的更新频率 为14秒一次
This commit is contained in:
2026-06-16 17:34:00 +08:00
parent 52fe17c0d5
commit 71aea48d9f
61 changed files with 2896 additions and 1648 deletions

View File

@@ -0,0 +1,188 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../models/device_task_model.dart';
abstract class DeviceTaskDatasource {
Future<List<DeviceTaskModel>> getDeviceTaskPool({
required String userId,
required int siteId,
required int orgId,
int pageNum = 1,
int pageSize = 99999999,
});
Future<bool> cancelTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
});
Future<bool> pauseTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
});
Future<Map<String, dynamic>> recoveryTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
});
}
class DeviceTaskDatasourceImpl implements DeviceTaskDatasource {
final Dio dio;
final ILoggerService _logger = GetIt.I<ILoggerService>();
DeviceTaskDatasourceImpl(this.dio);
@override
Future<List<DeviceTaskModel>> getDeviceTaskPool({
required String userId,
required int siteId,
required int orgId,
int pageNum = 1,
int pageSize = 99999999,
}) async {
try {
final url = 'http://1.95.137.212:59015/iot/deviceTask/deviceTaskPool';
final response = await dio.get(
url,
queryParameters: {
'userId': userId,
'siteId': siteId,
'orgId': orgId,
'pageNum': pageNum,
'pageSize': pageSize,
},
);
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['code'] == 200) {
final rows = data['rows'] as List? ?? [];
return rows
.map((item) => DeviceTaskModel.fromJson(item as Map<String, dynamic>))
.toList();
} else {
throw Exception(data['msg'] ?? '获取任务池失败');
}
} else {
throw Exception('HTTP ${response.statusCode}');
}
} catch (e) {
_logger.logWithLevel('❌ 获取任务池失败: $e');
rethrow;
}
}
@override
Future<bool> cancelTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
}) async {
try {
final url = 'http://1.95.137.212:59015/iot/deviceTask/cancelTask';
final response = await dio.post(
url,
data: {
'deviceId': deviceId,
'taskId': taskId,
'orgId': orgId,
'siteId': siteId,
},
);
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['code'] == 200) {
return data['data'] as bool? ?? false;
} else {
throw Exception(data['msg'] ?? '取消任务失败');
}
} else {
throw Exception('HTTP ${response.statusCode}');
}
} catch (e) {
_logger.logWithLevel('❌ 取消任务失败: $e');
rethrow;
}
}
@override
Future<bool> pauseTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
}) async {
try {
final url = 'http://1.95.137.212:59015/iot/deviceTask/pauseTask';
final response = await dio.post(
url,
data: {
'deviceId': deviceId,
'taskId': taskId,
'orgId': orgId,
'siteId': siteId,
},
);
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['code'] == 200) {
return data['data'] as bool? ?? false;
} else {
throw Exception(data['msg'] ?? '暂停任务失败');
}
} else {
throw Exception('HTTP ${response.statusCode}');
}
} catch (e) {
_logger.logWithLevel('❌ 暂停任务失败: $e');
rethrow;
}
}
@override
Future<Map<String, dynamic>> recoveryTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
}) async {
try {
final url = 'http://1.95.137.212:59015/iot/deviceTask/recoveryTask';
final response = await dio.post(
url,
data: {
'deviceId': deviceId,
'taskId': taskId,
'orgId': orgId,
'siteId': siteId,
},
);
if (response.statusCode == 200) {
final data = response.data as Map<String, dynamic>;
if (data['code'] == 200) {
return data['data'] as Map<String, dynamic>? ?? {};
} else {
throw Exception(data['msg'] ?? '恢复任务失败');
}
} else {
throw Exception('HTTP ${response.statusCode}');
}
} catch (e) {
_logger.logWithLevel('❌ 恢复任务失败: $e');
rethrow;
}
}
}

View File

@@ -0,0 +1,40 @@
import '../../domain/entities/device_task_entity.dart';
class DeviceTaskModel extends DeviceTaskEntity {
const DeviceTaskModel({
required super.id,
required super.deviceId,
required super.taskStatus,
required super.taskStatusTranslate,
super.routeId,
super.siteId,
super.orgId,
super.createTime,
});
factory DeviceTaskModel.fromJson(Map<String, dynamic> json) {
return DeviceTaskModel(
id: json['id'] as int,
deviceId: json['deviceId'] as String? ?? '',
taskStatus: json['taskStaus'] as String? ?? '',
taskStatusTranslate: json['taskStausTranslate'] as String? ?? '',
routeId: json['routeId'] as int?,
siteId: json['siteId'] as int?,
orgId: json['orgId'] as int?,
createTime: json['createTime'] as String?,
);
}
DeviceTaskEntity toEntity() {
return DeviceTaskEntity(
id: id,
deviceId: deviceId,
taskStatus: taskStatus,
taskStatusTranslate: taskStatusTranslate,
routeId: routeId,
siteId: siteId,
orgId: orgId,
createTime: createTime,
);
}
}

View File

@@ -0,0 +1,93 @@
import 'package:fpdart/fpdart.dart';
import '../../../../core/error/failure.dart';
import '../../domain/entities/device_task_entity.dart';
import '../../domain/repositories/device_task_repository.dart';
import '../datasources/device_task_datasource.dart';
class DeviceTaskRepositoryImpl implements DeviceTaskRepository {
final DeviceTaskDatasource datasource;
DeviceTaskRepositoryImpl({required this.datasource});
@override
Future<Either<Failure, List<DeviceTaskEntity>>> getDeviceTaskPool({
required String userId,
required int siteId,
required int orgId,
int pageNum = 1,
int pageSize = 99999999,
}) async {
try {
final models = await datasource.getDeviceTaskPool(
userId: userId,
siteId: siteId,
orgId: orgId,
pageNum: pageNum,
pageSize: pageSize,
);
return Right(models.map((model) => model.toEntity()).toList());
} catch (e) {
return Left(Failure(e.toString()));
}
}
@override
Future<Either<Failure, bool>> cancelTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
}) async {
try {
final result = await datasource.cancelTask(
deviceId: deviceId,
taskId: taskId,
orgId: orgId,
siteId: siteId,
);
return Right(result);
} catch (e) {
return Left(Failure(e.toString()));
}
}
@override
Future<Either<Failure, bool>> pauseTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
}) async {
try {
final result = await datasource.pauseTask(
deviceId: deviceId,
taskId: taskId,
orgId: orgId,
siteId: siteId,
);
return Right(result);
} catch (e) {
return Left(Failure(e.toString()));
}
}
@override
Future<Either<Failure, Map<String, dynamic>>> recoveryTask({
required String deviceId,
required int taskId,
required int orgId,
required int siteId,
}) async {
try {
final result = await datasource.recoveryTask(
deviceId: deviceId,
taskId: taskId,
orgId: orgId,
siteId: siteId,
);
return Right(result);
} catch (e) {
return Left(Failure(e.toString()));
}
}
}

View File

@@ -198,24 +198,24 @@ class PathRepositoryImpl implements PathRepository {
url,
headers: {'Accept': 'application/xml, text/xml, */*'},
);
print('[XML接口] 响应状态码: ${response.statusCode}');
print('[XML接口] 响应内容长度: ${response.body.length}');
print('[XML接口] Content-Type: ${response.headers['content-type']}');
/// print('[XML接口] 响应状态码: ${response.statusCode}');
////print('[XML接口] 响应内容长度: ${response.body.length}');
///print('[XML接口] Content-Type: ${response.headers['content-type']}');
if (response.statusCode == 200) {
// 打印前200字符确认格式
final preview = response.body.length > 200
? response.body.substring(0, 200)
: response.body;
print('[XML接口] 响应开头: $preview');
/// print('[XML接口] 响应开头: $preview');
// 判断是JSON还是XML格式
final trimmed = response.body.trim();
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
print('[XML接口] 检测到JSON格式,使用JSON解析');
///print('[XML接口] 检测到JSON格式,使用JSON解析');
return _parseJsonResponse(response.body);
} else {
print('[XML接口] 检测到XML格式,使用XML解析');
///print('[XML接口] 检测到XML格式,使用XML解析');
return _parseXmlResponse(response.body);
}
} else {
@@ -224,7 +224,7 @@ class PathRepositoryImpl implements PathRepository {
);
}
} catch (e) {
print('[XML接口] 错误: $e');
/// print('[XML接口] 错误: $e');
throw Exception('Network error in getWorkRecordsBySiteId: $e');
}
}
@@ -252,7 +252,7 @@ class PathRepositoryImpl implements PathRepository {
records.add(WorkRecordEntity.fromJson(recordsData));
}
print('[XML接口] 最终解析记录数: ${records.length}');
/// print('[XML接口] 最终解析记录数: ${records.length}');
return records;
}
@@ -276,7 +276,7 @@ class PathRepositoryImpl implements PathRepository {
// 使用非贪婪匹配,确保每个data节点独立提取
final dataRegex = RegExp(r'<data>([\s\S]*?)</data>');
final dataMatches = dataRegex.allMatches(body);
print('[XML接口] 找到data节点数量: ${dataMatches.length}');
///print('[XML接口] 找到data节点数量: ${dataMatches.length}');
// 解析所有工作记录
final List<WorkRecordEntity> records = [];
@@ -292,9 +292,9 @@ class PathRepositoryImpl implements PathRepository {
final recordElement = document.rootElement;
final recordData = _parseXmlRecord(recordElement);
print(
'[XML接口] data[$i] 解析结果: workName=${recordData['workName']}, id=${recordData['id']}, imgUrl=${recordData['imgUrl']}',
);
/// print(
/// '[XML接口] data[$i] 解析结果: workName=${recordData['workName']}, id=${recordData['id']}, imgUrl=${recordData['imgUrl']}',
/// );
records.add(WorkRecordEntity.fromXml(recordData));
} catch (e) {
@@ -302,7 +302,7 @@ class PathRepositoryImpl implements PathRepository {
}
}
print('[XML接口] 最终解析记录数: ${records.length}');
///print('[XML接口] 最终解析记录数: ${records.length}');
return records;
}
@@ -310,15 +310,15 @@ class PathRepositoryImpl implements PathRepository {
Map<String, dynamic> _parseXmlRecord(XmlElement recordElement) {
final Map<String, dynamic> result = {};
print('[XML解析] 开始解析节点,子元素数量: ${recordElement.childElements.length}');
//// print('[XML解析] 开始解析节点,子元素数量: ${recordElement.childElements.length}');
for (final child in recordElement.childElements) {
final tagName = child.name.local;
final innerText = child.innerText.trim();
print(
'[XML解析] 标签: $tagName, 值: ${innerText.length > 50 ? innerText.substring(0, 50) + '...' : innerText}',
);
// print(
// '[XML解析] 标签: $tagName, 值: ${innerText.length > 50 ? innerText.substring(0, 50) + '...' : innerText}',
// );
// 特殊处理jsonData节点(包含嵌套结构)
if (tagName == 'jsonData') {
@@ -329,7 +329,7 @@ class PathRepositoryImpl implements PathRepository {
}
}
print('[XML解析] 解析完成,结果keys: ${result.keys.toList()}');
//print('[XML解析] 解析完成,结果keys: ${result.keys.toList()}');
return result;
}
@@ -392,4 +392,42 @@ class PathRepositoryImpl implements PathRepository {
return coordinates;
}
/// 创建设备任务(通过接口执行作业)
/// 接口地址: http://1.95.137.212:59015/iot/deviceTask/createDeviceTask
/// 入参: {"deviceId":"...","routeId":76,"siteId":22}
@override
Future<void> createDeviceTask({
required String deviceId,
required int routeId,
required int siteId,
}) async {
final url = Uri.parse('http://1.95.137.212:59015/iot/deviceTask/createDeviceTask');
final body = jsonEncode({
'deviceId': deviceId,
'routeId': routeId,
'siteId': siteId,
});
print('📤 [创建设备任务] 请求参数: $body');
try {
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: body,
);
print('📥 [创建设备任务] 响应状态码: ${response.statusCode}');
print('📥 [创建设备任务] 响应内容: ${response.body}');
if (response.statusCode != 200) {
throw Exception('创建设备任务失败: HTTP ${response.statusCode}');
}
} catch (e) {
print('❌ [创建设备任务] 错误: $e');
throw Exception('创建设备任务失败: $e');
}
}
}