This commit is contained in:
mmc
2026-03-13 12:37:59 +08:00
parent f818937e0c
commit 9e6e94b5f7
2 changed files with 104 additions and 25 deletions

View File

@@ -144,8 +144,7 @@ class CircQueue<T> {
Future<bool> 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<T> {
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<T> {
/// 构造函数
TracePoint({int queueCapacity = 5, int maxMemoryBytes = 1024 * 1024}) {
_queue = CircQueue<T>(
queueCapacity,
deepCopy: true,
maxMemoryBytes: maxMemoryBytes,
);
_queue = CircQueue<T>(queueCapacity, deepCopy: true, maxMemoryBytes: maxMemoryBytes);
_lock = TryLock();
reset();
}
@@ -225,9 +219,7 @@ class TracePoint<T> {
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<T> {
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<T> {
return;
}
final hasCurrentPoint =
_tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length;
final hasCurrentPoint = _tracePoint.isNotEmpty && _completePointIndex < _tracePoint.length;
if (hasCurrentPoint) {
_tracePoint = _tracePoint.sublist(0, _completePointIndex);

View File

@@ -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<MapPageEnterprise> {
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<MapPageEnterprise> {
Future<void> _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<MapPageEnterprise> {
_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<String, dynamic> 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<MapPageEnterprise> {
// 保存作业区域完成状态
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<MapPageEnterprise> {
// 2. 重置所有页面状态(恢复初始值)
setState(() {
_traceManager.setMode(TPMode.LOCATION);
isreceiveFirstCompletePoint = false;
// 2. 清空打点和轨迹数据
_markedPoints.clear();
@@ -930,6 +1003,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_traceManager.reset();
_mapController.dispose();
_pathPlanningSub?.cancel(); // 🔥 取消订阅
_saveDataToLocal(); // 🔥 页面销毁时保存最终状态
super.dispose();
}
@@ -1223,7 +1297,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
strokeWidth: 1.0, // 折线宽度
isDotted: false, // 非虚线(Line模式)
borderColor: Colors.white, // 可选:添加白色描边,提升辨识度
borderStrokeWidth: 0.5,
borderStrokeWidth: 1,
),
],
),
@@ -1457,9 +1531,9 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
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<MapPageEnterprise> {
/// 开始作业
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<MapPageEnterprise> {
isStartWork = false; // 🔥 关键:停止作业标志
_workStatus = WorkStatus.paused;
});
_saveDataToLocal(); // 🔥 保存暂停状态
context.read<DevicesCubit>().updateAppState(AppState.none);
await context.read<DevicesCubit>().pauseRoutePlanning();
}
@@ -1531,7 +1608,10 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_showHeadingWarn = false;
_showControlModeWarn = false;
isStopWork = true; //已经点击过停止
isreceiveFirstCompletePoint = false;
});
_traceManager.reset();
_saveDataToLocal(); // 🔥 保存暂停状态
_traceManager.setMode(TPMode.LOCATION);
context.read<DevicesCubit>().updateAppState(AppState.none);
await context.read<DevicesCubit>().stopRoutePlanning();
@@ -1544,6 +1624,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
setState(() {
_workStatus = WorkStatus.working;
});
_saveDataToLocal(); // 🔥 保存暂停状态
context.read<DevicesCubit>().updateAppState(AppState.routePlanning);
await context.read<DevicesCubit>().resumeRoutePlanning();
}
@@ -1631,7 +1712,8 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_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<MapPageEnterprise> {
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<MapPageEnterprise> {
if (isFinishWork) {
_workStatus = WorkStatus.idle;
ToastUtils.showError(context, '作业已停止');
_traceManager.setMode(TPMode.LOCATION);
_traceManager.reset();
isStopWork = true;
isreceiveFirstCompletePoint = false;
}
if (state is DeviceStatusUpdated) {