优化掉核心功能中print打印影响性能的代码用日志对象代替打印

This commit is contained in:
2026-04-15 08:43:39 +08:00
parent 507935166e
commit b25315fc11
13 changed files with 256 additions and 121 deletions

View File

@@ -30,6 +30,7 @@ class AuthCubit extends Cubit<AuthState> {
final AppUserCubit appCubit;
final NetMessageDispatcher dispatcher;
final AuthTcpDatasource _authTcpDatasource;
final ILoggerService _logger = GetIt.I<ILoggerService>();
StreamSubscription? _kickOutSub; // 新增:用于管理监听生命周期
@@ -74,7 +75,7 @@ class AuthCubit extends Cubit<AuthState> {
/// 退出登录 (主动或被动)
Future<void> logout() async {
print("退出登录");
//print("退出登录");
await storage.deleteUser();
tcp.disconnect();
appCubit.clearAuth();
@@ -99,13 +100,13 @@ class AuthCubit extends Cubit<AuthState> {
// }
/// TCP 指令监听
void _listenToAuthResponse() {
print('>>> [AUTH] begin 指令监听:');
_logger.logWithLevel('[AUTH] 监听 TCP 0x12 指令...', level: 'DEBUG');
_kickOutSub?.cancel(); // 防止重复监听
// 直接监听原始数据包,自己处理 JSON 解析(去掉 CRC 字节)
_kickOutSub = dispatcher.onCommand(0x12).listen((packet) {
print('>>> [AUTH] 收到 0x12 原始包,payload 长度=${packet.payload.length}, 内容=${packet.payload}');
_logger.logWithLevel('[AUTH] 获取原始包:$packet', level: 'DEBUG');
_logger.logWithLevel('>>> [AUTH] 收到 0x12 原始包,payload 长度=${packet.payload.length}, 内容=${packet.payload}', level: 'DEBUG');
try {
// 🔥 关键:手动去掉最后 2 个 CRC 字节
String jsonString;
@@ -114,25 +115,23 @@ class AuthCubit extends Cubit<AuthState> {
} else {
jsonString = utf8.decode(packet.payload);
}
print('>>> [AUTH] 去除 CRC 后的 JSON: $jsonString');
_logger.logWithLevel('[AUTH] 获取 JSON: $jsonString', level: 'DEBUG');
final jsonMap = jsonDecode(jsonString);
// print('>>> [AUTH] JSON 解析成功:$jsonMap');
_logger.logWithLevel('[AUTH] 获取 JSON Map: $jsonMap', level: 'DEBUG');
final respond = jsonMap['respond'] ?? '';
if (respond == 'have_logged_in') {
print('>>> [AUTH] ⚠️ 检测到异地登录 (respond=have_logged_in),开始退出...');
_logger.logWithLevel('[AUTH] ⚠️ 检测到异地登录 (respond=have_logged_in),开始退出...', level: 'WARN');
logout();
} else {
// print('>>> [AUTH] ℹ️ 收到其他 0x12 消息,忽略:respond=$respond');
_logger.logWithLevel('[AUTH] ⚠️ 检测到异地登录 (respond=$respond),开始退出...', level: 'WARN');
}
} catch (e) {
//print('>>> [AUTH] ❌ 解析失败:$e');
_logger.logWithLevel('[AUTH] ❌ JSON 解析失败:$e', level: 'ERROR');
}
});
print('>>> [AUTH] ✅ 0x12 监听器已建立完成');
_logger.logWithLevel('[AUTH] 监听 TCP 0x12 指令...', level: 'DEBUG');
}
@@ -146,21 +145,20 @@ class AuthCubit extends Cubit<AuthState> {
/// 🔥 息屏/后台后恢复到前台时的重连方法
Future<void> reconnectAfterResume() async {
print('📱 [AUTH] 检测到应用恢复到前台,检查 TCP 连接状态...');
_logger.logWithLevel('[AUTH] 检测到应用恢复到前台,检查 TCP 连接状态...', level: 'DEBUG');
// 如果 TCP 未连接,则执行重连
if (!tcp.isConnected) {
print('⚠️ [AUTH] TCP 未连接,开始重连...');
_logger.logWithLevel('[AUTH] TCP 未连接,开始重连...',
level: 'DEBUG');
try {
await tcp.connect(host: TCPConsts.TCP_IP, port: TCPConsts.TCP_PORT);
tcp.startHeartbeat(interval: const Duration(seconds: 4));
print('✅ [AUTH] TCP 重连成功!');
_logger.logWithLevel('[AUTH] TCP 重连成功!', level: 'DEBUG');
} catch (e) {
print('❌ [AUTH] TCP 重连失败:$e');
// 可以选择重试或者通知用户
_logger.logWithLevel('[AUTH] TCP 重连失败:$e', level: 'ERROR');
}
} else {
print('✅ [AUTH] TCP 连接正常,无需重连');
_logger.logWithLevel('[AUTH] TCP 已连接,无需重连', level: 'DEBUG');
// 可选:发送一个心跳包确认连接有效
tcp.sendHeartbeat();
}

View File

@@ -15,6 +15,8 @@ import '../../../domain/entities/device_location_entity.dart';
class DeviceHttpDatasourceImpl implements DeviceHttpDatasource {
final Dio dio;
final UserStorage _userStorage; // 🔥 新增字段
final ILoggerService _logger = GetIt.I<ILoggerService>();
// 🔥 修改构造函数,注入 UserStorage
DeviceHttpDatasourceImpl(this.dio, this._userStorage);
@@ -22,7 +24,7 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource {
// 🔥 辅助方法:获取 Token
Future<String?> _getToken() async {
final user = await _userStorage.getUser();
debugPrint('用户信息: $user');
_logger.logWithLevel('用户信息: $user', level: 'INFO');
return user?.token;
}
@@ -94,7 +96,8 @@ class DeviceHttpDatasourceImpl implements DeviceHttpDatasource {
Future<int> switchDevice(String platform, String deviceId) async {
final logger = GetIt.I<ILoggerService>() as SentryLoggerImpl;
final token = await _getToken();
print('用户点击switchDevice方法开始触发: $token');
// print('用户点击switchDevice方法开始触发: $token');
_logger.logWithLevel('用户点击switchDevice方法开始触发', level: 'DEBUG');
logger.logWithLevel('用户点击switchDevice方法开始触发', level: 'DEBUG');
logger.logWithLevel('用户点击switchDevice方法API 请求开始', level: 'INFO', data: {'url': 'https://serviceri.satabot.com/iot/device/switchDevice'});
var response = await dio.post(

View File

@@ -1,7 +1,9 @@
import 'dart:convert';
import 'package:get_it/get_it.dart';
import 'package:maibu_satabot_v2/common.dart';
import '../../../../../core/logging/i_logger_service.dart';
import '../../../../../core/storage/user_storage.dart';
import '../../models/device_add_path_point_model.dart';
import '../path_http_datasource.dart';
@@ -10,21 +12,23 @@ import 'package:logger/logger.dart';
class PathHttpDatasourceImpl implements PathHttpDatasource {
final UserStorage _userStorage;
final ILoggerService _logger = GetIt.I<ILoggerService>();
PathHttpDatasourceImpl(this._userStorage);
@override
Future<List<DeviceAddPathPointModel>> generatePathRaw({required Map<String, dynamic> body}) async {
try {
// 1. 先打印基础信息
print('=== 最终发送给后端的请求体 ===');
print('请求体类型:${body.runtimeType}');
_logger.logWithLevel( '请求体类型:${body.runtimeType}',level: 'INFO');
// 2. 格式化打印JSON(带缩进,清晰展示嵌套结构)
final jsonString = const JsonEncoder.withIndent(' ').convert(body);
final _jsonString = jsonEncode(body);
print('完整JSON请求体:\n$jsonString');
// print('完整JSON请求体:\n$jsonString');
_logger.logWithLevel( '请求体:$_jsonString',level: 'INFO');
// 3. 可选:单独打印holes的JSON(重点关注)
//final holesJson = body['holes'] as List;
@@ -38,9 +42,11 @@ class PathHttpDatasourceImpl implements PathHttpDatasource {
//}
} catch (e) {
// 防止JSON序列化失败导致崩溃
print('打印请求体失败:$e');
//print('打印请求体失败:$e');
_logger.logWithLevel( '打印请求体失败:$e',level: 'ERROR');
// 降级打印原始body(虽然格式乱,但能看基础数据)
print('原始body数据:$body');
// print('原始body数据:$body');
_logger.logWithLevel( '原始body数据:$body',level: 'ERROR');
}
final token = (await _userStorage.getUser())?.token;
@@ -58,7 +64,8 @@ class PathHttpDatasourceImpl implements PathHttpDatasource {
final decoded = jsonDecode(response.body) as Map<String, dynamic>;
if (decoded['success'] == true) {
final pathJson = decoded['data']?['path'];
print('路径数据: $pathJson'); // 调试输出路径数据
// print('路径数据: $pathJson'); // 调试输出路径数据
_logger.logWithLevel( '路径数据: $pathJson',level: 'INFO');
if (pathJson == null) {
throw Exception('API returned null for "path"');
}

View File

@@ -59,7 +59,7 @@ class RoutePlanSendEntity {
byteData.setInt8(offset++, endFlag2); // 0xAB → -85
var uint8list = byteData.buffer.asUint8List();
// 关键:直接返回原始二进制字节(不做任何映射/转换)
print("发送的指令字节数组,$uint8list");
// print("发送的指令字节数组,$uint8list");
return byteData.buffer.asUint8List();
}

View File

@@ -2,6 +2,7 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:fpdart/fpdart.dart';
import 'package:maibu_satabot_v2/core/storage/user_storage.dart';
@@ -9,23 +10,29 @@ import 'package:maibu_satabot_v2/features/devices/domain/entities/device_run_hos
import 'package:maibu_satabot_v2/features/devices/domain/errors/device_failure.dart';
import 'package:maibu_satabot_v2/features/devices/domain/repositories/device_hostrity_work_repository.dart';
import '../../../../core/logging/i_logger_service.dart';
class DeviceHostrityWorkRepositoryImpl implements DeviceHostrityWorkRepositoryRepository {
final Dio client;
final UserStorage userStorage;
final ILoggerService _logger = GetIt.I<ILoggerService>();
DeviceHostrityWorkRepositoryImpl({required this.client, required this.userStorage});
@override
Future<Either<DeviceFailure, List<DeviceRunStatisticsEntity>>> getDeviceHRunStatistics({required String deviceId}) async {
try {
debugPrint('开始获取用户信息...');
// debugPrint('开始获取用户信息...');
_logger.logWithLevel('开始获取用户信息...', level: 'info');
final user = await userStorage.getUser();
if (user == null || user.token == null) {
debugPrint('用户未登录或缺少 token');
// debugPrint('用户未登录或缺少 token');
_logger.logWithLevel('用户未登录或缺少 token', level: 'error');
return Left(DeviceFailure.unauthorized(message: 'User not logged in or token is missing'));
}
final token = user.token!;
debugPrint('用户信息获取成功,Token: $token');
// debugPrint('用户信息获取成功,Token: $token');
_logger.logWithLevel('用户信息获取成功,Token: $token', level: 'info');
final response = await client.get(
'https://serviceri.satabot.com/iot/device/getDeviceRunStatistics?deviceId=$deviceId',
@@ -49,18 +56,22 @@ class DeviceHostrityWorkRepositoryImpl implements DeviceHostrityWorkRepositoryRe
.toList();
return Right(statistics);
} else {
debugPrint('服务器返回错误码: ${jsonBody['code']}');
//debugPrint('服务器返回错误码: ${jsonBody['code']}');
_logger.logWithLevel('服务器返回错误码: ${jsonBody['code']}', level: 'error');
return Left(DeviceFailure.serverError(message: '服务器返回错误码: ${jsonBody['code']}'));
}
} else {
debugPrint('网络请求失败,状态码: ${response.statusCode}');
// debugPrint('网络请求失败,状态码: ${response.statusCode}');
_logger.logWithLevel('网络请求失败,状态码: ${response.statusCode}', level: 'error');
return Left(DeviceFailure.networkError(message: '网络请求失败,状态码: ${response.statusCode}'));
}
} on DioException catch (e) {
debugPrint('Dio 请求失败: ${e.message}');
//debugPrint('Dio 请求失败: ${e.message}');
_logger.logWithLevel('Dio 请求失败: ${e.message}', level: 'error');
return Left(DeviceFailure.networkError(message: e.message ?? '未知错误'));
} catch (e) {
debugPrint('请求过程中发生异常: $e');
// debugPrint('请求过程中发生异常: $e');
_logger.logWithLevel('请求过程中发生异常: $e', level: 'error');
return Left(DeviceFailure.unknownError(message: e.toString()));
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:collection';
import 'package:get_it/get_it.dart';
import 'package:isar_community/isar.dart';
import 'package:maibu_satabot_v2/core/logging/i_logger_service.dart';
import 'package:maibu_satabot_v2/features/devices/data/models/device_add_path_point_model.dart';
@@ -13,6 +14,8 @@ import '../models/route_plan_send_entity.dart';
class RoutePlanningRepositoryImpl implements RoutePlanningRepository {
final TcpClient tcp;
late PathPlanner _planner;
final ILoggerService _logger = GetIt.I<ILoggerService>();
// 🔥 新增:存储 AppState 的引用
dynamic _appState;
@@ -23,7 +26,8 @@ class RoutePlanningRepositoryImpl implements RoutePlanningRepository {
@override
Future<void> startRoutePlanning(Queue<DeviceAddPathPointModel> locationQueue) async {
// 直接传入 DeviceAddPathPointModel 列表(无需转换)
print("[底层开始发送指令了]");
// print("[底层开始发送指令了]");
_logger.log("开始路径规划");
final List<DeviceAddPathPointModel> locations = locationQueue.toList();
_planner.startRoutePlanning(locations);
}
@@ -60,6 +64,7 @@ class RoutePlanningRepositoryImpl implements RoutePlanningRepository {
// true = 使用新的 ACK 握手机制 (将来)
// false = 使用现有逻辑 (现在)
class PathPlanningMode {
static bool useAckHandshake = false; // 默认使用现有逻辑
}
@@ -68,7 +73,7 @@ class PathPlanner {
final Queue<DeviceAddPathPointModel> locationQueue = Queue();
final TcpClient tcpClient;
bool isStart = false;
final ILoggerService _logger = GetIt.I<ILoggerService>();
// 新增:作业控制状态
bool _isPaused = false;
bool _isStopped = false;
@@ -80,7 +85,7 @@ class PathPlanner {
PathPlanner(this.tcpClient);
void sendNextLocation() {
print("[在发送指令sendNextLocation方法中]");
_logger.log("[发送sendNextLocation方法指令]");
// if (isStart && locationQueue.isEmpty) {
// isStart = false;
// print("[track]");
@@ -89,17 +94,19 @@ class PathPlanner {
// }
// 关键检查:暂停或停止时不再发送
if (_isPaused) {
print("⏸️ 当前处于暂停状态,停止发送指令");
_logger.log("[暂停状态],停止发送指令");
return;
}
if (_isStopped || (isStart && locationQueue.isEmpty)) {
isStart = false;
if (_isStopped) {
print("⏹️ 已停止作业,清空队列");
//print("⏹️ 已停止作业,清空队列");
_logger.log("[路径点发送完毕]");
locationQueue.clear(); // 清空剩余队列
} else {
print("[路径点发送完毕]");
//print("[路径点发送完毕]");
_logger.log("[路径点发送完毕]");
}
_isStopped = false; // 重置停止标志
return;
@@ -114,7 +121,8 @@ class PathPlanner {
speed: 1000,
);
print("====Lat:${entity.latitude} ====Lng:${entity.longitude}");
//print("====Lat:${entity.latitude} ====Lng:${entity.longitude}");
_logger.log("[发送指令]");
tcpClient.sendPathPoint( routePlanSendEntity);
isStart = true;
}
@@ -130,43 +138,51 @@ class PathPlanner {
isStart = true;
_isPaused = false; // 🔥 只在第一次调用时重置
_isStopped = false; // 🔥 只在第一次调用时重置
print("[首次加载] 队列长度:${locations.length}");
// print("[首次加载] 队列长度:${locations.length}");
_logger.log("[首次加载] 队列长度:${locations.length}");
} else {
// 🔥 后续调用(来自 Dispatcher)只更新队列,不重置状态
print("[更新队列] 当前处于 ${_isPaused ? '暂停' : _isStopped ? '停止' : '工作'} 状态");
//print("[更新队列] 当前处于 ${_isPaused ? '暂停' : _isStopped ? '停止' : '工作'} 状态");
_logger.log("[更新队列] 当前处于 ${_isPaused ? '暂停' : _isStopped ? '停止' : '工作'} 状态");
if (!_isPaused && !_isStopped) {
// 如果不是暂停/停止状态,才添加新数据
locationQueue.addAll(locations);
}
}
print("[发送指令要转换类型了完成]");
// print("[发送指令要转换类型了完成]");
_logger.log("[发送指令要转换类型了完成]");
// 🔥 关键检查:如果是暂停/停止状态,直接返回
if (_isPaused) {
print("⏸️ 当前处于暂停状态,拒绝发送指令");
// print("⏸️ 当前处于暂停状态,拒绝发送指令");
_logger.log("[暂停状态]");
return;
}
if (_isStopped) {
print("⏹️ 当前处于停止状态,拒绝发送指令");
// print("⏹️ 当前处于停止状态,拒绝发送指令");
_logger.log("[停止状态]");
return;
}
print("[发送指令要转换类型了完成]");
// sendNextLocation();
// 🔥 根据全局开关选择使用哪套发送逻辑
if (PathPlanningConfig.useAckHandshake) {
print("🔥 使用 ACK 握手机制发送路径点");
// print("🔥 使用 ACK 握手机制发送路径点");
_logger.log("[使用 ACK 握手机制发送路径点]");
sendNextLocationWithAck(sl<NetMessageDispatcher>());
} else {
print("🔥 使用现有逻辑发送路径点");
// print("🔥 使用现有逻辑发送路径点");
_logger.log("[使用现有逻辑发送路径点]");
sendNextLocation();
}
}
/// 暂停
void pauseRPWork() {
print("⏸️ 暂停作业,设置_isPaused = true");
//print("⏸️ 暂停作业,设置_isPaused = true");
_logger.log("[暂停作业,设置_isPaused = true]");
_isPaused = true;
var entity = new RoutePlanSendEntity(
@@ -176,12 +192,14 @@ class PathPlanner {
targetLongitude: 0,
speed: 0,
);
print("📡 发送暂停指令到设备...");
// print("📡 发送暂停指令到设备...");
_logger.log("[发送暂停指令到设备...]");
tcpClient.sendDeviceStateChange(entity);
}
/// 恢复
void resumeRPWork() {
print("▶️ 恢复作业,设置_isPaused = false");
//print("▶️ 恢复作业,设置_isPaused = false");
_logger.log("[恢复作业,设置_isPaused = false]");
_isPaused = false;
var entity = new RoutePlanSendEntity(
@@ -191,7 +209,8 @@ class PathPlanner {
targetLongitude: 0,
speed: 0,
);
print("📡 发送恢复指令到设备...");
// print("📡 发送恢复指令到设备...");
_logger.log("[发送恢复指令到设备...]");
tcpClient.sendDeviceStateChange(entity);
// 恢复后继续发送下一个点
@@ -200,7 +219,8 @@ class PathPlanner {
// sendNextLocation();
// }
if (locationQueue.isNotEmpty) {
print("📍 恢复发送下一个路径点");
//print("📍 恢复发送下一个路径点");
_logger.log("[恢复发送下一个路径点]");
if (PathPlanningConfig.useAckHandshake) {
sendNextLocationWithAck(sl<NetMessageDispatcher>());
} else {
@@ -210,12 +230,14 @@ class PathPlanner {
}
/// 停止
void stopRoutePlanning() {
print("⏹️ 停止作业,设置_isStopped = true");
// print("⏹️ 停止作业,设置_isStopped = true");
_logger.log("[停止作业,设置_isStopped = true]");
_isStopped = true;
_isPaused = false; // 清除暂停状态
// 🔥 核心修复:清空队列
print("🗑️ 清空待发送队列,剩余 ${locationQueue.length} 个点");
// print("🗑️ 清空待发送队列,剩余 ${locationQueue.length} 个点");
_logger.log("[清空待发送队列,剩余 ${locationQueue.length} 个点]");
locationQueue.clear();
@@ -228,7 +250,8 @@ class PathPlanner {
targetLongitude: 0,
speed: 0,
);
print("📡 发送停止指令到设备...");
// print("📡 发送停止指令到设备...");
_logger.log("[发送停止指令到设备...]");
tcpClient.sendDeviceStateChange(entity);
// 发送完成工作播报指令
sendWorkCompleteBroadcast();
@@ -243,32 +266,38 @@ class PathPlanner {
targetLongitude: 0,
speed: 0,
);
print("发送完成工作播报指令...");
// print("发送完成工作播报指令...");
_logger.log("[发送完成工作播报指令...]");
tcpClient.sendDeviceStateChange(entity);
}
// 🔥 新增:ACK 握手机制的发送方法 (新模式)
void sendNextLocationWithAck(NetMessageDispatcher dispatcher) {
print("[在发送指令 sendNextLocationWithAck 方法中 - ACK 模式]");
// print("[在发送指令 sendNextLocationWithAck 方法中 - ACK 模式]");
_logger.log("[在发送指令 sendNextLocationWithAck 方法中 - ACK 模式]");
// 🔥 关键检查:如果正在等待 ACK,不要重复发送
if (_waitingForAck) {
print("⏳ 正在等待 ACK 确认,跳过发送");
//print("⏳ 正在等待 ACK 确认,跳过发送");
_logger.log("[正在等待 ACK 确认,跳过发送]");
return;
}
// 🔥 关键检查:暂停或停止时不再发送
if (_isPaused) {
print("⏸️ 当前处于暂停状态,停止发送指令");
//print("⏸️ 当前处于暂停状态,停止发送指令");
_logger.log("[暂停状态]");
return;
}
if (_isStopped || (isStart && locationQueue.isEmpty)) {
isStart = false;
if (_isStopped) {
print("️ 已停止作业,清空队列");
// print("️ 已停止作业,清空队列");
_logger.log("[已停止作业,清空队列]");
locationQueue.clear(); // 清空剩余队列
} else {
print("[路径点发送完毕]");
_logger.log("[路径点发送完毕]");
}
_isStopped = false; // 重置停止标志
return;
@@ -287,14 +316,17 @@ class PathPlanner {
speed: 1000,
);
print("====Lat:${entity.latitude} ====Lng:${entity.longitude}");
//print("====Lat:${entity.latitude} ====Lng:${entity.longitude}");
_logger.log("[发送路径点] Lat:${entity.latitude} Lng:${entity.longitude}");
tcpClient.sendPathPoint( routePlanSendEntity);
isStart = true;
// 🔥 关键:标记为正在等待 ACK
_waitingForAck = true;
dispatcher.setExpectedPointIndex(pointIndex); // 🔥 通知 Dispatcher
print(" 已锁定发送,等待 ACK 确认 (0x02)...");
//sprint(" 已锁定发送,等待 ACK 确认 (0x02)...");
_logger.log("[已锁定发送,等待 ACK 确认 (0x02)...]");
}
}

View File

@@ -2,16 +2,20 @@ import 'dart:async';
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:maibu_satabot_v2/features/devices/domain/entities/running_status_entity.dart';
import 'package:maibu_satabot_v2/features/devices/domain/entities/gps_entity.dart';
import 'package:maibu_satabot_v2/core/network/protocol_decoder.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../../../../core/network/net_message_dispatcher.dart';
import 'device_status_event.dart';
import 'device_status_state.dart';
class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
final NetMessageDispatcher _dispatcher;
final ILoggerService _logger = GetIt.I<ILoggerService>();
// 持有订阅引用,仅在 close 时取消
StreamSubscription? _stringSub;
@@ -38,6 +42,7 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
debugPrint('🔗 [DeviceStatusBloc] 初始化 TCP 数据流订阅(终身有效)');
// 订阅字符串流 (0x02)
_stringSub = _dispatcher.onStringMessage().listen(
(jsonString) {
@@ -63,12 +68,15 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
// );
_isSubscribed = true;
debugPrint('✅ [DeviceStatusBloc] 订阅建立完成,将持续监听数据流');
// debugPrint('✅ [DeviceStatusBloc] 订阅建立完成,将持续监听数据流');
_logger.log('✅ [DeviceStatusBloc] 订阅建立完成,将持续监听数据流');
}
// 🔥 核心修复:重置时仅清空状态,绝对不再触碰订阅关系
Future<void> _handleReset(DeviceStatusReset event, Emitter<DeviceStatusState> emit) async {
debugPrint('🔄 收到重置事件:仅清空状态,保持订阅活跃(不重连)');
// debugPrint('🔄 收到重置事件:仅清空状态,保持订阅活跃(不重连)');
_logger.log('🔄 收到重置事件:仅清空状态,保持订阅活跃(不重连)');
// 只 emit 初始状态,让 UI 清除旧设备的数据(如速度归零、轨迹清除)
emit(DeviceStatusInitial());
@@ -82,7 +90,8 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
Emitter<DeviceStatusState> emit,
) async {
try {
debugPrint('🔍 开始解析数据:${event.jsonString}');
// debugPrint('🔍 开始解析数据:${event.jsonString}');
_logger.log('🔍 开始解析数据:${event.jsonString}');
final fields = event.jsonString.trim().split(',');
if (fields.length < 18) {
@@ -94,10 +103,12 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
final status = RunningStatusEntity.fromFields(fields);
final gps = GPSEntity(status.latitude, status.longitude);
debugPrint('✅ 解析成功,更新状态:Lat=${gps.latitude}, Lng=${gps.longitude}');
//debugPrint('✅ 解析成功,更新状态:Lat=${gps.latitude}, Lng=${gps.longitude}');
_logger.log('✅ 解析成功,更新状态:Lat=${gps.latitude}, Lng=${gps.longitude}');
emit(DeviceStatusUpdated(status, gps));
} catch (e, stack) {
debugPrint('❌ 解析异常:$e\n$stack');
//debugPrint('❌ 解析异常:$e\n$stack');
_logger.log('❌ 解析异常:$e\n$stack');
emit(DeviceStatusError('解析失败:$e'));
}
}
@@ -109,7 +120,8 @@ class DeviceStatusBloc extends Bloc<DeviceStatusEvent, DeviceStatusState> {
try {
final eventStr = event.jsonData['event'] ?? '';
final deviceId = event.jsonData['deviceId'] ?? '未知';
debugPrint('收到推送事件:$eventStr, 设备:$deviceId');
// debugPrint('收到推送事件:$eventStr, 设备:$deviceId');
_logger.log('收到推送事件:$eventStr, 设备:$deviceId');
// 这里可以根据需要 emit 新状态
} catch (e) {
emit(DeviceStatusError('解析推送消息失败:$e'));

View File

@@ -13,6 +13,7 @@ import 'package:maibu_satabot_v2/features/devices/domain/usecases/unbind_device_
import 'package:maibu_satabot_v2/features/devices/domain/usecases/update_devicename_usecase.dart';
import '../../../../core/consts/tcp_consts.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../../../../core/network/tcp/tcp_client.dart';
import '../../data/models/device_add_path_point_model.dart';
import '../../data/models/device_work_area_param_model.dart';
@@ -44,6 +45,9 @@ class DevicesCubit extends Cubit<DevicesState> {
// 🔥 关键:注入全局服务
final PathPlanningService _pathPlanningService;
final ILoggerService _logger = GetIt.I<ILoggerService>();
DevicesCubit(
this.repository,
this._getUserDeviceUseCase,
@@ -115,7 +119,8 @@ class DevicesCubit extends Cubit<DevicesState> {
successCode,
) {
// 核心修复:int 转 bool 条件判断
print('更新设备名称结果代码: $successCode'); // 调试输出结果代码
//print('更新设备名称结果代码: $successCode'); // 调试输出结果代码
_logger.logWithLevel('更新设备名称结果代码: $successCode');
final isSuccess = successCode == 1; // 显式转为 bool
if (isSuccess) {
//final updatedDevices = state.devices?.map((device) {
@@ -218,7 +223,8 @@ class DevicesCubit extends Cubit<DevicesState> {
// 🔥 关键修复 1:先强制断开旧连接!
// 这一步会销毁旧 Socket,清除旧 Listener,防止旧数据继续推送
if (_tcpClient.isConnected) {
debugPrint('🛑 检测到已连接,先断开旧 TCP 连接...');
//debugPrint('🛑 检测到已连接,先断开旧 TCP 连接...');
_logger.logWithLevel('🔥 检测到已连接,先断开旧 TCP 连接...');
_tcpClient.disconnects(forSwitch: true);
// 稍微等待一下,确保底层 Socket 资源释放 (可选,但推荐)
// await Future.delayed(const Duration(milliseconds: 100));
@@ -226,7 +232,8 @@ class DevicesCubit extends Cubit<DevicesState> {
// 🔥 关键修复 2:发起新连接
// connect 方法内部会自动调用 _sendAuthPacket -> 获取设备列表 -> 自动订阅当前选中的设备
debugPrint('🔌 开始重新新连接 TCP,将自动订阅新设备:${device.deviceName}');
// debugPrint('🔌 开始重新新连接 TCP,将自动订阅新设备:${device.deviceName}');
_logger.logWithLevel('🔌 启动重新新连接 TCP,将自动订阅新设备:${device.deviceName}');
await _tcpClient.connectBySwitch(host: TCPConsts.TCP_IP, port: TCPConsts.TCP_PORT, deviceName: device.deviceName);
// 🔥 关键修复 3:重置设备状态 Bloc,清除旧设备图表数据
_deviceStatusBloc.add(DeviceStatusReset());
@@ -347,20 +354,24 @@ class DevicesCubit extends Cubit<DevicesState> {
// 开始路径规划
Future<void> startRoutePlanning(Queue<DeviceAddPathPointModel> locationQueue) async {
print("cubit层开始路径规划");
/// print("cubit层开始路径规划");
_logger.logWithLevel('开始路径规划');
// 清空全局 Service 中的队列
// _routePlanningUseCase.clearLocationQueue();
final List<DeviceAddPathPointModel> pathList = locationQueue.toList();
print('✅ 队列转换为 List,长度:${pathList.length}');
// print('✅ 队列转换为 List,长度:${pathList.length}');
_logger.logWithLevel('队列转换为 List,长度:${pathList.length}');
_pathPlanningService.updateQueue(pathList);
print('✅ 队列更新成功');
//print('✅ 队列更新成功');
_logger.logWithLevel('队列更新成功');
// 开始路径规划
emit(state.copyWith(isLoading: true));
//传入全局的Service 中路径规划队列
Queue<DeviceAddPathPointModel> queue = _pathPlanningService.getQueue();
print('📦 从 Service 获取的队列长度:${queue.length}');
//print('📦 从 Service 获取的队列长度:${queue.length}');
_logger.logWithLevel('从 Service 获取的队列长度:${queue.length}');
final result = await _routePlanningUseCase.startRoutePlanning(queue);
result.fold(
(failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message ?? '路径规划启动失败')),
@@ -407,7 +418,8 @@ class DevicesCubit extends Cubit<DevicesState> {
void setArrivedLocation(double latitude, double longitude) {
emit(state.copyWith(arriLatitude: latitude, arriLongitude: longitude));
print('✅ [DevicesCubit] 监听更新已完成到达位置:Lat=$latitude, Lng=$longitude');
// print('✅ [DevicesCubit] 监听更新已完成到达位置:Lat=$latitude, Lng=$longitude');
_logger.logWithLevel('✅ [DevicesCubit] 监听更新已完成到达位置:Lat=$latitude, Lng=$longitude');
}
//获取已到达的点的经纬度
@@ -418,6 +430,7 @@ class DevicesCubit extends Cubit<DevicesState> {
// 重置已到达记录
void resetArrivedLocation() {
emit(state.copyWith(arriLatitude: null, arriLongitude: null));
print('🔄 [DevicesCubit] 已重置到达位置');
//print('🔄 [DevicesCubit] 已重置到达位置');
_logger.logWithLevel('🔄 [DevicesCubit] 已重置到达位置');
}
}

View File

@@ -1,6 +1,8 @@
// lib/features/devices/domain/services/path_planning_service.dart
import 'dart:collection';
import 'package:flutter/cupertino.dart';
import 'package:get_it/get_it.dart';
import '../../../core/logging/i_logger_service.dart';
import '../data/models/device_add_path_point_model.dart';
class PathPlanningService {
@@ -8,6 +10,8 @@ class PathPlanningService {
factory PathPlanningService() => _instance;
PathPlanningService._internal();
final ILoggerService _logger = GetIt.I<ILoggerService>();
// 🔥 核心:全局唯一的可变队列
final Queue<DeviceAddPathPointModel> locationQueue = Queue();
@@ -18,8 +22,10 @@ class PathPlanningService {
/// 🔥 存:生成路径后立即存储
void updateQueue(List<DeviceAddPathPointModel> locations) {
debugPrint('进入[PathPlanningService]updateQueue方法尝试更新空队列');
_logger.logWithLevel('进入[PathPlanningService]updateQueue方法尝试更新空队列');
if (locations.isEmpty) {
debugPrint('⚠️ [PathPlanningService] 尝试更新空队列');
_logger.logWithLevel('⚠️ [PathPlanningService] 尝试更新空队列');
return;
}
@@ -28,20 +34,26 @@ class PathPlanningService {
currentIndex = 0;
totalCount = locations.length;
debugPrint('✅ [PathPlanningService] 队列已更新,共 $totalCount 个点');
//debugPrint('✅ [PathPlanningService] 队列已更新,共 $totalCount 个点');
_logger.logWithLevel('✅ [PathPlanningService] 队列已更新,共 $totalCount 个点');
}
/// 🔥 取:发送时取出第一个点
DeviceAddPathPointModel? removeFirst() {
if (locationQueue.isEmpty) {
debugPrint('⚠️ [PathPlanningService] 队列为空');
//debugPrint('⚠️ [PathPlanningService] 队列为空');
_logger.logWithLevel('⚠️ [PathPlanningService] 队列为空');
return null;
}
final point = locationQueue.removeFirst();
currentIndex++;
debugPrint(
// debugPrint(
// '📍 [PathPlanningService] 取出第 $currentIndex/$totalCount 个点:'
// '${point.latitude}, ${point.longitude}',
// );
_logger.logWithLevel(
'📍 [PathPlanningService] 取出第 $currentIndex/$totalCount 个点:'
'${point.latitude}, ${point.longitude}',
);
@@ -63,7 +75,8 @@ class PathPlanningService {
isRunning = false;
currentIndex = 0;
totalCount = 0;
debugPrint('🧹 [PathPlanningService] 队列已清空');
//debugPrint('🧹 [PathPlanningService] 队列已清空');
_logger.logWithLevel('🧹 [PathPlanningService] 队列已清空');
}

View File

@@ -23,11 +23,11 @@ class MyCubit extends Cubit<MyState> {
try {
final params = UpdateNameParams(nickName);
final result = await _updateNameUsecase(params);
print("$result 修改名称结构");
//print("$result 修改名称结构");
// 4. 恢复 fold 逻辑,处理 UseCase 返回结果(关键:更新 UI 状态)
result.fold((failure) => emit(state.copyWith(isLoading: false, errorMessage: failure.message ?? '修改昵称失败')), (successCode) {
print("$successCode 修改名称结构");
//print("$successCode 修改名称结构");
final isSuccess = successCode == 200;
if (isSuccess) {
emit(state.copyWith(isLoading: false, errorMessage: '', nickName: nickName));

View File

@@ -2,12 +2,15 @@ import 'dart:ffi';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:get_it/get_it.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../../../../core/storage/user_storage.dart';
class RemoteHttpDatasource {
final Dio _dio;
final UserStorage _userStorage; // 🔥 新增字段
final ILoggerService _logger = GetIt.I<ILoggerService>();
RemoteHttpDatasource(this._dio, this._userStorage);
@@ -44,23 +47,26 @@ class RemoteHttpDatasource {
print("请求权限的数据,$deviceId,");
try {
final responseData = response.data as Map<String, dynamic>;
debugPrint("📊 [HTTP 响应] 完整数据:$responseData");
//debugPrint("📊 [HTTP 响应] 完整数据:$responseData");
_logger.log("📊 [HTTP 响应] 完整数据:$responseData");
// 🔥 关键:先获取响应的 data 字段,再获取 remoteControl
final dataField = responseData['data'] as Map<String, dynamic>?;
if (dataField != null) {
final bool hasRemoteControl = dataField['remoteControl'] as bool? ?? false;
debugPrint("✅ [HTTP 响应] remoteControl=$hasRemoteControl");
//debugPrint("✅ [HTTP 响应] remoteControl=$hasRemoteControl");
_logger.log("✅ [HTTP 响应] remoteControl=$hasRemoteControl");
// 🔥 直接返回 remoteControl 的布尔值
return hasRemoteControl;
} else {
debugPrint("❌ [HTTP 响应] 缺少 data 字段");
//debugPrint("❌ [HTTP 响应] 缺少 data 字段");
_logger.log("❌ [HTTP 响应] 缺少 data 字段");
return false;
}
} catch (e) {
debugPrint('❌ [RemoteHttp] 解析响应失败:$e');
// debugPrint('❌ [RemoteHttp] 解析响应失败:$e');
_logger.log('❌ [RemoteHttp] 解析响应失败:$e');
return false;
}
}

View File

@@ -3,7 +3,9 @@ import 'dart:convert';
import 'dart:ffi';
import 'package:flutter/cupertino.dart';
import 'package:get_it/get_it.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../../../../core/network/protocol_decoder.dart';
import '../../../../core/network/tcp/tcp_client.dart';
import '../../../../core/protocol/machine_protocol_codec.dart';
@@ -19,6 +21,7 @@ class RemoteControlRepositoryImpl implements RemoteControlRepository {
final DiffSteerUseCase _diffSteer;
final RemoteHttpDatasource _remoteHttp;
final RemoteTcpDatasource _remoteTcp;
final ILoggerService _logger = GetIt.I<ILoggerService>();
RemoteControlRepositoryImpl(this._tcpClient, this._diffSteer, this._remoteHttp, this._remoteTcp);
@@ -34,9 +37,13 @@ class RemoteControlRepositoryImpl implements RemoteControlRepository {
final speeds = _diffSteer.calculate(status.originX, status.originY);
debugPrint('🎮 [摇杆数据] originX: ${status.originX}, originY: ${status.originY}');
debugPrint('⚙️ [电机速度] left: ${speeds['left']}, right: ${speeds['right']}');
debugPrint('🚨 [急停状态] emergency: ${status.isEmergency ? 1 : 0}');
//debugPrint('🎮 [摇杆数据] originX: ${status.originX}, originY: ${status.originY}');
_logger.logWithLevel('⚙️ [电机速度] left: ${speeds['left']}, right: ${speeds['right']}');
//debugPrint('⚙️ [电机速度] left: ${speeds['left']}, right: ${speeds['right']}');
_logger.logWithLevel('⚙️ [电机速度] left: ${speeds['left']}, right: ${speeds['right']}');
//debugPrint('🚨 [急停状态] emergency: ${status.isEmergency ? 1 : 0}');
_logger.logWithLevel('🚨 [急停状态] emergency: ${status.isEmergency ? 1 : 0}');
// 2. 调用 Codec:仅生成协议要求的 8 字节 Payload 负载数据
final payload = MachineProtocolCodec.encodeRemoteControlPayload(
@@ -65,10 +72,12 @@ class RemoteControlRepositoryImpl implements RemoteControlRepository {
Future<bool> requestControlPermission( String deviceName, String deviceId) async {
try {
_remoteTcp.sendSwitchControlRequest(deviceName);
debugPrint('🔑 [RemoteControl] TCP已发送权限请求');
// debugPrint('🔑 [RemoteControl] TCP已发送权限请求');
_logger.logWithLevel('🔑 [RemoteControl] TCP已发送权限请求');
return await _remoteHttp.requestRemoteControlViaHttp(deviceName, deviceId);
} catch (e) {
debugPrint('❌ [RemoteControl] 权限请求失败:$e');
//sdebugPrint('❌ [RemoteControl] 权限请求失败:$e');
_logger.logWithLevel('❌ [RemoteControl] 权限请求失败:$e');
rethrow;
}
}

View File

@@ -7,9 +7,11 @@ import 'package:dart_ping/dart_ping.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:maibu_satabot_v2/features/remote_control/data/models/running_status_model.dart';
import 'package:maibu_satabot_v2/features/remote_control/presentation/bloc/remote_control_state.dart';
import '../../../../core/logging/i_logger_service.dart';
import '../../../../core/network/net_message_dispatcher.dart';
import '../../../devices/domain/entities/running_status_entity.dart';
import '../../domain/entities/machine_control_status_entity.dart';
@@ -25,6 +27,8 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
StreamSubscription? _stringMessageSub; //
static const platform = MethodChannel('com.maibu.satabot/ping');
int _currentPing = 50;
final ILoggerService _logger = GetIt.I<ILoggerService>();
RemoteControlCubit(this._repository, this._requestControlPermissionUseCase, this.dispatcher)
@@ -39,26 +43,32 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
}
void _initStringMessageListener() {
print('>>> [RemoteControl] begin 初始化 0x02 字符串监听器');
//print('>>> [RemoteControl] begin 初始化 0x02 字符串监听器');
_logger.logWithLevel('>>> [RemoteControl] begin 初始化 0x02 字符串监听器');
_stringMessageSub?.cancel();
_stringMessageSub = dispatcher.onStringMessage().listen((message) async {
print('>>> [RemoteControl] 收到 0x02 字符串推送:$message');
// print('>>> [RemoteControl] 收到 0x02 字符串推送:$message');
_logger.logWithLevel('>>> [RemoteControl] 收到 0x02 字符串推送:$message');
if (message.isEmpty) {
print('⚠️ [RemoteControl] 消息为空,跳过解析');
//print('⚠️ [RemoteControl] 消息为空,跳过解析');
_logger.logWithLevel('⚠️ [RemoteControl] 消息为为空,跳过解析');
return;
}
try {
// 🔥 关键:使用与 DeviceStatusBloc 相同的解析方法
print('>>> [RemoteControl] 🔍 开始解析数据(使用 fromFields)...');
// print('>>> [RemoteControl] 🔍 开始解析数据(使用 fromFields)...');
_logger.logWithLevel('>>> [RemoteControl] 🔍 开始解析数据(使用 fromFields)...');
final fields = message.trim().split(',');
print('>>> [RemoteControl] 字段数量:${fields.length}');
//print('>>> [RemoteControl] 字段数量:${fields.length}');
_logger.logWithLevel('>>> [RemoteControl] 字段数量:${fields.length}');
if (fields.length < 18) {
print('⚠️ [RemoteControl] 字段不足:${fields.length},期望 ≥18');
//print('⚠️ [RemoteControl] 字段不足:${fields.length},期望 ≥18');
_logger.logWithLevel('⚠️ [RemoteControl] 字段不足:${fields.length},期望 ≥18');
return;
}
@@ -83,13 +93,15 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
} catch (e, stackTrace) {
print('>>> [RemoteControl] ❌ 解析失败:$e');
// print('>>> [RemoteControl] ❌ 解析失败:$e');
_logger.logWithLevel('>>> [RemoteControl] ❌ 解析失败:$e');
// print('>>> [RemoteControl] ❌ 堆栈跟踪:$stackTrace');
// print('>>> [RemoteControl] ❌ 原始消息:$message');
}
});
print('>>> [RemoteControl] ✅ 0x02 字符串监听器已建立完成');
//print('>>> [RemoteControl] ✅ 0x02 字符串监听器已建立完成');
_logger.logWithLevel('>>> [RemoteControl] ✅ 0x02 字符串监听器已建立完成');
}
@@ -109,7 +121,8 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
battery: int.tryParse(newStatus.battery) ?? 0,
));
debugPrint('✅ [更新运行状态] 电压:${newStatus.voltage}V, 电量:${newStatus.battery}%');
// debugPrint('✅ [更新运行状态] 电压:${newStatus.voltage}V, 电量:${newStatus.battery}%');
_logger.logWithLevel('✅ [更新运行状态] 电压:${newStatus.voltage}V, 电量:${newStatus.battery}%');
}
}
@@ -124,11 +137,13 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
// });
// }
Future<void> _initPacketListener() async {
print('>>> [RemoteControl] begin 初始化 0x12 监听器');
//print('>>> [RemoteControl] begin 初始化 0x12 监听器');
_logger.logWithLevel('>>> [RemoteControl] begin 0x12 监听器');
_kickOutSub?.cancel(); // 防止重复监听
_kickOutSub = dispatcher.onCommand(0x12).listen((packet) {
print('>>> [RemoteControl] 收到 0x12 原始包,payload 长度=${packet.payload.length}');
//print('>>> [RemoteControl] 收到 0x12 原始包,payload 长度=${packet.payload.length}');
_logger.logWithLevel('>>> [RemoteControl] 收到 0x12 原始包,payload 长度=${packet.payload.length}');
try {
// 🔥 关键:手动去掉最后 2 个 CRC 字节
@@ -139,7 +154,8 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
jsonString = utf8.decode(packet.payload);
}
print('>>> [RemoteControl] 去除 CRC 后的 JSON: $jsonString');
//print('>>> [RemoteControl] 去除 CRC 后的 JSON: $jsonString');
_logger.logWithLevel('>>> [RemoteControl] 去除 CRC 后的 JSON: $jsonString');
final jsonMap = jsonDecode(jsonString);
@@ -148,12 +164,14 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
final platform = jsonMap['platform'];
final respondData = jsonMap['respond'];
print('>>> [RemoteControl] 📋 requestType=$requestType, platform=$platform');
//print('>>> [RemoteControl] 📋 requestType=$requestType, platform=$platform');
_logger.logWithLevel('>>> [RemoteControl] 📋 requestType=$requestType, platform=$platform');
// 情况 1: 响应格式 - {"respond":{"switchResult":true,"deviceId":"...","holder":"you"}}
if (respondData != null && respondData is Map) {
final switchResult = respondData['switchResult'];
print('>>> [RemoteControl] 📊 收到切换结果响应:switchResult = $switchResult');
//print('>>> [RemoteControl] 📊 收到切换结果响应:switchResult = $switchResult');
_logger.logWithLevel('>>> [RemoteControl] 📊 收到切换结果响应:switchResult = $switchResult');
if (!isClosed) {
if (switchResult == true) {
@@ -171,33 +189,39 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
else if (requestType == 'switch_control') {
// 🔥 关键判断:只有当是其他平台(web)请求时才弹窗
if (platform != null && platform.toString().toLowerCase() != 'app') {
print('>>> [RemoteControl] 🚨 $platform 端请求控制权,打开弹窗询问用户');
//print('>>> [RemoteControl] 🚨 $platform 端请求控制权,打开弹窗询问用户');
_logger.logWithLevel('>>> [RemoteControl] 🚨 $platform 端请求控制权,打开弹窗询问用户');
if (!isClosed) {
emit(state.copyWith(showPermissionRequestDialog: true));
}
} else {
print('>>> [RemoteControl] ℹ️ APP 自己的请求回显,忽略不弹窗');
//print('>>> [RemoteControl] ℹ️ APP 自己的请求回显,忽略不弹窗');
_logger.logWithLevel('>>> [RemoteControl] ℹ️ APP 自己的请求回显,忽略不弹窗');
}
}
// 情况 3: 异地登录通知 - {"request":"have_logged_in",...}
else if (requestType == 'have_logged_in') {
print('>>> [RemoteControl] ⚠️ 检测到异地登录,打开弹窗提示');
//print('>>> [RemoteControl] ⚠️ 检测到异地登录,打开弹窗提示');
_logger.logWithLevel('>>> [RemoteControl] ⚠️ 检测到异地登录,打开弹窗提示');
if (!isClosed) {
emit(state.copyWith(showPermissionRequestDialog: true));
}
}
else {
print('>>> [RemoteControl] ℹ️ 未知类型的 0x12 包,忽略');
// print('>>> [RemoteControl] ℹ️ 未知类型的 0x12 包,忽略');
_logger.logWithLevel('>>> [RemoteControl] ℹ️ 未知类型的 0x12 包,忽略');
}
} catch (e) {
print('>>> [RemoteControl] ❌ 解析失败:$e');
//print('>>> [RemoteControl] ❌ 解析失败:$e');
_logger.logWithLevel('>>> [RemoteControl] ❌ 解析失败:$e');
}
});
final c = getNetworkDelay();
emit(state.copyWith(
ping: await c, // 这里直接使用异步返回的数值
));
print('>>> [RemoteControl] ✅ 0x12 监听器已建立完成');
//print('>>> [RemoteControl] ✅ 0x12 监听器已建立完成');
_logger.logWithLevel('>>> [RemoteControl] ✅ 0x12 监听器已建立完成');
}
@@ -222,7 +246,8 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
// 4. 更新功能开关 (比如割刀速度、灯光、点火等)
void updateFunction({int? mower, int? lift, int? ignition, bool? emergency}) {
debugPrint('🔧 [updateFunction] 调用 - mower: $mower, lift: $lift, ignition: $ignition, emergency: $emergency');
// debugPrint('🔧 [updateFunction] 调用 - mower: $mower, lift: $lift, ignition: $ignition, emergency: $emergency');
_logger.logWithLevel('🔧 [updateFunction] 调用 - mower: $mower, lift: $lift, ignition: $ignition, emergency: $emergency');
final updatedEntity = state.controlEntity.copyWith(
mower: mower,
lift: lift,
@@ -235,6 +260,7 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
isEmergency: emergency ?? state.isEmergency,
));
debugPrint('✅ [updateFunction] 状态已更新并 emit');
_logger.logWithLevel('✅ [updateFunction] 状态已更新并 emit');
}
void updateOriginY(int y) {
@@ -322,14 +348,16 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
// 3. 处理结果
result.fold(
(failure) {
print('❌ [RemoteControl] 请求控制权限失败:${failure.message}');
//print('❌ [RemoteControl] 请求控制权限失败:${failure.message}');
_logger.logWithLevel('❌ [RemoteControl] 请求控制权限失败:${failure.message}');
// 可以在这里显示错误提示或重新打开弹窗
emit(state.copyWith(showPermissionRequestDialog: true));
},
(success) {
// 更新状态
print('✅ [RemoteControl] 请求控制权限成功:$success');
//print('✅ [RemoteControl] 请求控制权限成功:$success');
_logger.logWithLevel('✅ [RemoteControl] 请求控制权限成功:$success');
///处理result
if(success){
emit(state.copyWith(hasPermission: true));
@@ -343,12 +371,14 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
}
/// 发送底盘指令
void sendChassisCommand(int i) {
debugPrint(' [底盘指令] ${i}');
// debugPrint(' [底盘指令] ${i}');
_logger.logWithLevel(' [底盘指令] ${i}');
updateFunction(lift: i);
}
/// 发送割刀指令
void sendMowerCommand(int i) {
debugPrint(' [割刀指令] ${i}');
// debugPrint(' [割刀指令] ${i}');
_logger.logWithLevel(' [割刀指令] ${i}');
updateFunction(mower: i);
}
/// 发送点火指令
@@ -356,6 +386,7 @@ class RemoteControlCubit extends Cubit<RemoteControlState> {
//void updateFunction({int? mower, int? lift, int? ignition, bool? emergency})
// updateFunction(mower:0, lift: 0, ignition: i, emergency: false);
debugPrint(' [点火指令] ${i}');
_logger.logWithLevel(' [点火指令] ${i}');
updateFunction(ignition: i);
}
// 发送障碍物识别指令