Merge branch 'feature/my' of http://1.95.137.212:57001/APP/FlutterApp into feature/my
This commit is contained in:
@@ -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";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,12 @@ 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';
|
||||
import '../network/dio_client.dart';
|
||||
@@ -102,9 +106,19 @@ Future<void> 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()));
|
||||
|
||||
|
||||
|
||||
/// . 路径生成
|
||||
sl.registerLazySingleton<PathRepository>(() => PathRepositoryImpl());
|
||||
sl.registerLazySingleton<GeneratePathUseCase>(
|
||||
() => GeneratePathUseCaseImpl(sl<PathRepository>()),
|
||||
);
|
||||
|
||||
|
||||
/// 6. 认证 (Auth)
|
||||
// --- 关键修改点 1: AuthCubit 必须在 GoRouter 之前注册,并传入参数 ---
|
||||
sl.registerLazySingleton(
|
||||
|
||||
@@ -5,4 +5,7 @@ abstract class DeviceHttpDatasource {
|
||||
Future<int> bindDevice(String deviceId, String deviceAlias);
|
||||
Future<int> unbindDevice(String deviceId);
|
||||
Future<int> switchDevice(String platform, String deviceId);
|
||||
|
||||
Future<dynamic> getDeviceLocation(String username) async {}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -78,4 +80,45 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource {
|
||||
// TODO: implement unbindDevice
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<dynamic> getDeviceLocation(String deviceame) async {
|
||||
// TODO: implement getDeviceLocation
|
||||
try {
|
||||
// 发起 GET 请求
|
||||
final response = await dio.get(
|
||||
'https://serviceri.satabot.com/iot/device/userDevice',
|
||||
queryParameters: {'tenantName': deviceame},
|
||||
// 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']; // 返回设备数据
|
||||
final locationData = data['data'];// 假设数据结构,测试时候如有不妥就修改结果的实例化
|
||||
return DeviceLocationEntity(
|
||||
deviceName: locationData['deviceName'],
|
||||
latitude: locationData['latitude'],
|
||||
longitude: locationData['longitude'],
|
||||
);
|
||||
|
||||
} else {
|
||||
throw Exception(data['msg'] ?? '业务异常');
|
||||
}
|
||||
} else {
|
||||
throw Exception('网络请求失败: ${response.statusCode}');
|
||||
}
|
||||
} catch (e) {
|
||||
throw Exception('获取设备位置失败: $e');
|
||||
}
|
||||
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
class DeviceAddPathPointModel {
|
||||
final double latitude;
|
||||
final double longitude;
|
||||
|
||||
DeviceAddPathPointModel({required this.latitude, required this.longitude});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'latitude': latitude,
|
||||
'longitude': longitude,
|
||||
};
|
||||
|
||||
factory DeviceAddPathPointModel.fromJson(Map<String, dynamic> json) => DeviceAddPathPointModel(
|
||||
latitude: json['latitude'],
|
||||
longitude: json['longitude'],
|
||||
);
|
||||
}
|
||||
@@ -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<Either<DeviceFailure, DeviceLocationEntity>>getDeviceLocation(String username) async {
|
||||
// TODO: implement getDeviceLocation
|
||||
var result = await _deviceHttpDatasource.getDeviceLocation(username);
|
||||
return Right(result);
|
||||
// throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<List<DeviceAddPathPointModel>> generatePath(List<DeviceAddPathPointModel> 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<dynamic> 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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
@@ -11,4 +11,6 @@ abstract class DeviceHostrityWorkRepositoryRepository {
|
||||
required String deviceId,
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Either<DeviceFailure, DeviceLocationEntity>> getDeviceLocation(String username);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import '../../data/models/device_add_path_point_model.dart';
|
||||
|
||||
abstract class PathRepository {
|
||||
// Generate path(打点生成路径规划)
|
||||
Future<List<DeviceAddPathPointModel>> generatePath(List<DeviceAddPathPointModel> coordinates);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import '../../data/models/device_add_path_point_model.dart';
|
||||
import '../repositories/path_repository.dart';
|
||||
|
||||
abstract class GeneratePathUseCase {
|
||||
Future<List<DeviceAddPathPointModel>> execute(List<DeviceAddPathPointModel> coordinates);
|
||||
}
|
||||
|
||||
class GeneratePathUseCaseImpl implements GeneratePathUseCase {
|
||||
final PathRepository _repository;
|
||||
|
||||
GeneratePathUseCaseImpl(this._repository);
|
||||
|
||||
@override
|
||||
Future<List<DeviceAddPathPointModel>> execute(List<DeviceAddPathPointModel> coordinates) async {
|
||||
return await _repository.generatePath(coordinates);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Either<DeviceFailure, DeviceLocationEntity>> call(String Devicename) async {
|
||||
return await repository.getDeviceLocation(Devicename);
|
||||
}
|
||||
}
|
||||
@@ -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<DevicesState> {
|
||||
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<void> 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<DevicesState> {
|
||||
|
||||
emit(state.copyWith(devices: newList, selectedDevice: newSelected));
|
||||
}
|
||||
|
||||
// 切换设备
|
||||
Future<void> switchDevice(DeviceEntity device) async {
|
||||
// 保持现有列表,只改 loading
|
||||
emit(state.copyWith(isLoading: true));
|
||||
@@ -75,4 +76,19 @@ 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);
|
||||
result.fold(
|
||||
(failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message)),
|
||||
(location) => emit(state.copyWith(
|
||||
isLoading: false,
|
||||
deviceLatitude: location.latitude,
|
||||
deviceLongitude: location.longitude,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<Object?> get props => [devices, selectedDevice, isLoading, errorMessage];
|
||||
List<Object?> get props => [devices, selectedDevice, isLoading,
|
||||
errorMessage,
|
||||
deviceLatitude,
|
||||
deviceLongitude,
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user