|
|
@@ -1,154 +1,232 @@
|
|
|
<template>
|
|
|
<div class="taskPanel">
|
|
|
- <a-spin :spinning="state.loading">
|
|
|
- <a-form ref="formRef" layout="vertical" :hideRequiredMark="true" :model="state.formModel">
|
|
|
- <!-- 任务名称 -->
|
|
|
- <a-form-item label='任务名称' name="name" :rules="[{ required: true, message: '任务名称不能为空', whitespace: true }]">
|
|
|
- <a-input placeholder="请输入任务名称" :maxlength="20" v-model:value="state.formModel.name" />
|
|
|
- </a-form-item>
|
|
|
- <!-- 执行航线 -->
|
|
|
- <a-form-item label="执行航线" name="file_id" :rules="[{ required: true, message: '执行航线不能为空' }]">
|
|
|
- <a-button type="primary">
|
|
|
- 选择航线
|
|
|
- </a-button>
|
|
|
- <div class="wayline-panel" style="padding-top: 5px;">
|
|
|
- <div class="title">
|
|
|
- <a-tooltip :title="wayline.name">
|
|
|
- <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
|
|
|
- {{ wayline.name }}</div>
|
|
|
- </a-tooltip>
|
|
|
- <div class="ml10">
|
|
|
+ <div class="taskPanel-info">
|
|
|
+ <div class="taskPanel-info-title">
|
|
|
+ 新建机场任务
|
|
|
+ </div>
|
|
|
+ <a-spin :spinning="state.loading">
|
|
|
+ <div class="taskPanel-info-content">
|
|
|
+ <a-form ref="formRef" layout="vertical" :hideRequiredMark="true" :model="state.formModel">
|
|
|
+ <!-- 任务名称 -->
|
|
|
+ <a-form-item label='任务名称' name="name" :rules="[{ required: true, message: '任务名称不能为空', whitespace: true }]">
|
|
|
+ <a-input placeholder="请输入任务名称" :maxlength="20" v-model:value="state.formModel.name" />
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 执行航线 -->
|
|
|
+ <a-form-item label="执行航线" name="file_id" :rules="[{ required: true, message: '执行航线不能为空' }]">
|
|
|
+ <a-button type="primary" @click="handleClickSelectWayline">
|
|
|
+ <PlusOutlined />
|
|
|
+ 选择航线
|
|
|
+ </a-button>
|
|
|
+ <div v-if="waylineInfo">
|
|
|
+ <div class="wayline-panel">
|
|
|
+ <div class="wayline-panel-title">
|
|
|
+ <div class="wayline-panel-title-left">
|
|
|
+ {{ waylineInfo.name }}
|
|
|
+ </div>
|
|
|
+ <div class="wayline-panel-title-right">
|
|
|
+ <UserOutlined />
|
|
|
+ {{ waylineInfo.user_name }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div style="margin-bottom: 5px;">
|
|
|
+ <img :src="aircraftSrc">
|
|
|
+ {{ waylineInfo.drone_model }}
|
|
|
+ </div>
|
|
|
+ <div style="margin-bottom: 5px;">
|
|
|
+ <CameraFilled />
|
|
|
+ {{ waylineInfo.payload_model }}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 更新时间 {{ waylineInfo.update_time }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 执行设备 -->
|
|
|
+ <a-form-item label="执行设备" name="dock_sn" :rules="[{ required: true, message: '执行设备不能为空' }]">
|
|
|
+ <a-button type="primary" @click="handleClickSelectDevice">
|
|
|
+ <PlusOutlined />
|
|
|
+ 选择设备
|
|
|
+ </a-button>
|
|
|
+ <div v-if="deviceInfo">
|
|
|
+ <div class="device-panel">
|
|
|
+ <div class="device-panel-cell">
|
|
|
+ <img :src="dockSrc">
|
|
|
+ <div>
|
|
|
+ {{ deviceInfo.name }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="device-panel-cell">
|
|
|
+ <img :src="aircraftSrc">
|
|
|
+ <div>
|
|
|
+ {{ deviceInfo.children.name }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 任务精度 -->
|
|
|
+ <a-form-item label="任务精度" name="wayline_precision_type">
|
|
|
+ <a-radio-group button-style="solid" v-model:value="state.formModel.wayline_precision_type">
|
|
|
+ <a-radio-button :value="1">
|
|
|
+ 高精度RTK
|
|
|
+ </a-radio-button>
|
|
|
+ <a-radio-button :value="0">
|
|
|
+ GNSS
|
|
|
+ </a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 任务策略 -->
|
|
|
+ <a-form-item label="任务策略" name="task_type">
|
|
|
+ <div style="white-space: nowrap;">
|
|
|
+ <a-radio-group button-style="solid" v-model:value="state.formModel.task_type">
|
|
|
+ <a-radio-button :value="0">
|
|
|
+ 立即
|
|
|
+ </a-radio-button>
|
|
|
+ <a-radio-button :value="1">
|
|
|
+ 定时
|
|
|
+ </a-radio-button>
|
|
|
+ <a-radio-button :value="2">
|
|
|
+ 循环
|
|
|
+ </a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ </div>
|
|
|
+ </a-form-item>
|
|
|
+ <template v-if="state.formModel.task_type === 1">
|
|
|
+ <!-- 执行时间 -->
|
|
|
+ <a-form-item label="执行时间" name="task_time" :rules="[{ required: true, message: '执行时间不能为空' }]">
|
|
|
+ <a-date-picker style="width: 100%;" :show-time="{ format: 'HH:mm' }" format="YYYY-MM-DD HH:mm"
|
|
|
+ valueFormat="YYYY-MM-DD HH:mm" placeholder="请选择执行时间" v-model:value="state.formModel.task_time" />
|
|
|
+ </a-form-item>
|
|
|
+ </template>
|
|
|
+ <template v-if="state.formModel.task_type === 2">
|
|
|
+ <!-- 执行日期 -->
|
|
|
+ <a-form-item label="执行日期" name="task_days" :rules="[{ required: true, message: '执行日期不能为空' }]">
|
|
|
+ <a-range-picker style="width: 100%;" valueFormat="YYYY-MM-DD"
|
|
|
+ :disabledDate="(current: any) => current < moment().subtract(1, 'days')"
|
|
|
+ :placeholder="['开始日期', '结束日期']" v-model:value="state.formModel.task_days" />
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 执行时间 -->
|
|
|
+ <a-form-item label="执行时间" name="task_periods" :rules="[{ validator: checkTaskPeriods, required: true }]">
|
|
|
+ <div style="display: flex;align-items: center;">
|
|
|
+ <a-time-picker placeholder="开始时间" format="HH:mm" valueFormat="YYYY-MM-DD HH:mm"
|
|
|
+ v-model:value="state.formModel.task_periods[0]" />
|
|
|
+ <div style="color: #FFFFFF;">-</div>
|
|
|
+ <a-time-picker placeholder="结束时间" format="HH:mm" valueFormat="YYYY-MM-DD HH:mm"
|
|
|
+ v-model:value="state.formModel.task_periods[1]" />
|
|
|
+ </div>
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 任务开始执行的电量 -->
|
|
|
+ <a-form-item label="任务开始执行的电量" name="min_battery_capacity">
|
|
|
+ <a-input-number :min="50" :max="100" :formatter="(value: number) => `${value}%`"
|
|
|
+ :parser="(value: string) => value.replace('%', '')"
|
|
|
+ v-model:value="state.formModel.min_battery_capacity">
|
|
|
+ </a-input-number>
|
|
|
+ </a-form-item>
|
|
|
+ </template>
|
|
|
+ <!-- 返航高度 -->
|
|
|
+ <a-form-item label="返航高度(相对机场返航高度)" name="rth_altitude">
|
|
|
+ <a-input-number style="width: 100%;" :min="20" :max="1500" v-model:value="state.formModel.rth_altitude" />
|
|
|
+ </a-form-item>
|
|
|
+ <!-- 自动断点续飞 -->
|
|
|
+ <a-form-item label="自动断点续飞" name="breakpoint_continuation">
|
|
|
+ <a-switch checked-children="开" un-checked-children="关"
|
|
|
+ v-model:checked="state.formModel.breakpoint_continuation" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </div>
|
|
|
+ </a-spin>
|
|
|
+ <div class="taskPanel-info-footer">
|
|
|
+ <a-button style="background: #3c3c3c;margin-right: 10px;" @click="onClickCancel">
|
|
|
+ 取消
|
|
|
+ </a-button>
|
|
|
+ <a-button type="primary" @click="handleClickConfirm">
|
|
|
+ 确定
|
|
|
+ </a-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="taskPanel-modal" v-if="waylineState.visible">
|
|
|
+ <div class="taskPanel-modal-title">
|
|
|
+ <div>
|
|
|
+ 航线列表
|
|
|
+ </div>
|
|
|
+ <a style="color: #FFFFFF;">
|
|
|
+ <CloseOutlined @click="waylineState.visible = false" />
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ <a-spin :spinning="waylineState.listLoading">
|
|
|
+ <div class="taskPanel-modal-content" v-if="waylineState.list.length">
|
|
|
+ <div class="wayline-panel" v-for="item in waylineState.list" :key="item.id"
|
|
|
+ @click="state.formModel.file_id = item.id">
|
|
|
+ <div class="wayline-panel-title">
|
|
|
+ <div class="wayline-panel-title-left">
|
|
|
+ {{ item.name }}
|
|
|
+ </div>
|
|
|
+ <div class="wayline-panel-title-right">
|
|
|
<UserOutlined />
|
|
|
+ {{ item.user_name }}
|
|
|
</div>
|
|
|
- <a-tooltip :title="wayline.user_name">
|
|
|
- <div class="ml5 pr10"
|
|
|
- style="width: 80px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">{{
|
|
|
- wayline.user_name }}</div>
|
|
|
- </a-tooltip>
|
|
|
</div>
|
|
|
- <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
|
|
|
- <span>
|
|
|
- <RocketOutlined />
|
|
|
- </span>
|
|
|
- <span class="ml5">{{ DEVICE_NAME[wayline.drone_model_key] }}</span>
|
|
|
- <span class="ml10">
|
|
|
- <CameraFilled style="border-top: 1px solid; padding-top: -3px;" />
|
|
|
- </span>
|
|
|
- <span class="ml5" v-for="payload in wayline.payload_model_keys" :key="payload.id">
|
|
|
- {{ DEVICE_NAME[payload] }}
|
|
|
- </span>
|
|
|
+ <div style="margin-bottom: 5px;">
|
|
|
+ <img :src="aircraftSrc">
|
|
|
+ {{ item.drone_model }}
|
|
|
+ </div>
|
|
|
+ <div style="margin-bottom: 5px;">
|
|
|
+ <CameraFilled />
|
|
|
+ {{ item.payload_model }}
|
|
|
</div>
|
|
|
- <div class="mt5 ml10" style="color: hsla(0,0%,100%,0.35);">
|
|
|
- <span class="mr10">Update at {{ new Date(wayline.update_time).toLocaleString() }}</span>
|
|
|
+ <div>
|
|
|
+ 更新时间 {{ item.update_time }}
|
|
|
</div>
|
|
|
</div>
|
|
|
- </a-form-item>
|
|
|
- <!-- 执行设备 -->
|
|
|
- <a-form-item label="执行设备" name="dock_sn" :rules="[{ required: true, message: '执行设备不能为空' }]">
|
|
|
- <a-button type="primary">
|
|
|
- 选择设备
|
|
|
- </a-button>
|
|
|
- <div class="panel" style="padding-top: 5px;">
|
|
|
- <div class="title">
|
|
|
- <a-tooltip :title="dock.nickname">
|
|
|
- <div class="pr10" style="width: 120px; white-space: nowrap; text-overflow: ellipsis; overflow: hidden;">
|
|
|
- {{ dock.nickname }}</div>
|
|
|
- </a-tooltip>
|
|
|
+ </div>
|
|
|
+ <a-empty style="margin-top: 20%;" :image="noDataSrc" :image-style="{ height: '60px' }" v-else />
|
|
|
+ </a-spin>
|
|
|
+ </div>
|
|
|
+ <div class="taskPanel-modal" v-if="deviceState.visible">
|
|
|
+ <div class="taskPanel-modal-title">
|
|
|
+ <div>
|
|
|
+ 设备列表
|
|
|
+ </div>
|
|
|
+ <a style="color: #FFFFFF;">
|
|
|
+ <CloseOutlined @click="deviceState.visible = false" />
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ <a-spin :spinning="deviceState.listLoading">
|
|
|
+ <div class="taskPanel-modal-content" v-if="deviceState.list.length">
|
|
|
+ <div class="device-panel" v-for="item in deviceState.list" :key="item.sn"
|
|
|
+ @click="state.formModel.dock_sn = item.sn">
|
|
|
+ <div class="device-panel-cell">
|
|
|
+ <img :src="dockSrc">
|
|
|
+ <div>
|
|
|
+ {{ item.name }}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="ml10 mt5" style="color: hsla(0,0%,100%,0.65);">
|
|
|
- <span>
|
|
|
- <RocketOutlined />
|
|
|
- </span>
|
|
|
- <!-- <span class="ml5">{{ dock.children?.nickname ?? 'No drone' }}</span> -->
|
|
|
+ <div class="device-panel-cell">
|
|
|
+ <img :src="aircraftSrc">
|
|
|
+ <div>
|
|
|
+ {{ item.children.name }}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </a-form-item>
|
|
|
- <!-- 任务精度 -->
|
|
|
- <a-form-item label="任务精度" name="wayline_precision_type">
|
|
|
- <a-radio-group button-style="solid" v-model:value="state.formModel.wayline_precision_type">
|
|
|
- <a-radio-button :value="1">
|
|
|
- 高精度RTK
|
|
|
- </a-radio-button>
|
|
|
- <a-radio-button :value="0">
|
|
|
- GNSS
|
|
|
- </a-radio-button>
|
|
|
- </a-radio-group>
|
|
|
- </a-form-item>
|
|
|
- <!-- 任务策略 -->
|
|
|
- <a-form-item label="任务策略" name="task_type">
|
|
|
- <div style="white-space: nowrap;">
|
|
|
- <a-radio-group button-style="solid" v-model:value="state.formModel.task_type">
|
|
|
- <a-radio-button :value="0">
|
|
|
- 立即
|
|
|
- </a-radio-button>
|
|
|
- <a-radio-button :value="1">
|
|
|
- 定时
|
|
|
- </a-radio-button>
|
|
|
- <a-radio-button :value="2">
|
|
|
- 循环
|
|
|
- </a-radio-button>
|
|
|
- </a-radio-group>
|
|
|
- </div>
|
|
|
- </a-form-item>
|
|
|
- <template v-if="state.formModel.task_type === 1">
|
|
|
- <!-- 执行时间 -->
|
|
|
- <a-form-item label="执行时间" name="select_execute_date_time" :rules="[{ required: true, message: '执行时间不能为空' }]">
|
|
|
- <a-date-picker style="width: 100%;" show-time valueFormat="YYYY-MM-DD HH:mm:ss" placeholder="请选择执行时间"
|
|
|
- v-model:value="state.formModel.select_execute_date_time" />
|
|
|
- </a-form-item>
|
|
|
- </template>
|
|
|
- <template v-if="state.formModel.task_type === 2">
|
|
|
- <!-- 执行日期 -->
|
|
|
- <a-form-item label="执行日期" name="select_execute_range_date" :rules="[{ required: true, message: '执行日期不能为空' }]">
|
|
|
- <a-range-picker style="width: 100%;" valueFormat="YYYY-MM-DD"
|
|
|
- :disabledDate="(current: any) => current < moment().subtract(1, 'days')" :placeholder="['开始日期', '结束日期']"
|
|
|
- v-model:value="state.formModel.select_execute_range_date" />
|
|
|
- </a-form-item>
|
|
|
- <!-- 执行时间 -->
|
|
|
- <a-form-item label="执行时间" name="select_execute_range_time">
|
|
|
- <a-range-picker style="width: 100%;" :show-time="{ format: 'HH:mm' }" format="HH:mm" valueFormat="HH:mm"
|
|
|
- :placeholder="['开始时间', '结束时间']" v-model:value="state.formModel.select_execute_range_time" />
|
|
|
- </a-form-item>
|
|
|
- <!-- 任务开始执行的电量 -->
|
|
|
- <a-form-item label="任务开始执行的电量" name="min_battery_capacity">
|
|
|
- <a-input-number :min="50" :max="100" :formatter="(value: number) => `${value}%`"
|
|
|
- :parser="(value: string) => value.replace('%', '')" v-model:value="state.formModel.min_battery_capacity">
|
|
|
- </a-input-number>
|
|
|
- </a-form-item>
|
|
|
- </template>
|
|
|
- <!-- 返航高度 -->
|
|
|
- <a-form-item label="返航高度(相对机场返航高度)" name="rth_altitude">
|
|
|
- <a-input-number style="width: 100%;" :min="20" :max="1500" v-model:value="state.formModel.rth_altitude" />
|
|
|
- </a-form-item>
|
|
|
- <!-- 自动断点续飞 -->
|
|
|
- <a-form-item label="自动断点续飞" name="breakpoint_continuation">
|
|
|
- <a-switch checked-children="开" un-checked-children="关"
|
|
|
- v-model:checked="state.formModel.breakpoint_continuation" />
|
|
|
- </a-form-item>
|
|
|
- <!-- 自动断点续飞 -->
|
|
|
- <a-form-item>
|
|
|
- <div class="taskPanel-footer">
|
|
|
- <a-button style="background: #3c3c3c;margin-right: 10px;" @click="onClickCancel">
|
|
|
- 取消
|
|
|
- </a-button>
|
|
|
- <a-button type="primary" @click="handleClickConfirm">
|
|
|
- 确定
|
|
|
- </a-button>
|
|
|
- </div>
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-spin>
|
|
|
+ </div>
|
|
|
+ <a-empty style="margin-top: 20%;" :image="noDataSrc" :image-style="{ height: '60px' }" v-else />
|
|
|
+ </a-spin>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { ref, computed, reactive } from 'vue'
|
|
|
-import { RocketOutlined, CameraFilled, UserOutlined } from '@ant-design/icons-vue'
|
|
|
-import { useMyStore } from '/@/store'
|
|
|
-import { WaylineFile } from '/@/types/wayline'
|
|
|
-import { Device, DEVICE_NAME } from '/@/types/device'
|
|
|
-import moment from 'moment'
|
|
|
-import { createPlan } from '/@/api/wayline'
|
|
|
+import { ref, reactive, watch, computed, onMounted } from 'vue';
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
+import { PlusOutlined, CloseOutlined, UserOutlined, CameraFilled } from '@ant-design/icons-vue';
|
|
|
+import noDataSrc from '/@/assets/icons/no-data.png';
|
|
|
+import aircraftSrc from '/@/components/airport/icons/aircraft.svg';
|
|
|
+import dockSrc from '/@/components/airport/icons/dockInfo.svg';
|
|
|
+import moment from 'moment';
|
|
|
+import { createPlan } from '/@/api/wayline';
|
|
|
+import { apis } from '/@/api/custom';
|
|
|
+import { DEVICE_NAME } from '/@/types/device'
|
|
|
|
|
|
interface Props {
|
|
|
onClickConfirm: (data: any) => Promise<any>,
|
|
|
@@ -161,16 +239,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
|
|
|
const formRef = ref();
|
|
|
|
|
|
-const store = useMyStore()
|
|
|
-
|
|
|
-const dock = computed<Device>(() => {
|
|
|
- return store.state.dockInfo
|
|
|
-})
|
|
|
-
|
|
|
-const wayline = computed<WaylineFile>(() => {
|
|
|
- return store.state.waylineInfo
|
|
|
-})
|
|
|
-
|
|
|
interface State {
|
|
|
loading: boolean,
|
|
|
formModel: {
|
|
|
@@ -179,9 +247,9 @@ interface State {
|
|
|
dock_sn: string;
|
|
|
wayline_precision_type: number;
|
|
|
task_type: number;
|
|
|
- select_execute_date_time?: string;
|
|
|
- select_execute_range_date?: any[],
|
|
|
- select_execute_range_time?: any[],
|
|
|
+ task_time: string;
|
|
|
+ task_days: any[],
|
|
|
+ task_periods: any[],
|
|
|
min_battery_capacity: number,
|
|
|
rth_altitude: number,
|
|
|
breakpoint_continuation: boolean;
|
|
|
@@ -196,47 +264,323 @@ const state: State = reactive({
|
|
|
dock_sn: '',// 执行设备
|
|
|
wayline_precision_type: 1,// 任务精度
|
|
|
task_type: 0,// 任务策略
|
|
|
- select_execute_date_time: undefined,// 定时-执行时间
|
|
|
- select_execute_range_date: undefined,// 循环-执行日期
|
|
|
- select_execute_range_time: undefined,// 循环-执行时间
|
|
|
+ task_time: '',// 定时-执行时间
|
|
|
+ task_days: [],// 循环-执行日期
|
|
|
+ task_periods: [],// 循环-执行时间
|
|
|
min_battery_capacity: 90,// 循环-任务开始执行的电量
|
|
|
rth_altitude: 20,// 返航高度
|
|
|
breakpoint_continuation: true,// 自动断点续飞
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+const waylineState = reactive({
|
|
|
+ visible: false,
|
|
|
+ listLoading: false,
|
|
|
+ list: [] as {
|
|
|
+ id: string,
|
|
|
+ name: string,
|
|
|
+ update_time: string,
|
|
|
+ user_name: string,
|
|
|
+ drone_model: string,
|
|
|
+ payload_model: string,
|
|
|
+ }[],
|
|
|
+})
|
|
|
+
|
|
|
+const waylineInfo = computed(() => {
|
|
|
+ const fileId = state.formModel.file_id;
|
|
|
+ return waylineState.list.find(item => item.id === fileId);
|
|
|
+});
|
|
|
+
|
|
|
+const deviceState = reactive({
|
|
|
+ visible: false,
|
|
|
+ listLoading: false,
|
|
|
+ list: [] as {
|
|
|
+ sn: string,
|
|
|
+ name: string,
|
|
|
+ drone_model: string,
|
|
|
+ children: {
|
|
|
+ sn: string,
|
|
|
+ name: string,
|
|
|
+ },
|
|
|
+ }[],
|
|
|
+})
|
|
|
+
|
|
|
+const deviceInfo = computed(() => {
|
|
|
+ const dockSn = state.formModel.dock_sn;
|
|
|
+ return deviceState.list.find(item => item.sn === dockSn);
|
|
|
+});
|
|
|
+
|
|
|
+// 获取航线列表
|
|
|
+const fetchWaylineList = async () => {
|
|
|
+ waylineState.listLoading = true;
|
|
|
+ try {
|
|
|
+ const res = await apis.fetchAllWaylineList();
|
|
|
+ const list = res.data.map((item: any) => {
|
|
|
+ return {
|
|
|
+ id: item.id,
|
|
|
+ name: item.name,
|
|
|
+ update_time: moment(item.update_time).format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ user_name: item.user_name,
|
|
|
+ drone_model: DEVICE_NAME[item.drone_model_key],
|
|
|
+ payload_model: item.payload_model_keys.map((key: any) => DEVICE_NAME[key]).join('、'),
|
|
|
+ }
|
|
|
+ })
|
|
|
+ waylineState.list = list;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ } finally {
|
|
|
+ waylineState.listLoading = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取设备列表
|
|
|
+const fetchDeviceList = async () => {
|
|
|
+ deviceState.listLoading = true;
|
|
|
+ try {
|
|
|
+ const res = await apis.fetchAllDockDeviceList();
|
|
|
+ // 在线设备列表
|
|
|
+ const olineList = res.data.filter((item: any) => item.status);
|
|
|
+ const list = olineList.map((item: any) => {
|
|
|
+ return {
|
|
|
+ sn: item.device_sn,
|
|
|
+ name: item.nickname,
|
|
|
+ drone_model: item.children?.device_name || '',
|
|
|
+ children: {
|
|
|
+ sn: item.children?.device_sn || '',
|
|
|
+ name: item.children?.nickname || '',
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ deviceState.list = list;
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ } finally {
|
|
|
+ deviceState.listLoading = false;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ await Promise.all([
|
|
|
+ fetchWaylineList(),
|
|
|
+ fetchDeviceList(),
|
|
|
+ ])
|
|
|
+})
|
|
|
+
|
|
|
+watch(() => waylineState.visible, async (visible) => {
|
|
|
+ if (visible) {// 更新航线列表
|
|
|
+ await fetchWaylineList();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+watch(() => deviceState.visible, async (visible) => {
|
|
|
+ if (visible) {// 更新设备列表
|
|
|
+ await fetchDeviceList();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+// 检查执行时间
|
|
|
+const checkTaskPeriods = (rule: any, values: string) => {
|
|
|
+ if (values?.length) {
|
|
|
+ const startTime = values[0];
|
|
|
+ const endTime = values[1];
|
|
|
+ if (!startTime) {
|
|
|
+ return Promise.reject('开始时间不能为空');
|
|
|
+ } else if (!endTime) {
|
|
|
+ return Promise.reject('结束时间不能为空');
|
|
|
+ } else if (startTime > endTime) {
|
|
|
+ return Promise.reject('结束时间不能早于开始时间');
|
|
|
+ } else {
|
|
|
+ return Promise.resolve();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return Promise.reject('执行时间不能为空');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 点击选择航线
|
|
|
+const handleClickSelectWayline = () => {
|
|
|
+ waylineState.visible = true;
|
|
|
+ deviceState.visible = false;
|
|
|
+}
|
|
|
+
|
|
|
+// 点击选择设备
|
|
|
+const handleClickSelectDevice = () => {
|
|
|
+ deviceState.visible = true;
|
|
|
+ waylineState.visible = false;
|
|
|
+}
|
|
|
+
|
|
|
// 点击确定
|
|
|
const handleClickConfirm = async () => {
|
|
|
- formRef.value?.validateFields().then(async (values: any) => {
|
|
|
+ formRef.value?.validateFields().then((values: any) => {
|
|
|
+ const waylineDroneModel = waylineInfo.value?.drone_model;
|
|
|
+ const droneModel = deviceInfo.value?.drone_model;
|
|
|
+ if (waylineDroneModel !== droneModel) {
|
|
|
+ return message.warning('请选择相同型号的设备');
|
|
|
+ }
|
|
|
const data = { ...values };
|
|
|
- // await createPlan()
|
|
|
+ if (values.task_time) {
|
|
|
+ data.task_time = moment(values.task_time).valueOf();
|
|
|
+ }
|
|
|
+ if (values.task_days?.length === 2) {
|
|
|
+ const startDate = moment(values.task_days[0]).valueOf();
|
|
|
+ const endDate = moment(values.task_days[1]).valueOf();
|
|
|
+ data.task_days = [startDate, endDate];
|
|
|
+ }
|
|
|
+ if (values.task_periods?.length === 2) {
|
|
|
+ const startDate = moment(values.task_periods[0]).valueOf();
|
|
|
+ const endDate = moment(values.task_periods[1]).valueOf();
|
|
|
+ data.task_periods = [startDate, endDate];
|
|
|
+ }
|
|
|
console.log(data, 'data');
|
|
|
+ // await createPlan()
|
|
|
}).catch((error: any) => {
|
|
|
console.error(error);
|
|
|
});
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
-<style lang="scss">
|
|
|
+<style lang="scss" scoped>
|
|
|
.taskPanel {
|
|
|
- width: 100%;
|
|
|
height: 100%;
|
|
|
color: #FFFFFF;
|
|
|
- overflow-y: auto;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &-info {
|
|
|
+ width: 300px;
|
|
|
+ height: 100%;
|
|
|
+ padding: 0 10px 10px;
|
|
|
+ border-right: 1px solid #4f4f4f;
|
|
|
+ background-color: #232323;
|
|
|
+
|
|
|
+ &-title {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ padding-left: 10px;
|
|
|
+ border-bottom: 1px solid #4f4f4f;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-content {
|
|
|
+ width: 100%;
|
|
|
+ height: calc(100vh - 100px);
|
|
|
+ overflow: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-footer {
|
|
|
+ width: 100%;
|
|
|
+ height: 60px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ button {
|
|
|
+ width: 48%;
|
|
|
+ color: #FFFFFF;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-modal {
|
|
|
+ width: 280px;
|
|
|
+ height: 100%;
|
|
|
+ padding: 0 10px 10px;
|
|
|
+ background-color: #232323;
|
|
|
+ position: absolute;
|
|
|
+ left: 100%;
|
|
|
+ top: 0;
|
|
|
+ z-index: 2;
|
|
|
+
|
|
|
+ &-title {
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ border-bottom: 1px solid #4f4f4f;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-content {
|
|
|
+ width: 100%;
|
|
|
+ height: calc(100vh - 50px);
|
|
|
+ overflow: auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- &-footer {
|
|
|
+.wayline-panel {
|
|
|
+ width: 100%;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #3c3c3c;
|
|
|
+ border-radius: 4px;
|
|
|
+ color: #FFFFFF;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-top: 10px;
|
|
|
+
|
|
|
+ &-title {
|
|
|
display: flex;
|
|
|
- padding: 10px 0;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ margin-bottom: 5px;
|
|
|
|
|
|
- button {
|
|
|
- width: 45%;
|
|
|
- color: #fff;
|
|
|
- border: 0;
|
|
|
+ &-left {
|
|
|
+ width: 120px;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
+
|
|
|
+ &-right {
|
|
|
+ width: 80px;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+.device-panel {
|
|
|
+ width: 100%;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #3c3c3c;
|
|
|
+ border-radius: 4px;
|
|
|
+ color: #FFFFFF;
|
|
|
+ cursor: pointer;
|
|
|
+ margin-top: 10px;
|
|
|
|
|
|
+ &-cell {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 5px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ margin-right: 5px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-cell:last-child {
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.taskPanel {
|
|
|
form {
|
|
|
- margin: 10px;
|
|
|
+ margin: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .ant-form-item {
|
|
|
+ margin-bottom: 12px;
|
|
|
}
|
|
|
|
|
|
form,
|