删除撤回逻辑优化完善

This commit is contained in:
mmc
2026-03-03 10:13:32 +08:00
parent ca90d8dc05
commit cf5415308a
2 changed files with 161 additions and 87 deletions

View File

@@ -352,34 +352,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
),
'planModel': _currentWorkMode == WorkMode.bow ? 0 : 2, // 作业模式值
};
// 2. 解析并打印 Path
try {
final List<dynamic> pathData = jsonDecode(savePath['path'] as String);
print('\n🗺️ 路径数据 (共 ${pathData.length} 个点):');
// 格式化打印前 3 个点,避免数据过多刷屏
for (int i = 0; i < math.min(3, pathData.length); i++) {
final point = pathData[i] as Map<String, dynamic>;
print(' 点 $i: lat=${point['lat']}, lon=${point['lon']}');
}
if (pathData.length > 3) {
print(' ... 还有 ${pathData.length - 3} 个点');
}
} catch (e) {
print('❌ 解析 path 失败: $e');
}
// 3. 解析并打印 Outer
try {
final List<dynamic> outerData = jsonDecode(savePath['outer'] as String);
print('\n📏 外边界数据 (共 ${outerData.length} 个点):');
// 格式化打印所有外边界点(通常数量少)
for (int i = 0; i < outerData.length; i++) {
final point = outerData[i] as Map<String, dynamic>;
print(' 点 $i: lat=${point['lat']}, lon=${point['lon']}');
}
} catch (e) {
print('❌ 解析 outer 失败: $e');
}
// 3. 构造 workRecord (包裹一层)
final Map<String, dynamic> workRecord = {
@@ -425,6 +397,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
debugPrint('保存地块响应体: $responseBody');
if (response.statusCode == 200) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('地块「$plotName」保存成功!'), backgroundColor: Colors.green));
// 保存成功
setState(() {
_markedPoints.clear(); // 清空打点
@@ -434,8 +407,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_isPanelOpen = false; // 关闭操作面板
_isWorkAreaCompleted = false; // 重置作业区域完成状态
});
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('地块「$plotName」保存成功!'), backgroundColor: Colors.green));
} else {
throw Exception('服务器错误: ${response.statusCode}, $responseBody');
}
@@ -453,34 +424,125 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
return polygonPoints;
}
void _undoLastPoint() {
if (_markedPoints.isNotEmpty) {
setState(() {
_markedPoints.removeLast(); // 删除最后一个打点
});
debugPrint('撤回成功,剩余打点数量:${_markedPoints.length}');
} else {
debugPrint('无打点可撤回');
// 可选:提示用户
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无打点可撤回')));
}
//void _undoLastPoint() {
// if (_markedPoints.isNotEmpty) {
// setState(() {
// _markedPoints.removeLast(); // 删除最后一个打点
// });
// debugPrint('撤回成功,剩余打点数量:${_markedPoints.length}');
// } else {
// debugPrint('无打点可撤回');
// // 可选:提示用户
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无打点可撤回')));
// }
//}
// ========== 统一撤回方法(适配完成后状态) ==========
void _undoAction() {
setState(() {
// 1. 作业区域模式
if (_currentAreaMode == AreaMode.work) {
if (_markedPoints.isNotEmpty) {
_markedPoints.removeLast();
// 作业点撤回后,若路径已生成,重新生成路径(保持同步)
if (_isWorkAreaCompleted && _markedPoints.length >= 3) {
_generatePath(showTips: false);
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已撤回作业区域最后一个点,剩余${_markedPoints.length}个点')));
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无作业区域点可撤回')));
}
return;
}
// 2. 空洞模式(完成后优先撤回已完成的空洞)
if (_currentAreaMode == AreaMode.obstacle) {
if (_currentObstaclePoints.isNotEmpty) {
_currentObstaclePoints.removeLast();
// 如果当前空洞的点撤空了,退出编辑状态
if (_currentObstaclePoints.isEmpty) {
_isObstacleEditing = false;
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已撤回当前空洞最后1个点,剩余${_currentObstaclePoints.length}个点')));
return; // 撤完点就结束,不执行后面的逻辑
}
// 第二步:当前空洞无点可撤 → 再撤回「上一个完整空洞」
if (_obstacleHoles.isNotEmpty) {
_obstacleHoles.removeLast();
// 撤完空洞后重新生成路径(排除该空洞)
if (_isWorkAreaCompleted) {
_generatePath(showTips: false);
}
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已撤回上一个完整空洞,剩余${_obstacleHoles.length}个空洞')));
return;
}
// 第三步:无任何可撤内容
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无空洞可撤回')));
}
});
}
// ========== 核心:清空所有打点和轨迹 ==========
void _deleteAllPoints() {
if (_markedPoints.isNotEmpty) {
setState(() {
_markedPoints.clear(); // 清空所有打点
});
debugPrint('删除成功,已清空所有打点和轨迹');
// 可选:提示用户
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有打点和轨迹')));
} else {
debugPrint('无打点可删除');
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无打点可删除')));
}
// 兼容原有调用(可保留,也可直接用上面的_unifiedUndo)
void _undoLastPoint() => _undoAction();
void _undoObstaclePoint() => _undoAction();
// ========== 统一删除方法(适配完成后状态) ==========
void _deleteAllAction() {
setState(() {
// 1. 作业区域模式:清空作业点 + 重置路径
if (_currentAreaMode == AreaMode.work) {
if (_markedPoints.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无作业区域点可删除')));
return;
}
_markedPoints.clear();
gcjPathPoints.clear();
gcjOuterPoints.clear();
_isWorkAreaCompleted = false;
_saveBoxOpen = false;
typedPathList.clear();
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有作业区域点和路径')));
}
// 2. 空洞模式:清空所有空洞 + 恢复UI + 重新生成路径
else if (_currentAreaMode == AreaMode.obstacle) {
if (_obstacleHoles.isEmpty && _currentObstaclePoints.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无空洞可删除')));
return;
}
_obstacleHoles.clear();
_currentObstaclePoints.clear();
_isObstacleEditing = false;
// 清空后重新生成路径(无空洞)
if (_isWorkAreaCompleted) {
_generatePath(showTips: false);
}
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有空洞')));
}
});
}
// 兼容原有调用
void _deleteAllPoints() => _deleteAllAction();
void _clearAllObstacles() => _deleteAllAction();
// ========== 核心:清空所有打点和轨迹 ==========
//void _deleteAllPoints() {
// if (_markedPoints.isNotEmpty) {
// setState(() {
// _markedPoints.clear(); // 清空所有打点
// });
// debugPrint('删除成功,已清空所有打点和轨迹');
// // 可选:提示用户
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有打点和轨迹')));
// } else {
// debugPrint('无打点可删除');
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无打点可删除')));
// }
//}
/// ===============================
/// 企业级定位初始化(已修复坐标系)
/// ===============================
@@ -634,32 +696,36 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('已添加第${_obstacleHoles.length}个障碍物区域'), backgroundColor: Colors.green));
}
void _undoObstaclePoint() {
if (_currentObstaclePoints.isNotEmpty) {
setState(() => _currentObstaclePoints.removeLast());
debugPrint('撤回障碍物打点,剩余:${_currentObstaclePoints.length}个');
} else if (_obstacleHoles.isNotEmpty) {
// 无当前绘制点时,删除最后一组障碍物
setState(() => _obstacleHoles.removeLast());
debugPrint('删除最后一组障碍物,剩余组数:${_obstacleHoles.length}');
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无障碍物打点可撤回')));
}
}
//void _undoObstaclePoint() {
// if (_currentObstaclePoints.isNotEmpty) {
// setState(() => _currentObstaclePoints.removeLast());
// debugPrint('撤回障碍物打点,剩余:${_currentObstaclePoints.length}个');
// } else if (_obstacleHoles.isNotEmpty) {
// // 无当前绘制点时,删除最后一组障碍物
// setState(() => _obstacleHoles.removeLast());
// debugPrint('删除最后一组障碍物,剩余组数:${_obstacleHoles.length}');
// } else {
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('暂无障碍物打点可撤回')));
// }
//}
// ========== 障碍物模式:清空所有障碍物 ==========
void _clearAllObstacles() {
setState(() {
_obstacleHoles.clear();
_currentObstaclePoints.clear();
_isObstacleEditing = false;
});
debugPrint('已清空所有障碍物区域');
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有障碍物区域'), backgroundColor: Colors.amber));
}
//// ========== 障碍物模式:清空所有障碍物 ==========
//void _clearAllObstacles() {
// setState(() {
// _obstacleHoles.clear();
// _currentObstaclePoints.clear();
// _isObstacleEditing = false;
// });
// debugPrint('已清空所有障碍物区域');
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已清空所有障碍物区域'), backgroundColor: Colors.amber));
//}
// ========== 核心方法:打点逻辑 ==========
void _addMarkedPoint() {
if (_currentAreaMode == AreaMode.work && _isWorkAreaCompleted) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('作业区域已完成,无法继续添加打点!'), backgroundColor: Colors.red));
return;
}
setState(() {
if (_currentAreaMode == AreaMode.work) {
_markedPoints.add(_mapCenter);
@@ -1827,6 +1893,7 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
initialRobotMode: RobotMode.point,
initialAreaMode: AreaMode.work,
initialWorkMode: _currentWorkMode!,
canUndo: _isWorkAreaCompleted && _currentAreaMode == AreaMode.work ? false : true,
onComplete: () async {
debugPrint(
'操作完成回调:当前机器人模式=$_currentRobotMode,当前区域模式=$_currentAreaMode,当前作业模式:$_currentWorkMode,作业区域点:$_markedPoints,作业行距=$_workDistance,航线方向角=$_angle',
@@ -1846,19 +1913,22 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
},
onUndoTap: () {
// 区分模式:作业区域撤回/障碍物撤回
if (_currentAreaMode == AreaMode.work) {
_undoLastPoint();
} else {
_undoObstaclePoint();
}
//if (_currentAreaMode == AreaMode.work) {
// _undoLastPoint();
//} else {
// _undoObstaclePoint();
//}
_undoAction();
},
onDeleteTap: () {
_deleteAllAction();
// 区分模式:作业区域清空/障碍物清空
if (_currentAreaMode == AreaMode.work) {
_deleteAllPoints();
} else {
_clearAllObstacles();
}
//if (_currentAreaMode == AreaMode.work) {
// _deleteAllPoints();
//} else {
// _clearAllObstacles();
//}
},
onRobotModeChanged: (mode) {
setState(() => _currentRobotMode = mode);

View File

@@ -10,6 +10,7 @@ class BottomOperationPanel extends StatefulWidget {
// 新增:外部控制初始选中的标签(默认地块)
final String initialSelectedTab;
final WorkMode initialWorkMode;
final bool? canUndo; // 是否可以撤回(控制撤回按钮状态)
// 回调函数:向外部传递事件
final VoidCallback onComplete; // 完成按钮点击回调
final ValueChanged<RobotMode>? onRobotModeChanged; // 机器人模式变更回调
@@ -41,6 +42,7 @@ class BottomOperationPanel extends StatefulWidget {
this.onDistanceTap,
this.onDeleteTap,
this.onUndoTap,
this.canUndo, // 接收撤回按钮状态
});
@override
@@ -52,6 +54,7 @@ class _BottomOperationPanelState extends State<BottomOperationPanel> {
late AreaMode _areaMode;
// 新增:当前选中的标签(地块/航线)- 核心状态
late String _currentTab;
late bool canUndo;
// 新增:航线模式下的作业行距(默认0.5米)
double _operationDistance = 0.5;
@@ -62,6 +65,7 @@ class _BottomOperationPanelState extends State<BottomOperationPanel> {
_robotMode = widget.initialRobotMode;
_areaMode = widget.initialAreaMode;
// 初始化选中的标签
canUndo = widget.canUndo ?? true;
_currentTab = widget.initialSelectedTab;
}
@@ -194,7 +198,7 @@ class _BottomOperationPanelState extends State<BottomOperationPanel> {
debugPrint('点击了删除按钮,清空所有打点');
widget.onDeleteTap?.call();
}),
_buildActionButton(Icons.undo_outlined, '撤回', true, () {
_buildActionButton(Icons.undo_outlined, '撤回', widget.canUndo ?? true, () {
debugPrint('点击了撤回按钮,删除最后一个打点');
widget.onUndoTap?.call();
}),