天气窗口与执行约束 温度和速度显示
This commit is contained in:
@@ -706,15 +706,59 @@ export default function CesiumMap({ realtimePosition, pathPoints = [], devices =
|
||||
};
|
||||
}, []);
|
||||
|
||||
const focusEntityRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!viewerRef.current || !focusLocation) return;
|
||||
if (!viewerRef.current || !focusLocation) {
|
||||
if (focusEntityRef.current) {
|
||||
viewerRef.current?.entities.remove(focusEntityRef.current);
|
||||
focusEntityRef.current = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const viewer = viewerRef.current;
|
||||
const Cesium = window.Cesium;
|
||||
|
||||
// 选择图片
|
||||
let image = carImg;
|
||||
if (focusLocation.type === "plane" || focusLocation.type === "drone") {
|
||||
image = planeImg;
|
||||
} else if (focusLocation.type === "robot") {
|
||||
image = droneInspectImg;
|
||||
} else if (focusLocation.type === "mower") {
|
||||
image = carImg;
|
||||
}
|
||||
|
||||
// 如果已经有 focusEntity,先移除
|
||||
if (focusEntityRef.current) {
|
||||
viewer.entities.remove(focusEntityRef.current);
|
||||
}
|
||||
|
||||
// 添加新的 focusEntity
|
||||
focusEntityRef.current = viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(Number(focusLocation.lon), Number(focusLocation.lat), 0),
|
||||
billboard: {
|
||||
image: image,
|
||||
width: 60,
|
||||
height: 60,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||||
},
|
||||
label: {
|
||||
text: focusLocation.name,
|
||||
font: "12px sans-serif",
|
||||
pixelOffset: new Cesium.Cartesian2(0, -80),
|
||||
fillColor: Cesium.Color.YELLOW,
|
||||
showBackground: true,
|
||||
backgroundColor: Cesium.Color.BLACK.withAlpha(0.6)
|
||||
}
|
||||
});
|
||||
|
||||
viewer.camera.flyTo({
|
||||
destination: window.Cesium.Cartesian3.fromDegrees(Number(focusLocation.lon), Number(focusLocation.lat), focusLocation.height),
|
||||
destination: Cesium.Cartesian3.fromDegrees(Number(focusLocation.lon), Number(focusLocation.lat), focusLocation.height || 800),
|
||||
orientation: {
|
||||
heading: window.Cesium.Math.toRadians(0.0),
|
||||
pitch: window.Cesium.Math.toRadians(-90.0),
|
||||
heading: Cesium.Math.toRadians(0.0),
|
||||
pitch: Cesium.Math.toRadians(-90.0),
|
||||
roll: 0.0,
|
||||
},
|
||||
duration: 1.5
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
Row, Col, Card, Button, Space, Table, Tag, Typography, Progress, Badge,
|
||||
Tabs, Input, Switch, Divider, Tooltip, Timeline, Select, message, DatePicker,
|
||||
@@ -24,6 +24,7 @@ import dayjs from 'dayjs';
|
||||
import utils from '@/lib/utils';
|
||||
import CesiumMap from '../Map';
|
||||
import { getUAVState } from '@/api/device';
|
||||
import { fix2, getVal } from '@/lib/utils';
|
||||
|
||||
const { Text, Title } = Typography;
|
||||
const { RangePicker } = DatePicker;
|
||||
@@ -38,9 +39,40 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
|
||||
// 任务列表 独立筛选状态
|
||||
const [listDrone, setListDrone] = useState(null);
|
||||
const [listDroneRealtime, setListDroneRealtime] = useState(null);
|
||||
const [listDateRange, setListDateRange] = useState(null);
|
||||
const [taskList, setTaskList] = useState([]);
|
||||
|
||||
const listDroneTimerRef = useRef<any>(null);
|
||||
|
||||
// 定时获取任务列表所选无人机的实时状态
|
||||
useEffect(() => {
|
||||
const fetchRealtime = async () => {
|
||||
if (listDrone?.gateway_sn && listDrone?.device_sn) {
|
||||
try {
|
||||
const res = await getUAVState({
|
||||
sn: listDrone.gateway_sn,
|
||||
droneSn: listDrone.device_sn
|
||||
});
|
||||
if (res.code === 200) {
|
||||
setListDroneRealtime(res.data);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取列表无人机实时状态失败', err);
|
||||
}
|
||||
} else {
|
||||
setListDroneRealtime(null);
|
||||
}
|
||||
};
|
||||
|
||||
fetchRealtime();
|
||||
listDroneTimerRef.current = setInterval(fetchRealtime, 3000);
|
||||
|
||||
return () => {
|
||||
if (listDroneTimerRef.current) clearInterval(listDroneTimerRef.current);
|
||||
};
|
||||
}, [listDrone]);
|
||||
|
||||
// 工作看板 独立筛选状态
|
||||
const [boardDrone, setBoardDrone] = useState(null);
|
||||
const [boardDateRange, setBoardDateRange] = useState(null);
|
||||
@@ -62,7 +94,9 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
if (res.code === 200 && res.data) {
|
||||
setFocusLocation({
|
||||
lon: res.data.longitude,
|
||||
lat: res.data.latitude
|
||||
lat: res.data.latitude,
|
||||
type: drone.type || 'plane',
|
||||
name: drone.drone_callsign || drone.name || drone.device_sn
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -465,11 +499,11 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
utils.message.success('航线执行任务创建成功');
|
||||
setRthModalVisible(false);
|
||||
getListTask();
|
||||
if (onRefresh) {
|
||||
setTimeout(() => {
|
||||
onRefresh();
|
||||
}, 1500)
|
||||
}
|
||||
//if (onRefresh) {
|
||||
// setTimeout(() => {
|
||||
// onRefresh();
|
||||
// }, 1500)
|
||||
//}
|
||||
|
||||
//await getTrackFn({
|
||||
// uuid: res.data.task_uuid
|
||||
@@ -502,7 +536,7 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
|
||||
const topCards = [
|
||||
{
|
||||
title: '今日航线计划', value: todayCount, unit: '条', trend: trend, trendColor: trendColor,
|
||||
title: '今日航线计划', value: todayCount, unit: '条', desc: '进行中', trend: trend, trendColor: trendColor,
|
||||
icon: <LayoutGrid size={22} />, color: '#165DFF'
|
||||
},
|
||||
{ title: '执行中任务', value: runList.length, unit: '个', desc: '进行中', icon: <Plane size={22} />, color: '#165DFF' },
|
||||
@@ -906,7 +940,7 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>风速</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>{listDrone?.wind_speed ?? '-'} m/s</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>{fix2((listDroneRealtime || listDrone)?.wind_speed)} m/s</div>
|
||||
<div style={{ fontSize: 12, color: '#00B42A' }}>适宜</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -917,7 +951,7 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>温度</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>{listDrone?.environment_temperature ?? '-'}℃</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>{fix2((listDroneRealtime || listDrone)?.environment_temperature)}℃</div>
|
||||
<div style={{ fontSize: 12, color: '#00B42A' }}>适宜</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -927,9 +961,11 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
<Droplets size={20} style={{ color: '#FF7D00' }} />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>降水概率</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>10%</div>
|
||||
<div style={{ fontSize: 12, color: '#00B42A' }}>低</div>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>降水状态</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>{getVal((listDroneRealtime || listDrone)?.rainfall)}</div>
|
||||
<div style={{ fontSize: 12, color: (listDroneRealtime || listDrone)?.rainfall === 'no_rain' ? '#00B42A' : '#F53F3F' }}>
|
||||
{(listDroneRealtime || listDrone)?.rainfall === 'no_rain' ? '低风险' : '有雨'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -939,8 +975,12 @@ export default function WayLinePage({ planedevices, onRefresh }) {
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>GNSS质量</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>良好</div>
|
||||
<div style={{ fontSize: 12, color: '#00B42A' }}>适宜</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 700, color: '#1D2129' }}>
|
||||
{(listDroneRealtime || listDrone)?.position_state?.rtk_number ?? 0} RTK
|
||||
</div>
|
||||
<div style={{ fontSize: 12, color: (listDroneRealtime || listDrone)?.position_state?.is_fixed === 'fixing_successful' ? '#00B42A' : '#FF7D00' }}>
|
||||
{(listDroneRealtime || listDrone)?.position_state?.is_fixed === 'fixing_successful' ? '已固定' : '未固定'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -159,6 +159,15 @@ export function getWeatherType(weatherText = "") {
|
||||
return "cloudy";
|
||||
}
|
||||
|
||||
export const fix2 = (val) => {
|
||||
if (val === null || val === undefined || isNaN(val)) return '-';
|
||||
return Number(val).toFixed(2);
|
||||
};
|
||||
|
||||
export const getVal = (val) => val == "no_rain" ? "无" : (val || '-');
|
||||
|
||||
|
||||
|
||||
// ==============================================
|
||||
// 通用导出表格为 CSV / Excel(通用版,不写死任何字段)
|
||||
// ==============================================
|
||||
|
||||
Reference in New Issue
Block a user