创建任务
This commit is contained in:
@@ -355,21 +355,17 @@ export default function CesiumMap({ realtimePosition, pathPoints = [], devices =
|
||||
const [workspace, layerName] = layerFullName.split(':');
|
||||
if (!workspace || !layerName) return;
|
||||
const wmsUrl = `${baseUrl}/wms`;
|
||||
console.log("addLayerFromList", wmsUrl, workspace, layerName, index)
|
||||
addWmsLayerToCesium(wmsUrl, workspace, layerName, index);
|
||||
}
|
||||
|
||||
function getLayerBoundsAndFit(wmsUrl, layerName) {
|
||||
console.log('=== 获取图层范围开始 ===');
|
||||
console.log('参数:', { wmsUrl, layerName });
|
||||
|
||||
const getCapabilitiesUrl = `${wmsUrl}?service=WMS&version=1.1.1&request=GetCapabilities`;
|
||||
console.log('GetCapabilities URL:', getCapabilitiesUrl);
|
||||
|
||||
fetch(getCapabilitiesUrl)
|
||||
.then(response => response.text())
|
||||
.then(xmlText => {
|
||||
console.log('GetCapabilities响应:', xmlText);
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
|
||||
const layerElements = xmlDoc.getElementsByTagName('Layer');
|
||||
@@ -435,7 +431,6 @@ export default function CesiumMap({ realtimePosition, pathPoints = [], devices =
|
||||
const layerIdentifier = `${workspace}:${layerName}`;
|
||||
let baseUrl = wmsUrl;
|
||||
const cesiumLayers = [];
|
||||
console.log(wmsUrl, workspace, layerName, index, "wmsUrl, workspace, layerName, index")
|
||||
//if (index == 2) {
|
||||
// flyToLayer(layerIdentifier, baseUrl);
|
||||
//}
|
||||
|
||||
@@ -70,12 +70,40 @@ export default function WayLinePage({ planedevices }) {
|
||||
min_battery_capacity: 50,
|
||||
task_type: 'immediate',
|
||||
repeat_type: 'nonrepeating',
|
||||
repeat_option: { interval: 1 },
|
||||
repeat_option: {
|
||||
interval: 1,
|
||||
days_of_week: [],
|
||||
days_of_month: [],
|
||||
week_of_month: 1,
|
||||
},
|
||||
time_zone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
begin_at: null,
|
||||
end_at: null,
|
||||
|
||||
recurring_task_start_time_list: [],
|
||||
});
|
||||
// 根据 repeat_type 自动构建接口需要的 repeat_option
|
||||
const buildRepeatOption = () => {
|
||||
const { repeat_type, repeat_option } = taskForm;
|
||||
const { interval, days_of_week, days_of_month, week_of_month } = repeat_option;
|
||||
|
||||
if (repeat_type === 'nonrepeating') return undefined;
|
||||
|
||||
switch (repeat_type) {
|
||||
case 'daily':
|
||||
return { interval: Math.max(1, interval) };
|
||||
|
||||
case 'weekly':
|
||||
return { interval, days_of_week };
|
||||
|
||||
case 'absolute_monthly':
|
||||
return { interval, days_of_month };
|
||||
|
||||
case 'relative_monthly':
|
||||
return { interval, week_of_month, days_of_week };
|
||||
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchWaylineList = async () => {
|
||||
try {
|
||||
@@ -130,9 +158,10 @@ export default function WayLinePage({ planedevices }) {
|
||||
const payload = {
|
||||
...taskForm,
|
||||
wayline_uuid: waylineUuid,
|
||||
// 如果是立即任务,begin_at 为 null 或当前时间戳
|
||||
begin_at: taskForm.task_type === 'immediate' ? null : (taskForm.begin_at ? dayjs(taskForm.begin_at).unix() : null),
|
||||
end_at: taskForm.end_at ? dayjs(taskForm.end_at).unix() : null,
|
||||
//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()),
|
||||
};
|
||||
|
||||
@@ -922,56 +951,68 @@ export default function WayLinePage({ planedevices }) {
|
||||
</Row>
|
||||
|
||||
{/* ============================================== */}
|
||||
{/* ✅ 创建航线任务弹窗(已放在页面底部) */}
|
||||
{/* ============================================== */}
|
||||
<Modal open={createTaskModal} title="创建航线任务" onCancel={resetModals} footer={null} maskClosable={false} width={600} scrollable>
|
||||
<Modal
|
||||
open={createTaskModal}
|
||||
title="创建航线任务"
|
||||
onCancel={resetModals}
|
||||
footer={null}
|
||||
maskClosable={false}
|
||||
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 text-black">航线名称 <span className="text-red-500">*</span></label>
|
||||
<Input value={taskForm.name} onChange={(e) => setTaskForm({ ...taskForm, name: e.target.value })} placeholder="请输入航线名称" />
|
||||
<label className="text-sm block mb-1">航线名称 <span className="text-red-500">*</span></label>
|
||||
<Input
|
||||
value={taskForm.name}
|
||||
onChange={(e) => setTaskForm({ ...taskForm, name: e.target.value })}
|
||||
placeholder="请输入"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">选择航线 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">选择航线 <span className="text-red-500">*</span></label>
|
||||
<Select
|
||||
showSearch
|
||||
placeholder="请选择航线"
|
||||
value={waylineUuid}
|
||||
onChange={setWaylineUuid}
|
||||
options={waylineList}
|
||||
style={{ width: '100%' }}
|
||||
locale={{ emptyText: '暂无数据' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">机场SN <span className="text-red-500">*</span></label>
|
||||
<Input value={taskForm.sn} onChange={(e) => setTaskForm({ ...taskForm, sn: e.target.value })} placeholder="机场SN" disabled />
|
||||
<label className="text-sm block mb-1">机场SN <span className="text-red-500">*</span></label>
|
||||
<Input value={taskForm.sn} disabled />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">降落地场SN</label>
|
||||
<Input value={taskForm.landing_dock_sn} onChange={(e) => setTaskForm({ ...taskForm, landing_dock_sn: e.target.value })} placeholder="可不填" />
|
||||
<label className="text-sm block mb-1">降落地场SN</label>
|
||||
<Input
|
||||
value={taskForm.landing_dock_sn}
|
||||
onChange={(e) => setTaskForm({ ...taskForm, landing_dock_sn: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 飞行参数 */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">返航高度(m) <span className="text-red-500">*</span></label>
|
||||
<InputNumber min={0} value={taskForm.rth_altitude} onChange={(val) => setTaskForm({ ...taskForm, rth_altitude: val || 0 })} style={{ width: '100%' }} />
|
||||
<label className="text-sm block mb-1">返航高度(m)</label>
|
||||
<InputNumber
|
||||
min={0}
|
||||
value={taskForm.rth_altitude}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, rth_altitude: v })}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">返航模式 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">返航模式</label>
|
||||
<Select
|
||||
value={taskForm.rth_mode}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, rth_mode: val })}
|
||||
options={[
|
||||
{ label: '智能高度', value: 'optimal' },
|
||||
{ label: '设定高度', value: 'preset' }
|
||||
]}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, rth_mode: v })}
|
||||
options={[{ label: '智能', value: 'optimal' }, { label: '预设', value: 'preset' }]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
@@ -979,26 +1020,20 @@ export default function WayLinePage({ planedevices }) {
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">航线精度 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">航线精度</label>
|
||||
<Select
|
||||
value={taskForm.wayline_precision_type}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, wayline_precision_type: val })}
|
||||
options={[
|
||||
{ label: 'GPS模式(无需RTK收敛)', value: 'gps' },
|
||||
{ label: 'RTK高精度(需等待收敛)', value: 'rtk' }
|
||||
]}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, wayline_precision_type: v })}
|
||||
options={[{ label: 'GPS', value: 'gps' }, { label: 'RTK', value: 'rtk' }]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">自动断点续飞 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">断点续飞</label>
|
||||
<Select
|
||||
value={taskForm.resumable_status}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, resumable_status: val })}
|
||||
options={[
|
||||
{ label: '自动断点续飞', value: 'auto' },
|
||||
{ label: '手动断点续飞', value: 'manual' }
|
||||
]}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, resumable_status: v })}
|
||||
options={[{ label: '自动', value: 'auto' }, { label: '手动', value: 'manual' }]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
@@ -1006,102 +1041,191 @@ export default function WayLinePage({ planedevices }) {
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">最低执行电量(%) <span className="text-red-500">*</span></label>
|
||||
<InputNumber min={50} max={100} value={taskForm.min_battery_capacity} onChange={(val) => setTaskForm({ ...taskForm, min_battery_capacity: val || 50 })} style={{ width: '100%' }} />
|
||||
<label className="text-sm block mb-1">最低电量(%)</label>
|
||||
<InputNumber
|
||||
min={50}
|
||||
max={100}
|
||||
value={taskForm.min_battery_capacity}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, min_battery_capacity: v })}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">任务航线类型 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">任务类型</label>
|
||||
<Select
|
||||
value={taskForm.task_type}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, task_type: val })}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, task_type: v })}
|
||||
options={[
|
||||
{ label: '立即任务', value: 'immediate' },
|
||||
{ label: '单次定时任务', value: 'timed' },
|
||||
{ label: '重复任务', value: 'recurring' },
|
||||
{ label: '连续任务', value: 'continuous' },
|
||||
{ label: '立即', value: 'immediate' },
|
||||
//{ label: '单次定时', value: 'timed' },
|
||||
//{ label: '重复', value: 'recurring' },
|
||||
//{ label: '连续', value: 'continuous' },
|
||||
]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 根据任务类型显示不同字段 */}
|
||||
{/* 时间选择 */}
|
||||
{(taskForm.task_type === 'timed' || taskForm.task_type === 'recurring' || taskForm.task_type === 'continuous') && (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">开始时间 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">开始时间</label>
|
||||
<DatePicker
|
||||
showTime
|
||||
placeholder="开始时间"
|
||||
value={taskForm.begin_at}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, begin_at: v })}
|
||||
style={{ width: '100%' }}
|
||||
value={taskForm.begin_at ? dayjs(taskForm.begin_at) : null}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, begin_at: val })}
|
||||
/>
|
||||
</div>
|
||||
{(taskForm.task_type === 'recurring' || taskForm.task_type === 'continuous') && (
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">结束时间 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">结束时间</label>
|
||||
<DatePicker
|
||||
showTime
|
||||
placeholder="结束时间"
|
||||
value={taskForm.end_at}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, end_at: v })}
|
||||
style={{ width: '100%' }}
|
||||
value={taskForm.end_at ? dayjs(taskForm.end_at) : null}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, end_at: val })}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 重复任务配置 repeat_option 对象绑定 */}
|
||||
{taskForm.task_type === 'recurring' && (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">重复模式 <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">重复模式</label>
|
||||
<Select
|
||||
value={taskForm.repeat_type}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, repeat_type: val })}
|
||||
onChange={(v) => setTaskForm({ ...taskForm, repeat_type: v })}
|
||||
options={[
|
||||
{ label: '不重复', value: 'nonrepeating' },
|
||||
{ label: '每天', value: 'daily' },
|
||||
{ label: '每周', value: 'weekly' },
|
||||
{ label: '每月(按日期)', value: 'absolute_monthly' },
|
||||
{ label: '每月(按星期)', value: 'relative_monthly' },
|
||||
{ label: '每月(日期)', value: 'absolute_monthly' },
|
||||
{ label: '每月(星期)', value: 'relative_monthly' },
|
||||
]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">重复间隔(天/周/月) <span className="text-red-500">*</span></label>
|
||||
<label className="text-sm block mb-1">重复间隔</label>
|
||||
<InputNumber
|
||||
min={1}
|
||||
value={taskForm.repeat_option.interval}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, repeat_option: { ...taskForm.repeat_option, interval: val || 1 } })}
|
||||
onChange={(v) => setTaskForm({
|
||||
...taskForm,
|
||||
repeat_option: { ...taskForm.repeat_option, interval: v }
|
||||
})}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 每周 */}
|
||||
{taskForm.repeat_type === 'weekly' && (
|
||||
<div>
|
||||
<label className="text-sm block mb-1">周几执行</label>
|
||||
<Select
|
||||
mode="multiple"
|
||||
value={taskForm.repeat_option.days_of_week}
|
||||
onChange={(v) => setTaskForm({
|
||||
...taskForm,
|
||||
repeat_option: { ...taskForm.repeat_option, days_of_week: v }
|
||||
})}
|
||||
options={[
|
||||
{ label: '周日', value: 0 },
|
||||
{ label: '周一', value: 1 },
|
||||
{ label: '周二', value: 2 },
|
||||
{ label: '周三', value: 3 },
|
||||
{ label: '周四', value: 4 },
|
||||
{ label: '周五', value: 5 },
|
||||
{ label: '周六', value: 6 }
|
||||
]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 按月日期 */}
|
||||
{taskForm.repeat_type === 'absolute_monthly' && (
|
||||
<div>
|
||||
<label className="text-sm block mb-1">每月几日</label>
|
||||
<Select
|
||||
mode="multiple"
|
||||
value={taskForm.repeat_option.days_of_month}
|
||||
onChange={(v) => setTaskForm({
|
||||
...taskForm,
|
||||
repeat_option: { ...taskForm.repeat_option, days_of_month: v }
|
||||
})}
|
||||
options={Array.from({ length: 31 }, (_, i) => ({ label: i + 1, value: i + 1 }))}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 按月星期 */}
|
||||
{taskForm.repeat_type === 'relative_monthly' && (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm block mb-1">第几周</label>
|
||||
<Select
|
||||
value={taskForm.repeat_option.week_of_month}
|
||||
onChange={(v) => setTaskForm({
|
||||
...taskForm,
|
||||
repeat_option: { ...taskForm.repeat_option, week_of_month: v }
|
||||
})}
|
||||
options={[1, 2, 3, 4].map(w => ({ label: `第${w}周`, value: w }))}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm block mb-1">周几</label>
|
||||
<Select
|
||||
mode="multiple"
|
||||
value={taskForm.repeat_option.days_of_week}
|
||||
onChange={(v) => setTaskForm({
|
||||
...taskForm,
|
||||
repeat_option: { ...taskForm.repeat_option, days_of_week: v }
|
||||
})}
|
||||
options={[
|
||||
{ label: '周日', value: 0 },
|
||||
{ label: '周一', value: 1 },
|
||||
{ label: '周二', value: 2 },
|
||||
{ label: '周三', value: 3 },
|
||||
{ label: '周四', value: 4 },
|
||||
{ label: '周五', value: 5 },
|
||||
{ label: '周六', value: 6 }
|
||||
]}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="text-sm block mb-1 text-black">执行时间点列表</label>
|
||||
<label className="text-sm block mb-1">执行时间点</label>
|
||||
<Select
|
||||
mode="tags"
|
||||
placeholder="输入秒级时间戳或选择时间 (多选)"
|
||||
style={{ width: '100%' }}
|
||||
value={taskForm.recurring_task_start_time_list}
|
||||
onChange={(val) => setTaskForm({ ...taskForm, recurring_task_start_time_list: val })}
|
||||
onChange={(v) => setTaskForm({
|
||||
...taskForm,
|
||||
recurring_task_start_time_list: v
|
||||
})}
|
||||
placeholder="输入时间戳"
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
<Text type="secondary" style={{ fontSize: 11 }}>注:重复任务需指定具体执行的时间点列表。</Text>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="text-xs text-slate-400 mt-2">
|
||||
<div>绑定无人机:{listDrone?.drone_callsign || '-'}({listDrone?.gateway_sn || '-'})</div>
|
||||
</div>
|
||||
|
||||
{/* 按钮 */}
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<Button onClick={resetModals}>取消</Button>
|
||||
<Button type="primary" loading={loading} onClick={createFlightTask}>创建航线</Button>
|
||||
<Button type="primary" loading={loading} onClick={createFlightTask}>确认创建</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user