获取单个无人机详情
This commit is contained in:
@@ -97,6 +97,15 @@ export function loginApi(data) {
|
||||
|
||||
// 可视化面板获取无人机信息
|
||||
|
||||
// 获取无人机实时状态详情
|
||||
export function getUAVState(params) {
|
||||
return api({
|
||||
url: '/iot/device/getUAVState',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 获取所有航线
|
||||
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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<any>(null);
|
||||
const uavTimerRef = useRef<any>(null);
|
||||
|
||||
// 定时获取无人机状态
|
||||
|
||||
|
||||
const calcPercent = (value, max) => {
|
||||
const num = Number(value);
|
||||
if (!Number.isFinite(num) || max <= 0) return 0;
|
||||
@@ -1413,13 +1419,69 @@ const RobotControlCenter = ({ setView }) => {
|
||||
<div>
|
||||
<h1 className="text-xl font-bold text-white mb-1">
|
||||
{selectedDevice?.name}
|
||||
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<span className="bg-[#00e5ff]/10 text-[#00e5ff] text-xs px-3 py-1.5 rounded-lg border border-[#00e5ff]/30">视频链路已配置</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 无人机状态概览 */}
|
||||
{selectedDevice?.type === 'plane' && (uavState || selectedDevice) && (
|
||||
<div className="grid grid-cols-5 gap-3 mb-6">
|
||||
<div className="bg-white/5 backdrop-blur-sm rounded-xl p-4 border border-[#243157]/40 shadow-sm">
|
||||
<p className="text-xs text-[#9ca3af] mb-1.5 flex items-center gap-1.5">
|
||||
<Battery className="w-3.5 h-3.5" /> 电池电量
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 h-1.5 bg-slate-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full transition-all ${((uavState || selectedDevice).capacity_percent || 0) < 20 ? 'bg-red-500' : 'bg-green-500'}`}
|
||||
style={{ width: `${(uavState || selectedDevice).capacity_percent || 0}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<span className="text-sm font-bold text-white">{(uavState || selectedDevice).capacity_percent || 0}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-white/5 backdrop-blur-sm rounded-xl p-4 border border-[#243157]/40 shadow-sm">
|
||||
<p className="text-xs text-[#9ca3af] mb-1.5 flex items-center gap-1.5">
|
||||
<ArrowUp className="w-3.5 h-3.5" /> 飞行高度
|
||||
</p>
|
||||
<p className="text-sm font-bold text-white">
|
||||
{Number((uavState || selectedDevice).height || 0).toFixed(2)} <span className="text-[10px] font-normal text-slate-400">m</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white/5 backdrop-blur-sm rounded-xl p-4 border border-[#243157]/40 shadow-sm">
|
||||
<p className="text-xs text-[#9ca3af] mb-1.5 flex items-center gap-1.5">
|
||||
<Wifi className="w-3.5 h-3.5" /> 信号/卫星
|
||||
</p>
|
||||
<p className="text-sm font-bold text-white">
|
||||
{(uavState || selectedDevice).position_state?.gps_number || 0} <span className="text-[10px] font-normal text-slate-400">GPS</span>
|
||||
<span className="mx-1 text-slate-600">/</span>
|
||||
{(uavState || selectedDevice).position_state?.rtk_number || 0} <span className="text-[10px] font-normal text-slate-400">RTK</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white/5 backdrop-blur-sm rounded-xl p-4 border border-[#243157]/40 shadow-sm">
|
||||
<p className="text-xs text-[#9ca3af] mb-1.5 flex items-center gap-1.5">
|
||||
<Activity className="w-3.5 h-3.5" /> 环境风速
|
||||
</p>
|
||||
<p className="text-sm font-bold text-white">
|
||||
{Number((uavState || selectedDevice).wind_speed || 0).toFixed(2)} <span className="text-[10px] font-normal text-slate-400">m/s</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="bg-white/5 backdrop-blur-sm rounded-xl p-4 border border-[#243157]/40 shadow-sm">
|
||||
<p className="text-xs text-[#9ca3af] mb-1.5 flex items-center gap-1.5">
|
||||
<Settings className="w-3.5 h-3.5" /> RTK 状态
|
||||
</p>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<div className={`w-2 h-2 rounded-full ${(uavState || selectedDevice).position_state?.is_fixed === 'fixing_successful' ? 'bg-green-500' : 'bg-yellow-500'}`}></div>
|
||||
<span className="text-xs font-bold text-white">
|
||||
{(uavState || selectedDevice).position_state?.is_fixed === 'fixing_successful' ? '已固定' : '未固定'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/*<div className="grid grid-cols-5 gap-3">
|
||||
<div className="bg-white/5 backdrop-blur-sm rounded-xl p-4 border border-[#243157]/40 shadow-sm">
|
||||
<p className="text-xs text-[#9ca3af] mb-1.5">当前位置</p>
|
||||
|
||||
@@ -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 (
|
||||
<Content style={{ margin: '0 8', }}>
|
||||
<Row gutter={[8, 8]} style={{ marginBottom: 12, flexWrap: 'wrap' }}>
|
||||
@@ -226,12 +253,12 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
|
||||
<span style={{ color: '#52c41a' }}><ThunderboltOutlined /></span>
|
||||
<span style={{ fontSize: 12 }}>电量 {fix2(selectedDevice.capacity_percent || 100)}%</span>
|
||||
<span style={{ fontSize: 12 }}>电量 {fix2((uavState || selectedDevice).capacity_percent || 100)}%</span>
|
||||
</div>
|
||||
{selectedDevice.environment_temperature && (
|
||||
{(uavState || selectedDevice).environment_temperature && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<span style={{ fontSize: 12 }}>温度</span>
|
||||
<span style={{ color: '#faad14' }}>{fix2(selectedDevice.environment_temperature || 25)}℃</span>
|
||||
<span style={{ color: '#faad14' }}>{fix2((uavState || selectedDevice).environment_temperature || 25)}℃</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -265,11 +292,22 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
|
||||
<>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span style={{ color: '#666', fontSize: 12 }}>飞行高度</span>
|
||||
<span style={{ fontSize: 12 }}>{fix2(selectedDevice.height)} m</span>
|
||||
<span style={{ fontSize: 12 }}>{fix2((uavState || selectedDevice).height)} m</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span style={{ color: '#666', fontSize: 12 }}>飞行风速</span>
|
||||
<span style={{ fontSize: 12 }}>{fix2(selectedDevice.wind_speed)} m/s</span>
|
||||
<span style={{ fontSize: 12 }}>{fix2((uavState || selectedDevice).wind_speed)} m/s</span>
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<span style={{ color: '#666', fontSize: 12 }}>rtk数量</span>
|
||||
<span style={{ fontSize: 12 }}>
|
||||
{/*<Badge count={(uavState || selectedDevice).position_state?.gps_number || 0} style={{ backgroundColor: '#1890ff', transform: 'scale(0.8)' }} />
|
||||
<span style={{ margin: '0 2px' }}>/</span>*/}
|
||||
<Badge
|
||||
showZero={true}
|
||||
count={(uavState || selectedDevice)?.position_state?.rtk_number || 0}
|
||||
style={{ backgroundColor: '#52c41a', transform: 'scale(0.8)' }}
|
||||
/> </span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -308,6 +346,8 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
|
||||
<DroneVideoPlayer
|
||||
device={selectedDevice}
|
||||
height={160}
|
||||
wind_speed={uavState?.wind_speed}
|
||||
h={uavState?.height}
|
||||
showSourceSelect={false}
|
||||
videoSource={videoSource}
|
||||
onSourceChange={setVideoSource}
|
||||
@@ -374,10 +414,10 @@ export default function DeviceOverviewPage({ devices, planedevices, devicesAll,
|
||||
<Card title="环境与飞行条件" bordered={false} style={{ borderRadius: 12, marginBottom: 8 }}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", gap: 12, alignItems: "center" }}>
|
||||
<div style={{ display: "flex", border: "1px solid #e8e8e8", borderRadius: 12, overflow: "hidden", flex: 1 }}>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px", borderRight: "1px solid #e8e8e8" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>风速</div><div style={{ fontSize: 14, fontWeight: 700, color: '#222', marginTop: 2 }}>{fix2(selectedDevice?.wind_speed)} m/s</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px", borderRight: "1px solid #e8e8e8" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>温度</div><div style={{ fontSize: 14, fontWeight: 700, color: '#222', marginTop: 2 }}>{fix2(selectedDevice?.environment_temperature)}℃</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px", borderRight: "1px solid #e8e8e8" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>降雨</div><div style={{ fontSize: 14, fontWeight: 700, color: '#222', marginTop: 2 }}>{getVal(selectedDevice?.rainfall)}</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>RTK</div><div style={{ fontSize: 14, fontWeight: 700, color: '#52c41a', marginTop: 2 }}>{selectedDevice?.position_state?.is_fixed === 'fixing_successful' ? '固定' : '未固定'}</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px", borderRight: "1px solid #e8e8e8" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>风速</div><div style={{ fontSize: 14, fontWeight: 700, color: '#222', marginTop: 2 }}>{fix2((uavState || selectedDevice)?.wind_speed)} m/s</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px", borderRight: "1px solid #e8e8e8" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>温度</div><div style={{ fontSize: 14, fontWeight: 700, color: '#222', marginTop: 2 }}>{fix2((uavState || selectedDevice)?.environment_temperature)}℃</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px", borderRight: "1px solid #e8e8e8" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>降雨</div><div style={{ fontSize: 14, fontWeight: 700, color: '#222', marginTop: 2 }}>{getVal((uavState || selectedDevice)?.rainfall)}</div></div>
|
||||
<div style={{ flex: 1, textAlign: 'center', whiteSpace: "nowrap", padding: "12px 4px" }}><div style={{ fontSize: 11, color: '#666', fontWeight: 600 }}>RTK</div><div style={{ fontSize: 14, fontWeight: 700, color: '#52c41a', marginTop: 2 }}>{(uavState || selectedDevice)?.position_state?.is_fixed === 'fixing_successful' ? '固定' : '未固定'}</div></div>
|
||||
</div>
|
||||
<div style={{ width: 110, padding: '12px 4px', borderRadius: 8, background: '#f6ffed', border: '1px solid #b7eb8f', textAlign: 'center', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 4 }}>
|
||||
<div className="flex items-center gap-1">
|
||||
|
||||
@@ -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<any>(null);
|
||||
const timerRef = useRef<any>(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 ? (
|
||||
<Descriptions column={2} size="small" layout="vertical">
|
||||
<Descriptions.Item label={<><ThunderboltOutlined /> 电池电量</>}>
|
||||
<Progress percent={device.capacity_percent || 0} size="small" status={(device.capacity_percent || 0) < 20 ? 'exception' : 'active'} />
|
||||
<Progress percent={(uavState || device).capacity_percent || 0} size="small" status={((uavState || device).capacity_percent || 0) < 20 ? 'exception' : 'active'} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={<><EnvironmentOutlined /> 飞行高度</>}>
|
||||
<Text strong style={{ fontSize: 16 }}>{fix2(device.height)} m</Text>
|
||||
<Text strong style={{ fontSize: 16 }}>{fix2((uavState || device).height)} m</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="环境风速"><Text>{fix2(device.wind_speed)} m/s</Text></Descriptions.Item>
|
||||
<Descriptions.Item label="环境温度"><Text>{fix2(device.environment_temperature)} ℃</Text></Descriptions.Item>
|
||||
<Descriptions.Item label="环境风速"><Text>{fix2((uavState || device).wind_speed)} m/s</Text></Descriptions.Item>
|
||||
<Descriptions.Item label="环境温度"><Text>{fix2((uavState || device).environment_temperature)} ℃</Text></Descriptions.Item>
|
||||
<Descriptions.Item label="降雨状态">
|
||||
<Tag color={device.rainfall === 'no_rain' ? 'green' : 'red'}>{getVal(device.rainfall)}</Tag>
|
||||
<Tag color={(uavState || device).rainfall === 'no_rain' ? 'green' : 'red'}>{getVal((uavState || device).rainfall)}</Tag>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="返航距离"><Text>{fix2(device.home_distance)} m</Text></Descriptions.Item>
|
||||
<Descriptions.Item label="返航距离"><Text>{fix2((uavState || device).home_distance)} m</Text></Descriptions.Item>
|
||||
<Descriptions.Item label="GPS 卫星数">
|
||||
<Badge count={device.position_state?.gps_number || 0} style={{ backgroundColor: '#1890ff' }} />
|
||||
<Badge count={(uavState || device).position_state?.gps_number || 0} style={{ backgroundColor: '#1890ff' }} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="RTK 卫星数">
|
||||
<Badge count={device.position_state?.rtk_number || 0} style={{ backgroundColor: '#52c41a' }} />
|
||||
<Badge count={(uavState || device).position_state?.rtk_number || 0} style={{ backgroundColor: '#52c41a' }} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="RTK 状态" span={2}>
|
||||
<Tag color={device.position_state?.is_fixed === 'fixing_successful' ? 'success' : 'warning'}>
|
||||
{device.position_state?.is_fixed === 'fixing_successful' ? 'RTK 已固定' : '未固定'}
|
||||
<Tag color={(uavState || device).position_state?.is_fixed === 'fixing_successful' ? 'success' : 'warning'}>
|
||||
{(uavState || device).position_state?.is_fixed === 'fixing_successful' ? 'RTK 已固定' : '未固定'}
|
||||
</Tag>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
@@ -19,6 +19,8 @@ interface DroneVideoPlayerProps {
|
||||
|
||||
const DroneVideoPlayer: React.FC<DroneVideoPlayerProps> = ({
|
||||
device,
|
||||
wind_speed,
|
||||
h,
|
||||
height = 160,
|
||||
showSourceSelect = true,
|
||||
dualVideo = false,
|
||||
@@ -230,19 +232,22 @@ const DroneVideoPlayer: React.FC<DroneVideoPlayerProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
top: 6,
|
||||
left: 6,
|
||||
background: 'rgba(0,0,0,0.5)',
|
||||
color: '#fff',
|
||||
padding: '2px 6px',
|
||||
borderRadius: 4,
|
||||
fontSize: 10,
|
||||
zIndex: 5
|
||||
}}>
|
||||
{isDrone ? '无人机视频' : '机场视频'}
|
||||
</div>
|
||||
{showSourceSelect && (
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
top: 6,
|
||||
left: 6,
|
||||
background: 'rgba(0,0,0,0.5)',
|
||||
color: '#fff',
|
||||
padding: '2px 6px',
|
||||
borderRadius: 4,
|
||||
fontSize: 10,
|
||||
zIndex: 5
|
||||
}}>
|
||||
{isDrone ? '无人机视频' : '机场视频'}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{/* 底部信息叠加 */}
|
||||
{isDrone && device && (
|
||||
@@ -258,8 +263,8 @@ const DroneVideoPlayer: React.FC<DroneVideoPlayerProps> = ({
|
||||
padding: '4px 8px',
|
||||
fontSize: 10
|
||||
}}>
|
||||
<span>高度 {device.height?.toFixed(2) || '-'}m</span>
|
||||
<span>风速 {device.wind_speed?.toFixed(2) || '-'}m/s</span>
|
||||
<span>高度 {h.toFixed(2) || device.height?.toFixed(2) || '-'}m</span>
|
||||
<span>风速 {wind_speed.toFixed(2) || device.wind_speed?.toFixed(2) || '0'}m/s</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user