diff --git a/src/components/Map.jsx b/src/components/Map.jsx index 2de7482..5457c72 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -1677,14 +1677,37 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, handler.setInputAction((movement) => { - const picked = viewer.scene.pick(movement.position); - if (window.Cesium.defined(picked) && picked.id?.properties?.robot) { - const robot = picked.id.properties.robot.getValue(); - robot.feStatus == 1 && onCameraClickRef.current?.(robot); - } - }, window.Cesium.ScreenSpaceEventType.LEFT_CLICK); + // ========= 增加防护,直接拦截 movement.position undefined ========= + if (!movement || !movement.position) return; - handler.setInputAction((movement) => { + const picked = viewer.scene.pick(movement.position); + let robot = null; + if (window.Cesium.defined(picked) && picked.id) { + const robotProp = picked.id.properties?.robot; + robot = robotProp ? (typeof robotProp.getValue === "function" ? robotProp.getValue() : robotProp) : (picked.id.robotData || null); + if (!robot) { + const pickedCarto = viewer.scene.globe.pick(movement.position, viewer.scene); + if (window.Cesium.defined(pickedCarto)) { + const clon = window.Cesium.Math.toDegrees(pickedCarto.longitude); + const clat = window.Cesium.Math.toDegrees(pickedCarto.latitude); + let best = null; + let bestDist = 0.002; + devices.forEach(d => { + const raw = d?.locationMessage || d?.lastRunningStatus || {}; + const dlon = Number(raw.longitude); + const dlat = Number(raw.latitude); + if (!isFinite(dlon) || !isFinite(dlat)) return; + const dist = Math.hypot(dlon - clon, dlat - clat); + if (dist < bestDist) { bestDist = dist; best = d; } + }); + robot = best; + } + } + } + console.log('点击地图,拾取到设备', robot); + if (robot) { + onCameraClickRef.current?.(robot); + } if (from !== "deviceStatus") return; const cartesian = viewer.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid); @@ -1696,6 +1719,9 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, onMarkPointRef.current?.({ lon, lat }); }, window.Cesium.ScreenSpaceEventType.LEFT_CLICK); + + + if (onClearDraw) { onClearDraw(clearDrawingPath); } @@ -1703,7 +1729,7 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, return () => { handler.destroy(); }; - }, [drawPoints, from]); + }, [drawPoints, from, devices]); //useEffect(() => { // const viewer = viewerRef.current; @@ -1875,6 +1901,7 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, if (realtimePosition?.heading !== undefined && !isNaN(Number(realtimePosition.heading))) { let headingDeg = Number(realtimePosition.heading); + rotation = Cesium.Math.toRadians(headingDeg); diff --git a/src/components/SystemSetting/Organization.tsx b/src/components/SystemSetting/Organization.tsx index e8dfdbb..b6a1e04 100644 --- a/src/components/SystemSetting/Organization.tsx +++ b/src/components/SystemSetting/Organization.tsx @@ -158,7 +158,7 @@ export default function Organization() {
- +
{/* 表格 + 统一分页 */} diff --git a/src/components/devices/RobotTaskPage.tsx b/src/components/devices/RobotTaskPage.tsx index 271ebc7..a14c200 100644 --- a/src/components/devices/RobotTaskPage.tsx +++ b/src/components/devices/RobotTaskPage.tsx @@ -6,7 +6,8 @@ import { TimePicker, Popconfirm, App, - Radio + Radio, + Empty } from 'antd'; import { PlusOutlined, ImportOutlined, NodeIndexOutlined, @@ -93,6 +94,7 @@ export default function RobotTaskPage() { const [runningPoolTask, setRunningPoolTask] = useState(null);//正在执行的任务 + const [proPoints, setProPoints] = useState({});//规划点 // 当前执行任务的机器人 @@ -160,6 +162,7 @@ export default function RobotTaskPage() { const handleFinish = (data) => { + console.log('任务完成回调', data); setExecute(false); setShowVideo(false); // 任务完成关闭视频 utils.message.success(t('devices.fixed2TaskSuspended2Fixed2CompletedFixed2')); @@ -274,42 +277,7 @@ export default function RobotTaskPage() { // 处理路线点回调:taskId必须和当前选中任务一致 controller.onRoutePost = (msg) => { console.log('收到 route_post 消息:', msg); - const { taskId, data } = msg; - - // 1. 先在任务池中查找该taskId对应的任务 - const matchedTask = taskPoolList.find(task => String(task.id) === String(taskId)); - - // 2. 两种情况处理: - // a) 当前没有选中任务,且匹配到了任务池中的任务 → 自动选中该任务 - // b) 当前已选中任务,且选中任务的id === 传来的taskId → 更新数据 - const isSameAsSelected = runningPoolTask && String(runningPoolTask.id) === String(taskId); - const shouldSelectNewTask = !runningPoolTask && matchedTask; - - if (isSameAsSelected || shouldSelectNewTask) { - console.log('taskId匹配成功,处理路线数据', { - taskId, - runningPoolTaskId: runningPoolTask?.id, - matchedTask - }); - - // 如果是匹配到新任务就设置选中状态 - if (shouldSelectNewTask) { - setRunningPoolTask(matchedTask); - } - - // 先直接用推送的data设置点(实时性) - if (data) { - setPoints(data); - } - - - } else { - console.log('taskId不匹配,忽略本次推送', { - receivedTaskId: taskId, - currentSelectedTaskId: runningPoolTask?.id, - matchedTaskFound: !!matchedTask - }); - } + setProPoints(msg); }; @@ -322,6 +290,8 @@ export default function RobotTaskPage() { if (controllerRef.current) { controllerRef.current.destroy?.(); } + setExecute(false); + controllerRef.current = null; }; @@ -349,6 +319,10 @@ export default function RobotTaskPage() { // 找到对应的设备 const targetDevice = devices.find(d => d.serialNumber === runningTask.deviceId); + setRunningPoolTask(runningTask); // 设置当前任务 + setExecute(true); + setExecutingRobot(targetDevice); + setClearNavLine(v => v + 1); // 清空地图轨迹 if (!targetDevice) return; @@ -359,14 +333,20 @@ export default function RobotTaskPage() { // 切换设备 console.log('🔄 检测到正在执行任务的新设备,开始连接', targetDevice); - setRunningPoolTask(runningTask); // 设置当前任务 - setExecute(true); - setExecutingRobot(targetDevice); - setClearNavLine(v => v + 1); // 清空地图轨迹 + if (isFirstConnect.current) { isFirstConnect.current = false; controllerRef.current?.connectDevice(targetDevice); } else { controllerRef.current?.switchDevice(targetDevice); } setShowVideo(true); }, [devices, taskPoolList, executingRobot, runningPoolTask]); + useEffect(() => { + console.log('runningPoolTask, proPoints', runningPoolTask, proPoints); + if (!runningPoolTask?.id || !proPoints?.taskId) return; + if (runningPoolTask?.id == proPoints?.taskId) { + setPoints(proPoints?.data || []); + } + + + }, [runningPoolTask, proPoints]); const realtimePosition = useMemo(() => { @@ -471,6 +451,7 @@ export default function RobotTaskPage() { }, [taskPoolList]); const getRouteOut = async () => { try { + if (!selectedPathWork?.id) return; const res = await getSingleRouteList({ id: selectedPathWork?.id }); // coverage(区域覆盖)绘制为多边形,其余为折线/单点 @@ -508,7 +489,6 @@ export default function RobotTaskPage() { }, [selectedPathWork?.id]) // 调用接口获取路线详情 const fetchRouteDetail = async (id) => { - console.log(id, "获取正在执行任务的id") try { const params = { taskId: id, @@ -1578,128 +1558,127 @@ export default function RobotTaskPage() { style={cardStyle} >
- {routeList - //.filter(item => { - // if (!routeSearch) return true; - // const name = (item.workName || item.name || '').toLowerCase(); - // const id = String(item.id || '').toLowerCase(); - // const key = routeSearch.toLowerCase(); - // return name.includes(key) || id.includes(key); - //}) - .map(route => ( -
{ - e.stopPropagation(); - // 先清空再设置,确保每次点击都能触发 useEffect 的重绘 - setSelectedPathWork(null); - // 在下一个 tick 中设置,确保 state 重置生效 - setTimeout(() => { - setSelectedPathWork(route); - }, 0); - }} - onMouseEnter={e => { - // 只有未选中的项,悬浮才变色 - if (selectedPathWork?.id !== route.id) { - e.currentTarget.style.borderColor = '#165DFF'; - } - }} - onMouseLeave={e => { - // 只有未选中的项,离开才恢复透明 - if (selectedPathWork?.id !== route.id) { - e.currentTarget.style.borderColor = 'transparent'; - } - }} - > -
- {route.imgUrl ? ( - {route.workName - ) : ( -
- -
- )} -
- - {/* 路线信息 */} -
-
- {route.workName || route.name || t('devices.unnamedRoute')} -
-
- ID: {route.id} -
-
- {/* 删除按钮 */} - -
+ )) + ) + }
+ diff --git a/src/locales/en/index.ts b/src/locales/en/index.ts index 42bef26..afc6935 100644 --- a/src/locales/en/index.ts +++ b/src/locales/en/index.ts @@ -1273,7 +1273,7 @@ const en = { videoFixed2: ' Airport video', - fixed2TaskSuspended2Fixed2CompletedFixed2: 'Fixed2 Task Suspended2 Fixed2 Completed Fixed2', + fixed2TaskSuspended2Fixed2CompletedFixed2: 'Task Completed ', deletedSuccessfullyFixed2: '航线 Deleted successfully Fixed2', @@ -2578,7 +2578,7 @@ const en = { addMenu: 'Add Menu', editSite: 'Edit Station', addSite: 'Add Station', - selectsite:'Select Station', + selectsite: 'Select Station', diff --git a/src/pages/RealTimeMonitor.tsx b/src/pages/RealTimeMonitor.tsx index 2c37876..5dff2dd 100644 --- a/src/pages/RealTimeMonitor.tsx +++ b/src/pages/RealTimeMonitor.tsx @@ -39,6 +39,7 @@ import { getSiteUAVList, getWayLine, createWaylineTask, getUAVState, postFlightCommmand, getFlightTaskDetail } from '../api/device'; +import utils from '../lib/utils'; const { Option } = Select; const { Search } = Input; @@ -142,6 +143,7 @@ const RealTimeMonitorPage = () => { }; }, [robotRealtimePosition]); const [runningPoolTask, setRunningPoolTask] = useState(null); + const [proPoints, setProPoints] = useState({});//规划点 // ========= UI 状态 ========= const [selectedDevice, setSelectedDevice] = useState(null); @@ -175,17 +177,18 @@ const RealTimeMonitorPage = () => { controller.onLocationInfoUpdate = (pos) => { setRobotRealtimePosition(pos); }; + controller.onIsFinished = handleFinish; + controller.onRoutePost = (msg) => { - console.log('[RTMonitor] route_post:', msg); const { taskId, data } = msg; - const matchedTask = taskPoolList.find(task => String(task.id) === String(taskId)); - const sameAsSelected = runningPoolTask && String(runningPoolTask.id) === String(taskId); - if ((!runningPoolTask && matchedTask) || sameAsSelected) { - if (!runningPoolTask && matchedTask) setRunningPoolTask(matchedTask); - if (data) setPoints(data); - loadTaskPath(taskId); - } + //const matchedTask = taskPoolList.find(task => String(task.id) === String(taskId)); + //const sameAsSelected = runningPoolTask && String(runningPoolTask.id) === String(taskId); + //if ((!runningPoolTask && matchedTask) || sameAsSelected) { + // if (!runningPoolTask && matchedTask) setRunningPoolTask(matchedTask); + console.log('[RTMonitor] route_post:', data) + setProPoints(msg); + //} }; controller.init(); @@ -199,6 +202,28 @@ const RealTimeMonitorPage = () => { }; // eslint-disable-next-line }, []); + useEffect(() => { + //console.log('runningPoolTask?.id, proPoints?.taskId', proPoints) + if (!runningPoolTask?.id || !proPoints?.taskId) return; + if (runningPoolTask?.id == proPoints?.taskId) { + console.log('1111111111', proPoints?.data); + setPoints(proPoints?.data); + } + + + }, [runningPoolTask, proPoints]); + const handleFinish = (data) => { + setExecute(false); + + utils.message.success(t('devices.fixed2TaskSuspended2Fixed2CompletedFixed2')); + setPoints([]); + setPolyPoints([]); + setRunningPoolTask(null); + setExcuteStatus('stop'); + }; + // ============================================================ + // WebSocket 连接 + // ============================================================ // 拉取基础数据 @@ -298,7 +323,7 @@ const RealTimeMonitorPage = () => { .filter(p => !isNaN(p.lng) && !isNaN(p.lat) && Math.abs(p.lng) < 180 && Math.abs(p.lat) < 90 && p.lng !== 0 && p.lat !== 0); console.log('[RTMonitor] fetchRouteDetailAndShow:', routeId, mapPoints); if (mapPoints.length) { - setPoints(mapPoints); + setPolyPoints(mapPoints); setRouteMode(mode || ''); @@ -796,7 +821,6 @@ const RealTimeMonitorPage = () => { if (newTask) { setRunningPoolTask(newTask); await loadTaskPath(newTask.id); - await fetchDetailTaskPath(newTask.id); setExcuteStatus('running'); } } else { @@ -980,6 +1004,8 @@ const RealTimeMonitorPage = () => {
📡 {t('devices.realtimePosition')}
Lng: {Number(robotRealtimePosition.longitude || robotRealtimePosition.lng || 0).toFixed(5)}
Lat: {Number(robotRealtimePosition.latitude || robotRealtimePosition.lat || 0).toFixed(5)}
+
yaw: {Number(robotRealtimePosition.heading || 0).toFixed(5)}
+ )} @@ -1312,7 +1338,6 @@ const RealTimeMonitorPage = () => { {(runningPoolTask || deviceTasks.current) ? ( (() => { const task = runningPoolTask || deviceTasks.current; - console.log(task, " dsada") return ( @@ -1433,7 +1458,7 @@ const RealTimeMonitorPage = () => { type="text" size="small" icon={} - disabled={!selectedDevice || selectedDevice.onlineStatus !== 1} + //disabled={!selectedDevice || selectedDevice.onlineStatus !== 1} onClick={(e) => { e.stopPropagation(); handleRouteExecute(route);