Merge branch 'feature/my' of http://1.95.137.212:57001/APP/FlutterApp into feature/my
This commit is contained in:
@@ -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<void> init() async {
|
||||
sl.registerLazySingleton<GeneratePathUseCase>(
|
||||
() => GeneratePathUseCaseImpl(sl<PathRepository>()),
|
||||
);
|
||||
///.路径获取和删除
|
||||
sl.registerLazySingleton(() => GetWorkRecordUseCase(sl<PathRepository>()));
|
||||
sl.registerLazySingleton(() => DeleteWorkRecordUseCase(sl<PathRepository>()));
|
||||
|
||||
|
||||
/// 6. 认证 (Auth)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
class ReferencePoint {
|
||||
final double lat;
|
||||
final double lon;
|
||||
|
||||
ReferencePoint({required this.lat, required this.lon});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
};
|
||||
}
|
||||
|
||||
class OuterBoundary {
|
||||
final List<Position> position;
|
||||
final double sideWidth;
|
||||
|
||||
OuterBoundary({required this.position, required this.sideWidth});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'position': position.map((p) => p.toJson()).toList(),
|
||||
'sideWidth': sideWidth,
|
||||
};
|
||||
}
|
||||
|
||||
class HoleBoundary {
|
||||
final List<Position> position;
|
||||
final double sideWidth;
|
||||
|
||||
HoleBoundary({required this.position, required this.sideWidth});
|
||||
|
||||
Map<String, dynamic> 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<String, dynamic> toJson() => {
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
};
|
||||
}
|
||||
@@ -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<List<DeviceAddPathPointModel>> generatePath(List<DeviceAddPathPointModel> coordinates) async {
|
||||
Future<List<DeviceAddPathPointModel>> generatePath({
|
||||
required ReferencePoint reference,
|
||||
required int heading,
|
||||
required OuterBoundary outer,
|
||||
required List<HoleBoundary> 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<Map<String, dynamic>> 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<String, dynamic>;
|
||||
return data;
|
||||
} else {
|
||||
throw Exception('Save failed with status: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('Network error in saveWorkRecord: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Map<String, dynamic>>> 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<String, dynamic>;
|
||||
if (data['code'] == 200 && data.containsKey('data')) {
|
||||
return List<Map<String, dynamic>>.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<Map<String, dynamic>> 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<String, dynamic>;
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<List<DeviceAddPathPointModel>> generatePath(List<DeviceAddPathPointModel> coordinates);
|
||||
Future<List<DeviceAddPathPointModel>> generatePath({
|
||||
required ReferencePoint reference,
|
||||
required int heading,
|
||||
required OuterBoundary outer,
|
||||
required List<HoleBoundary> holes,
|
||||
required int workType,
|
||||
});
|
||||
|
||||
// Save work record (新增)
|
||||
Future<Map<String, dynamic>> saveWorkRecord({
|
||||
required String workName,
|
||||
required String userId,
|
||||
required String jsonData,
|
||||
});
|
||||
|
||||
// Get work record (查询)
|
||||
Future<List<Map<String, dynamic>>> getWorkRecord({
|
||||
required String userId,
|
||||
});
|
||||
|
||||
|
||||
// Delete work record (删除)
|
||||
Future<Map<String, dynamic>> deleteWorkRecord({
|
||||
required String workName,
|
||||
});
|
||||
|
||||
}
|
||||
@@ -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<Either<DeviceFailure, Map<String, dynamic>>> call(String workName) async {
|
||||
try {
|
||||
final result = await repository.deleteWorkRecord(workName: workName);
|
||||
return Right(result);
|
||||
} catch (e) {
|
||||
return Left(DeviceFailure.networkError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<List<DeviceAddPathPointModel>> execute(List<DeviceAddPathPointModel> coordinates);
|
||||
Future<List<DeviceAddPathPointModel>> execute({
|
||||
required ReferencePoint reference,
|
||||
required int heading,
|
||||
required OuterBoundary outer,
|
||||
required List<HoleBoundary> holes,
|
||||
required int workType,
|
||||
});
|
||||
}
|
||||
|
||||
class GeneratePathUseCaseImpl implements GeneratePathUseCase {
|
||||
final PathRepository _repository;
|
||||
|
||||
GeneratePathUseCaseImpl(this._repository);
|
||||
|
||||
//完成路径的生成
|
||||
@override
|
||||
Future<List<DeviceAddPathPointModel>> execute(List<DeviceAddPathPointModel> coordinates) async {
|
||||
return await _repository.generatePath(coordinates);
|
||||
Future<List<DeviceAddPathPointModel>> execute({
|
||||
required ReferencePoint reference,
|
||||
required int heading,
|
||||
required OuterBoundary outer,
|
||||
required List<HoleBoundary> holes,
|
||||
required int workType,
|
||||
}) async {
|
||||
return await _repository.generatePath(
|
||||
reference: reference,
|
||||
heading: heading,
|
||||
outer: outer,
|
||||
holes: holes,
|
||||
workType: workType,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Either<DeviceFailure, List<Map<String, dynamic>>>> call(String userId) async {
|
||||
try {
|
||||
final result = await repository.getWorkRecord(userId: userId);
|
||||
return Right(result);
|
||||
} catch (e) {
|
||||
return Left(DeviceFailure.networkError(message: e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<DevicesState> {
|
||||
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<DevicesState> {
|
||||
(failure) => emit(
|
||||
state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: failure.message, // 假设你的 Failure 类有 message 字段
|
||||
errorMessage: failure.message, //
|
||||
),
|
||||
),
|
||||
(deviceList) {
|
||||
@@ -64,7 +74,7 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
|
||||
emit(state.copyWith(devices: newList, selectedDevice: newSelected));
|
||||
}
|
||||
// 切换设备
|
||||
/// 切换设备
|
||||
Future<void> switchDevice(DeviceEntity device) async {
|
||||
// 保持现有列表,只改 loading
|
||||
emit(state.copyWith(isLoading: true));
|
||||
@@ -76,7 +86,7 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
selectDevice(device);
|
||||
}, (r) => emit(state.copyWith(isLoading: false, selectedDevice: device)));
|
||||
}
|
||||
// 获取设备位置
|
||||
/// 获取设备位置
|
||||
Future<void> getDeviceLocation(DeviceEntity device) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
final result = await _getDeviceLocationUseCase.call(device.deviceName);
|
||||
@@ -89,6 +99,29 @@ class DevicesCubit extends Cubit<DevicesState> {
|
||||
)),
|
||||
);
|
||||
}
|
||||
///获取记录
|
||||
Future<void> 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<void> 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(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ class DevicesState extends Equatable {
|
||||
final String? errorMessage; // 错误信息
|
||||
final double? deviceLatitude; // 新增字段
|
||||
final double? deviceLongitude; // 新增字段
|
||||
|
||||
final List<Map<String, dynamic>>? 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<Map<String, dynamic>>? workRecords,
|
||||
}) {
|
||||
return DevicesState(
|
||||
devices: devices ?? this.devices,
|
||||
@@ -42,5 +44,6 @@ class DevicesState extends Equatable {
|
||||
errorMessage,
|
||||
deviceLatitude,
|
||||
deviceLongitude,
|
||||
workRecords,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user