diff --git a/lib/core/di/injection.dart b/lib/core/di/injection.dart index b104e51f..471056c1 100644 --- a/lib/core/di/injection.dart +++ b/lib/core/di/injection.dart @@ -26,9 +26,11 @@ import '../../features/devices/data/repositories/device_repository_impl.dart'; import '../../features/devices/data/repositories/generate_path_repository_Impl.dart'; import '../../features/devices/domain/repositories/device_hostrity_work_repository.dart'; import '../../features/devices/domain/repositories/path_repository.dart'; +import '../../features/devices/domain/usecases/delete_work_record_usecase.dart'; import '../../features/devices/domain/usecases/device_work_hostrirty_usecase.dart'; import '../../features/devices/domain/usecases/generate_path_usecase.dart'; import '../../features/devices/domain/usecases/get_device_location_usecase.dart'; +import '../../features/devices/domain/usecases/get_work_record_usecase.dart'; import '../../features/remote_control/presentation/bloc/remote_control_cubit.dart'; import '../app/app_user_cubit.dart'; import '../network/dio_client.dart'; @@ -117,6 +119,9 @@ Future init() async { sl.registerLazySingleton( () => GeneratePathUseCaseImpl(sl()), ); +///.路径获取和删除 + sl.registerLazySingleton(() => GetWorkRecordUseCase(sl())); + sl.registerLazySingleton(() => DeleteWorkRecordUseCase(sl())); /// 6. 认证 (Auth) diff --git a/lib/features/devices/data/models/device_work_area_param_model.dart b/lib/features/devices/data/models/device_work_area_param_model.dart new file mode 100644 index 00000000..3548bf63 --- /dev/null +++ b/lib/features/devices/data/models/device_work_area_param_model.dart @@ -0,0 +1,47 @@ +class ReferencePoint { + final double lat; + final double lon; + + ReferencePoint({required this.lat, required this.lon}); + + Map toJson() => { + 'lat': lat, + 'lon': lon, + }; +} + +class OuterBoundary { + final List position; + final double sideWidth; + + OuterBoundary({required this.position, required this.sideWidth}); + + Map toJson() => { + 'position': position.map((p) => p.toJson()).toList(), + 'sideWidth': sideWidth, + }; +} + +class HoleBoundary { + final List position; + final double sideWidth; + + HoleBoundary({required this.position, required this.sideWidth}); + + Map toJson() => { + 'position': position.map((p) => p.toJson()).toList(), + 'sideWidth': sideWidth, + }; +} + +class Position { + final double lat; + final double lon; + + Position({required this.lat, required this.lon}); + + Map toJson() => { + 'lat': lat, + 'lon': lon, + }; +} diff --git a/lib/features/devices/data/repositories/generate_path_repository_Impl.dart b/lib/features/devices/data/repositories/generate_path_repository_Impl.dart index 6c01b57b..62c1414a 100644 --- a/lib/features/devices/data/repositories/generate_path_repository_Impl.dart +++ b/lib/features/devices/data/repositories/generate_path_repository_Impl.dart @@ -3,16 +3,28 @@ import 'dart:convert'; import '../../domain/repositories/path_repository.dart'; import '../models/device_add_path_point_model.dart'; +import '../models/device_work_area_param_model.dart'; class PathRepositoryImpl implements PathRepository { final String baseUrl = 'https://your-backend-api.com'; // 后端接口地址 // 生成路径 @override - Future> generatePath(List coordinates) async { + Future> generatePath({ + required ReferencePoint reference, + required int heading, + required OuterBoundary outer, + required List holes, + required int workType, + }) async { final url = Uri.parse('$baseUrl/api/path'); final headers = {'Content-Type': 'application/json'}; + final body = jsonEncode({ - 'coordinates': coordinates.map((p) => p.toJson()).toList(), + 'reference': reference.toJson(), + 'heading': heading, + 'outer': outer.toJson(), + 'holes': holes.map((hole) => hole.toJson()).toList(), + 'workType': workType, }); try { @@ -27,4 +39,85 @@ class PathRepositoryImpl implements PathRepository { throw Exception('Network error: $e'); } } + // 保存工作记录 + @override + Future> saveWorkRecord({ + required String workName, + required String userId, + required String jsonData, + }) async { + final url = Uri.parse('https://serviceri.satabot.com/iot/workRecord/add'); + final headers = {'Content-Type': 'application/json'}; + final body = jsonEncode({ + 'workName': workName, + 'userId': userId, + 'jsonData': jsonData, + }); + + try { + final response = await http.post(url, headers: headers, body: body); + if (response.statusCode == 200) { + final data = jsonDecode(response.body) as Map; + return data; + } else { + throw Exception('Save failed with status: ${response.statusCode}'); + } + } catch (e) { + throw Exception('Network error in saveWorkRecord: $e'); + } + } + + @override + Future>> getWorkRecord({required String userId}) async { + final timestamp = DateTime.now().millisecondsSinceEpoch; + final url = Uri.parse('https://serviceri.satabot.com/iot/workRecord/selectByUserId') + .replace(queryParameters: { + 'userId': userId, + '_t': timestamp.toString(), + }); + + try { + final response = await http.get(url); + if (response.statusCode == 200) { + final data = jsonDecode(response.body) as Map; + if (data['code'] == 200 && data.containsKey('data')) { + return List>.from(data['data']); + } else { + throw Exception('API error: ${data['msg'] ?? 'Unknown'}'); + } + } else { + throw Exception('HTTP ${response.statusCode}: ${response.reasonPhrase}'); + } + } catch (e) { + throw Exception('Network error in getWorkRecord: $e'); + } + } + + @override + Future> deleteWorkRecord({required String workName}) async { + final timestamp = DateTime.now().millisecondsSinceEpoch; + final url = Uri.parse('https://serviceri.satabot.com/iot/workRecord/deleteByWorkName') + .replace(queryParameters: { + 'workName': workName, + '_t': timestamp.toString(), + }); + + try { + final response = await http.get(url); + final data = jsonDecode(response.body) as Map; + + if (response.statusCode == 200 && data['code'] == 200) { + return data; // 返回 {"code": 200, "msg": "删除成功"} + } else { + throw Exception('Delete failed: ${data['msg'] ?? response.reasonPhrase}'); + } + } catch (e) { + throw Exception('Network error in deleteWorkRecord: $e'); + } + } + + + + + } diff --git a/lib/features/devices/domain/repositories/path_repository.dart b/lib/features/devices/domain/repositories/path_repository.dart index f70dddb3..aaa1c673 100644 --- a/lib/features/devices/domain/repositories/path_repository.dart +++ b/lib/features/devices/domain/repositories/path_repository.dart @@ -1,6 +1,32 @@ import '../../data/models/device_add_path_point_model.dart'; +import '../../data/models/device_work_area_param_model.dart'; abstract class PathRepository { // Generate path(打点生成路径规划) - Future> generatePath(List coordinates); + Future> generatePath({ + required ReferencePoint reference, + required int heading, + required OuterBoundary outer, + required List holes, + required int workType, + }); + + // Save work record (新增) + Future> saveWorkRecord({ + required String workName, + required String userId, + required String jsonData, + }); + + // Get work record (查询) + Future>> getWorkRecord({ + required String userId, + }); + + + // Delete work record (删除) + Future> deleteWorkRecord({ + required String workName, + }); + } \ No newline at end of file diff --git a/lib/features/devices/domain/usecases/delete_work_record_usecase.dart b/lib/features/devices/domain/usecases/delete_work_record_usecase.dart new file mode 100644 index 00000000..50992911 --- /dev/null +++ b/lib/features/devices/domain/usecases/delete_work_record_usecase.dart @@ -0,0 +1,18 @@ + import 'package:fpdart/fpdart.dart'; + +import '../errors/device_failure.dart'; +import '../repositories/path_repository.dart'; + +class DeleteWorkRecordUseCase { + final PathRepository repository; + DeleteWorkRecordUseCase(this.repository); + + Future>> call(String workName) async { + try { + final result = await repository.deleteWorkRecord(workName: workName); + return Right(result); + } catch (e) { + return Left(DeviceFailure.networkError(message: e.toString())); + } + } + } diff --git a/lib/features/devices/domain/usecases/generate_path_usecase.dart b/lib/features/devices/domain/usecases/generate_path_usecase.dart index f269b29b..0c540a52 100644 --- a/lib/features/devices/domain/usecases/generate_path_usecase.dart +++ b/lib/features/devices/domain/usecases/generate_path_usecase.dart @@ -1,20 +1,37 @@ import '../../data/models/device_add_path_point_model.dart'; +import '../../data/models/device_work_area_param_model.dart'; import '../repositories/path_repository.dart'; abstract class GeneratePathUseCase { - Future> execute(List coordinates); + Future> execute({ + required ReferencePoint reference, + required int heading, + required OuterBoundary outer, + required List holes, + required int workType, + }); } class GeneratePathUseCaseImpl implements GeneratePathUseCase { final PathRepository _repository; GeneratePathUseCaseImpl(this._repository); - +//完成路径的生成 @override - Future> execute(List coordinates) async { - return await _repository.generatePath(coordinates); + Future> execute({ + required ReferencePoint reference, + required int heading, + required OuterBoundary outer, + required List holes, + required int workType, + }) async { + return await _repository.generatePath( + reference: reference, + heading: heading, + outer: outer, + holes: holes, + workType: workType, + ); } - - } diff --git a/lib/features/devices/domain/usecases/get_work_record_usecase.dart b/lib/features/devices/domain/usecases/get_work_record_usecase.dart new file mode 100644 index 00000000..f8d21a59 --- /dev/null +++ b/lib/features/devices/domain/usecases/get_work_record_usecase.dart @@ -0,0 +1,18 @@ +import 'package:fpdart/fpdart.dart'; +import '../../domain/errors/device_failure.dart'; +import '../../domain/repositories/path_repository.dart'; + +class GetWorkRecordUseCase { + final PathRepository repository; + + GetWorkRecordUseCase(this.repository); + + Future>>> call(String userId) async { + try { + final result = await repository.getWorkRecord(userId: userId); + return Right(result); + } catch (e) { + return Left(DeviceFailure.networkError(message: e.toString())); + } + } +} diff --git a/lib/features/devices/presentation/bloc/devices_cubit.dart b/lib/features/devices/presentation/bloc/devices_cubit.dart index 5e428a00..e8e2b407 100644 --- a/lib/features/devices/presentation/bloc/devices_cubit.dart +++ b/lib/features/devices/presentation/bloc/devices_cubit.dart @@ -3,15 +3,25 @@ import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity. import 'package:maibu_satabot_v2/features/devices/domain/repositories/device_repository.dart'; import 'package:maibu_satabot_v2/features/devices/domain/usecases/get_user_device_usecase.dart'; +import '../../domain/usecases/delete_work_record_usecase.dart'; import '../../domain/usecases/get_device_location_usecase.dart'; +import '../../domain/usecases/get_work_record_usecase.dart'; import 'devices_state.dart'; class DevicesCubit extends Cubit { final GetUserDeviceUseCase _getUserDeviceUseCase; final GetDeviceLocationUseCase _getDeviceLocationUseCase; final DeviceRepository repository; + final GetWorkRecordUseCase _getWorkRecordUseCase; + final DeleteWorkRecordUseCase _deleteWorkRecordUseCase; - DevicesCubit(this.repository, this._getUserDeviceUseCase, this._getDeviceLocationUseCase) + + DevicesCubit(this.repository, + this._getUserDeviceUseCase, + this._getDeviceLocationUseCase, + this._getWorkRecordUseCase, + this._deleteWorkRecordUseCase, + ) : super(const DevicesState()); // 获取所有设备列表 @@ -27,7 +37,7 @@ class DevicesCubit extends Cubit { (failure) => emit( state.copyWith( isLoading: false, - errorMessage: failure.message, // 假设你的 Failure 类有 message 字段 + errorMessage: failure.message, // ), ), (deviceList) { @@ -64,7 +74,7 @@ class DevicesCubit extends Cubit { emit(state.copyWith(devices: newList, selectedDevice: newSelected)); } - // 切换设备 + /// 切换设备 Future switchDevice(DeviceEntity device) async { // 保持现有列表,只改 loading emit(state.copyWith(isLoading: true)); @@ -76,7 +86,7 @@ class DevicesCubit extends Cubit { selectDevice(device); }, (r) => emit(state.copyWith(isLoading: false, selectedDevice: device))); } - // 获取设备位置 + /// 获取设备位置 Future getDeviceLocation(DeviceEntity device) async { emit(state.copyWith(isLoading: true)); final result = await _getDeviceLocationUseCase.call(device.deviceName); @@ -89,6 +99,29 @@ class DevicesCubit extends Cubit { )), ); } + ///获取记录 + Future loadWorkRecords(String userId) async { + emit(state.copyWith(isLoading: true)); + final result = await _getWorkRecordUseCase(userId); + result.fold( + (failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message)), + (records) => emit(state.copyWith(isLoading: false, workRecords: records)), + ); + } + /// 删除工作记录 + Future deleteWorkRecord(String workName) async { + emit(state.copyWith(isLoading: true)); + final result = await _deleteWorkRecordUseCase(workName); + result.fold( + (failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message)), + (_) => emit( + state.copyWith( + isLoading: false, + workRecords: state.workRecords?.where((record) => record != workName).toList(), + ), + ), + ); + } } diff --git a/lib/features/devices/presentation/bloc/devices_state.dart b/lib/features/devices/presentation/bloc/devices_state.dart index 04a848e4..fd58e83b 100644 --- a/lib/features/devices/presentation/bloc/devices_state.dart +++ b/lib/features/devices/presentation/bloc/devices_state.dart @@ -8,7 +8,7 @@ class DevicesState extends Equatable { final String? errorMessage; // 错误信息 final double? deviceLatitude; // 新增字段 final double? deviceLongitude; // 新增字段 - + final List>? workRecords; const DevicesState({ this.devices = const [], this.selectedDevice, @@ -16,6 +16,7 @@ class DevicesState extends Equatable { this.errorMessage, this.deviceLatitude, this.deviceLongitude, + this.workRecords }); // 使用 copyWith 方便局部更新状态 @@ -26,6 +27,7 @@ class DevicesState extends Equatable { String? errorMessage, double? deviceLatitude, double? deviceLongitude, + List>? workRecords, }) { return DevicesState( devices: devices ?? this.devices, @@ -42,5 +44,6 @@ class DevicesState extends Equatable { errorMessage, deviceLatitude, deviceLongitude, + workRecords, ]; }