diff --git a/env.js b/env.js index a14bf14..8715ca4 100644 --- a/env.js +++ b/env.js @@ -9,17 +9,17 @@ const currentEnv = import.meta.env?.MODE || process.env.NODE_ENV; // 环境配置映射 const envConfig = { [ENV.DEV]: { - //baseURL: 'http://192.168.2.59:8081',//http://192.168.2.56:8081 + baseURL: 'http://1.95.137.212:8081',//http://192.168.2.56:8081 ////baseURL: 'http://1.95.137.212:59015',//http://192.168.2.56:8081 //WS_URL: 'ws://192.168.2.59:9002/ws/', //mqtt_url: "ws://1.95.137.212:8083/mqtt", //geoserver_url: "http://192.168.2.59:7000/geoserver" - baseURL: 'http://1.95.137.212:8081',//http://192.168.2.56:8081 - //baseURL: 'http://192.168.2.34:8081',//http://192.168.2.56:8081 + //baseURL: 'http://1.95.137.212:8081',//http://192.168.2.56:8081 + //baseURL: 'http://192.168.2.62:8081',//http://192.168.2.56:8081 //baseURL: 'https://serviceri.satabot.com', - //WS_URL: 'ws://1.95.137.212:9002/ws/', - WS_URL: 'ws://192.168.2.34:9002/ws/', + WS_URL: 'ws://1.95.137.212:9002/ws/', + //WS_URL: 'ws://192.168.2.62:9002/ws/', mqtt_url: "ws://1.95.137.212:8083/mqtt", geoserver_url: "http://1.95.137.212:7900/geoserver" diff --git a/src/components/Map.jsx b/src/components/Map.jsx index c93d07a..22eeb1d 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -39,6 +39,8 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, const planLineRef = useRef(null); // points 规划航线 const navLineRef = useRef(null); // 完成点实时轨迹 const markedPointsRef = useRef([]); // 标记点实体 + const { t } = useTranslation(); + const realtimeEntityRef = useRef(null); const realtimeLineRef = useRef(null); @@ -343,8 +345,7 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, } }, [markedPoints]); - function showRobotTooltip(tooltip, robot, position) { - const { t } = useTranslation(); + function showRobotTooltip(tooltip, robot, position, t) { const statusMap = { 1: { text: t('common.working'), color: "#10b981" }, 2: { text: t('devices.idle'), color: "#f59e0b" }, @@ -1400,7 +1401,7 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine, const picked = viewer.scene.pick(movement.endPosition); if (window.Cesium.defined(picked) && picked.id?.properties?.robot) { const robot = picked.id.properties.robot.getValue(); - showRobotTooltip(tooltipRef.current, robot, movement.endPosition); + showRobotTooltip(tooltipRef.current, robot, movement.endPosition, t); } else { tooltipRef.current.style.display = "none"; } diff --git a/src/components/devices/DeviceControl.tsx b/src/components/devices/DeviceControl.tsx index 2e08d54..82d7007 100644 --- a/src/components/devices/DeviceControl.tsx +++ b/src/components/devices/DeviceControl.tsx @@ -459,8 +459,17 @@ const RobotControlCenter = ({ setView }) => { } const getControl = (serialnum) => { setIsConnecting(true); + let userParse = null; + try { + const dataStr = localStorage.getItem("userInfo"); + userParse = dataStr ? JSON.parse(dataStr) : null; + } catch (e) { + console.error("用户信息解析失败", e); + } - const data = { platform: "web", deviceId: serialnum }; + const token = userParse.token || Cookies.get("Admin-Token"); + + const data = { platform: "web", deviceId: serialnum, token: token }; getJurisdiction(data).then(res => { if (res?.data?.code === 200 && res?.data?.data?.remoteControl == true) { console.log("获取远程遥控权限成功"); diff --git a/src/components/devices/DeviceStatusPage.tsx b/src/components/devices/DeviceStatusPage.tsx index 109e786..353cab2 100644 --- a/src/components/devices/DeviceStatusPage.tsx +++ b/src/components/devices/DeviceStatusPage.tsx @@ -1,4 +1,4 @@ -import React, { +import React, { useState, useEffect, useMemo, @@ -78,6 +78,7 @@ export default function DeviceStatusPage() { const [arrivedPoint, setArrivedPoint] = useState(null);//完成点 const [isLoopMode, setIsLoopMode] = useState(true); const controllerRef = useRef(null); + const isFirstConnect = useRef(true); const [messageApi, contextHolder] = message.useMessage(); @@ -388,7 +389,6 @@ export default function DeviceStatusPage() { const runningStatus = useMemo(() => { - console.log(locationInfo, "locationInfo") // 判断对象是否为空 if ((!wsDeviceInfo || Object.keys(wsDeviceInfo).length === 0) && (!locationInfo || Object.keys(locationInfo).length === 0) && !isUAV) { return {}; @@ -408,7 +408,6 @@ export default function DeviceStatusPage() { ...locationInfo }; }, [device, wsDeviceInfo, isUAV, locationInfo]); - console.log(runningStatus, "runningStatus") const { video: robotVideo, error, ready } = useWebRTCPlayer( (!isUAV && isVideoPlaying) ? (device?.serialNumber || '') : '', @@ -485,14 +484,19 @@ export default function DeviceStatusPage() { useEffect(() => { if (!device || !controllerRef.current || !device?.serialNumber || isUAV) { - //controllerRef.current?.destroy(); - //setWsDeviceInfo({}); return; } setWsDeviceInfo({}); setLocationInfo({}); - controllerRef.current.connectDevice(device); + if (isFirstConnect.current) { + + isFirstConnect.current = false; + controllerRef.current.connectDevice(device); + } else { + + controllerRef.current.switchDevice(device); + } }, [device?.serialNumber]); diff --git a/src/components/devices/RobotTaskPage.tsx b/src/components/devices/RobotTaskPage.tsx index 8e5a417..6a1f7f1 100644 --- a/src/components/devices/RobotTaskPage.tsx +++ b/src/components/devices/RobotTaskPage.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useRef, useMemo } from 'react'; +import React, { useState, useEffect, useRef, useMemo } from 'react'; import { Row, Col, Card, Button, Space, Table, Tag, Typography, Progress, Badge, Tabs, Input, Switch, Divider, Tooltip, Timeline, Select, message, DatePicker, @@ -141,6 +141,7 @@ export default function RobotTaskPage() { }); const [messageApi, contextHolder] = message.useMessage(); const controllerRef = useRef(null); + const isFirstConnect = useRef(true); const handleFinish = (data) => { setExecute(false); setShowVideo(false); // 任务完成关闭视频 @@ -240,7 +241,7 @@ export default function RobotTaskPage() { setExecute(true); setExecutingRobot(targetDevice); setClearNavLine(v => v + 1); // 清空地图轨迹 - controllerRef.current?.connectDevice(targetDevice); + if (isFirstConnect.current) { isFirstConnect.current = false; controllerRef.current?.connectDevice(targetDevice); } else { controllerRef.current?.switchDevice(targetDevice); } setShowVideo(true); }; @@ -300,7 +301,7 @@ export default function RobotTaskPage() { setExecute(true); setExecutingRobot(targetDevice); setClearNavLine(v => v + 1); // 清空地图轨迹 - controllerRef.current?.connectDevice(targetDevice); + if (isFirstConnect.current) { isFirstConnect.current = false; controllerRef.current?.connectDevice(targetDevice); } else { controllerRef.current?.switchDevice(targetDevice); } setShowVideo(true); }, [devices, taskPoolList, executingRobot, runningPoolTask]); @@ -450,7 +451,7 @@ export default function RobotTaskPage() { setExecute(true); setExecutingRobot(targetDevice); setClearNavLine(v => v + 1); // 清空地图轨迹 - controllerRef.current?.connectDevice(targetDevice); + if (isFirstConnect.current) { isFirstConnect.current = false; controllerRef.current?.connectDevice(targetDevice); } else { controllerRef.current?.switchDevice(targetDevice); } setShowVideo(true); } } @@ -556,7 +557,7 @@ export default function RobotTaskPage() { fetchTaskList(); fetchTaskPoolList(); fetchTaskHistoryList(); - controllerRef.current?.connectDevice(selectedRobotForExecute); + if (isFirstConnect.current) { isFirstConnect.current = false; controllerRef.current?.connectDevice(selectedRobotForExecute); } else { controllerRef.current?.switchDevice(selectedRobotForExecute); } setShowVideo(true); // 连接成功后自动打开视频 } else { diff --git a/src/components/devices/XboxController.tsx b/src/components/devices/XboxController.tsx index 1eebad8..a0172ed 100644 --- a/src/components/devices/XboxController.tsx +++ b/src/components/devices/XboxController.tsx @@ -116,7 +116,7 @@ const XboxController = ({ onGamepadUpdate, handleControlModal, isControlled, isC return (
{ - if (connected && !isControlled && hasControlRight) { + if (!isControlled) { console.log("点击了无控制权限,发起权限请求"); // 示例:调用你代码中已有的权限请求弹窗逻辑 handleControlModal({ control: true, type: "switchPermission" }); @@ -125,7 +125,7 @@ const XboxController = ({ onGamepadUpdate, handleControlModal, isControlled, isC {/* Gamepad Status Badge */}
{!connected ? ( t('devices.controllerNotConnected') - ) : !hasControlRight ? ( - t('devices.otherWebConnected') ) : isConnecting ? ( t('devices.control2') ) : isControlled ? ( diff --git a/src/components/devices/deviceController.js b/src/components/devices/deviceController.js index 983e38b..ae87f9b 100644 --- a/src/components/devices/deviceController.js +++ b/src/components/devices/deviceController.js @@ -1,7 +1,6 @@ import throttle from 'lodash/throttle'; import { wsManager } from '../WebSocketManager.ts'; import { - getControlRight, getJurisdiction, releaseControl } from '../../api/device.ts'; @@ -63,11 +62,15 @@ export default class DeviceController { document.addEventListener('visibilitychange', this.handleVisibilityChange); document.addEventListener('beforeunload', this.handleBeforeUnload); } + levae() { + wsManager.close(); + + } handleVisibilityChange() { if (document.visibilityState === 'hidden') { - console.log('?? 页�面进入后台,释放控制权限'); - + console.log('Page hidden, release control'); + //this.release(); wsManager.close(); this.connectedDeviceSn = null; @@ -76,7 +79,7 @@ export default class DeviceController { } if (document.visibilityState === 'visible' && this.currentDevice) { if (!this.currentDevice?.serialNumber) return; - console.log('? 页面切回前台,自动重连 WebSocket'); + console.log('Page visible, reconnect WebSocket'); setTimeout(() => { this.connectDevice(this.currentDevice); }, 500); @@ -84,7 +87,7 @@ export default class DeviceController { } handleBeforeUnload() { - console.log('?? 浏览器即将关闭/刷新,释放控制权限'); + console.log('Browser closing/refreshing, release control'); this.release(); } @@ -95,35 +98,30 @@ export default class DeviceController { this.wsStatus !== 'connected' && this.currentDevice?.serialNumber ) { - console.log('?? 后台保活:重新连接 WebSocket'); + console.log('Keep alive: reconnect WebSocket'); this.connectDevice(this.currentDevice); } }, 8000); } - async release() { - console.log('?? 释放控制权限'); - //if (this.isControlled && this.connectedDeviceSn) { + if (!this.connectedDeviceSn) return; const data = { platform: 'web', type: 1, deviceId: this.connectedDeviceSn, + token: this.userInfo.token, }; const url = `${envConfig.baseURL}/forward/device/releaseControl`; - console.log('?? 释放控制权限1111'); try { await releaseControl(data); - console.log('?? 释放控制权限1111222'); - const blob = new Blob([JSON.stringify(data)], { type: 'application/json' }); navigator.sendBeacon(url, blob); - console.log('✅ 已发送 releaseControl 请求'); + console.log('releaseControl sent'); } catch (e) { - console.error('Failed to send releaseControl beacon:', e); + console.error('Failed to send releaseControl:', e); } - //} } destroy() { @@ -138,6 +136,7 @@ export default class DeviceController { document.removeEventListener('beforeunload', this.handleBeforeUnload); this.release(); + this.levae(); this.unSubMessage?.(); this.unSubStatus?.(); @@ -172,6 +171,7 @@ export default class DeviceController { wsManager.close(); try { + console.log('Connecting to', this.wsUrl); wsManager.connect(sn, this.wsUrl); this.connectedDeviceSn = sn; @@ -182,11 +182,42 @@ export default class DeviceController { } } + async switchDevice(device) { + if (!device) return; + if (!device.serialNumber) return; + + const newSn = device.serialNumber; + + if (this.connectedDeviceSn === newSn && this.wsStatus === 'connected') { + console.log('switchDevice: same device, skip'); + return; + } + + console.log('Connecting to switchDevice: switching to', newSn); + + this.currentDevice = device; + this.connectedDeviceSn = newSn; + this.wsDeviceInfo = {}; + this.locationInfo = {}; + this.isControlled = false; + this.onControlStatusChange?.(false); + + wsManager.send({ + type: 'AUTH', + token: this.userInfo.token, + userName: this.userInfo.username, + deviceId: newSn, + }); + + await this.getControl(newSn); + } + async getControl(serialnum) { try { const res = await getJurisdiction({ platform: 'web', deviceId: serialnum, + token: this.userInfo.token, }); this.isControlled = res?.code === 200 && res?.data?.remoteControl === true; @@ -200,10 +231,7 @@ export default class DeviceController { requestControl() { if (this.isRequestControl) return; - if (!this.hasControlRight) { - this.messageApi.warning(i18n.t('devices.noneControl')); - return; - } + this.isRequestControl = true; this.onRequestControlStatusChange?.(true); @@ -246,7 +274,7 @@ export default class DeviceController { } handleWsMessage(msg) { - console.log('?? 收到消息:', msg); + console.log('WS message:', msg); switch (msg.type) { case 'deviceInfo': { const data = {}; @@ -280,7 +308,7 @@ export default class DeviceController { this.isRequestControl = false; this.onRequestControlStatusChange?.(false); - if (msg.success === false || msg?.respond?.switchResult === false) { + if (msg?.success === false || msg?.respond?.switchResult === false) { this.isControlled = false; this.onControlStatusChange?.(false); this.messageApi.error({ key: 'control', content: msg.message || i18n.t('devices.controlFailed') }); @@ -294,15 +322,14 @@ export default class DeviceController { case "device_task_change": { if (msg.deviceId != this.connectedDeviceSn) return; this.onIsFinished?.(true); - console.log('?? 任务结束收到,', msg); - + console.log('task change:', msg); + break; } case "device_task_arrive_point": { if (msg.deviceId != this.connectedDeviceSn) return; - this.handleArrivedPoint?.(msg.entity); - console.log('?? 收到抵达,', msg); - + console.log('arrive point:', msg); + break; } case 'switchPermission': { diff --git a/src/locales/en/index.ts b/src/locales/en/index.ts index 7ddd3b3..28a8346 100644 --- a/src/locales/en/index.ts +++ b/src/locales/en/index.ts @@ -659,6 +659,8 @@ const en = { optimize: 'Optimize', optionalEmpty: 'Optional Empty', otherWebControlling: 'Other Web Controlling', + platformRequestControl: "{{platform}} platformRequestControl", + outDock: 'Out Dock', outdoor: 'Outdoor', panorama: 'Panorama', @@ -1285,9 +1287,10 @@ const en = { failedFixed22: '权限校验 Failed Fixed2', - noneControl: 'None Control 权限', + noneControl: 'None Control jurisdiction', fixed2ControlFixed2: 'Fixed2 Control 请求 超时 Fixed2', + controlFailed:"请求被拒绝", }, video: { onlineVideo: 'Online Video', diff --git a/src/locales/zh/index.ts b/src/locales/zh/index.ts index fd98ecd..988a256 100644 --- a/src/locales/zh/index.ts +++ b/src/locales/zh/index.ts @@ -1302,6 +1302,9 @@ const zh = { cancel: "取消", UnitsRobot: "台", UnitsDrone: "架", + platformRequestControl: "{{platform}} 正在请求控制权限", + controlFailed: "controlFailed", + }, video: { onlineVideo: '在线视频',