diff --git a/src/api/api.ts b/src/api/api.ts index 87fdf5f..f304537 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -97,6 +97,15 @@ export function loginApi(data) { // 可视化面板获取无人机信息 +// 获取无人机实时状态详情 +export function getUAVState(params) { + return api({ + url: '/iot/device/getUAVState', + method: 'get', + params + }) +} + // 获取所有航线 diff --git a/src/api/device.ts b/src/api/device.ts index 82810d7..001989c 100644 --- a/src/api/device.ts +++ b/src/api/device.ts @@ -40,6 +40,15 @@ export function getControlRight(params) { }) } +// 获取无人机实时状态详情 +export function getUAVState(params) { + return request({ + url: '/iot/UAV/getUAVState', + method: 'get', + params + }) +} + // 远程遥控 判断是否有权限/forward/device/remoteControl platform:web export function getJurisdiction(data) { return request({ @@ -215,13 +224,3 @@ export function getAllDevice(data) { }) } -//根据单个机场获取信息/iot/device/getUAVState - -export function getSingleUAV(data) { - return request({ - url: `/iot/device/getUAVState`, - method: 'get', - params: data - }) -} - diff --git a/src/components/devices/DeviceControl.tsx b/src/components/devices/DeviceControl.tsx index 9ce1b57..b0733b7 100644 --- a/src/components/devices/DeviceControl.tsx +++ b/src/components/devices/DeviceControl.tsx @@ -10,7 +10,7 @@ import { X } from 'lucide-react'; import XboxController from './XboxController'; -import { getControlRight, getFlightTaskDetail, getJurisdiction, getLiveStream, getPlaneDeviceList, getsinglePlan, getsinglePlanTrack, getWayLine, getWorkData, getWorkList, postFlightCommmand, saveDeviceTask, updateFlightTaskStatus } from '@/api/api'; +import { getControlRight, getFlightTaskDetail, getJurisdiction, getLiveStream, getPlaneDeviceList, getsinglePlan, getsinglePlanTrack, getUAVState, getWayLine, getWorkData, getWorkList, postFlightCommmand, saveDeviceTask, updateFlightTaskStatus } from '@/api/api'; import { message as antdMessage, Button, DatePicker, Input, InputNumber, Modal, Select, Tooltip } from 'antd'; import CesiumMap from './Map'; @@ -1071,6 +1071,12 @@ const RobotControlCenter = ({ setView }) => { setIsModalOpen(false); } } + const [uavState, setUavState] = useState(null); + const uavTimerRef = useRef(null); + + // 定时获取无人机状态 + + const calcPercent = (value, max) => { const num = Number(value); if (!Number.isFinite(num) || max <= 0) return 0; @@ -1413,13 +1419,69 @@ const RobotControlCenter = ({ setView }) => {

{selectedDevice?.name} -

视频链路已配置
+ + {/* 无人机状态概览 */} + {selectedDevice?.type === 'plane' && (uavState || selectedDevice) && ( +
+
+

+ 电池电量 +

+
+
+
+
+ {(uavState || selectedDevice).capacity_percent || 0}% +
+
+
+

+ 飞行高度 +

+

+ {Number((uavState || selectedDevice).height || 0).toFixed(2)} m +

+
+
+

+ 信号/卫星 +

+

+ {(uavState || selectedDevice).position_state?.gps_number || 0} GPS + / + {(uavState || selectedDevice).position_state?.rtk_number || 0} RTK +

+
+
+

+ 环境风速 +

+

+ {Number((uavState || selectedDevice).wind_speed || 0).toFixed(2)} m/s +

+
+
+

+ RTK 状态 +

+
+
+ + {(uavState || selectedDevice).position_state?.is_fixed === 'fixing_successful' ? '已固定' : '未固定'} + +
+
+
+ )} {/*

当前位置

diff --git a/src/components/devices/DeviceOverviewPage.tsx b/src/components/devices/DeviceOverviewPage.tsx index efb9eb8..8932dcb 100644 --- a/src/components/devices/DeviceOverviewPage.tsx +++ b/src/components/devices/DeviceOverviewPage.tsx @@ -22,6 +22,7 @@ import AgoraTextTest from '../AgoraRtc.tsx'; import { useWebRTCPlayer } from '../useWebRTCStream.tsx'; import VideoPlayer from '../VideoPlayer.tsx.tsx'; import CesiumMap from '../Map.jsx'; +import { getUAVState } from '@/api/device.ts'; const { Content } = Layout; const { Text, Title } = Typography; @@ -48,6 +49,7 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll, const [zoomedVideo, setZoomedVideo] = useState(null); const [mowerView, setMowerView] = useState('front'); const [videoSource, setVideoSource] = useState('drone'); // 恢复 videoSource 状态管理 + const [uavState, setUavState] = useState(null); const selectedDevice = React.useMemo(() => { const sn = selectedSn || (devicesAll?.[0]?.device_sn || devicesAll?.[0]?.serialNumber); @@ -109,6 +111,31 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll, if (onDeviceSelect) onDeviceSelect(id); }; + + useEffect(() => { + const fetchUavState = async () => { + if (isUAV && selectedDevice?.gateway_sn && selectedDevice?.device_sn) { + try { + const res = await getUAVState({ + sn: selectedDevice.gateway_sn, + droneSn: selectedDevice.device_sn + }); + if (res.code === 200) { + setUavState(res.data); + } + } catch (err) { + console.error('获取无人机状态失败', err); + } + } else { + setUavState(null); + } + }; + + fetchUavState(); + + + }, [isUAV, selectedDevice]); + return ( @@ -226,12 +253,12 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
- 电量 {fix2(selectedDevice.capacity_percent || 100)}% + 电量 {fix2((uavState || selectedDevice).capacity_percent || 100)}%
- {selectedDevice.environment_temperature && ( + {(uavState || selectedDevice).environment_temperature && (
温度 - {fix2(selectedDevice.environment_temperature || 25)}℃ + {fix2((uavState || selectedDevice).environment_temperature || 25)}℃
)}
@@ -265,11 +292,22 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll, <>
飞行高度 - {fix2(selectedDevice.height)} m + {fix2((uavState || selectedDevice).height)} m
飞行风速 - {fix2(selectedDevice.wind_speed)} m/s + {fix2((uavState || selectedDevice).wind_speed)} m/s +
+
+ rtk数量 + + {/* + /*/} +
)} @@ -308,6 +346,8 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
-
风速
{fix2(selectedDevice?.wind_speed)} m/s
-
温度
{fix2(selectedDevice?.environment_temperature)}℃
-
降雨
{getVal(selectedDevice?.rainfall)}
-
RTK
{selectedDevice?.position_state?.is_fixed === 'fixing_successful' ? '固定' : '未固定'}
+
风速
{fix2((uavState || selectedDevice)?.wind_speed)} m/s
+
温度
{fix2((uavState || selectedDevice)?.environment_temperature)}℃
+
降雨
{getVal((uavState || selectedDevice)?.rainfall)}
+
RTK
{(uavState || selectedDevice)?.position_state?.is_fixed === 'fixing_successful' ? '固定' : '未固定'}
diff --git a/src/components/devices/DeviceStatusPage.tsx b/src/components/devices/DeviceStatusPage.tsx index a1f86c6..703ac74 100644 --- a/src/components/devices/DeviceStatusPage.tsx +++ b/src/components/devices/DeviceStatusPage.tsx @@ -33,6 +33,12 @@ import { EnvironmentOutlined, } from '@ant-design/icons'; +import { + getsinglePlanTrack, + getFlightTaskDetail, + getUAVState, +} from '../../api/device.ts'; + import XboxController from './XboxController'; import DroneVideoPlayer from './DroneVideoPlayer'; import CesiumMap from '../Map.jsx'; @@ -78,6 +84,8 @@ export default function DeviceStatusPage({ }); const [mowerView, setMowerView] = useState('front'); + const [uavState, setUavState] = useState(null); + const timerRef = useRef(null); const device = useMemo(() => { const sn = @@ -144,6 +152,31 @@ export default function DeviceStatusPage({ controllerRef.current.connectDevice(device); }, [device]); + // 定时获取无人机状态 + useEffect(() => { + const fetchUavState = async () => { + if (isUAV && device?.gateway_sn && device?.device_sn) { + try { + const res = await getUAVState({ + sn: device.gateway_sn, + droneSn: device.device_sn + }); + if (res.code === 200) { + setUavState(res.data); + } + } catch (err) { + console.error('获取无人机状态失败', err); + } + } else { + setUavState(null); + } + }; + + fetchUavState(); + + + }, [isUAV, device]); + const mapDevices = useMemo(() => { if (!device) return []; @@ -413,26 +446,26 @@ export default function DeviceStatusPage({ {isUAV ? ( 电池电量}> - + 飞行高度}> - {fix2(device.height)} m + {fix2((uavState || device).height)} m - {fix2(device.wind_speed)} m/s - {fix2(device.environment_temperature)} ℃ + {fix2((uavState || device).wind_speed)} m/s + {fix2((uavState || device).environment_temperature)} ℃ - {getVal(device.rainfall)} + {getVal((uavState || device).rainfall)} - {fix2(device.home_distance)} m + {fix2((uavState || device).home_distance)} m - + - + - - {device.position_state?.is_fixed === 'fixing_successful' ? 'RTK 已固定' : '未固定'} + + {(uavState || device).position_state?.is_fixed === 'fixing_successful' ? 'RTK 已固定' : '未固定'} diff --git a/src/components/devices/DroneVideoPlayer.tsx b/src/components/devices/DroneVideoPlayer.tsx index 210b9a9..b0f17a3 100644 --- a/src/components/devices/DroneVideoPlayer.tsx +++ b/src/components/devices/DroneVideoPlayer.tsx @@ -19,6 +19,8 @@ interface DroneVideoPlayerProps { const DroneVideoPlayer: React.FC = ({ device, + wind_speed, + h, height = 160, showSourceSelect = true, dualVideo = false, @@ -230,19 +232,22 @@ const DroneVideoPlayer: React.FC = ({
)} -
- {isDrone ? '无人机视频' : '机场视频'} -
+ {showSourceSelect && ( +
+ {isDrone ? '无人机视频' : '机场视频'} +
+ )} + {/* 底部信息叠加 */} {isDrone && device && ( @@ -258,8 +263,8 @@ const DroneVideoPlayer: React.FC = ({ padding: '4px 8px', fontSize: 10 }}> - 高度 {device.height?.toFixed(2) || '-'}m - 风速 {device.wind_speed?.toFixed(2) || '-'}m/s + 高度 {h.toFixed(2) || device.height?.toFixed(2) || '-'}m + 风速 {wind_speed.toFixed(2) || device.wind_speed?.toFixed(2) || '0'}m/s
)}