路径规划修复
This commit is contained in:
@@ -16,17 +16,17 @@ class RoutePlanningRepositoryImpl implements RoutePlanningRepository {
|
||||
late PathPlanner _planner;
|
||||
final ILoggerService _logger = GetIt.I<ILoggerService>();
|
||||
|
||||
|
||||
// 🔥 新增:存储 AppState 的引用
|
||||
dynamic _appState;
|
||||
|
||||
RoutePlanningRepositoryImpl({required this.tcp}) { // ✅ 加 {required} 和类型注解
|
||||
RoutePlanningRepositoryImpl({required this.tcp}) {
|
||||
// ✅ 加 {required} 和类型注解
|
||||
_planner = PathPlanner(tcp);
|
||||
}
|
||||
@override
|
||||
Future<void> startRoutePlanning(Queue<DeviceAddPathPointModel> locationQueue) async {
|
||||
// 直接传入 DeviceAddPathPointModel 列表(无需转换)
|
||||
// print("[底层开始发送指令了]");
|
||||
// print("[底层开始发送指令了]");
|
||||
_logger.log("开始路径规划");
|
||||
final List<DeviceAddPathPointModel> locations = locationQueue.toList();
|
||||
_planner.startRoutePlanning(locations);
|
||||
@@ -55,6 +55,7 @@ class RoutePlanningRepositoryImpl implements RoutePlanningRepository {
|
||||
// TODO: implement getCurrentAppState
|
||||
return _appState;
|
||||
}
|
||||
|
||||
void setAppState(dynamic state) {
|
||||
_appState = state;
|
||||
}
|
||||
@@ -64,8 +65,7 @@ class RoutePlanningRepositoryImpl implements RoutePlanningRepository {
|
||||
// true = 使用新的 ACK 握手机制 (将来)
|
||||
// false = 使用现有逻辑 (现在)
|
||||
class PathPlanningMode {
|
||||
|
||||
static bool useAckHandshake = false; // 默认使用现有逻辑
|
||||
static bool useAckHandshake = false; // 默认使用现有逻辑
|
||||
}
|
||||
|
||||
// PathPlanner
|
||||
@@ -78,9 +78,8 @@ class PathPlanner {
|
||||
bool _isPaused = false;
|
||||
bool _isStopped = false;
|
||||
// 新增:ACK 握手状态 (仅新模式使用)
|
||||
bool _waitingForAck = false; // 是否正在等待 ACK 确认
|
||||
int _currentPointIndex = 0; // 🔥 当前发送的点编号(从 0 开始递增)
|
||||
|
||||
bool _waitingForAck = false; // 是否正在等待 ACK 确认
|
||||
int _currentPointIndex = 0; // 🔥 当前发送的点编号(从 0 开始递增)
|
||||
|
||||
PathPlanner(this.tcpClient);
|
||||
|
||||
@@ -102,7 +101,7 @@ class PathPlanner {
|
||||
isStart = false;
|
||||
if (_isStopped) {
|
||||
//print("⏹️ 已停止作业,清空队列");
|
||||
_logger.log("[路径点发送完毕]");
|
||||
_logger.log("[路径点发送完毕] 停止");
|
||||
locationQueue.clear(); // 清空剩余队列
|
||||
} else {
|
||||
//print("[路径点发送完毕]");
|
||||
@@ -123,10 +122,11 @@ class PathPlanner {
|
||||
|
||||
//print("====Lat:${entity.latitude} ====Lng:${entity.longitude}");
|
||||
_logger.log("[发送指令]");
|
||||
tcpClient.sendPathPoint( routePlanSendEntity);
|
||||
tcpClient.sendPathPoint(routePlanSendEntity);
|
||||
isStart = true;
|
||||
}
|
||||
/// 开始
|
||||
|
||||
/// 开始
|
||||
void startRoutePlanning(List<DeviceAddPathPointModel> locations) {
|
||||
/// locationQueue.addAll(locations);
|
||||
/// isStart = true;
|
||||
@@ -138,30 +138,36 @@ class PathPlanner {
|
||||
isStart = true;
|
||||
_isPaused = false; // 🔥 只在第一次调用时重置
|
||||
_isStopped = false; // 🔥 只在第一次调用时重置
|
||||
// print("[首次加载] 队列长度:${locations.length}");
|
||||
// print("[首次加载] 队列长度:${locations.length}");
|
||||
_logger.log("[首次加载] 队列长度:${locations.length}");
|
||||
} else {
|
||||
// 🔥 后续调用(来自 Dispatcher)只更新队列,不重置状态
|
||||
//print("[更新队列] 当前处于 ${_isPaused ? '暂停' : _isStopped ? '停止' : '工作'} 状态");
|
||||
_logger.log("[更新队列] 当前处于 ${_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;
|
||||
}
|
||||
@@ -169,47 +175,36 @@ class PathPlanner {
|
||||
// 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");
|
||||
_logger.log("[暂停作业,设置_isPaused = true]");
|
||||
_isPaused = true;
|
||||
|
||||
var entity = new RoutePlanSendEntity(
|
||||
commandType: 0x01,
|
||||
pointCounts: 2,
|
||||
targetLatitude: 0,
|
||||
targetLongitude: 0,
|
||||
speed: 0,
|
||||
);
|
||||
// print("📡 发送暂停指令到设备...");
|
||||
var entity = new RoutePlanSendEntity(commandType: 0x01, pointCounts: 2, targetLatitude: 0, targetLongitude: 0, speed: 0);
|
||||
// print("📡 发送暂停指令到设备...");
|
||||
_logger.log("[发送暂停指令到设备...]");
|
||||
tcpClient.sendDeviceStateChange(entity);
|
||||
}
|
||||
|
||||
/// 恢复
|
||||
void resumeRPWork() {
|
||||
//print("▶️ 恢复作业,设置_isPaused = false");
|
||||
_logger.log("[恢复作业,设置_isPaused = false]");
|
||||
_isPaused = false;
|
||||
|
||||
var entity = new RoutePlanSendEntity(
|
||||
commandType: 0x01,
|
||||
pointCounts: 3,
|
||||
targetLatitude: 0,
|
||||
targetLongitude: 0,
|
||||
speed: 0,
|
||||
);
|
||||
// print("📡 发送恢复指令到设备...");
|
||||
var entity = new RoutePlanSendEntity(commandType: 0x01, pointCounts: 3, targetLatitude: 0, targetLongitude: 0, speed: 0);
|
||||
// print("📡 发送恢复指令到设备...");
|
||||
_logger.log("[发送恢复指令到设备...]");
|
||||
tcpClient.sendDeviceStateChange(entity);
|
||||
|
||||
@@ -228,52 +223,38 @@ 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();
|
||||
|
||||
|
||||
|
||||
|
||||
var entity = new RoutePlanSendEntity(
|
||||
commandType: 0x01,
|
||||
pointCounts: 0,
|
||||
targetLatitude: 0,
|
||||
targetLongitude: 0,
|
||||
speed: 0,
|
||||
);
|
||||
// print("📡 发送停止指令到设备...");
|
||||
_logger.log("[发送停止指令到设备...]");
|
||||
var entity = new RoutePlanSendEntity(commandType: 0x01, pointCounts: 0, targetLatitude: 0, targetLongitude: 0, speed: 0);
|
||||
// print("📡 发送停止指令到设备...");
|
||||
_logger.log("[发送停止指令到设备...] 按下停止按钮");
|
||||
tcpClient.sendDeviceStateChange(entity);
|
||||
// 发送完成工作播报指令
|
||||
sendWorkCompleteBroadcast();
|
||||
//sendWorkCompleteBroadcast();
|
||||
}
|
||||
|
||||
//发送完成工作播报指令
|
||||
void sendWorkCompleteBroadcast() {
|
||||
var entity = new RoutePlanSendEntity(
|
||||
commandType: 0x01,
|
||||
pointCounts: 0xFF,
|
||||
targetLatitude: 0,
|
||||
targetLongitude: 0,
|
||||
speed: 0,
|
||||
);
|
||||
// print("发送完成工作播报指令...");
|
||||
var entity = new RoutePlanSendEntity(commandType: 0x01, pointCounts: 0xFF, targetLatitude: 0, targetLongitude: 0, speed: 0);
|
||||
// print("发送完成工作播报指令...");
|
||||
_logger.log("[发送完成工作播报指令...]");
|
||||
tcpClient.sendDeviceStateChange(entity);
|
||||
}
|
||||
|
||||
// 🔥 新增:ACK 握手机制的发送方法 (新模式)
|
||||
// 🔥 新增:ACK 握手机制的发送方法 (新模式)
|
||||
void sendNextLocationWithAck(NetMessageDispatcher dispatcher) {
|
||||
// print("[在发送指令 sendNextLocationWithAck 方法中 - ACK 模式]");
|
||||
// print("[在发送指令 sendNextLocationWithAck 方法中 - ACK 模式]");
|
||||
_logger.log("[在发送指令 sendNextLocationWithAck 方法中 - ACK 模式]");
|
||||
// 🔥 关键检查:如果正在等待 ACK,不要重复发送
|
||||
if (_waitingForAck) {
|
||||
@@ -292,7 +273,7 @@ class PathPlanner {
|
||||
if (_isStopped || (isStart && locationQueue.isEmpty)) {
|
||||
isStart = false;
|
||||
if (_isStopped) {
|
||||
// print("️ 已停止作业,清空队列");
|
||||
// print("️ 已停止作业,清空队列");
|
||||
_logger.log("[已停止作业,清空队列]");
|
||||
locationQueue.clear(); // 清空剩余队列
|
||||
} else {
|
||||
@@ -318,17 +299,13 @@ class PathPlanner {
|
||||
|
||||
//print("====Lat:${entity.latitude} ====Lng:${entity.longitude}");
|
||||
_logger.log("[发送路径点] Lat:${entity.latitude} Lng:${entity.longitude}");
|
||||
tcpClient.sendPathPoint( routePlanSendEntity);
|
||||
tcpClient.sendPathPoint(routePlanSendEntity);
|
||||
isStart = true;
|
||||
|
||||
// 🔥 关键:标记为正在等待 ACK
|
||||
_waitingForAck = true;
|
||||
dispatcher.setExpectedPointIndex(pointIndex); // 🔥 通知 Dispatcher
|
||||
dispatcher.setExpectedPointIndex(pointIndex); // 🔥 通知 Dispatcher
|
||||
//sprint(" 已锁定发送,等待 ACK 确认 (0x02)...");
|
||||
_logger.log("[已锁定发送,等待 ACK 确认 (0x02)...]");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'dart:async';
|
||||
/// 轨迹模式枚举
|
||||
enum TPMode {
|
||||
NAVIGATION, // 导航模式:绘制规划已完成路径和当前路径
|
||||
LOCATION, // 定位模式:仅绘制当前点
|
||||
LOCATION, // 定位模式:仅绘制当前点(永远只有1个)
|
||||
TRACK, // 轨迹模式:实时绘制历史轨迹
|
||||
}
|
||||
|
||||
@@ -19,58 +19,46 @@ enum TPAction {
|
||||
class TryLock {
|
||||
bool _locked = false;
|
||||
|
||||
/// 尝试获取锁
|
||||
/// return: true-获取成功,false-已被锁定
|
||||
bool tryLock() {
|
||||
if (_locked) return false;
|
||||
_locked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 释放锁
|
||||
void release() {
|
||||
_locked = false;
|
||||
}
|
||||
|
||||
/// 检查是否已锁定
|
||||
bool get isLocked => _locked;
|
||||
}
|
||||
|
||||
// ======================== 环形队列实现 ========================
|
||||
class CircQueue<T> {
|
||||
final int capacity; // 队列容量
|
||||
final List<T?> buffer; // 存储缓冲区
|
||||
int head = 0; // 队头索引
|
||||
int tail = 0; // 队尾索引
|
||||
bool isFull = false; // 队列满标志
|
||||
final bool deepCopy; // 是否深拷贝元素
|
||||
final int maxMemoryBytes; // 最大内存限制(字节)
|
||||
int currentMemoryBytes = 0; // 当前已使用内存
|
||||
final int capacity;
|
||||
final List<T?> buffer;
|
||||
int head = 0;
|
||||
int tail = 0;
|
||||
bool isFull = false;
|
||||
final bool deepCopy;
|
||||
final int maxMemoryBytes;
|
||||
int currentMemoryBytes = 0;
|
||||
|
||||
CircQueue(
|
||||
this.capacity, {
|
||||
this.deepCopy = true,
|
||||
this.maxMemoryBytes = 1024 * 1024, // 默认1MB
|
||||
}) : buffer = List<T?>.filled(capacity, null);
|
||||
CircQueue(this.capacity, {this.deepCopy = true, this.maxMemoryBytes = 1024 * 1024}) : buffer = List<T?>.filled(capacity, null);
|
||||
|
||||
/// 清空队列
|
||||
void clear() {
|
||||
head = tail;
|
||||
isFull = false;
|
||||
currentMemoryBytes = 0;
|
||||
}
|
||||
|
||||
/// 判断队列是否为空
|
||||
bool isEmpty() {
|
||||
return head == tail && !isFull;
|
||||
}
|
||||
|
||||
/// 判断队列是否已满
|
||||
bool isFullFn() {
|
||||
return isFull;
|
||||
}
|
||||
|
||||
/// 估算对象大小(JSON序列化后的字节长度)
|
||||
int _estimateSize(T item) {
|
||||
try {
|
||||
return utf8.encode(jsonEncode(item)).length;
|
||||
@@ -79,7 +67,6 @@ class CircQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 深拷贝对象
|
||||
T? _deepClone(T? item) {
|
||||
if (!deepCopy || item == null) return item;
|
||||
try {
|
||||
@@ -89,10 +76,8 @@ class CircQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 入队操作
|
||||
bool enter(T item) {
|
||||
final itemSize = _estimateSize(item);
|
||||
// 检查队列满或内存超限
|
||||
if (isFullFn() || (currentMemoryBytes + itemSize > maxMemoryBytes)) {
|
||||
return false;
|
||||
}
|
||||
@@ -106,7 +91,6 @@ class CircQueue<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 出队操作
|
||||
T? out() {
|
||||
if (isEmpty()) return null;
|
||||
|
||||
@@ -119,7 +103,6 @@ class CircQueue<T> {
|
||||
return _deepClone(item);
|
||||
}
|
||||
|
||||
/// 丢弃指定数量的元素
|
||||
bool discard(int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (isEmpty()) return false;
|
||||
@@ -135,12 +118,10 @@ class CircQueue<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 获取队列元素个数
|
||||
int getDepth() {
|
||||
return isFull ? capacity : (tail + capacity - head) % capacity;
|
||||
}
|
||||
|
||||
/// 异步入队(支持超时)
|
||||
Future<bool> send(T item, {int timeoutMs = 0}) async {
|
||||
final start = DateTime.now().millisecondsSinceEpoch;
|
||||
while (!enter(item)) {
|
||||
@@ -152,7 +133,6 @@ class CircQueue<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 异步出队(支持超时)
|
||||
Future<T?> recv({int timeoutMs = 0}) async {
|
||||
final start = DateTime.now().millisecondsSinceEpoch;
|
||||
while (true) {
|
||||
@@ -165,7 +145,6 @@ class CircQueue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 转换为列表(用于调试/序列化)
|
||||
List<T?> toList() {
|
||||
final result = <T?>[];
|
||||
int i = head;
|
||||
@@ -179,22 +158,18 @@ class CircQueue<T> {
|
||||
}
|
||||
|
||||
class TracePoint<T> {
|
||||
// 私有成员变量
|
||||
late final CircQueue<T> _queue;
|
||||
List<T> _tracePoint = [];
|
||||
int _completePointIndex = 0;
|
||||
late final TryLock _lock;
|
||||
TPMode _mode = TPMode.LOCATION;
|
||||
|
||||
// 公开的回调(无下划线,外部可访问)
|
||||
void Function(T)? onCurrentPointUpdated;
|
||||
void Function(T)? onCompletePointAdded;
|
||||
|
||||
// 测试用方法
|
||||
bool tryLock() => _lock.tryLock();
|
||||
void release() => _lock.release();
|
||||
|
||||
/// 构造函数
|
||||
TracePoint({int queueCapacity = 5, int maxMemoryBytes = 1024 * 1024}) {
|
||||
_queue = CircQueue<T>(queueCapacity, deepCopy: true, maxMemoryBytes: maxMemoryBytes);
|
||||
_lock = TryLock();
|
||||
@@ -204,12 +179,12 @@ class TracePoint<T> {
|
||||
/// 复位所有状态
|
||||
void reset() {
|
||||
_queue.clear();
|
||||
_tracePoint = [];
|
||||
_tracePoint.clear();
|
||||
_completePointIndex = 0;
|
||||
_lock.release();
|
||||
}
|
||||
|
||||
/// 设置工作模式
|
||||
/// 设置模式
|
||||
void setMode(TPMode mode) {
|
||||
reset();
|
||||
_mode = mode;
|
||||
@@ -221,20 +196,29 @@ class TracePoint<T> {
|
||||
|
||||
/// 添加/更新轨迹点
|
||||
void upsert(T point, [TPAction act = TPAction.UPDATE]) {
|
||||
// 严格按模式分发
|
||||
switch (_mode) {
|
||||
case TPMode.NAVIGATION:
|
||||
act == TPAction.UPDATE ? _updateCurrentPoint(point) : _addCompletePoint(point);
|
||||
if (act == TPAction.UPDATE) {
|
||||
_updateCurrentPoint(point);
|
||||
} else {
|
||||
_addCompletePoint(point);
|
||||
}
|
||||
break;
|
||||
|
||||
case TPMode.LOCATION:
|
||||
// LOCATION 永远只保留最新一个点
|
||||
_updateCurrentPoint(point);
|
||||
break;
|
||||
|
||||
case TPMode.TRACK:
|
||||
// TRACK 每个点都直接添加,不进队列
|
||||
_addCompletePoint(point);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取轨迹点列表(深拷贝,线程安全)
|
||||
/// 获取轨迹列表
|
||||
List<T>? getTracePoint() {
|
||||
if (_lock.tryLock()) {
|
||||
final trace = List<T>.from(_tracePoint);
|
||||
@@ -246,63 +230,48 @@ class TracePoint<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新当前点(私有方法)
|
||||
/// 更新当前点(LOCATION 永远只有1个)
|
||||
void _updateCurrentPoint(T point) {
|
||||
if (point == null) {
|
||||
print('updateCurrentPoint: point is NULL');
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lock.tryLock()) {
|
||||
try {
|
||||
switch (_mode) {
|
||||
case TPMode.NAVIGATION:
|
||||
if (_tracePoint.isEmpty) {
|
||||
print('updateCurrentPoint: tracePoint is empty , wait first completed point, discard current point: $point');
|
||||
} else {
|
||||
if (_tracePoint.isNotEmpty) {
|
||||
_tracePoint = _tracePoint.sublist(0, _completePointIndex);
|
||||
_tracePoint.add(point);
|
||||
// 触发公开的回调(无下划线)
|
||||
onCurrentPointUpdated?.call(point);
|
||||
}
|
||||
break;
|
||||
|
||||
case TPMode.LOCATION:
|
||||
if (_tracePoint.isEmpty) {
|
||||
_tracePoint.add(point);
|
||||
} else {
|
||||
_tracePoint[0] = point;
|
||||
}
|
||||
// 触发公开的回调(无下划线)
|
||||
// 核心:永远清空,只保留最新一个
|
||||
_tracePoint.clear();
|
||||
_tracePoint.add(point);
|
||||
onCurrentPointUpdated?.call(point);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
_lock.release();
|
||||
}
|
||||
} else {
|
||||
print('updateCurrentPoint: lock!!!, discard current point: $point');
|
||||
}
|
||||
}
|
||||
|
||||
/// 添加完成点(私有方法)
|
||||
/// 添加完成点
|
||||
void _addCompletePoint(T point) {
|
||||
if (point == null) {
|
||||
print('addCompletePoint: point is NULL');
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lock.tryLock()) {
|
||||
try {
|
||||
// 先消费队列
|
||||
while (!_queue.isEmpty()) {
|
||||
final queuedPoint = _queue.out();
|
||||
if (queuedPoint != null) {
|
||||
_addPoint(queuedPoint);
|
||||
}
|
||||
}
|
||||
// 添加当前点
|
||||
_addPoint(point);
|
||||
// 触发公开的回调(无下划线)
|
||||
onCompletePointAdded?.call(point);
|
||||
} catch (e) {
|
||||
print('addCompletePoint failure: $e');
|
||||
@@ -310,23 +279,29 @@ class TracePoint<T> {
|
||||
_lock.release();
|
||||
}
|
||||
} else {
|
||||
_queue.enter(point);
|
||||
print('addCompletePoint: lock!!!, enter queue, wait disposing: $point');
|
||||
if (_mode != TPMode.TRACK) {
|
||||
// TRACK 模式不加队列,直接丢弃旧的保证流畅
|
||||
_queue.enter(point);
|
||||
}
|
||||
print('addCompletePoint: lock!!!');
|
||||
}
|
||||
}
|
||||
|
||||
/// 内部添加点逻辑(私有方法)
|
||||
/// 内部添加点
|
||||
void _addPoint(T point) {
|
||||
if (point == null) {
|
||||
print('point NULL:');
|
||||
if (_mode == TPMode.LOCATION) {
|
||||
// LOCATION 强制只保留1个
|
||||
_tracePoint.clear();
|
||||
_tracePoint.add(point);
|
||||
_completePointIndex = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
final hasCurrentPoint = _tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length;
|
||||
final hasCurrent = _tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length;
|
||||
|
||||
if (hasCurrentPoint) {
|
||||
if (hasCurrent) {
|
||||
_tracePoint = _tracePoint.sublist(0, _completePointIndex);
|
||||
_tracePoint.insert(_completePointIndex, point);
|
||||
_tracePoint.add(point);
|
||||
} else {
|
||||
_tracePoint.add(point);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:latlong2/latlong.dart';
|
||||
@@ -46,6 +47,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import '../path_list_pages.dart';
|
||||
import 'package:maibu_satabot_v2/core/logging/i_logger_service.dart';
|
||||
|
||||
// 定义轨迹点类型(经纬度)
|
||||
typedef PlotPoint = LatLng;
|
||||
@@ -92,6 +94,8 @@ class MapPageEnterprise extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
final ILoggerService _logger = GetIt.I<ILoggerService>();
|
||||
|
||||
final _dispatcher = sl<NetMessageDispatcher>();
|
||||
bool _isRefreshing = false; // 新增:页面刷新状态标志
|
||||
bool _isVideoDialogOpen = false; // 控制视频弹窗显示
|
||||
@@ -270,6 +274,8 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
// 新增:加载本地存储数据方法
|
||||
Future<void> _loadSavedData() async {
|
||||
try {
|
||||
_traceManager.setMode(TPMode.LOCATION);
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final workStatusStr = prefs.getString(kSavedWorkStatus);
|
||||
if (workStatusStr != null) {
|
||||
@@ -929,9 +935,12 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
// ========== 新增:页面刷新初始化方法 ==========
|
||||
Future<void> _handleRefresh() async {
|
||||
if (_workStatus != WorkStatus.idle) {
|
||||
_showPageToast(message: "请先停止作业再刷新页面哦!", type: ToastType.warn);
|
||||
return;
|
||||
_stopWork();
|
||||
}
|
||||
//if (_workStatus != WorkStatus.idle) {
|
||||
// _showPageToast(message: "请先停止作业再刷新页面哦!", type: ToastType.warn);
|
||||
// return;
|
||||
//}
|
||||
_cancelAllToast();
|
||||
if (_isRefreshing) return;
|
||||
|
||||
@@ -1026,7 +1035,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_workStatus = WorkStatus.idle;
|
||||
isStartWork = false;
|
||||
isStopWork = false;
|
||||
_mapCenter = _getDefaultValidCenter();
|
||||
|
||||
// 轨迹管理器重置
|
||||
_traceManager.reset();
|
||||
@@ -1407,6 +1415,8 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_traceManager.upsert(_currentWgsLatLng as PlotPoint, TPAction.UPDATE);
|
||||
tracePoint = _traceManager.getTracePoint();
|
||||
gctracePoint = batchWgs84ToGcj02(tracePoint!);
|
||||
_logger.log("[转换后gctracePoint]: $gctracePoint");
|
||||
_logger.log("[当前轨迹模式]:${_traceManager.getMode()}"); // 这里必须加 ()
|
||||
|
||||
//_currentLatLng = gcjPoint; // ✅ 状态变量在setState内更新
|
||||
if (_isValidLatLng(gcjPoint.latitude, gcjPoint.longitude)) {
|
||||
@@ -1753,6 +1763,8 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
}
|
||||
|
||||
void _stopWork() async {
|
||||
_logger.log('按下停止按钮');
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
isStartWork = false; // 🔥 关键:停止作业标志
|
||||
@@ -1761,6 +1773,10 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
_showControlModeWarn = false;
|
||||
isStopWork = true; //已经点击过停止
|
||||
isreceiveFirstCompletePoint = false;
|
||||
_traceManager.setMode(TPMode.LOCATION);
|
||||
_traceManager.reset();
|
||||
tracePoint = [];
|
||||
gctracePoint = [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1769,10 +1785,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
|
||||
_saveDataToLocal(); // 🔥 保存暂停状态
|
||||
_showPageToast(message: "作业已停止", type: ToastType.error);
|
||||
_traceManager.setMode(TPMode.LOCATION);
|
||||
_traceManager.reset();
|
||||
tracePoint = [];
|
||||
gctracePoint = [];
|
||||
}
|
||||
|
||||
/// 继续作业
|
||||
@@ -2336,8 +2348,10 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
|
||||
if (arriLatitude != null && arriLongitude != null) {
|
||||
targetLatLng = LatLng(arriLatitude, arriLongitude);
|
||||
if (__isValidLatLng(targetLatLng)) {
|
||||
debugPrint("${targetLatLng}收到完成点arriLatitude");
|
||||
if (!isreceiveFirstCompletePoint) {
|
||||
//debugPrint("${targetLatLng}收到完成点arriLatitude");
|
||||
if (!isreceiveFirstCompletePoint && isStartWork && _workStatus == WorkStatus.working) {
|
||||
debugPrint("收到完成点arriLatitude");
|
||||
|
||||
_traceManager.setMode(TPMode.NAVIGATION);
|
||||
isreceiveFirstCompletePoint = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user