From 08d91aa8b12a8f3dd266b18d084f90d47fa6b32f Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Thu, 26 Feb 2026 08:45:37 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=BB=91=E5=AE=9A=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=9A=84=E4=BD=8D=E7=BD=AE=E7=9A=84=E6=9B=B4=E6=96=B0=E5=92=8C?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/consts/http_api_consts.dart | 7 ++++ .../datasources/device_http_datasource.dart | 3 ++ .../impl/device_http_datasource_impl.dart | 34 +++++++++++++++++++ .../repositories/device_repository_impl.dart | 9 +++++ .../entities/device_location_entity.dart | 11 ++++++ .../device_hostrity_work_repository.dart | 2 ++ .../repositories/device_repository.dart | 3 ++ .../usecases/get_device_location_usecase.dart | 16 +++++++++ .../presentation/bloc/devices_cubit.dart | 24 ++++++++++--- .../presentation/bloc/devices_state.dart | 14 +++++++- 10 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 lib/features/devices/domain/entities/device_location_entity.dart create mode 100644 lib/features/devices/domain/usecases/get_device_location_usecase.dart diff --git a/lib/core/consts/http_api_consts.dart b/lib/core/consts/http_api_consts.dart index b304ce23..54c3010b 100644 --- a/lib/core/consts/http_api_consts.dart +++ b/lib/core/consts/http_api_consts.dart @@ -14,4 +14,11 @@ class HttpApiConsts { static const String unbindDevice = "$baseUrl/forward/device/unbind"; // 切换设备 static const String switchDevice = "$baseUrl/forward/device/switchDevice"; + + + // 获取设备位置 + static const String getDeviceLocation = "$baseUrl/iot/device/userDevice"; + + + } diff --git a/lib/features/devices/data/datasources/device_http_datasource.dart b/lib/features/devices/data/datasources/device_http_datasource.dart index f11ae76e..23c9ea9e 100644 --- a/lib/features/devices/data/datasources/device_http_datasource.dart +++ b/lib/features/devices/data/datasources/device_http_datasource.dart @@ -5,4 +5,7 @@ abstract class DeviceHttpDatasource { Future bindDevice(String deviceId, String deviceAlias); Future unbindDevice(String deviceId); Future switchDevice(String platform, String deviceId); + + Future getDeviceLocation(String username) async {} + } diff --git a/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart b/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart index 334089cf..ea5fc9ae 100644 --- a/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart +++ b/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart @@ -78,4 +78,38 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource { // TODO: implement unbindDevice throw UnimplementedError(); } + + @override + Future getDeviceLocation(String username) async { + // TODO: implement getDeviceLocation + try { + // 发起 GET 请求 + final response = await dio.get( + 'https://serviceri.satabot.com/iot/device/userDevice', + queryParameters: {'tenantName': username}, + // options: Options( + // headers: { + // 'Content-Type': 'application/json', + // 'Authorization': 'Bearer ${await _getToken()}', // 获取 Token + // }, + // ), + ); + + // 检查响应状态码 + if (response.statusCode == 200) { + final data = response.data; + if (data['code'] == 200) { + return data['data']; // 返回设备数据 + } else { + throw Exception(data['msg'] ?? '业务异常'); + } + } else { + throw Exception('网络请求失败: ${response.statusCode}'); + } + } catch (e) { + throw Exception('获取设备位置失败: $e'); + } + + throw UnimplementedError(); + } } diff --git a/lib/features/devices/data/repositories/device_repository_impl.dart b/lib/features/devices/data/repositories/device_repository_impl.dart index 652da73b..9b44610c 100644 --- a/lib/features/devices/data/repositories/device_repository_impl.dart +++ b/lib/features/devices/data/repositories/device_repository_impl.dart @@ -2,6 +2,7 @@ import 'package:dio/dio.dart'; import 'package:fpdart/src/either.dart'; import 'package:maibu_satabot_v2/features/devices/data/datasources/device_http_datasource.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/entities/device_location_entity.dart'; import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart'; import '../../domain/repositories/device_repository.dart'; @@ -69,4 +70,12 @@ class DeviceRepositoryImpl implements DeviceRepository { return Left(DeviceFailure(cleanMessage)); } } + // TODO: implement switchDevice 实现获取设备的列表 + @override + Future>getDeviceLocation(String username) async { + // TODO: implement getDeviceLocation + var result = await _deviceHttpDatasource.getDeviceLocation(username); + return Right(result); + // throw UnimplementedError(); + } } diff --git a/lib/features/devices/domain/entities/device_location_entity.dart b/lib/features/devices/domain/entities/device_location_entity.dart new file mode 100644 index 00000000..953b3960 --- /dev/null +++ b/lib/features/devices/domain/entities/device_location_entity.dart @@ -0,0 +1,11 @@ +class DeviceLocationEntity { + final String deviceName; + final double latitude; // 新增字段 + final double longitude; // 新增字段 + + DeviceLocationEntity({ + required this.deviceName, + required this.latitude, + required this.longitude, + }); +} diff --git a/lib/features/devices/domain/repositories/device_hostrity_work_repository.dart b/lib/features/devices/domain/repositories/device_hostrity_work_repository.dart index 41be2bbd..290db2ae 100644 --- a/lib/features/devices/domain/repositories/device_hostrity_work_repository.dart +++ b/lib/features/devices/domain/repositories/device_hostrity_work_repository.dart @@ -11,4 +11,6 @@ abstract class DeviceHostrityWorkRepositoryRepository { required String deviceId, }); + + } diff --git a/lib/features/devices/domain/repositories/device_repository.dart b/lib/features/devices/domain/repositories/device_repository.dart index c963e6d0..a357a5c4 100644 --- a/lib/features/devices/domain/repositories/device_repository.dart +++ b/lib/features/devices/domain/repositories/device_repository.dart @@ -1,5 +1,6 @@ import 'package:fpdart/fpdart.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/entities/device_location_entity.dart'; import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart'; abstract class DeviceRepository { @@ -15,4 +16,6 @@ abstract class DeviceRepository { String platform, String deviceId, ); + // 获取设备位置 + Future> getDeviceLocation(String username); } diff --git a/lib/features/devices/domain/usecases/get_device_location_usecase.dart b/lib/features/devices/domain/usecases/get_device_location_usecase.dart new file mode 100644 index 00000000..897878db --- /dev/null +++ b/lib/features/devices/domain/usecases/get_device_location_usecase.dart @@ -0,0 +1,16 @@ +// features/devices/domain/usecases/get_device_location_usecase.dart +import 'package:fpdart/fpdart.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/entities/device_location_entity.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/repositories/device_repository.dart'; +import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart'; + +class GetDeviceLocationUseCase { + final DeviceRepository repository; + + GetDeviceLocationUseCase(this.repository); + //获取设备的位置 + Future> call(String username) async { + return await repository.getDeviceLocation(username); + } +} diff --git a/lib/features/devices/presentation/bloc/devices_cubit.dart b/lib/features/devices/presentation/bloc/devices_cubit.dart index c29bf8ea..5e428a00 100644 --- a/lib/features/devices/presentation/bloc/devices_cubit.dart +++ b/lib/features/devices/presentation/bloc/devices_cubit.dart @@ -3,21 +3,22 @@ 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/get_device_location_usecase.dart'; import 'devices_state.dart'; class DevicesCubit extends Cubit { final GetUserDeviceUseCase _getUserDeviceUseCase; - + final GetDeviceLocationUseCase _getDeviceLocationUseCase; final DeviceRepository repository; - DevicesCubit(this.repository, this._getUserDeviceUseCase) + DevicesCubit(this.repository, this._getUserDeviceUseCase, this._getDeviceLocationUseCase) : super(const DevicesState()); // 获取所有设备列表 Future fetchAllDevices(String username) async { emit(state.copyWith(isLoading: true)); try { - // 模拟网络请求获取列表 + // 网络请求获取列表 var resultEither = await _getUserDeviceUseCase.call( GetUserDeviceParams(username), ); @@ -63,7 +64,7 @@ class DevicesCubit extends Cubit { emit(state.copyWith(devices: newList, selectedDevice: newSelected)); } - + // 切换设备 Future switchDevice(DeviceEntity device) async { // 保持现有列表,只改 loading emit(state.copyWith(isLoading: true)); @@ -75,4 +76,19 @@ 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); + result.fold( + (failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message)), + (location) => emit(state.copyWith( + isLoading: false, + deviceLatitude: location.latitude, + deviceLongitude: location.longitude, + )), + ); + } + + } diff --git a/lib/features/devices/presentation/bloc/devices_state.dart b/lib/features/devices/presentation/bloc/devices_state.dart index 331f243c..04a848e4 100644 --- a/lib/features/devices/presentation/bloc/devices_state.dart +++ b/lib/features/devices/presentation/bloc/devices_state.dart @@ -6,12 +6,16 @@ class DevicesState extends Equatable { final DeviceEntity? selectedDevice; // 当前主界面选中的/操作的设备 final bool isLoading; // 是否正在加载 final String? errorMessage; // 错误信息 + final double? deviceLatitude; // 新增字段 + final double? deviceLongitude; // 新增字段 const DevicesState({ this.devices = const [], this.selectedDevice, this.isLoading = false, this.errorMessage, + this.deviceLatitude, + this.deviceLongitude, }); // 使用 copyWith 方便局部更新状态 @@ -20,15 +24,23 @@ class DevicesState extends Equatable { DeviceEntity? selectedDevice, bool? isLoading, String? errorMessage, + double? deviceLatitude, + double? deviceLongitude, }) { return DevicesState( devices: devices ?? this.devices, selectedDevice: selectedDevice ?? this.selectedDevice, isLoading: isLoading ?? this.isLoading, errorMessage: errorMessage, // 错误信息通常每次更新都要重新赋值或清空 + deviceLatitude: deviceLatitude ?? this.deviceLatitude, + deviceLongitude: deviceLongitude ?? this.deviceLongitude, ); } @override - List get props => [devices, selectedDevice, isLoading, errorMessage]; + List get props => [devices, selectedDevice, isLoading, + errorMessage, + deviceLatitude, + deviceLongitude, + ]; } From 0acc78f656782a14eed28547f0bcd7344fa37f2f Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Thu, 26 Feb 2026 09:24:59 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E4=B8=8D=E8=A7=84=E8=8C=83=E9=80=A0=E6=88=90?= =?UTF-8?q?=E7=9A=84=E6=AD=A7=E4=B9=89=EF=BC=8C=E5=92=8C=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/di/injection.dart | 4 +++- .../impl/device_http_datasource_impl.dart | 15 ++++++++++++--- .../usecases/get_device_location_usecase.dart | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/core/di/injection.dart b/lib/core/di/injection.dart index a73245df..68396a54 100644 --- a/lib/core/di/injection.dart +++ b/lib/core/di/injection.dart @@ -25,6 +25,7 @@ import '../../features/devices/data/repositories/device_hostriry_work_impl.dart' import '../../features/devices/data/repositories/device_repository_impl.dart'; import '../../features/devices/domain/repositories/device_hostrity_work_repository.dart'; import '../../features/devices/domain/usecases/device_work_hostrirty_usecase.dart'; +import '../../features/devices/domain/usecases/get_device_location_usecase.dart'; import '../../features/remote_control/presentation/bloc/remote_control_cubit.dart'; import '../app/app_user_cubit.dart'; import '../network/dio_client.dart'; @@ -102,7 +103,8 @@ Future init() async { /// 5. 状态管理 (Cubit/Bloc) sl.registerLazySingleton(() => AppUserCubit()); // AuthCubit 依赖它,必须先注册 - sl.registerLazySingleton(() => DevicesCubit(sl(), sl())); + sl.registerLazySingleton(() => GetDeviceLocationUseCase(sl())); + sl.registerLazySingleton(() => DevicesCubit(sl(), sl(), sl())); sl.registerFactory(() => RemoteControlCubit(sl())); /// 6. 认证 (Auth) diff --git a/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart b/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart index ea5fc9ae..cc51fada 100644 --- a/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart +++ b/lib/features/devices/data/datasources/impl/device_http_datasource_impl.dart @@ -3,6 +3,8 @@ import 'package:maibu_satabot_v2/core/consts/http_api_consts.dart'; import 'package:maibu_satabot_v2/features/devices/data/datasources/device_http_datasource.dart'; import 'package:maibu_satabot_v2/features/devices/domain/entities/device_entity.dart'; +import '../../../domain/entities/device_location_entity.dart'; + class DeviceHttpDatasourceImpl implements DeviceHttpDatasource { final Dio dio; @@ -80,13 +82,13 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource { } @override - Future getDeviceLocation(String username) async { + Future getDeviceLocation(String deviceame) async { // TODO: implement getDeviceLocation try { // 发起 GET 请求 final response = await dio.get( 'https://serviceri.satabot.com/iot/device/userDevice', - queryParameters: {'tenantName': username}, + queryParameters: {'tenantName': deviceame}, // options: Options( // headers: { // 'Content-Type': 'application/json', @@ -99,7 +101,14 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource { if (response.statusCode == 200) { final data = response.data; if (data['code'] == 200) { - return data['data']; // 返回设备数据 + //return data['data']; // 返回设备数据 + final locationData = data['data'];// 假设数据结构,测试时候如有不妥就修改结果的实例化 + return DeviceLocationEntity( + deviceName: locationData['deviceName'], + latitude: locationData['latitude'], + longitude: locationData['longitude'], + ); + } else { throw Exception(data['msg'] ?? '业务异常'); } diff --git a/lib/features/devices/domain/usecases/get_device_location_usecase.dart b/lib/features/devices/domain/usecases/get_device_location_usecase.dart index 897878db..8eb47f68 100644 --- a/lib/features/devices/domain/usecases/get_device_location_usecase.dart +++ b/lib/features/devices/domain/usecases/get_device_location_usecase.dart @@ -10,7 +10,7 @@ class GetDeviceLocationUseCase { GetDeviceLocationUseCase(this.repository); //获取设备的位置 - Future> call(String username) async { - return await repository.getDeviceLocation(username); + Future> call(String Devicename) async { + return await repository.getDeviceLocation(Devicename); } } From 56d8fe6d6b483a7bddadbc770dbc44757fc28c4d Mon Sep 17 00:00:00 2001 From: Songzex <2402265378@qq.com> Date: Thu, 26 Feb 2026 10:09:59 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E8=B7=AF=E5=8F=8A=E8=A7=84=E5=88=92-?= =?UTF-8?q?=E9=9B=86=E6=88=90(=E6=89=93=E7=82=B9=E7=BB=98=E5=88=B6)?= =?UTF-8?q?=E5=90=8E=E7=AB=AF=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/core/di/injection.dart | 12 ++++++++ .../models/device_add_path_point_model.dart | 16 ++++++++++ .../generate_path_repository_Impl.dart | 30 +++++++++++++++++++ .../domain/repositories/path_repository.dart | 6 ++++ .../usecases/generate_path_usecase.dart | 20 +++++++++++++ 5 files changed, 84 insertions(+) create mode 100644 lib/features/devices/data/models/device_add_path_point_model.dart create mode 100644 lib/features/devices/data/repositories/generate_path_repository_Impl.dart create mode 100644 lib/features/devices/domain/repositories/path_repository.dart create mode 100644 lib/features/devices/domain/usecases/generate_path_usecase.dart diff --git a/lib/core/di/injection.dart b/lib/core/di/injection.dart index 68396a54..b104e51f 100644 --- a/lib/core/di/injection.dart +++ b/lib/core/di/injection.dart @@ -23,8 +23,11 @@ import '../../features/auth/presentation/bloc/login_cubit.dart'; import '../../features/devices/data/datasources/device_http_datasource.dart'; import '../../features/devices/data/repositories/device_hostriry_work_impl.dart'; 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/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/remote_control/presentation/bloc/remote_control_cubit.dart'; import '../app/app_user_cubit.dart'; @@ -107,6 +110,15 @@ Future init() async { sl.registerLazySingleton(() => DevicesCubit(sl(), sl(), sl())); sl.registerFactory(() => RemoteControlCubit(sl())); + + +/// . 路径生成 + sl.registerLazySingleton(() => PathRepositoryImpl()); + sl.registerLazySingleton( + () => GeneratePathUseCaseImpl(sl()), + ); + + /// 6. 认证 (Auth) // --- 关键修改点 1: AuthCubit 必须在 GoRouter 之前注册,并传入参数 --- sl.registerLazySingleton( diff --git a/lib/features/devices/data/models/device_add_path_point_model.dart b/lib/features/devices/data/models/device_add_path_point_model.dart new file mode 100644 index 00000000..00ab59b1 --- /dev/null +++ b/lib/features/devices/data/models/device_add_path_point_model.dart @@ -0,0 +1,16 @@ +class DeviceAddPathPointModel { + final double latitude; + final double longitude; + + DeviceAddPathPointModel({required this.latitude, required this.longitude}); + + Map toJson() => { + 'latitude': latitude, + 'longitude': longitude, + }; + + factory DeviceAddPathPointModel.fromJson(Map json) => DeviceAddPathPointModel( + latitude: json['latitude'], + longitude: json['longitude'], + ); +} diff --git a/lib/features/devices/data/repositories/generate_path_repository_Impl.dart b/lib/features/devices/data/repositories/generate_path_repository_Impl.dart new file mode 100644 index 00000000..6c01b57b --- /dev/null +++ b/lib/features/devices/data/repositories/generate_path_repository_Impl.dart @@ -0,0 +1,30 @@ +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import '../../domain/repositories/path_repository.dart'; +import '../models/device_add_path_point_model.dart'; + +class PathRepositoryImpl implements PathRepository { + final String baseUrl = 'https://your-backend-api.com'; // 后端接口地址 + // 生成路径 + @override + Future> generatePath(List coordinates) async { + final url = Uri.parse('$baseUrl/api/path'); + final headers = {'Content-Type': 'application/json'}; + final body = jsonEncode({ + 'coordinates': coordinates.map((p) => p.toJson()).toList(), + }); + + try { + final response = await http.post(url, headers: headers, body: body); + if (response.statusCode == 200) { + final List jsonData = jsonDecode(response.body)['path']; + return jsonData.map((item) => DeviceAddPathPointModel.fromJson(item)).toList(); + } else { + throw Exception('Failed to load path: ${response.statusCode}'); + } + } catch (e) { + throw Exception('Network error: $e'); + } + } +} diff --git a/lib/features/devices/domain/repositories/path_repository.dart b/lib/features/devices/domain/repositories/path_repository.dart new file mode 100644 index 00000000..f70dddb3 --- /dev/null +++ b/lib/features/devices/domain/repositories/path_repository.dart @@ -0,0 +1,6 @@ +import '../../data/models/device_add_path_point_model.dart'; + +abstract class PathRepository { + // Generate path(打点生成路径规划) + Future> generatePath(List coordinates); +} \ No newline at end of file diff --git a/lib/features/devices/domain/usecases/generate_path_usecase.dart b/lib/features/devices/domain/usecases/generate_path_usecase.dart new file mode 100644 index 00000000..f269b29b --- /dev/null +++ b/lib/features/devices/domain/usecases/generate_path_usecase.dart @@ -0,0 +1,20 @@ +import '../../data/models/device_add_path_point_model.dart'; +import '../repositories/path_repository.dart'; + +abstract class GeneratePathUseCase { + Future> execute(List coordinates); +} + +class GeneratePathUseCaseImpl implements GeneratePathUseCase { + final PathRepository _repository; + + GeneratePathUseCaseImpl(this._repository); + + @override + Future> execute(List coordinates) async { + return await _repository.generatePath(coordinates); + } + + +} +