任务执行成功
This commit is contained in:
@@ -10,14 +10,16 @@ import {
|
||||
BranchesOutlined, CloudOutlined, ThunderboltOutlined, CheckCircleOutlined,
|
||||
InfoCircleOutlined, ClockCircleOutlined,
|
||||
SettingOutlined, WarningOutlined, ArrowRightOutlined,
|
||||
SearchOutlined, MoreOutlined, AimOutlined
|
||||
SearchOutlined, MoreOutlined, AimOutlined, PlayCircleOutlined
|
||||
} from '@ant-design/icons';
|
||||
import {
|
||||
Plane, Navigation, Wind, Thermometer, Droplets, Satellite,
|
||||
LayoutGrid, Clock, CheckCircle2, AlertCircle, Zap, Waves,
|
||||
Calendar, User, TrendingUp, Maximize2, Play, Square, X, MapPin, RotateCw
|
||||
} from 'lucide-react';
|
||||
import { getsinglePlan, getsinglePlanTrack, updateFlightTaskStatus, postFlightCommmand, getWayLine, createWaylineTask, getFlightTaskDetail } from '@/api/device';
|
||||
import {
|
||||
getsinglePlan, getsinglePlanTrack, updateFlightTaskStatus, postFlightCommmand, getWayLine, createWaylineTask, getFlightTaskDetail
|
||||
} from '@/api/device';
|
||||
import dayjs from 'dayjs';
|
||||
import utils from '@/lib/utils';
|
||||
import CesiumMap from '../Map';
|
||||
@@ -43,8 +45,17 @@ export default function WayLinePage({ planedevices }) {
|
||||
const [boardDateRange, setBoardDateRange] = useState(null);
|
||||
const [boardTaskList, setBoardTaskList] = useState([]);
|
||||
|
||||
// ✅ 航线列表 独立无人机筛选(新增)
|
||||
const [waylineDrone, setWaylineDrone] = useState(null);
|
||||
|
||||
const [points, setPoints] = useState([]);
|
||||
|
||||
// 航线列表相关状态
|
||||
const [selectedWayline, setSelectedWayline] = useState(null);
|
||||
const [rthModalVisible, setRthModalVisible] = useState(false);
|
||||
const [tempRthAltitude, setTempRthAltitude] = useState(100);
|
||||
const [waylineSearch, setWaylineSearch] = useState('');
|
||||
|
||||
// 任务控制相关状态
|
||||
const [selectedTask, setSelectedTask] = useState(null);
|
||||
const [taskstatus, setTaskStatus] = useState('suspended');
|
||||
@@ -117,7 +128,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
value: item.id
|
||||
}
|
||||
})
|
||||
setWaylineList(_list || []); // 取list数组
|
||||
setWaylineList(_list || []);
|
||||
}
|
||||
} catch (err) {
|
||||
message.error('获取航线列表失败');
|
||||
@@ -131,7 +142,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
setWaylineUuid('');
|
||||
setTaskForm({
|
||||
name: '',
|
||||
sn: listDrone?.gateway_sn || '',
|
||||
sn: waylineDrone?.gateway_sn || '',
|
||||
landing_dock_sn: '',
|
||||
rth_altitude: 100,
|
||||
rth_mode: 'optimal',
|
||||
@@ -159,9 +170,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
const payload = {
|
||||
...taskForm,
|
||||
wayline_uuid: waylineUuid,
|
||||
//task_type: 'recurring',
|
||||
repeat_type: taskForm.repeat_type,
|
||||
// ✅ 直接传入处理好的对象
|
||||
repeat_option: buildRepeatOption(),
|
||||
recurring_task_start_time_list: taskForm.recurring_task_start_time_list.map(t => dayjs(t).unix()),
|
||||
};
|
||||
@@ -170,7 +179,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
if (res.code === 200 || res.code === 0) {
|
||||
utils.message.success('创建任务成功');
|
||||
resetModals();
|
||||
getListTask(); // 刷新列表
|
||||
getListTask();
|
||||
} else {
|
||||
utils.message.error(res.msg || '创建失败');
|
||||
}
|
||||
@@ -181,12 +190,15 @@ export default function WayLinePage({ planedevices }) {
|
||||
}
|
||||
};
|
||||
|
||||
// 选中无人机时自动填充机场SN
|
||||
// 航线列表无人机变更时同步到表单
|
||||
useEffect(() => {
|
||||
if (listDrone) {
|
||||
setTaskForm(prev => ({ ...prev, sn: listDrone.gateway_sn || '' }));
|
||||
if (waylineDrone) {
|
||||
setTaskForm(prev => ({
|
||||
...prev,
|
||||
sn: waylineDrone.gateway_sn || ''
|
||||
}));
|
||||
}
|
||||
}, [listDrone]);
|
||||
}, [waylineDrone]);
|
||||
|
||||
// 顶部统计
|
||||
const [todayCount, setTodayCount] = useState(0);
|
||||
@@ -239,12 +251,12 @@ export default function WayLinePage({ planedevices }) {
|
||||
}, [taskList]);
|
||||
|
||||
|
||||
// 获取任务列表数据 【时间戳已改为秒级】
|
||||
// 获取任务列表数据
|
||||
const getListTask = async () => {
|
||||
if (!planedevices?.length) return;
|
||||
try {
|
||||
const defaultStart = dayjs().startOf('day').unix(); // 秒级
|
||||
const defaultEnd = dayjs().endOf('day').unix(); // 秒级
|
||||
const defaultStart = dayjs().startOf('day').unix();
|
||||
const defaultEnd = dayjs().endOf('day').unix();
|
||||
|
||||
const [beginAt, endAt] = listDateRange?.length === 2
|
||||
? [dayjs(listDateRange[0]).unix(), dayjs(listDateRange[1]).unix()]
|
||||
@@ -253,7 +265,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
const sns = listDrone ? [listDrone.gateway_sn] : planedevices.map(item => item.gateway_sn);
|
||||
const res = await getsinglePlan({ sns, beginAt, endAt });
|
||||
if (res?.code === 200) {
|
||||
// 处理嵌套数据结构:data: { [sn]: { list: [] } }
|
||||
let combinedList = [];
|
||||
if (res.data) {
|
||||
Object.values(res.data).forEach((item: any) => {
|
||||
@@ -267,12 +278,12 @@ export default function WayLinePage({ planedevices }) {
|
||||
}
|
||||
};
|
||||
|
||||
// 获取看板任务数据 【时间戳已改为秒级】
|
||||
// 获取看板任务数据
|
||||
const getBoardTask = async () => {
|
||||
if (!planedevices?.length) return;
|
||||
try {
|
||||
const defaultStart = dayjs().startOf('day').unix(); // 秒级
|
||||
const defaultEnd = dayjs().endOf('day').unix(); // 秒级
|
||||
const defaultStart = dayjs().startOf('day').unix();
|
||||
const defaultEnd = dayjs().endOf('day').unix();
|
||||
|
||||
const [beginAt, endAt] = boardDateRange?.length === 2
|
||||
? [dayjs(boardDateRange[0]).unix(), dayjs(boardDateRange[1]).unix()]
|
||||
@@ -281,7 +292,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
const sns = boardDrone ? [boardDrone.gateway_sn] : planedevices.map(item => item.gateway_sn);
|
||||
const res = await getsinglePlan({ sns, beginAt, endAt });
|
||||
if (res?.code === 200) {
|
||||
// 处理嵌套数据结构
|
||||
let combinedList = [];
|
||||
if (res.data) {
|
||||
Object.values(res.data).forEach((item: any) => {
|
||||
@@ -294,19 +304,20 @@ export default function WayLinePage({ planedevices }) {
|
||||
message.error('任务看板数据获取失败');
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchWaylineList();
|
||||
}, [])
|
||||
|
||||
// 初始化默认全部设备
|
||||
// 初始化默认设备
|
||||
useEffect(() => {
|
||||
if (planedevices?.length) {
|
||||
setListDrone(planedevices[0]); // 默认显示第一个无人机
|
||||
setBoardDrone(null); // 默认显示所有
|
||||
setListDrone(planedevices[0]);
|
||||
setWaylineDrone(planedevices[0]); // 航线列表默认选中第一个
|
||||
setBoardDrone(null);
|
||||
}
|
||||
}, [planedevices]);
|
||||
|
||||
// 各自筛选变更独立请求
|
||||
useEffect(() => {
|
||||
getListTask();
|
||||
}, [listDrone, listDateRange]);
|
||||
@@ -337,29 +348,23 @@ export default function WayLinePage({ planedevices }) {
|
||||
// 列表表格列
|
||||
const taskColumns = [
|
||||
{ title: '任务名称', dataIndex: 'name', width: 260, ellipsis: true, fixed: "left" },
|
||||
//{ title: '任务UUID', dataIndex: 'uuid', width: 260, ellipsis: true },
|
||||
{ title: '设备SN', dataIndex: 'sn', width: 140 },
|
||||
{ title: '状态', dataIndex: 'status', width: 80, render: getStatusTag },
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'begin_at',
|
||||
width: 170,
|
||||
title: '开始时间', dataIndex: 'begin_at', width: 170,
|
||||
render: t => t ? dayjs(t).format('YYYY-MM-DD HH:mm:ss') : '-'
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
dataIndex: 'end_at',
|
||||
width: 170,
|
||||
title: '结束时间', dataIndex: 'end_at', width: 170,
|
||||
render: t => t ? dayjs(t).format('YYYY-MM-DD HH:mm:ss') : '-'
|
||||
},
|
||||
];
|
||||
|
||||
// 表格行点击查看轨迹
|
||||
const handleRowClick = async (record) => {
|
||||
setSelectedTask(record); // 记录当前选中的任务
|
||||
setSelectedTask(record);
|
||||
try {
|
||||
getTaskDetail(record.uuid); // 获取任务详情
|
||||
|
||||
getTaskDetail(record.uuid);
|
||||
const res = await getsinglePlanTrack(record);
|
||||
if (res.code === 0 && res.data.track?.points?.length) {
|
||||
const points = res.data.track.points.map(item => ({
|
||||
@@ -373,21 +378,83 @@ export default function WayLinePage({ planedevices }) {
|
||||
}
|
||||
} catch (err) {
|
||||
message.error('请求失败');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
// 航线列表点击处理
|
||||
const handleWaylineClick = (wayline) => {
|
||||
setSelectedWayline(wayline);
|
||||
if (wayline.points && wayline.points.length > 0) {
|
||||
const mapPoints = wayline.points.map(p => ({
|
||||
lon: p.longitude || p.lon,
|
||||
lat: p.latitude || p.lat
|
||||
}));
|
||||
setPoints(mapPoints);
|
||||
} else if (wayline.track?.points?.length > 0) {
|
||||
const mapPoints = wayline.track.points.map(p => ({
|
||||
lon: p.longitude || p.lon,
|
||||
lat: p.latitude || p.lat
|
||||
}));
|
||||
setPoints(mapPoints);
|
||||
}
|
||||
};
|
||||
|
||||
// 执行航线按钮点击(改为图标)
|
||||
const handleExecuteClick = (e, wayline) => {
|
||||
e.stopPropagation();
|
||||
// ✅ 使用航线列表自己的无人机
|
||||
if (!waylineDrone?.gateway_sn) {
|
||||
utils.message.warning('请先在航线列表上方选择执行无人机');
|
||||
return;
|
||||
}
|
||||
setSelectedWayline(wayline);
|
||||
setTempRthAltitude(100);
|
||||
setRthModalVisible(true);
|
||||
};
|
||||
|
||||
// 确认执行航线任务
|
||||
const confirmExecuteWayline = async () => {
|
||||
if (!selectedWayline || !waylineDrone?.gateway_sn) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const payload = {
|
||||
name: `${selectedWayline.name}_${dayjs().format('MMDDHHmm')}`,
|
||||
sn: waylineDrone.gateway_sn, // ✅ 使用航线列表无人机
|
||||
wayline_uuid: selectedWayline.id || selectedWayline.uuid,
|
||||
rth_altitude: tempRthAltitude,
|
||||
task_type: 'immediate',
|
||||
rth_mode: 'optimal',
|
||||
wayline_precision_type: 'gps',
|
||||
resumable_status: 'auto',
|
||||
min_battery_capacity: 50,
|
||||
repeat_type: 'nonrepeating',
|
||||
time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
};
|
||||
|
||||
const res: any = await createWaylineTask(payload);
|
||||
if (res.code === 200 || res.code === 0) {
|
||||
utils.message.success('航线执行任务创建成功');
|
||||
setRthModalVisible(false);
|
||||
getListTask();
|
||||
} else {
|
||||
utils.message.error(res.msg || '执行失败');
|
||||
}
|
||||
} catch (err) {
|
||||
utils.message.error('创建任务异常');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 看板数据分组处理
|
||||
const groupBoardData = () => {
|
||||
// 待执行 = 准备中 + 待开始 + 已挂起 + 已终止
|
||||
const waitList = boardTaskList.filter(item =>
|
||||
['preparing', 'waiting', 'suspended', 'terminated'].includes(item.status)
|
||||
);
|
||||
// 执行中 = 运行中 + 执行中 + 恢复执行
|
||||
const runList = boardTaskList.filter(item =>
|
||||
['running', 'executing', 'restored'].includes(item.status)
|
||||
);
|
||||
// 已完成 = 执行成功
|
||||
const finishList = boardTaskList.filter(item =>
|
||||
['success'].includes(item.status)
|
||||
);
|
||||
@@ -397,13 +464,8 @@ export default function WayLinePage({ planedevices }) {
|
||||
|
||||
const topCards = [
|
||||
{
|
||||
title: '今日航线计划',
|
||||
value: todayCount,
|
||||
unit: '条',
|
||||
trend: trend,
|
||||
trendColor: trendColor,
|
||||
icon: <LayoutGrid size={22} />,
|
||||
color: '#165DFF'
|
||||
title: '今日航线计划', value: todayCount, unit: '条', trend: trend, trendColor: trendColor,
|
||||
icon: <LayoutGrid size={22} />, color: '#165DFF'
|
||||
},
|
||||
{ title: '执行中任务', value: runList.length, unit: '个', desc: '进行中', icon: <Plane size={22} />, color: '#165DFF' },
|
||||
{ title: '待审批任务', value: '4', unit: '个', trend: '较昨日 -1', trendColor: '#F53F3F', icon: <Calendar size={22} />, color: '#FF7D00' },
|
||||
@@ -412,7 +474,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
{ title: '覆盖装备', value: '4 类 / 9 台', unit: '', desc: '全部在线', icon: <Satellite size={22} />, color: '#165DFF' },
|
||||
];
|
||||
|
||||
|
||||
// 指令下发逻辑
|
||||
const sendFlightCommand = async (command: 'return_home' | 'return_home_cancel' | 'flighttask_pause' | 'flighttask_recovery') => {
|
||||
if (!listDrone?.device_sn) {
|
||||
@@ -429,7 +490,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
const res: any = await postFlightCommmand(data);
|
||||
if (res.code === 200 || res.code === 0) {
|
||||
utils.message.success('指令下发成功');
|
||||
// 切换状态
|
||||
if (command === 'return_home') setIsReturningHome(true);
|
||||
if (command === 'return_home_cancel') setIsReturningHome(false);
|
||||
if (command === 'flighttask_pause') setIsTaskPaused(true);
|
||||
@@ -443,8 +503,8 @@ export default function WayLinePage({ planedevices }) {
|
||||
setFlightCommandLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getTaskDetail = async (taskId) => {
|
||||
console.log('获取任务详情,taskId=', taskId);
|
||||
if (!taskId) return;
|
||||
setTaskDetail(null);
|
||||
setLoading(true);
|
||||
@@ -452,14 +512,12 @@ export default function WayLinePage({ planedevices }) {
|
||||
const res = await getFlightTaskDetail(taskId);
|
||||
if (res.code === 0) {
|
||||
setTaskDetail(res.data);
|
||||
|
||||
} else {
|
||||
setTaskDetail(null);
|
||||
utils.message.error('暂无详情');
|
||||
}
|
||||
} catch (err) {
|
||||
setTaskDetail(null);
|
||||
|
||||
utils.message.error('获取详情接口异常');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -489,7 +547,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
setTaskStatus('restored');
|
||||
}
|
||||
utils.message.success(statusText);
|
||||
// 刷新任务列表
|
||||
getListTask();
|
||||
} else {
|
||||
utils.message.error(res.msg || '操作失败');
|
||||
@@ -585,7 +642,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
options={planedevices?.map(item => ({
|
||||
value: item.device_sn,
|
||||
label: item.drone_callsign || item.device_sn || item.callsign
|
||||
|
||||
}))}
|
||||
value={listDrone?.device_sn}
|
||||
onChange={(val) => {
|
||||
@@ -737,7 +793,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</Space>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '8px' }}>
|
||||
{/* 执行/挂起/继续 逻辑 */}
|
||||
{selectedTask?.status === 'executing' || selectedTask?.status === 'running' || selectedTask?.status === 'restored' ? (
|
||||
<Button
|
||||
type="primary"
|
||||
@@ -766,7 +821,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
{selectedTask?.status === 'suspended' ? '继续任务' : '执行任务'}
|
||||
</Button>
|
||||
)}
|
||||
{/* 返航逻辑 */}
|
||||
<Button
|
||||
type="primary"
|
||||
danger={isReturningHome}
|
||||
@@ -778,7 +832,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
{isReturningHome ? '取消返航' : '返航'}
|
||||
</Button>
|
||||
|
||||
{/* 暂停/恢复逻辑 */}
|
||||
<Button
|
||||
type="default"
|
||||
icon={isTaskPaused ? <RotateCw size={16} /> : <Square size={16} />}
|
||||
@@ -797,9 +850,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
bodyStyle={{ padding: '16px' }}
|
||||
style={{ ...cardStyle, flex: 1 }}
|
||||
>
|
||||
{/* 顶部参数卡片区域,改成和截图一致的横向布局 */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: '8px', marginBottom: 16 }}>
|
||||
{/* 适宜性 */}
|
||||
<div style={{ background: '#F7F8FA', borderRadius: 10, padding: '12px', display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
<div style={{ width: 40, height: 40, borderRadius: '50%', background: 'rgba(22, 93, 255, 0.1)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<CloudOutlined size={20} style={{ color: '#165DFF' }} />
|
||||
@@ -810,7 +861,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 风速 */}
|
||||
<div style={{ background: '#F7F8FA', borderRadius: 10, padding: '12px', display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
<div style={{ width: 40, height: 40, borderRadius: '50%', background: 'rgba(22, 93, 255, 0.1)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Wind size={20} style={{ color: '#165DFF' }} />
|
||||
@@ -822,7 +872,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 温度 */}
|
||||
<div style={{ background: '#F7F8FA', borderRadius: 10, padding: '12px', display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
<div style={{ width: 40, height: 40, borderRadius: '50%', background: 'rgba(255, 125, 0, 0.1)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Thermometer size={20} style={{ color: '#FF7D00' }} />
|
||||
@@ -834,7 +883,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 降水概率 */}
|
||||
<div style={{ background: '#F7F8FA', borderRadius: 10, padding: '12px', display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
<div style={{ width: 40, height: 40, borderRadius: '50%', background: 'rgba(255, 125, 0, 0.1)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Droplets size={20} style={{ color: '#FF7D00' }} />
|
||||
@@ -846,7 +894,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* GNSS质量 */}
|
||||
<div style={{ background: '#F7F8FA', borderRadius: 10, padding: '12px', display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
<div style={{ width: 40, height: 40, borderRadius: '50%', background: 'rgba(0, 180, 42, 0.1)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Satellite size={20} style={{ color: '#00B42A' }} />
|
||||
@@ -859,7 +906,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 底部提示区域 */}
|
||||
<div style={{ display: 'flex', gap: '12px' }}>
|
||||
<div style={{ flex: 1, background: 'rgba(255, 125, 0, 0.1)', borderRadius: 8, padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<AlertCircle size={16} style={{ color: '#FF7D00' }} />
|
||||
@@ -876,7 +922,92 @@ export default function WayLinePage({ planedevices }) {
|
||||
|
||||
{/* 底部内容区 */}
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} xl={14}>
|
||||
<Col xs={24} xl={4}>
|
||||
<Card
|
||||
title={
|
||||
<div className="flex justify-between items-center w-full">
|
||||
<span style={{ fontSize: fontTitle, fontWeight: 700 }}>航线列表</span>
|
||||
{/* ✅ 航线列表独立无人机筛选 */}
|
||||
<Select
|
||||
size="small"
|
||||
style={{ width: 120 }}
|
||||
placeholder="选择无人机"
|
||||
showSearch
|
||||
allowClear
|
||||
options={planedevices?.map(item => ({
|
||||
value: item.device_sn,
|
||||
label: item.drone_callsign || item.device_sn || item.callsign
|
||||
}))}
|
||||
value={waylineDrone?.device_sn}
|
||||
onChange={(val) => {
|
||||
const find = planedevices.find(i => i.device_sn === val);
|
||||
setWaylineDrone(find || null);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
bordered={false}
|
||||
bodyStyle={{ padding: '12px', display: 'flex', flexDirection: 'column', height: 480 }}
|
||||
style={{ ...cardStyle, height: '100%' }}
|
||||
>
|
||||
<Input
|
||||
placeholder="搜索航线..."
|
||||
prefix={<SearchOutlined style={{ color: '#86909C' }} />}
|
||||
style={{ marginBottom: 12, borderRadius: 6 }}
|
||||
size="small"
|
||||
value={waylineSearch}
|
||||
onChange={e => setWaylineSearch(e.target.value)}
|
||||
/>
|
||||
<div style={{ flex: 1, overflowY: 'auto', paddingRight: 4 }} className="custom-scrollbar">
|
||||
{waylineList
|
||||
.filter(item => item.name?.toLowerCase().includes(waylineSearch.toLowerCase()))
|
||||
.map((item) => (
|
||||
<div
|
||||
key={item.id || item.uuid}
|
||||
onClick={() => handleWaylineClick(item)}
|
||||
style={{
|
||||
padding: '10px 12px',
|
||||
borderRadius: 8,
|
||||
marginBottom: 8,
|
||||
cursor: 'pointer',
|
||||
background: selectedWayline?.id === item.id ? '#E8F3FF' : '#F7F8FA',
|
||||
border: selectedWayline?.id === item.id ? '1px solid #165DFF' : '1px solid transparent',
|
||||
transition: 'all 0.2s',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
<div style={{ fontSize: 13, fontWeight: 600, color: '#1D2129', marginBottom: 4, paddingRight: 40 }}>
|
||||
{item.name}
|
||||
</div>
|
||||
<div style={{ fontSize: 11, color: '#86909C', display: 'flex', alignItems: 'center', gap: 4 }}>
|
||||
<Clock size={12} /> {item.update_time ? dayjs(item.update_time).format('MM-DD HH:mm') : '未知时间'}
|
||||
</div>
|
||||
{/* ✅ 执行按钮改为图标 */}
|
||||
<Tooltip title="执行航线">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<PlayCircleOutlined style={{ color: '#165DFF', fontSize: 18 }} />}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: 8,
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
}}
|
||||
onClick={(e) => handleExecuteClick(e, item)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
))}
|
||||
{waylineList.length === 0 && (
|
||||
<div style={{ textAlign: 'center', padding: '20px 0', color: '#86909C', fontSize: 12 }}>
|
||||
暂无航线数据
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} xl={12}>
|
||||
<Card
|
||||
title={<span style={{ fontSize: fontTitle, fontWeight: 700 }}>任务甘特视图 / 排班视图 <Text type="secondary" style={{ fontSize: 11, fontWeight: 400, marginLeft: 12 }}>今日 (2025-05-24)</Text></span>}
|
||||
extra={<MoreOutlined style={{ cursor: 'pointer', fontSize: 18 }} />}
|
||||
@@ -926,7 +1057,7 @@ export default function WayLinePage({ planedevices }) {
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} xl={10}>
|
||||
<Col xs={24} xl={8}>
|
||||
<Card
|
||||
title={
|
||||
<div className="flex justify-between items-center w-full">
|
||||
@@ -1016,14 +1147,11 @@ export default function WayLinePage({ planedevices }) {
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
{/*<div style={{ textAlign: 'center', marginTop: 12 }}>
|
||||
<Button type="link" size="small" style={{ fontSize: 12, color: '#86909C' }}>查看全部 <ArrowRightOutlined style={{ fontSize: 10 }} /></Button>
|
||||
</div>*/}
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* ============================================== */}
|
||||
{/* 创建任务弹窗 */}
|
||||
<Modal
|
||||
open={createTaskModal}
|
||||
title="创建航线任务"
|
||||
@@ -1033,7 +1161,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
width={650}
|
||||
>
|
||||
<div className="py-4 space-y-4">
|
||||
{/* 基础信息 */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1">航线名称 <span className="text-red-500">*</span></label>
|
||||
@@ -1069,7 +1196,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 飞行参数 */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1">返航高度(m)</label>
|
||||
@@ -1130,9 +1256,6 @@ export default function WayLinePage({ planedevices }) {
|
||||
onChange={(v) => setTaskForm({ ...taskForm, task_type: v })}
|
||||
options={[
|
||||
{ label: '立即', value: 'immediate' },
|
||||
//{ label: '单次定时', value: 'timed' },
|
||||
//{ label: '重复', value: 'recurring' },
|
||||
//{ label: '连续', value: 'continuous' },
|
||||
]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
@@ -1303,6 +1426,42 @@ export default function WayLinePage({ planedevices }) {
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
</div >
|
||||
{/* 执行航线设置返航高度 Modal */}
|
||||
<Modal
|
||||
title="执行航线任务"
|
||||
open={rthModalVisible}
|
||||
onOk={confirmExecuteWayline}
|
||||
onCancel={() => setRthModalVisible(false)}
|
||||
confirmLoading={loading}
|
||||
okText="立即执行"
|
||||
cancelText="取消"
|
||||
centered
|
||||
width={400}
|
||||
>
|
||||
<div style={{ padding: '10px 0' }}>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Text strong>所选航线:</Text>
|
||||
<Text>{selectedWayline?.name}</Text>
|
||||
</div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<Text strong>执行设备:</Text>
|
||||
<Text>{waylineDrone?.drone_callsign || waylineDrone?.device_sn || '未选择设备'}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ marginBottom: 8 }}><Text strong>返航高度 (m):</Text></div>
|
||||
<InputNumber
|
||||
min={20}
|
||||
max={500}
|
||||
value={tempRthAltitude}
|
||||
onChange={val => setTempRthAltitude(val || 100)}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
<div style={{ marginTop: 4, fontSize: 12, color: '#86909C' }}>
|
||||
建议高度:80m - 150m,请确保高于周围障碍物。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user