import React, { useState, useEffect } from 'react'; import { Layout, Card, Row, Col, Statistic, Tag, Button, Table, Typography, Space, Progress, Badge, Timeline, message, Select, Modal } from 'antd'; import { EnvironmentOutlined, RobotOutlined, BranchesOutlined, ThunderboltOutlined, CheckCircleOutlined, PauseOutlined, RocketOutlined, SyncOutlined, WarningOutlined, CloudOutlined, ClockCircleOutlined, ReloadOutlined, AimOutlined, ApiOutlined, SettingOutlined, PlusOutlined, ArrowRightOutlined, EditOutlined, FullscreenOutlined, InfoCircleOutlined } from '@ant-design/icons'; import { useSelector } from 'react-redux'; import { getDeviceListApi, getLiveStream, getPlaneDeviceList } from '../../api/device.ts'; import { RootState } from '@/src/store'; import DroneLivePlayer from '../VolcRtcPlayer.jsx'; const { Content } = Layout; const { Text, Title } = Typography; const taskTimeline = [ { time: '10:24:18', color: 'blue', text: 'UAV-C01 开始执行清洗航线 C-05', status: '任务开始' }, { time: '10:21:35', color: 'orange', text: 'RBT-01 开始执行巡检航线 P-02', status: '任务开始' }, { time: '10:18:02', color: 'green', text: 'GR-02 开始除草作业 G-01', status: '任务开始' }, { time: '10:15:47', color: 'gray', text: 'UAV-C02 任务待命就绪', status: '待命就绪' }, { time: '10:12:33', color: 'blue', text: 'UAV-C01 再次返机补水', status: '返机补给' }, { time: '09:58:10', color: 'green', text: 'RBT-02 完成巡检航线 P-01', status: '任务完成' }, ]; const logs = [ { time: '10:24:35', device: 'UAV-C01', type: '命令', desc: '起飞指令下发,开始作业' }, { time: '10:21:40', device: 'RBT-01', type: '命令', desc: '开始巡检任务 P-02' }, { time: '10:20:11', device: 'UAV-C02', type: '命令', desc: '转入待命状态' }, { time: '10:18:05', device: 'GR-02', type: '命令', desc: '除草作业开始 G-01' }, { time: '10:12:35', device: 'UAV-C01', type: '告警', desc: '返航补水' }, { time: '10:05:22', device: 'RBT-01', type: '事件', desc: '电量较低,建议回充', level: '低电量' }, ]; // 设备总览组件 export default function DeviceOverviewPage({ devices, planedevices, devicesAll, onViewStatus }) { const [selectedDevice, setSelectedDevice] = useState(null); const [planeVideo, setPlaneVideo] = useState([]); // 初始为空数组 const [zoomedVideo, setZoomedVideo] = useState(null); // 放大查看的视频数据 // 动态计算顶部卡片数据 const dynamicTopCards = React.useMemo(() => { const totalDrones = planedevices?.length || 0; const onlineDrones = planedevices?.filter(d => d.onlineStatus === 1).length || 0; const totalRobots = devicesAll?.filter(d => d.productName?.includes('巡检')).length || 0; const activeRobots = devicesAll?.filter(d => d.productName?.includes('巡检') && d.onlineStatus === 1).length || 0; const totalMowers = devicesAll?.filter(d => d.productName?.includes('割草机')).length || 0; const activeMowers = devicesAll?.filter(d => d.productName?.includes('割草机') && d.onlineStatus === 1).length || 0; return [ { title: '无人机机场状态', icon: , value: `${onlineDrones} / ${totalDrones}`, desc: onlineDrones > 0 ? '在线' : '离线', sub: `可调度 ${onlineDrones} 架`, color: '#1890ff' }, //{ title: '巡检机器人', icon: , value: `${totalRobots} 台`, desc: '', sub: `执行中 ${activeRobots}`, color: '#722ed1' }, { title: '机器人', icon: , value: `${totalMowers} 台`, desc: '', sub: `作业中 ${activeMowers}`, color: '#13c2c2' }, { title: '无人机', icon: , value: `${totalDrones} 架`, desc: '', sub: `待命 ${planedevices?.filter(d => d.productName?.includes('清洗') && d.onlineStatus === 1).length || 0}`, color: '#eb2f96' }, { title: '设备平均电量', icon: , value: '86%', desc: '', sub: '', color: '#52c41a' }, { title: '今日任务执行', icon: , value: '12 / 15', desc: '', sub: '完成率 80%', color: '#2f54eb' }, ]; }, [devicesAll, planedevices]); // 动态生成调度列表 const dynamicScheduleList = React.useMemo(() => { return devicesAll.map((d, index) => ({ id: d.deviceId || index, name: d.deviceAlias || d.deviceName || d.callsign || '未知设备', type: d.productName || '未知类型', status: d.onlineStatus === 1 ? '在线' : '离线', mode: d.status === 4 ? '待命' : '作业中', battery: d.capacity_percent || 100, position: d.position || '站内', task: d.status === 4 ? '待命' : '作业中', comm: d.rssi ? `${d.rssi}dBm` : '良好' })); }, [devicesAll]); const handleStart = () => message.success('任务已启动'); const handlePause = () => message.info('任务已暂停'); const handleReturn = () => message.info('返航指令已下发'); const handleRecharge = () => message.info('回充指令已下发'); const handleEmergencyStop = () => message.error('已触发急停!'); const getLiveDefault = () => { if (!selectedDevice?.gateway_sn) return; const data = { getway_sn: selectedDevice?.gateway_sn, drone_sn: selectedDevice?.device_sn, getway_camera_list: selectedDevice?.gateway_camera_list ?? [], drone_camera_list: selectedDevice?.drone_camera_list ?? [], video_expire: 7200, quality_type: "adaptive", } getLiveStream(data).then(res => { if (res.code == 200) { setPlaneVideo(res.data); } }) } // 数字保留两位小数 const fix2 = (val) => { if (val === null || val === undefined || isNaN(val)) return '-'; return Number(val).toFixed(2); }; // 安全取值 const getVal = (val) => val == "no_rain" ? "无" : (val || '-'); // 默认选中第一个 useEffect(() => { if (devicesAll && devicesAll.length > 0) { setSelectedDevice(devicesAll[0]); // 🔥 修复:存整个对象 } }, [devicesAll]); useEffect(() => { getLiveDefault(); }, [selectedDevice]) // 切换设备 const handleDeviceChange = (id) => { const target = devicesAll.find(item => (item.device_sn || item.serialNumber) === id); setSelectedDevice(target || null); // 🔥 修复:存对象 }; return (
{dynamicTopCards.map((card, idx) => (
{card.icon}
{card.title}
{card.value}
{card.sub &&
{card.sub}
}
))}
装备协同态势图} extra={