From 9e6e94b5f7d412ded7225914c19681c70781be4a Mon Sep 17 00:00:00 2001 From: mmc <1556375442@qq.com> Date: Fri, 13 Mar 2026 12:37:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../widgets/common/tracepoint.dart | 23 +--- .../widgets/map/testmap_pages.dart | 106 ++++++++++++++++-- 2 files changed, 104 insertions(+), 25 deletions(-) diff --git a/lib/features/home/presentation/widgets/common/tracepoint.dart b/lib/features/home/presentation/widgets/common/tracepoint.dart index 7473a39d..77be8686 100644 --- a/lib/features/home/presentation/widgets/common/tracepoint.dart +++ b/lib/features/home/presentation/widgets/common/tracepoint.dart @@ -144,8 +144,7 @@ class CircQueue { Future send(T item, {int timeoutMs = 0}) async { final start = DateTime.now().millisecondsSinceEpoch; while (!enter(item)) { - if (timeoutMs > 0 && - DateTime.now().millisecondsSinceEpoch - start >= timeoutMs) { + if (timeoutMs > 0 && DateTime.now().millisecondsSinceEpoch - start >= timeoutMs) { return false; } await Future.delayed(const Duration(milliseconds: 1)); @@ -159,8 +158,7 @@ class CircQueue { while (true) { final item = out(); if (item != null) return item; - if (timeoutMs > 0 && - DateTime.now().millisecondsSinceEpoch - start >= timeoutMs) { + if (timeoutMs > 0 && DateTime.now().millisecondsSinceEpoch - start >= timeoutMs) { return null; } await Future.delayed(const Duration(milliseconds: 1)); @@ -198,11 +196,7 @@ class TracePoint { /// 构造函数 TracePoint({int queueCapacity = 5, int maxMemoryBytes = 1024 * 1024}) { - _queue = CircQueue( - queueCapacity, - deepCopy: true, - maxMemoryBytes: maxMemoryBytes, - ); + _queue = CircQueue(queueCapacity, deepCopy: true, maxMemoryBytes: maxMemoryBytes); _lock = TryLock(); reset(); } @@ -225,9 +219,7 @@ class TracePoint { void upsert(T point, [TPAction act = TPAction.UPDATE]) { switch (_mode) { case TPMode.NAVIGATION: - act == TPAction.UPDATE - ? _updateCurrentPoint(point) - : _addCompletePoint(point); + act == TPAction.UPDATE ? _updateCurrentPoint(point) : _addCompletePoint(point); break; case TPMode.LOCATION: _updateCurrentPoint(point); @@ -262,9 +254,7 @@ class TracePoint { switch (_mode) { case TPMode.NAVIGATION: if (_tracePoint.isEmpty) { - print( - 'updateCurrentPoint: tracePoint is empty , wait first completed point, discard current point: $point', - ); + print('updateCurrentPoint: tracePoint is empty , wait first completed point, discard current point: $point'); } else { _tracePoint = _tracePoint.sublist(0, _completePointIndex); _tracePoint.add(point); @@ -328,8 +318,7 @@ class TracePoint { return; } - final hasCurrentPoint = - _tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length; + final hasCurrentPoint = _tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length; if (hasCurrentPoint) { _tracePoint = _tracePoint.sublist(0, _completePointIndex); diff --git a/lib/features/home/presentation/widgets/map/testmap_pages.dart b/lib/features/home/presentation/widgets/map/testmap_pages.dart index f35db709..328d1a69 100644 --- a/lib/features/home/presentation/widgets/map/testmap_pages.dart +++ b/lib/features/home/presentation/widgets/map/testmap_pages.dart @@ -56,6 +56,13 @@ const String kSavedGcjOuterPoints = 'saved_gcj_outer_points'; const String kSavedMarkedPoints = 'saved_marked_points'; const String kSavedObstacleHoles = 'saved_obstacle_holes'; const String kSavedIsWorkAreaCompleted = 'saved_is_work_area_completed'; +const String kSavedIsWorkPanelOpen = 'saved_is_work_panel_open'; +const String kSavedSelectedPlot = 'saved_selected_plot'; +const String kSavedStartWorkList = 'saved_start_work_list'; +const String kSavedWorkMode = 'saved_work_mode'; +const String kSavedWorkStatus = 'saved_work_status'; // 作业状态(idle/working/paused) +const String kSavedIsStartWork = 'saved_is_start_work'; // 是否开始作业 +const String kSavedIsStopWork = 'saved_is_stop_work'; // 是否点击过停止 // 保持 PlotData 类不变 class PlotData { @@ -86,6 +93,7 @@ class _MapPageEnterpriseState extends State { bool _isVideoDialogOpen = false; // 控制视频弹窗显示 String _videoStreamUrl = ""; bool isStopWork = false; //是否点击过停止 + bool isreceiveFirstCompletePoint = false; Offset _videoPopupPos = const Offset(0, 100); // 弹窗初始位置 // 🔥 关键修复:添加截图全局Key final GlobalKey _mapRepaintKey = GlobalKey(); @@ -243,6 +251,16 @@ class _MapPageEnterpriseState extends State { Future _loadSavedData() async { try { final prefs = await SharedPreferences.getInstance(); + final workStatusStr = prefs.getString(kSavedWorkStatus); + if (workStatusStr != null) { + _workStatus = WorkStatus.values.firstWhere((e) => e.toString() == workStatusStr, orElse: () => WorkStatus.idle); + } + + // 2. 恢复是否开始作业 + isStartWork = prefs.getBool(kSavedIsStartWork) ?? false; + + // 3. 恢复是否点击过停止 + isStopWork = prefs.getBool(kSavedIsStopWork) ?? false; // 加载路径点 final pathJson = prefs.getString(kSavedGcjPathPoints); @@ -278,6 +296,31 @@ class _MapPageEnterpriseState extends State { _isWorkAreaCompleted = prefs.getBool(kSavedIsWorkAreaCompleted) ?? false; _saveBoxOpen = _isWorkAreaCompleted; + // ====================== 🔥 新增恢复逻辑 ====================== + // 1. 恢复作业面板状态 + _isWorkPanelOpen = prefs.getBool(kSavedIsWorkPanelOpen) ?? false; + + // 2. 恢复作业模式 + workMode = prefs.getString(kSavedWorkMode) ?? "弓字模式"; + + // 3. 恢复作业列表 + final startWorkJson = prefs.getString(kSavedStartWorkList); + if (startWorkJson != null) { + startWorkList = jsonDecode(startWorkJson); + } + + // 4. 恢复选中地块 + final selectedPlotJson = prefs.getString(kSavedSelectedPlot); + if (selectedPlotJson != null && selectedPlotJson.isNotEmpty) { + final Map plotMap = jsonDecode(selectedPlotJson); + _selectedPlot = PlotData( + id: plotMap['id'] ?? '', + plotName: plotMap['plotName'] ?? '', + imageUrl: plotMap['imageUrl'] ?? '', + jsonData: plotMap['jsonData'], + ); + } + if (mounted) { setState(() {}); // 移动地图到绘制内容中心 @@ -318,6 +361,35 @@ class _MapPageEnterpriseState extends State { // 保存作业区域完成状态 prefs.setBool(kSavedIsWorkAreaCompleted, _isWorkAreaCompleted); + + // 1. 保存作业面板显示状态 + prefs.setBool(kSavedIsWorkPanelOpen, _isWorkPanelOpen); + + // 2. 保存作业模式 + prefs.setString(kSavedWorkMode, workMode); + + // 3. 保存作业列表 + prefs.setString(kSavedStartWorkList, jsonEncode(startWorkList)); + prefs.setString(kSavedWorkStatus, _workStatus.toString()); + + // 2. 保存是否开始作业 + prefs.setBool(kSavedIsStartWork, isStartWork); + + // 3. 保存是否点击过停止 + prefs.setBool(kSavedIsStopWork, isStopWork); + + // 4. 保存选中地块 + if (_selectedPlot != null) { + final plotMap = { + 'id': _selectedPlot!.id, + 'plotName': _selectedPlot!.plotName, + 'imageUrl': _selectedPlot!.imageUrl, + 'jsonData': _selectedPlot!.jsonData, + }; + prefs.setString(kSavedSelectedPlot, jsonEncode(plotMap)); + } else { + prefs.remove(kSavedSelectedPlot); + } } catch (e) { debugPrint('保存本地数据失败:$e'); } @@ -764,6 +836,7 @@ class _MapPageEnterpriseState extends State { // 2. 重置所有页面状态(恢复初始值) setState(() { _traceManager.setMode(TPMode.LOCATION); + isreceiveFirstCompletePoint = false; // 2. 清空打点和轨迹数据 _markedPoints.clear(); @@ -930,6 +1003,7 @@ class _MapPageEnterpriseState extends State { _traceManager.reset(); _mapController.dispose(); _pathPlanningSub?.cancel(); // 🔥 取消订阅 + _saveDataToLocal(); // 🔥 页面销毁时保存最终状态 super.dispose(); } @@ -1223,7 +1297,7 @@ class _MapPageEnterpriseState extends State { strokeWidth: 1.0, // 折线宽度 isDotted: false, // 非虚线(Line模式) borderColor: Colors.white, // 可选:添加白色描边,提升辨识度 - borderStrokeWidth: 0.5, + borderStrokeWidth: 1, ), ], ), @@ -1457,9 +1531,9 @@ class _MapPageEnterpriseState extends State { for (int i = 0; i < gctracePoint!.length - 1; i++) Polyline( points: [gctracePoint![i], gctracePoint![i + 1]], - color: Colors.blueAccent, + color: Color(0xFF00C853), strokeWidth: 3, - isDotted: true, // 虚线区分作业区域 + isDotted: false, // 虚线区分作业区域 ), ], ), @@ -1469,12 +1543,14 @@ class _MapPageEnterpriseState extends State { /// 开始作业 void _startWork() async { + _traceManager.reset(); isStopWork = false; + _saveDataToLocal(); if (startWorkList.isEmpty) { ToastUtils.showInfo(context, '作业列表为空,请重新选择路径'); return; } - _traceManager.setMode(TPMode.NAVIGATION); + _traceManager.setMode(TPMode.LOCATION); setState(() { isStartWork = true; // 🔥 关键:停止作业标志 @@ -1520,6 +1596,7 @@ class _MapPageEnterpriseState extends State { isStartWork = false; // 🔥 关键:停止作业标志 _workStatus = WorkStatus.paused; }); + _saveDataToLocal(); // 🔥 保存暂停状态 context.read().updateAppState(AppState.none); await context.read().pauseRoutePlanning(); } @@ -1531,7 +1608,10 @@ class _MapPageEnterpriseState extends State { _showHeadingWarn = false; _showControlModeWarn = false; isStopWork = true; //已经点击过停止 + isreceiveFirstCompletePoint = false; }); + _traceManager.reset(); + _saveDataToLocal(); // 🔥 保存暂停状态 _traceManager.setMode(TPMode.LOCATION); context.read().updateAppState(AppState.none); await context.read().stopRoutePlanning(); @@ -1544,6 +1624,7 @@ class _MapPageEnterpriseState extends State { setState(() { _workStatus = WorkStatus.working; }); + _saveDataToLocal(); // 🔥 保存暂停状态 context.read().updateAppState(AppState.routePlanning); await context.read().resumeRoutePlanning(); } @@ -1631,7 +1712,8 @@ class _MapPageEnterpriseState extends State { _showControlModeWarn = false; isStartWork = false; }); - if (isStopWork) return; + _saveDataToLocal(); + if (isStopWork || !isStartWork) return; _stopWork(); }, icon: const Icon(Icons.close, color: Colors.grey, size: 20), @@ -2078,8 +2160,15 @@ class _MapPageEnterpriseState extends State { LatLng? targetLatLng; if (arriLatitude != null && arriLongitude != null) { targetLatLng = LatLng(arriLatitude, arriLongitude); - debugPrint("${targetLatLng}收到完成点gctracePoint"); - _traceManager.upsert(targetLatLng, TPAction.ADD); + if (__isValidLatLng(targetLatLng)) { + debugPrint("${targetLatLng}收到完成点gctracePoint"); + if (!isreceiveFirstCompletePoint) { + _traceManager.setMode(TPMode.NAVIGATION); + isreceiveFirstCompletePoint = true; + } + + _traceManager.upsert(targetLatLng, TPAction.ADD); + } } double currentLat = 0.0; @@ -2092,8 +2181,9 @@ class _MapPageEnterpriseState extends State { if (isFinishWork) { _workStatus = WorkStatus.idle; ToastUtils.showError(context, '作业已停止'); - _traceManager.setMode(TPMode.LOCATION); + _traceManager.reset(); isStopWork = true; + isreceiveFirstCompletePoint = false; } if (state is DeviceStatusUpdated) {