sean.zhou
2 years ago
40 changed files with 2385 additions and 647 deletions
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
import request, { IWorkspaceResponse } from '/@/api/http/request' |
||||
import { ELocalStorageKey } from '/@/types' |
||||
import { NightLightsStateEnum, DistanceLimitStatus, ObstacleAvoidance } from '/@/types/device-setting' |
||||
|
||||
const MNG_API_PREFIX = '/manage/api/v1' |
||||
const workspaceId: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) || '' |
||||
|
||||
export interface PutDevicePropsBody { |
||||
night_lights_state?: NightLightsStateEnum;// 夜航灯开关
|
||||
height_limit?: number;// 限高设置
|
||||
distance_limit_status?: DistanceLimitStatus;// 限远开关
|
||||
obstacle_avoidance?: ObstacleAvoidance;// 飞行器避障开关设置
|
||||
} |
||||
|
||||
/** |
||||
* 设置设备属性 |
||||
* @param params |
||||
* @returns |
||||
*/ |
||||
// /manage/api/v1/devices/{{workspace_id}}/devices/{{device_sn}}/property
|
||||
export async function putDeviceProps (deviceSn: string, body: PutDevicePropsBody): Promise<IWorkspaceResponse<{}>> { |
||||
const resp = await request.put(`${MNG_API_PREFIX}/devices/${workspaceId}/devices/${deviceSn}/property`, body) |
||||
return resp.data |
||||
} |
@ -1,182 +0,0 @@
@@ -1,182 +0,0 @@
|
||||
<template> |
||||
<div class="header">Task Plan Library</div> |
||||
<div class="plan-panel-wrapper"> |
||||
<!-- <router-link :to=" '/' + ERouterName.CREATE_PLAN"> |
||||
<a-button type="primary">Create Plan</a-button> |
||||
</router-link> --> |
||||
<a-table class="plan-table" :columns="columns" :data-source="plansData.data" row-key="job_id" |
||||
:pagination="paginationProp" :scroll="{ x: '100%', y: 600 }" @change="refreshData"> |
||||
<template #status="{ record }"> |
||||
<span v-if="taskProgressMap[record.bid]"> |
||||
<a-progress type="line" :percent="taskProgressMap[record.bid]?.progress?.percent" |
||||
:status="taskProgressMap[record.bid]?.status.indexOf(ETaskStatus.FAILED) != -1 ? 'exception' : taskProgressMap[record.bid]?.status.indexOf(ETaskStatus.OK) != -1 ? 'success' : 'normal'"> |
||||
<template #format="percent"> |
||||
<a-tooltip :title="taskProgressMap[record.bid]?.status"> |
||||
<div style="white-space: nowrap; text-overflow: ellipsis; overflow: hidden; position: absolute; left: 5px; top: -12px;"> |
||||
{{ percent }}% {{ taskProgressMap[record.bid]?.status }} |
||||
</div> |
||||
</a-tooltip> |
||||
</template> |
||||
</a-progress> |
||||
</span> |
||||
</template> |
||||
<template #action="{ record }"> |
||||
<span class="action-area"> |
||||
<a-popconfirm |
||||
title="Are you sure execute this task?" |
||||
ok-text="Yes" |
||||
cancel-text="No" |
||||
@confirm="executePlan(record.job_id)" |
||||
> |
||||
<a-button type="primary" size="small">Execute</a-button> |
||||
</a-popconfirm> |
||||
</span> |
||||
</template> |
||||
</a-table> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { reactive, ref } from '@vue/reactivity' |
||||
import { message } from 'ant-design-vue' |
||||
import { TableState } from 'ant-design-vue/lib/table/interface' |
||||
import { computed, onMounted, watch } from 'vue' |
||||
import { IPage } from '../api/http/type' |
||||
import { executeWaylineJobs, getWaylineJobs } from '../api/wayline' |
||||
import { getRoot } from '../root' |
||||
import { useMyStore } from '../store' |
||||
import { ELocalStorageKey, ERouterName } from '../types/enums' |
||||
import router from '/@/router' |
||||
import { ETaskStatus } from '/@/types/wayline' |
||||
|
||||
const store = useMyStore() |
||||
|
||||
const workspaceId = localStorage.getItem(ELocalStorageKey.WorkspaceId)! |
||||
|
||||
const root = getRoot() |
||||
const body: IPage = { |
||||
page: 1, |
||||
total: 0, |
||||
page_size: 50 |
||||
} |
||||
const paginationProp = reactive({ |
||||
pageSizeOptions: ['20', '50', '100'], |
||||
showQuickJumper: true, |
||||
showSizeChanger: true, |
||||
pageSize: 50, |
||||
current: 1, |
||||
total: 0 |
||||
}) |
||||
|
||||
const columns = [ |
||||
{ |
||||
title: 'Plan Name', |
||||
dataIndex: 'job_name' |
||||
}, |
||||
{ |
||||
title: 'Flight Route Name', |
||||
dataIndex: 'file_name', |
||||
ellipsis: true |
||||
}, |
||||
{ |
||||
title: 'Dock Name', |
||||
dataIndex: 'dock_name', |
||||
ellipsis: true |
||||
}, |
||||
{ |
||||
title: 'Creator', |
||||
dataIndex: 'username', |
||||
}, |
||||
{ |
||||
title: 'Updated', |
||||
dataIndex: 'update_time' |
||||
}, |
||||
{ |
||||
title: 'Status', |
||||
key: 'status', |
||||
width: 200, |
||||
slots: { customRender: 'status' } |
||||
}, |
||||
|
||||
{ |
||||
title: 'Action', |
||||
slots: { customRender: 'action' } |
||||
} |
||||
] |
||||
type Pagination = TableState['pagination'] |
||||
|
||||
interface TaskPlan { |
||||
bid: string, |
||||
job_id: string, |
||||
job_name: string, |
||||
file_name: string, |
||||
dock_name: string, |
||||
username: string, |
||||
create_time: string, |
||||
} |
||||
|
||||
const plansData = reactive({ |
||||
data: [] as TaskPlan[] |
||||
}) |
||||
|
||||
function createPlan () { |
||||
root.$router.push('/' + ERouterName.CREATE_PLAN) |
||||
} |
||||
|
||||
const taskProgressMap = computed(() => store.state.taskProgressInfo) |
||||
|
||||
onMounted(() => { |
||||
getPlans() |
||||
}) |
||||
|
||||
function getPlans () { |
||||
getWaylineJobs(workspaceId, body).then(res => { |
||||
if (res.code !== 0) { |
||||
return |
||||
} |
||||
plansData.data = res.data.list |
||||
paginationProp.total = res.data.pagination.total |
||||
paginationProp.current = res.data.pagination.page |
||||
}) |
||||
} |
||||
|
||||
function refreshData (page: Pagination) { |
||||
body.page = page?.current! |
||||
body.page_size = page?.pageSize! |
||||
getPlans() |
||||
} |
||||
|
||||
function executePlan (jobId: string) { |
||||
executeWaylineJobs(workspaceId, jobId).then(res => { |
||||
if (res.code === 0) { |
||||
message.success('Executed Successfully') |
||||
getPlans() |
||||
} |
||||
}) |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.plan-panel-wrapper { |
||||
width: 100%; |
||||
padding: 16px; |
||||
.plan-table { |
||||
background: #fff; |
||||
margin-top: 10px; |
||||
} |
||||
.action-area { |
||||
color: $primary; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
.header { |
||||
width: 100%; |
||||
height: 60px; |
||||
background: #fff; |
||||
padding: 16px; |
||||
font-size: 20px; |
||||
font-weight: bold; |
||||
text-align: start; |
||||
color: #000; |
||||
} |
||||
</style> |
@ -0,0 +1,242 @@
@@ -0,0 +1,242 @@
|
||||
<template> |
||||
<div class="device-setting-wrapper"> |
||||
<div class="device-setting-header">设备属性设置</div> |
||||
<div class="device-setting-box"> |
||||
<!-- 飞行器夜航灯 --> |
||||
<div class="control-setting-item"> |
||||
<div class="control-setting-item-left"> |
||||
<div class="item-label">{{ deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].label }}</div> |
||||
<div class="item-status">{{ deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].value }}</div> |
||||
</div> |
||||
<div class="control-setting-item-right"> |
||||
<DeviceSettingPopover |
||||
:visible="deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].popConfirm.visible" |
||||
:loading="deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].popConfirm.loading" |
||||
@confirm="onConfirm(deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].settingKey)" |
||||
@cancel="onCancel(deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].settingKey)" |
||||
> |
||||
<template #formContent> |
||||
<div class="form-content"> |
||||
<span class="form-label">{{ deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].label }}:</span> |
||||
<a-switch checked-children="开" un-checked-children="关" v-model:checked="deviceSettingFormModel.nightLightsState" /> |
||||
</div> |
||||
</template> |
||||
<a @click="onShowPopConfirm(deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].settingKey)">Edit</a> |
||||
</DeviceSettingPopover> |
||||
</div> |
||||
</div> |
||||
<!-- 限高 --> |
||||
<div class="control-setting-item"> |
||||
<div class="control-setting-item-left"> |
||||
<div class="item-label">{{ deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].label }}</div> |
||||
<div class="item-status">{{ deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].value }}</div> |
||||
</div> |
||||
<div class="control-setting-item-right"> |
||||
<DeviceSettingPopover |
||||
:visible="deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].popConfirm.visible" |
||||
:loading="deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].popConfirm.loading" |
||||
@confirm="onConfirm(deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].settingKey)" |
||||
@cancel="onCancel(deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].settingKey)" |
||||
> |
||||
<template #formContent> |
||||
<div class="form-content"> |
||||
<span class="form-label">{{ deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].label }}:</span> |
||||
<a-input-number v-model:value="deviceSettingFormModel.heightLimit" :min="20" :max="1500" /> |
||||
m |
||||
</div> |
||||
</template> |
||||
<a @click="onShowPopConfirm(deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].settingKey)">Edit</a> |
||||
</DeviceSettingPopover> |
||||
</div> |
||||
</div> |
||||
<!-- 限远 --> |
||||
<div class="control-setting-item"> |
||||
<div class="control-setting-item-left"> |
||||
<div class="item-label">{{ deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].label }}</div> |
||||
<div class="item-status">{{ deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].value }}</div> |
||||
</div> |
||||
<div class="control-setting-item-right"> |
||||
<DeviceSettingPopover |
||||
:visible="deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].popConfirm.visible" |
||||
:loading="deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].popConfirm.loading" |
||||
@confirm="onConfirm(deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].settingKey)" |
||||
@cancel="onCancel(deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].settingKey)" |
||||
> |
||||
<template #formContent> |
||||
<div class="form-content"> |
||||
<span class="form-label">{{ deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].label }}:</span> |
||||
<a-switch style="margin-right: 10px;" checked-children="开" un-checked-children="关" v-model:checked="deviceSettingFormModel.distanceLimitStatus.state" /> |
||||
<a-input-number v-model:value="deviceSettingFormModel.distanceLimitStatus.distanceLimit" :min="15" :max="8000" /> |
||||
m |
||||
</div> |
||||
</template> |
||||
<a @click="onShowPopConfirm(deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].settingKey)">Edit</a> |
||||
</DeviceSettingPopover> |
||||
</div> |
||||
</div> |
||||
<!-- 水平避障 --> |
||||
<div class="control-setting-item"> |
||||
<div class="control-setting-item-left"> |
||||
<div class="item-label">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].label }}</div> |
||||
<div class="item-status">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].value }}</div> |
||||
</div> |
||||
<div class="control-setting-item-right"> |
||||
<DeviceSettingPopover |
||||
:visible="deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].popConfirm.visible" |
||||
:loading="deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].popConfirm.loading" |
||||
@confirm="onConfirm(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].settingKey)" |
||||
@cancel="onCancel(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].settingKey)" |
||||
> |
||||
<template #formContent> |
||||
<div class="form-content"> |
||||
<span class="form-label">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].label }}:</span> |
||||
<a-switch checked-children="开" un-checked-children="关" v-model:checked="deviceSettingFormModel.obstacleAvoidanceHorizon" /> |
||||
</div> |
||||
</template> |
||||
<a @click="onShowPopConfirm(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].settingKey)">Edit</a> |
||||
</DeviceSettingPopover> |
||||
</div> |
||||
</div> |
||||
<!-- 上视避障 --> |
||||
<div class="control-setting-item"> |
||||
<div class="control-setting-item-left"> |
||||
<div class="item-label">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].label }}</div> |
||||
<div class="item-status">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].value }}</div> |
||||
</div> |
||||
<div class="control-setting-item-right"> |
||||
<DeviceSettingPopover |
||||
:visible="deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].popConfirm.visible" |
||||
:loading="deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].popConfirm.loading" |
||||
@confirm="onConfirm(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].settingKey)" |
||||
@cancel="onCancel(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].settingKey)" |
||||
> |
||||
<template #formContent> |
||||
<div class="form-content"> |
||||
<span class="form-label">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].label }}:</span> |
||||
<a-switch checked-children="开" un-checked-children="关" v-model:checked="deviceSettingFormModel.obstacleAvoidanceUpside" /> |
||||
</div> |
||||
</template> |
||||
<a @click="onShowPopConfirm(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].settingKey)">Edit</a> |
||||
</DeviceSettingPopover> |
||||
</div> |
||||
</div> |
||||
<!-- 下视避障 --> |
||||
<div class="control-setting-item"> |
||||
<div class="control-setting-item-left"> |
||||
<div class="item-label">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].label }}</div> |
||||
<div class="item-status">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].value }}</div> |
||||
</div> |
||||
<div class="control-setting-item-right"> |
||||
<DeviceSettingPopover |
||||
:visible="deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].popConfirm.visible" |
||||
:loading="deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].popConfirm.loading" |
||||
@confirm="onConfirm(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].settingKey)" |
||||
@cancel="onCancel(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].settingKey)" |
||||
> |
||||
<template #formContent> |
||||
<div class="form-content"> |
||||
<span class="form-label">{{ deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].label }}:</span> |
||||
<a-switch checked-children="开" un-checked-children="关" v-model:checked="deviceSettingFormModel.obstacleAvoidanceDownside" /> |
||||
</div> |
||||
</template> |
||||
<a @click="onShowPopConfirm(deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].settingKey)">Edit</a> |
||||
</DeviceSettingPopover> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { defineProps, ref, watch } from 'vue' |
||||
import { DeviceInfoType } from '/@/types/device' |
||||
import { useMyStore } from '/@/store' |
||||
import { cloneDeep } from 'lodash' |
||||
import { initDeviceSetting, initDeviceSettingFormModel, DeviceSettingKeyEnum } from '/@/types/device-setting' |
||||
import { updateDeviceSettingInfoByOsd, updateDeviceSettingFormModelByOsd } from '/@/utils/device-setting' |
||||
import { useDeviceSetting } from './useDeviceSetting' |
||||
import DeviceSettingPopover from './DeviceSettingPopover.vue' |
||||
|
||||
const props = defineProps<{ |
||||
sn: string, |
||||
deviceInfo: DeviceInfoType, |
||||
}>() |
||||
|
||||
const store = useMyStore() |
||||
const deviceSetting = ref(cloneDeep(initDeviceSetting)) |
||||
const deviceSettingFormModelFromOsd = ref(cloneDeep(initDeviceSettingFormModel)) |
||||
const deviceSettingFormModel = ref(cloneDeep(initDeviceSettingFormModel)) // 真实使用的formModel |
||||
|
||||
// 根据设备osd信息更新信息 |
||||
watch(() => props.deviceInfo, (value) => { |
||||
updateDeviceSettingInfoByOsd(deviceSetting.value, value) |
||||
updateDeviceSettingFormModelByOsd(deviceSettingFormModelFromOsd.value, value) |
||||
// console.log('deviceInfo', value) |
||||
}, { |
||||
immediate: true, |
||||
deep: true |
||||
}) |
||||
|
||||
function onShowPopConfirm (settingKey: DeviceSettingKeyEnum) { |
||||
deviceSetting.value[settingKey].popConfirm.visible = true |
||||
deviceSettingFormModel.value = cloneDeep(deviceSettingFormModelFromOsd.value) |
||||
} |
||||
|
||||
function onCancel (settingKey: DeviceSettingKeyEnum) { |
||||
deviceSetting.value[settingKey].popConfirm.visible = false |
||||
} |
||||
|
||||
async function onConfirm (settingKey: DeviceSettingKeyEnum) { |
||||
deviceSetting.value[settingKey].popConfirm.loading = true |
||||
const body = genDevicePropsBySettingKey(settingKey, deviceSettingFormModel.value) |
||||
await setDeviceProps(props.sn, body) |
||||
deviceSetting.value[settingKey].popConfirm.loading = false |
||||
deviceSetting.value[settingKey].popConfirm.visible = false |
||||
} |
||||
|
||||
// 更新设备属性 |
||||
const { |
||||
genDevicePropsBySettingKey, |
||||
setDeviceProps, |
||||
} = useDeviceSetting() |
||||
|
||||
</script> |
||||
|
||||
<style lang='scss' scoped> |
||||
.device-setting-wrapper{ |
||||
border-bottom: 1px solid #515151; |
||||
|
||||
.device-setting-header{ |
||||
font-size: 14px; |
||||
font-weight: 600; |
||||
padding: 10px 10px 0px; |
||||
} |
||||
|
||||
.device-setting-box{ |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
justify-content: space-between; |
||||
padding: 4px 10px; |
||||
|
||||
.control-setting-item{ |
||||
width: 220px; |
||||
height: 58px; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
border: 1px solid #666; |
||||
margin: 4px 0; |
||||
padding: 0 8px; |
||||
|
||||
.control-setting-item-left{ |
||||
display: flex; |
||||
flex-direction: column; |
||||
|
||||
.item-label{ |
||||
font-weight: 700; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
<template> |
||||
<a-popover :visible="state.sVisible" |
||||
trigger="click" |
||||
v-bind="$attrs" |
||||
:overlay-class-name="overlayClassName" |
||||
placement="bottom" |
||||
@visibleChange=";" |
||||
v-on="$attrs"> |
||||
<template #content> |
||||
<div class="title-content"> |
||||
</div> |
||||
<slot name="formContent" /> |
||||
<div class="uranus-popconfirm-btns"> |
||||
<a-button size="sm" |
||||
@click="onCancel"> |
||||
{{ cancelText || '取消'}} |
||||
</a-button> |
||||
<a-button size="sm" |
||||
:loading="loading" |
||||
type="primary" |
||||
class="confirm-btn" |
||||
@click="onConfirm"> |
||||
{{ okText || '确定' }} |
||||
</a-button> |
||||
</div> |
||||
</template> |
||||
<template v-if="$slots.default"> |
||||
<slot></slot> |
||||
</template> |
||||
</a-popover> |
||||
</template> |
||||
|
||||
<script lang="ts" setup> |
||||
import { defineProps, defineEmits, reactive, watch, computed } from 'vue' |
||||
|
||||
const props = defineProps<{ |
||||
visible?: boolean, |
||||
loading?: Boolean, |
||||
disabled?: Boolean, |
||||
title?: String, |
||||
okText?: String, |
||||
cancelText?: String, |
||||
width?: Number, |
||||
}>() |
||||
|
||||
const emit = defineEmits(['cancel', 'confirm']) |
||||
|
||||
const state = reactive({ |
||||
sVisible: false, |
||||
loading: false, |
||||
}) |
||||
|
||||
watch(() => props.visible, (val) => { |
||||
state.sVisible = val || false |
||||
}) |
||||
|
||||
const loading = computed(() => { |
||||
return props.loading |
||||
}) |
||||
const okLabel = computed(() => { |
||||
return props.loading ? '' : '确定' |
||||
}) |
||||
|
||||
const overlayClassName = computed(() => { |
||||
const classList = ['device-setting-popconfirm'] |
||||
return classList.join(' ') |
||||
}) |
||||
|
||||
function onConfirm (e: Event) { |
||||
if (props.disabled) { |
||||
return |
||||
} |
||||
emit('confirm', e) |
||||
} |
||||
|
||||
function onCancel (e: Event) { |
||||
state.sVisible = false |
||||
emit('cancel', e) |
||||
} |
||||
|
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.device-setting-popconfirm { |
||||
min-width: 300px; |
||||
|
||||
.uranus-popconfirm-btns{ |
||||
display: flex; |
||||
padding: 10px 0px; |
||||
justify-content: flex-end; |
||||
|
||||
.confirm-btn{ |
||||
margin-left: 10px; |
||||
} |
||||
} |
||||
|
||||
.form-content{ |
||||
display: inline-flex; |
||||
align-items: center; |
||||
|
||||
.form-label{ |
||||
padding-right: 10px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
import { message } from 'ant-design-vue' |
||||
import { putDeviceProps, PutDevicePropsBody } from '/@/api/device-setting' |
||||
import { DeviceSettingKeyEnum, DeviceSettingFormModel, ObstacleAvoidanceStatusEnum, NightLightsStateEnum, DistanceLimitStatusEnum } from '/@/types/device-setting' |
||||
|
||||
export function useDeviceSetting () { |
||||
// 生成参数
|
||||
function genDevicePropsBySettingKey (key: DeviceSettingKeyEnum, fromModel: DeviceSettingFormModel) { |
||||
const body = {} as PutDevicePropsBody |
||||
if (key === DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET) { |
||||
body.night_lights_state = fromModel.nightLightsState ? NightLightsStateEnum.OPEN : NightLightsStateEnum.CLOSE |
||||
} else if (key === DeviceSettingKeyEnum.HEIGHT_LIMIT_SET) { |
||||
body.height_limit = fromModel.heightLimit |
||||
} else if (key === DeviceSettingKeyEnum.DISTANCE_LIMIT_SET) { |
||||
body.distance_limit_status = {} |
||||
if (fromModel.distanceLimitStatus.state) { |
||||
body.distance_limit_status.state = DistanceLimitStatusEnum.SET |
||||
body.distance_limit_status.distance_limit = fromModel.distanceLimitStatus.distanceLimit |
||||
} else { |
||||
body.distance_limit_status.state = DistanceLimitStatusEnum.UNSET |
||||
} |
||||
} else if (key === DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON) { |
||||
body.obstacle_avoidance = { |
||||
horizon: fromModel.obstacleAvoidanceHorizon ? ObstacleAvoidanceStatusEnum.OPEN : ObstacleAvoidanceStatusEnum.CLOSE |
||||
} |
||||
} else if (key === DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE) { |
||||
body.obstacle_avoidance = { |
||||
upside: fromModel.obstacleAvoidanceUpside ? ObstacleAvoidanceStatusEnum.OPEN : ObstacleAvoidanceStatusEnum.CLOSE |
||||
} |
||||
} else if (key === DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE) { |
||||
body.obstacle_avoidance = { |
||||
downside: fromModel.obstacleAvoidanceDownside ? ObstacleAvoidanceStatusEnum.OPEN : ObstacleAvoidanceStatusEnum.CLOSE |
||||
} |
||||
} |
||||
return body |
||||
} |
||||
|
||||
// 设置设备属性
|
||||
async function setDeviceProps (sn: string, body: PutDevicePropsBody) { |
||||
try { |
||||
const { code, message: msg } = await putDeviceProps(sn, body) |
||||
if (code === 0) { |
||||
// message.success('指令发送成功')
|
||||
return true |
||||
} |
||||
throw (msg) |
||||
} catch (e) { |
||||
message.error('设备属性设置失败') |
||||
return false |
||||
} |
||||
} |
||||
|
||||
return { |
||||
genDevicePropsBySettingKey, |
||||
setDeviceProps |
||||
} |
||||
} |
@ -0,0 +1,249 @@
@@ -0,0 +1,249 @@
|
||||
<template> |
||||
<div class="header">Task Plan Library</div> |
||||
<div class="plan-panel-wrapper"> |
||||
<a-table class="plan-table" :columns="columns" :data-source="plansData.data" row-key="job_id" |
||||
:pagination="paginationProp" :scroll="{ x: '100%', y: 600 }" @change="refreshData"> |
||||
<!-- 执行时间 --> |
||||
<template #duration="{ record }"> |
||||
<div> |
||||
<div>{{ formatTaskTime(record.execute_time) }}</div> |
||||
<div>{{ formatTaskTime(record.end_time) }}</div> |
||||
</div> |
||||
</template> |
||||
<!-- 任务类型 --> |
||||
<template #taskType="{ record }"> |
||||
<div>{{ formatTaskType(record) }}</div> |
||||
</template> |
||||
<!-- 失控动作 --> |
||||
<template #lostAction="{ record }"> |
||||
<div>{{ formatLostAction(record) }}</div> |
||||
</template> |
||||
<!-- 状态 --> |
||||
<template #status="{ record }"> |
||||
<div> |
||||
<div class="flex-display flex-align-center"> |
||||
<span class="circle-icon" :style="{backgroundColor: formatTaskStatus(record).color}"></span> |
||||
{{ formatTaskStatus(record).text }} |
||||
<a-tooltip v-if="!!record.code" placement="bottom" arrow-point-at-center > |
||||
<template #title> |
||||
<div>{{ getCodeMessage(record.code) }}</div> |
||||
</template> |
||||
<exclamation-circle-outlined class="ml5" :style="{color: commonColor.WARN, fontSize: '16px' }"/> |
||||
</a-tooltip> |
||||
</div> |
||||
<div v-if="record.status === TaskStatus.Carrying"> |
||||
<a-progress :percent="record.progress || 0" /> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<!-- 操作 --> |
||||
<template #action="{ record }"> |
||||
<span class="action-area"> |
||||
<a-popconfirm |
||||
v-if="record.status === TaskStatus.Wait" |
||||
title="Are you sure you want to delete flight task?" |
||||
ok-text="Yes" |
||||
cancel-text="No" |
||||
@confirm="onDeleteTask(record.job_id)" |
||||
> |
||||
<a-button type="primary" size="small">Delete</a-button> |
||||
</a-popconfirm> |
||||
</span> |
||||
</template> |
||||
</a-table> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { reactive, ref } from '@vue/reactivity' |
||||
import { message } from 'ant-design-vue' |
||||
import { TableState } from 'ant-design-vue/lib/table/interface' |
||||
import { onMounted } from 'vue' |
||||
import { IPage } from '/@/api/http/type' |
||||
import { deleteTask, getWaylineJobs, Task } from '/@/api/wayline' |
||||
import { useMyStore } from '/@/store' |
||||
import { ELocalStorageKey } from '/@/types/enums' |
||||
import { useFormatTask } from './use-format-task' |
||||
import { TaskStatus, TaskProgressInfo, TaskProgressStatus, TaskProgressWsStatusMap } from '/@/types/task' |
||||
import { useTaskProgressEvent } from './use-task-progress-event' |
||||
import { getErrorMessage } from '/@/utils/error-code/index' |
||||
import { commonColor } from '/@/utils/color' |
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue' |
||||
|
||||
const store = useMyStore() |
||||
const workspaceId = localStorage.getItem(ELocalStorageKey.WorkspaceId)! |
||||
|
||||
const body: IPage = { |
||||
page: 1, |
||||
total: 0, |
||||
page_size: 50 |
||||
} |
||||
const paginationProp = reactive({ |
||||
pageSizeOptions: ['20', '50', '100'], |
||||
showQuickJumper: true, |
||||
showSizeChanger: true, |
||||
pageSize: 50, |
||||
current: 1, |
||||
total: 0 |
||||
}) |
||||
|
||||
const columns = [ |
||||
{ |
||||
title: 'Planned/Actual Time', |
||||
dataIndex: 'duration', |
||||
width: 180, |
||||
slots: { customRender: 'duration' }, |
||||
}, |
||||
{ |
||||
title: 'Plan Name', |
||||
dataIndex: 'job_name', |
||||
width: 150, |
||||
ellipsis: true |
||||
}, |
||||
{ |
||||
title: 'Type', |
||||
dataIndex: 'taskType', |
||||
width: 120, |
||||
slots: { customRender: 'taskType' }, |
||||
}, |
||||
{ |
||||
title: 'Flight Route Name', |
||||
dataIndex: 'file_name', |
||||
width: 150, |
||||
ellipsis: true |
||||
}, |
||||
{ |
||||
title: 'Dock Name', |
||||
dataIndex: 'dock_name', |
||||
width: 120, |
||||
ellipsis: true |
||||
}, |
||||
{ |
||||
title: 'RTH Altitude Relative to Dock (m)', |
||||
dataIndex: 'rth_altitude', |
||||
width: 120, |
||||
ellipsis: true |
||||
}, |
||||
{ |
||||
title: 'Lost Action', |
||||
dataIndex: 'out_of_control_action', |
||||
width: 120, |
||||
slots: { customRender: 'lostAction' }, |
||||
}, |
||||
{ |
||||
title: 'Creator', |
||||
dataIndex: 'username', |
||||
width: 120, |
||||
}, |
||||
{ |
||||
title: 'Status', |
||||
key: 'status', |
||||
width: 200, |
||||
slots: { customRender: 'status' } |
||||
}, |
||||
{ |
||||
title: 'Action', |
||||
width: 120, |
||||
slots: { customRender: 'action' } |
||||
} |
||||
] |
||||
type Pagination = TableState['pagination'] |
||||
|
||||
const plansData = reactive({ |
||||
data: [] as Task[] |
||||
}) |
||||
|
||||
const { formatTaskType, formatTaskTime, formatLostAction, formatTaskStatus } = useFormatTask() |
||||
|
||||
// 设备任务执行进度更新 |
||||
function onTaskProgressWs (data: TaskProgressInfo) { |
||||
const { bid, output } = data |
||||
if (output) { |
||||
const { status, progress } = output || {} |
||||
const taskItem = plansData.data.find(task => task.job_id === bid) |
||||
if (!taskItem) return |
||||
if (status) { |
||||
taskItem.status = TaskProgressWsStatusMap[status] |
||||
// 执行中,更新进度 |
||||
if (status === TaskProgressStatus.Sent || status === TaskProgressStatus.inProgress) { |
||||
taskItem.progress = progress?.percent || 0 |
||||
} else if ([TaskProgressStatus.Rejected, TaskProgressStatus.Canceled, TaskProgressStatus.Timeout, TaskProgressStatus.Failed, TaskProgressStatus.OK].includes(status)) { |
||||
getPlans() |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
function getCodeMessage (code: number) { |
||||
return getErrorMessage(code) + `(code: ${code})` |
||||
} |
||||
|
||||
useTaskProgressEvent(onTaskProgressWs) |
||||
|
||||
onMounted(() => { |
||||
getPlans() |
||||
}) |
||||
|
||||
function getPlans () { |
||||
getWaylineJobs(workspaceId, body).then(res => { |
||||
if (res.code !== 0) { |
||||
return |
||||
} |
||||
plansData.data = res.data.list |
||||
paginationProp.total = res.data.pagination.total |
||||
paginationProp.current = res.data.pagination.page |
||||
}) |
||||
} |
||||
|
||||
function refreshData (page: Pagination) { |
||||
body.page = page?.current! |
||||
body.page_size = page?.pageSize! |
||||
getPlans() |
||||
} |
||||
|
||||
// 删除任务 |
||||
async function onDeleteTask (jobId: string) { |
||||
const { code } = await deleteTask(workspaceId, { |
||||
job_id: jobId |
||||
}) |
||||
if (code === 0) { |
||||
message.success('Deleted successfully') |
||||
getPlans() |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.plan-panel-wrapper { |
||||
width: 100%; |
||||
padding: 16px; |
||||
.plan-table { |
||||
background: #fff; |
||||
margin-top: 10px; |
||||
} |
||||
.action-area { |
||||
color: $primary; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.circle-icon { |
||||
display: inline-block; |
||||
width: 12px; |
||||
height: 12px; |
||||
margin-right: 3px; |
||||
border-radius: 50%; |
||||
vertical-align: middle; |
||||
flex-shrink: 0; |
||||
} |
||||
} |
||||
.header { |
||||
width: 100%; |
||||
height: 60px; |
||||
background: #fff; |
||||
padding: 16px; |
||||
font-size: 20px; |
||||
font-weight: bold; |
||||
text-align: start; |
||||
color: #000; |
||||
} |
||||
</style> |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
import { DEFAULT_PLACEHOLDER } from '/@/utils/constants' |
||||
import { Task } from '/@/api/wayline' |
||||
import { TaskStatusColor, TaskStatusMap, TaskTypeMap, OutOfControlActionMap } from '/@/types/task' |
||||
|
||||
export function useFormatTask () { |
||||
function formatTaskType (task: Task) { |
||||
return TaskTypeMap[task.task_type] || DEFAULT_PLACEHOLDER |
||||
} |
||||
|
||||
function formatTaskTime (time: string) { |
||||
return time || DEFAULT_PLACEHOLDER |
||||
} |
||||
|
||||
function formatLostAction (task: Task) { |
||||
return OutOfControlActionMap[task.out_of_control_action] || DEFAULT_PLACEHOLDER |
||||
} |
||||
|
||||
function formatTaskStatus (task: Task) { |
||||
const statusObj = { |
||||
text: '', |
||||
color: '' |
||||
} |
||||
const { status } = task |
||||
statusObj.text = TaskStatusMap[status] |
||||
statusObj.color = TaskStatusColor[status] |
||||
return statusObj |
||||
} |
||||
|
||||
return { |
||||
formatTaskType, |
||||
formatTaskTime, |
||||
formatLostAction, |
||||
formatTaskStatus, |
||||
} |
||||
} |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
import EventBus from '/@/event-bus/' |
||||
import { onMounted, onBeforeUnmount } from 'vue' |
||||
import { TaskProgressInfo } from '/@/types/task' |
||||
|
||||
export function useTaskProgressEvent (onTaskProgressWs: (data: TaskProgressInfo) => void): void { |
||||
function handleTaskProgress (payload: any) { |
||||
onTaskProgressWs(payload.data) |
||||
// eslint-disable-next-line no-unused-expressions
|
||||
// console.log('payload', payload.data)
|
||||
} |
||||
|
||||
onMounted(() => { |
||||
EventBus.on('deviceTaskProgress', handleTaskProgress) |
||||
}) |
||||
|
||||
onBeforeUnmount(() => { |
||||
EventBus.off('deviceTaskProgress', handleTaskProgress) |
||||
}) |
||||
} |
@ -1,123 +0,0 @@
@@ -1,123 +0,0 @@
|
||||
<template> |
||||
<div class="panel-wrapper" draggable="true"> |
||||
<div class="header">Wayline Library</div> |
||||
<a-button type="primary" style="margin-top:20px" @click="onRefresh" |
||||
>Refresh</a-button |
||||
> |
||||
<a-table class="table" :columns="columns" :data-source="data"> |
||||
<template #name="{ text, record }"> |
||||
<a :href="record.preview_url">{{ text }}</a> |
||||
</template> |
||||
<template #action> |
||||
<span class="action-area"> |
||||
action |
||||
</span> |
||||
</template> |
||||
</a-table> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { ref } from '@vue/reactivity' |
||||
import { onMounted } from 'vue' |
||||
import { ELocalStorageKey } from '../types/enums' |
||||
import { getWaylineFiles } from '/@/api/wayline' |
||||
const columns = [ |
||||
{ |
||||
title: 'FileName', |
||||
dataIndex: 'name', |
||||
key: 'name', |
||||
slots: { customRender: 'name' } |
||||
}, |
||||
{ |
||||
title: 'TemplateType', |
||||
dataIndex: 'template_type', |
||||
key: 'template_type' |
||||
}, |
||||
{ |
||||
title: 'Favorited', |
||||
dataIndex: 'favorite', |
||||
key: 'favorite' |
||||
}, |
||||
{ |
||||
title: 'DroneType', |
||||
dataIndex: 'drone_type', |
||||
key: 'drone_type' |
||||
}, |
||||
{ |
||||
title: 'PayloadType', |
||||
dataIndex: 'payload_type', |
||||
key: 'payload_type' |
||||
}, |
||||
{ |
||||
title: 'User', |
||||
dataIndex: 'user', |
||||
key: 'user' |
||||
}, |
||||
{ |
||||
title: 'Action', |
||||
key: 'action', |
||||
slots: { customRender: 'action' } |
||||
} |
||||
] |
||||
const data = ref([ |
||||
{ |
||||
key: '1', |
||||
name: 'name1', |
||||
template_type: '0', |
||||
drone_type: '0-60-0', |
||||
payload_type: 'PM320_DUAL', |
||||
user: 'pilot', |
||||
favorited: 'true' |
||||
} |
||||
]) |
||||
onMounted(() => { |
||||
onRefresh() |
||||
}) |
||||
const onRefresh = async () => { |
||||
const wid: string = localStorage.getItem(ELocalStorageKey.WorkspaceId) |
||||
data.value = [] |
||||
const index = 1 |
||||
const res = await getWaylineFiles(wid, { |
||||
page: 1, // 页数 |
||||
page_size: 9, // 每页大小 |
||||
order_by: 'update_time desc' // 排序, xxx_column_desc, xxx_column_asc, xxx_column(default asc) |
||||
}) |
||||
console.log(res) |
||||
res.data.list.forEach(ele => { |
||||
data.value.push({ |
||||
key: index.toString(), |
||||
name: ele.name, |
||||
template_type: ele.template_types[0], |
||||
drone_type: ele.drone_model_key, |
||||
payload_type: ele.payload_model_keys[0], |
||||
user: ele.user_name, |
||||
favorite: ele.favorited.toString() |
||||
}) |
||||
}) |
||||
console.log('wayline files:', data.value) |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.panel-wrapper { |
||||
width: 100%; |
||||
.table { |
||||
background: #fff; |
||||
margin-top: 32px; |
||||
} |
||||
.header { |
||||
width: 100%; |
||||
height: 60px; |
||||
background: #fff; |
||||
padding: 16px 24px; |
||||
font-size: 20px; |
||||
text-align: start; |
||||
color: #000; |
||||
} |
||||
.action-area { |
||||
color: $primary; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,148 @@
@@ -0,0 +1,148 @@
|
||||
// 夜航灯开关
|
||||
export enum NightLightsStateEnum { |
||||
CLOSE = 0, // 0-关闭
|
||||
OPEN = 1, // 1-打开
|
||||
} |
||||
|
||||
// 限远开关
|
||||
export enum DistanceLimitStatusEnum { |
||||
UNSET = 0, // 0-未设置
|
||||
SET = 1, // 1-已设置
|
||||
} |
||||
|
||||
export interface DistanceLimitStatus { |
||||
state?: DistanceLimitStatusEnum; |
||||
distance_limit?: number; // 限远
|
||||
} |
||||
|
||||
// 避障
|
||||
export enum ObstacleAvoidanceStatusEnum { |
||||
CLOSE = 0, // 0-关闭
|
||||
OPEN = 1, // 1-开启
|
||||
} |
||||
|
||||
export interface ObstacleAvoidance { |
||||
horizon?: ObstacleAvoidanceStatusEnum;// 水平避障开关
|
||||
upside?: ObstacleAvoidanceStatusEnum;// 上行方向避障开关
|
||||
downside?: ObstacleAvoidanceStatusEnum;// 下行方向避障开关
|
||||
} |
||||
|
||||
// 设备管理设置key
|
||||
export enum DeviceSettingKeyEnum { |
||||
NIGHT_LIGHTS_MODE_SET = 'night_lights_state', // 夜航灯开关
|
||||
HEIGHT_LIMIT_SET = 'height_limit', // 限高设置
|
||||
DISTANCE_LIMIT_SET = 'distance_limit_status', // 限远开关
|
||||
OBSTACLE_AVOIDANCE_HORIZON = 'obstacle_avoidance_horizon', // 水平避障状态
|
||||
OBSTACLE_AVOIDANCE_UPSIDE = 'obstacle_avoidance_upside', // 上视避障状态
|
||||
OBSTACLE_AVOIDANCE_DOWNSIDE = 'obstacle_avoidance_downside', // 下视避障状态
|
||||
} |
||||
|
||||
export type DeviceSettingType = Record<DeviceSettingKeyEnum, any> |
||||
|
||||
export const initDeviceSetting = { |
||||
[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET]: |
||||
{ |
||||
label: '飞行器夜航灯', |
||||
value: '', |
||||
trueValue: NightLightsStateEnum.CLOSE, |
||||
editable: false, |
||||
popConfirm: { |
||||
visible: false, |
||||
loading: false, |
||||
// content: '为保证飞行器的作业安全,建议打开夜航灯',
|
||||
label: '飞行器夜航灯', |
||||
}, |
||||
settingKey: DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET, |
||||
}, |
||||
[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET]: |
||||
{ |
||||
label: '限高', |
||||
value: '', |
||||
trueValue: 120, |
||||
editable: false, |
||||
popConfirm: { |
||||
visible: false, |
||||
loading: false, |
||||
// content: '限高:20 - 1500m',
|
||||
// info: '修改限高会影响当前机场的所有作业任务,建议确认作业情况后再进行修改',
|
||||
label: '限高', |
||||
}, |
||||
settingKey: DeviceSettingKeyEnum.HEIGHT_LIMIT_SET, |
||||
}, |
||||
[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET]: |
||||
{ |
||||
label: '限远', |
||||
value: '', |
||||
trueValue: DistanceLimitStatusEnum.UNSET, |
||||
// info: '限远(15 - 8000m)是约束飞行器相对机场的最大作业距离',
|
||||
editable: false, |
||||
popConfirm: { |
||||
visible: false, |
||||
loading: false, |
||||
// content: '限远 (15- 8000m) 是约束飞行器相对机场的最大作业距离',
|
||||
// info: '修改限远会影响当前机场的所有作业任务,建议确认作业情况后再进行修改',
|
||||
label: '限远', |
||||
|
||||
}, |
||||
settingKey: DeviceSettingKeyEnum.DISTANCE_LIMIT_SET, |
||||
}, |
||||
[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON]: |
||||
{ |
||||
label: '水平避障', |
||||
value: '', |
||||
trueValue: ObstacleAvoidanceStatusEnum.CLOSE, |
||||
// info: '飞行器的避障工作状态显示,可以快速开启/关闭飞行器避障,如需进一步设置请在设备运维页面设置',
|
||||
editable: false, |
||||
popConfirm: { |
||||
visible: false, |
||||
loading: false, |
||||
// content: '飞行器避障是保障飞行作业安全的基础功能,建议保持飞行器避障开启',
|
||||
label: '水平避障', |
||||
|
||||
}, |
||||
settingKey: DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON, |
||||
}, |
||||
[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE]: |
||||
{ |
||||
label: '上视避障', |
||||
value: '', |
||||
trueValue: ObstacleAvoidanceStatusEnum.CLOSE, |
||||
// info: '飞行器的避障工作状态显示,可以快速开启/关闭飞行器避障,如需进一步设置请在设备运维页面设置',
|
||||
editable: false, |
||||
popConfirm: { |
||||
visible: false, |
||||
loading: false, |
||||
// content: '飞行器避障是保障飞行作业安全的基础功能,建议保持飞行器避障开启',
|
||||
label: '上视避障', |
||||
|
||||
}, |
||||
settingKey: DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE, |
||||
}, |
||||
[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE]: |
||||
{ |
||||
label: '下视避障', |
||||
value: '', |
||||
trueValue: ObstacleAvoidanceStatusEnum.CLOSE, |
||||
// info: '飞行器的避障工作状态显示,可以快速开启/关闭飞行器避障,如需进一步设置请在设备运维页面设置',
|
||||
editable: false, |
||||
popConfirm: { |
||||
visible: false, |
||||
loading: false, |
||||
// content: '飞行器避障是保障飞行作业安全的基础功能,建议保持飞行器避障开启',
|
||||
label: '下视避障', |
||||
|
||||
}, |
||||
settingKey: DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE, |
||||
}, |
||||
} as DeviceSettingType |
||||
|
||||
export const initDeviceSettingFormModel = { |
||||
nightLightsState: false, // 夜航灯开关
|
||||
heightLimit: 20, // 限高设置
|
||||
distanceLimitStatus: { state: false, distanceLimit: 15 }, // 限远开关
|
||||
obstacleAvoidanceHorizon: false, // 飞行器避障-水平开关设置
|
||||
obstacleAvoidanceUpside: false, // 飞行器避障-上视开关设置
|
||||
obstacleAvoidanceDownside: false, // 飞行器避障-下视开关设置
|
||||
} |
||||
|
||||
export type DeviceSettingFormModel = typeof initDeviceSettingFormModel |
@ -0,0 +1,97 @@
@@ -0,0 +1,97 @@
|
||||
import { commonColor } from '/@/utils/color' |
||||
|
||||
// 任务类型
|
||||
export enum TaskType { |
||||
Immediate = 0, // 立即执行
|
||||
Single = 1, // 单次定时任务
|
||||
} |
||||
|
||||
export const TaskTypeMap = { |
||||
[TaskType.Immediate]: 'Immediate', |
||||
[TaskType.Single]: 'Timed & One-Time', |
||||
} |
||||
|
||||
// 失控动作
|
||||
export enum OutOfControlAction { |
||||
ReturnToHome = 0, |
||||
Hover = 1, |
||||
Land = 2, |
||||
} |
||||
|
||||
export const OutOfControlActionMap = { |
||||
[OutOfControlAction.ReturnToHome]: 'Return to Home', |
||||
[OutOfControlAction.Hover]: 'Hover', |
||||
[OutOfControlAction.Land]: 'Land', |
||||
} |
||||
|
||||
export const OutOfControlActionOptions = [ |
||||
{ value: OutOfControlAction.ReturnToHome, label: OutOfControlActionMap[OutOfControlAction.ReturnToHome] }, |
||||
{ value: OutOfControlAction.Hover, label: OutOfControlActionMap[OutOfControlAction.Hover] }, |
||||
{ value: OutOfControlAction.Land, label: OutOfControlActionMap[OutOfControlAction.Land] }, |
||||
] |
||||
|
||||
// 任务状态
|
||||
export enum TaskStatus { |
||||
Wait = 1, // 待执行
|
||||
Carrying = 2, // 执行中
|
||||
Success = 3, // 完成
|
||||
CanCel = 4, // 取消
|
||||
Fail = 5, // 失败
|
||||
} |
||||
|
||||
export const TaskStatusMap = { |
||||
[TaskStatus.Wait]: 'To be performed', |
||||
[TaskStatus.Carrying]: 'In progress', |
||||
[TaskStatus.Success]: 'Task completed', |
||||
[TaskStatus.CanCel]: 'Task canceled', |
||||
[TaskStatus.Fail]: 'Task failed', |
||||
} |
||||
|
||||
export const TaskStatusColor = { |
||||
[TaskStatus.Wait]: commonColor.BLUE, |
||||
[TaskStatus.Carrying]: commonColor.BLUE, |
||||
[TaskStatus.Success]: commonColor.NORMAL, |
||||
[TaskStatus.CanCel]: commonColor.FAIL, |
||||
[TaskStatus.Fail]: commonColor.FAIL, |
||||
} |
||||
|
||||
// 任务执行 ws 消息状态
|
||||
export enum TaskProgressStatus { |
||||
Sent = 'sent', // 已下发
|
||||
inProgress = 'in_progress', // 执行中
|
||||
Paused = 'paused', // 暂停
|
||||
Rejected = 'rejected', // 拒绝
|
||||
Canceled = 'canceled', // 取消或终止
|
||||
Timeout = 'timeout', // 超时
|
||||
Failed = 'failed', // 失败
|
||||
OK = 'ok', // 上传成功
|
||||
} |
||||
|
||||
// 任务进度消息
|
||||
export interface TaskProgressInfo { |
||||
bid: string, |
||||
output:{ |
||||
ext: { |
||||
current_waypoint_index: number, |
||||
media_count: number // 媒体文件
|
||||
}, |
||||
progress:{ |
||||
current_step: number, |
||||
percent: number |
||||
}, |
||||
status: TaskProgressStatus |
||||
}, |
||||
result: number, |
||||
} |
||||
|
||||
// ws status => log status
|
||||
export const TaskProgressWsStatusMap = { |
||||
[TaskProgressStatus.Sent]: TaskStatus.Carrying, |
||||
[TaskProgressStatus.inProgress]: TaskStatus.Carrying, |
||||
[TaskProgressStatus.Rejected]: TaskStatus.Fail, |
||||
[TaskProgressStatus.OK]: TaskStatus.Success, |
||||
[TaskProgressStatus.Failed]: TaskStatus.Fail, |
||||
[TaskProgressStatus.Canceled]: TaskStatus.CanCel, |
||||
[TaskProgressStatus.Timeout]: TaskStatus.Fail, |
||||
[TaskProgressStatus.Paused]: TaskStatus.Wait, |
||||
} |
@ -0,0 +1,193 @@
@@ -0,0 +1,193 @@
|
||||
import { DeviceInfoType } from '/@/types/device' |
||||
import { DeviceSettingType, DeviceSettingKeyEnum, DistanceLimitStatusEnum, ObstacleAvoidanceStatusEnum, DeviceSettingFormModel, NightLightsStateEnum } from '/@/types/device-setting' |
||||
import { DEFAULT_PLACEHOLDER } from './constants' |
||||
import { isNil } from 'lodash' |
||||
|
||||
const Unit_M = ' m' |
||||
|
||||
/** |
||||
* 根据osd 更新信息 |
||||
* @param deviceSetting |
||||
* @param deviceInfo |
||||
* @returns |
||||
*/ |
||||
export function updateDeviceSettingInfoByOsd (deviceSetting: DeviceSettingType, deviceInfo: DeviceInfoType) { |
||||
const { device, dock, gateway } = deviceInfo || {} |
||||
if (!deviceSetting) { |
||||
return |
||||
} |
||||
// 夜航灯
|
||||
let nightLightsState = '' as any |
||||
if (isNil(device?.night_lights_state)) { |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].value = DEFAULT_PLACEHOLDER |
||||
nightLightsState = DEFAULT_PLACEHOLDER |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].editable = true |
||||
nightLightsState = device?.night_lights_state |
||||
if (nightLightsState === NightLightsStateEnum.CLOSE) { |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].value = '关闭' |
||||
} else if (nightLightsState === NightLightsStateEnum.OPEN) { |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].value = '开启' |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].value = DEFAULT_PLACEHOLDER |
||||
} |
||||
} |
||||
deviceSetting[DeviceSettingKeyEnum.NIGHT_LIGHTS_MODE_SET].trueValue = nightLightsState |
||||
|
||||
// 限高
|
||||
let heightLimit = device?.height_limit as any |
||||
if (isNil(heightLimit) || heightLimit === 0) { |
||||
heightLimit = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].editable = false |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].editable = true |
||||
} |
||||
deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].trueValue = heightLimit |
||||
deviceSetting[DeviceSettingKeyEnum.HEIGHT_LIMIT_SET].value = heightLimit + Unit_M |
||||
|
||||
// 限远
|
||||
let distanceLimitStatus = '' as any |
||||
if (isNil(device?.distance_limit_status?.state)) { |
||||
distanceLimitStatus = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].value = DEFAULT_PLACEHOLDER |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].editable = true |
||||
distanceLimitStatus = device?.distance_limit_status?.state |
||||
if (distanceLimitStatus === DistanceLimitStatusEnum.UNSET) { |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].value = '关闭' |
||||
} else if (distanceLimitStatus === DistanceLimitStatusEnum.SET) { |
||||
const distanceLimit = device?.distance_limit_status?.distance_limit |
||||
if (distanceLimit) { |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].value = distanceLimit + Unit_M |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].value = DEFAULT_PLACEHOLDER |
||||
} |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].value = DEFAULT_PLACEHOLDER |
||||
} |
||||
} |
||||
deviceSetting[DeviceSettingKeyEnum.DISTANCE_LIMIT_SET].trueValue = distanceLimitStatus |
||||
|
||||
// 避障
|
||||
if (isNil(device?.obstacle_avoidance)) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].value = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].trueValue = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].value = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].trueValue = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].value = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].trueValue = DEFAULT_PLACEHOLDER |
||||
} else { |
||||
const { horizon, upside, downside } = device.obstacle_avoidance || {} |
||||
if (isNil(horizon)) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].value = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].trueValue = DEFAULT_PLACEHOLDER |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].editable = false |
||||
if (horizon === ObstacleAvoidanceStatusEnum.CLOSE) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].value = '关闭' |
||||
} else if (horizon === ObstacleAvoidanceStatusEnum.OPEN) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].value = '开启' |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].value = DEFAULT_PLACEHOLDER |
||||
} |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_HORIZON].trueValue = horizon |
||||
} |
||||
|
||||
if (isNil(upside)) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].value = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].trueValue = DEFAULT_PLACEHOLDER |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].editable = false |
||||
if (upside === ObstacleAvoidanceStatusEnum.CLOSE) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].value = '关闭' |
||||
} else if (upside === ObstacleAvoidanceStatusEnum.OPEN) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].value = '开启' |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].value = DEFAULT_PLACEHOLDER |
||||
} |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_UPSIDE].trueValue = upside |
||||
} |
||||
|
||||
if (isNil(downside)) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].editable = false |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].value = DEFAULT_PLACEHOLDER |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].trueValue = DEFAULT_PLACEHOLDER |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].editable = false |
||||
if (downside === ObstacleAvoidanceStatusEnum.CLOSE) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].value = '关闭' |
||||
} else if (downside === ObstacleAvoidanceStatusEnum.OPEN) { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].value = '开启' |
||||
} else { |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].value = DEFAULT_PLACEHOLDER |
||||
} |
||||
deviceSetting[DeviceSettingKeyEnum.OBSTACLE_AVOIDANCE_DOWNSIDE].trueValue = downside |
||||
} |
||||
} |
||||
return deviceSetting |
||||
} |
||||
|
||||
// 更新formModel
|
||||
export function updateDeviceSettingFormModelByOsd (deviceSettingFormModelFromOsd: DeviceSettingFormModel, deviceInfo: DeviceInfoType) { |
||||
const { device, dock, gateway } = deviceInfo || {} |
||||
if (!deviceSettingFormModelFromOsd) { |
||||
return |
||||
} |
||||
// 夜航灯
|
||||
const nightLightsState = device?.night_lights_state as any |
||||
if (!isNil(nightLightsState) && nightLightsState === NightLightsStateEnum.OPEN) { |
||||
deviceSettingFormModelFromOsd.nightLightsState = true |
||||
} else { |
||||
deviceSettingFormModelFromOsd.nightLightsState = false |
||||
} |
||||
|
||||
// 限高
|
||||
const heightLimit = device?.height_limit as any |
||||
if (isNil(heightLimit) || heightLimit === 0) { |
||||
deviceSettingFormModelFromOsd.heightLimit = 20 |
||||
} else { |
||||
deviceSettingFormModelFromOsd.heightLimit = heightLimit |
||||
} |
||||
|
||||
// 限远
|
||||
const distanceLimitStatus = device?.distance_limit_status?.state as any |
||||
if (!isNil(distanceLimitStatus) && distanceLimitStatus === DistanceLimitStatusEnum.SET) { |
||||
deviceSettingFormModelFromOsd.distanceLimitStatus.state = true |
||||
deviceSettingFormModelFromOsd.distanceLimitStatus.distanceLimit = device?.distance_limit_status?.distance_limit || 15 |
||||
} else { |
||||
deviceSettingFormModelFromOsd.distanceLimitStatus.state = false |
||||
deviceSettingFormModelFromOsd.distanceLimitStatus.distanceLimit = 15 |
||||
} |
||||
|
||||
// 避障
|
||||
if (isNil(device?.obstacle_avoidance)) { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceHorizon = false |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceUpside = false |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceDownside = false |
||||
} else { |
||||
const { horizon, upside, downside } = device.obstacle_avoidance || {} |
||||
if (!isNil(horizon) && horizon === ObstacleAvoidanceStatusEnum.OPEN) { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceHorizon = true |
||||
} else { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceHorizon = false |
||||
} |
||||
if (!isNil(upside) && upside === ObstacleAvoidanceStatusEnum.OPEN) { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceUpside = true |
||||
} else { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceUpside = false |
||||
} |
||||
if (!isNil(downside) && downside === ObstacleAvoidanceStatusEnum.OPEN) { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceDownside = true |
||||
} else { |
||||
deviceSettingFormModelFromOsd.obstacleAvoidanceDownside = false |
||||
} |
||||
} |
||||
return deviceSettingFormModelFromOsd |
||||
} |
@ -0,0 +1,310 @@
@@ -0,0 +1,310 @@
|
||||
export interface ErrorCode { |
||||
code: number; |
||||
msg: string; |
||||
} |
||||
|
||||
/** |
||||
* 根据错误码翻译错误信息 |
||||
* @param code |
||||
* @param errorMsg |
||||
* @returns |
||||
*/ |
||||
export function getErrorMessage (code: number, errorMsg?: string): string { |
||||
const errorInfo = ERROR_CODE.find((item: ErrorCode) => item.code === code) |
||||
return errorInfo ? errorInfo.msg : errorMsg || 'Server error' |
||||
} |
||||
|
||||
// 暂时只添加航线错误
|
||||
export const ERROR_CODE = [ |
||||
{ |
||||
code: 314001, |
||||
msg: 'The issued route task url is empty', |
||||
}, |
||||
{ |
||||
code: 314002, |
||||
msg: 'The issued route task md5 is empty', |
||||
}, |
||||
{ |
||||
code: 314003, |
||||
msg: 'MissionID is invalid', |
||||
}, |
||||
{ |
||||
code: 314004, |
||||
msg: 'Failed to send flight route task from cloud', |
||||
}, |
||||
{ |
||||
code: 314005, |
||||
msg: 'Route md5 check failed', |
||||
}, |
||||
{ |
||||
code: 314006, |
||||
msg: 'Timeout waiting for aircraft to upload route (waiting for gs_state)', |
||||
}, |
||||
{ |
||||
code: 314007, |
||||
msg: 'Failed to upload route to aircraft', |
||||
}, |
||||
{ |
||||
code: 314008, |
||||
msg: 'Timeout waiting for the aircraft to enter the route executable state', |
||||
}, |
||||
{ |
||||
code: 314009, |
||||
msg: 'Failed to open route mission', |
||||
}, |
||||
{ |
||||
code: 314010, |
||||
msg: 'Route execution failed', |
||||
}, |
||||
{ |
||||
code: 316001, |
||||
msg: 'Failed to set alternate point', |
||||
}, |
||||
{ |
||||
code: 316002, |
||||
msg: 'Alternate safety transfer altitude equipment failed', |
||||
}, |
||||
{ |
||||
code: 316003, |
||||
msg: 'Failed to set takeoff altitude. Remarks: The default safe takeoff height of the aircraft set by the current DJI Dock is: 1.8', |
||||
}, |
||||
{ |
||||
code: 316004, |
||||
msg: 'Failed to set runaway behavior', |
||||
}, |
||||
{ |
||||
code: 316005, |
||||
msg: 'Aircraft RTK convergence failed', |
||||
}, |
||||
{ |
||||
code: 316013, |
||||
msg: 'DJI Dock Moved', |
||||
}, |
||||
{ |
||||
code: 316015, |
||||
msg: 'The aircraft RTK convergence position is too far from the DJI Dock', |
||||
}, |
||||
{ |
||||
code: 316007, |
||||
msg: 'Set parameter timeout while waiting for aircraft to be ready', |
||||
}, |
||||
{ |
||||
code: 316008, |
||||
msg: 'Failed to gain control of aircraft', |
||||
}, |
||||
{ |
||||
code: 316009, |
||||
msg: 'Aircraft power is low', |
||||
}, |
||||
{ |
||||
code: 316010, |
||||
msg: 'After power on, the aircraft is not connected for more than 2 minutes (flight control OSD reception timeout)', |
||||
}, |
||||
{ |
||||
code: 316011, |
||||
msg: 'Landing Position Offset', |
||||
}, |
||||
|
||||
{ |
||||
code: 317001, |
||||
msg: 'Failed to get the number of media files', |
||||
}, |
||||
|
||||
{ |
||||
code: 319001, |
||||
msg: 'The task center is not currently idle', |
||||
}, |
||||
{ |
||||
code: 319002, |
||||
msg: 'dronenest communication timeout', |
||||
}, |
||||
{ |
||||
code: 319999, |
||||
msg: 'Unknown error, e.g. restart after crash', |
||||
}, |
||||
{ |
||||
code: 321000, |
||||
msg: 'Route execution failed, unknown error', |
||||
}, |
||||
{ |
||||
code: 321257, |
||||
msg: 'The route has already started and cannot be started again', |
||||
}, |
||||
{ |
||||
code: 321258, |
||||
msg: 'The route cannot be interrupted in this state', |
||||
}, |
||||
{ |
||||
code: 321259, |
||||
msg: 'The route has not started and cannot end the route', |
||||
}, |
||||
{ |
||||
code: 321513, |
||||
msg: 'Reach the height limit', |
||||
}, |
||||
{ |
||||
code: 321514, |
||||
msg: 'Reach the limit', |
||||
}, |
||||
{ |
||||
code: 321515, |
||||
msg: 'Crossing the restricted flight zone', |
||||
}, |
||||
{ |
||||
code: 321516, |
||||
msg: 'Low limit', |
||||
}, |
||||
|
||||
{ |
||||
code: 321517, |
||||
msg: 'Obstacle Avoidance', |
||||
}, |
||||
{ |
||||
code: 321769, |
||||
msg: 'Weak GPS signal', |
||||
}, |
||||
{ |
||||
code: 321770, |
||||
msg: 'The current gear state cannot be executed, B control seizes the control, and the gear is switched', |
||||
}, |
||||
{ |
||||
code: 321771, |
||||
msg: 'The home point is not refreshed', |
||||
}, |
||||
{ |
||||
code: 321772, |
||||
msg: 'The current battery is too low to start the task', |
||||
}, |
||||
{ |
||||
code: 321773, |
||||
msg: 'Low battery return', |
||||
}, |
||||
{ |
||||
code: 321776, |
||||
msg: 'RTK not ready', |
||||
}, |
||||
{ |
||||
code: 321778, |
||||
msg: 'The aircraft is idling on the ground and is not allowed to start the route, thinking that the user is not ready.', |
||||
}, |
||||
{ |
||||
code: 322282, |
||||
msg: 'User interrupt (B control takeover)', |
||||
}, |
||||
{ |
||||
code: 514100, |
||||
msg: 'Command not supported', |
||||
}, |
||||
{ |
||||
code: 514101, |
||||
msg: 'Failed to close putter', |
||||
}, |
||||
{ |
||||
code: 514102, |
||||
msg: 'Failed to release putter', |
||||
}, |
||||
{ |
||||
code: 514103, |
||||
msg: 'Aircraft battery is low', |
||||
}, |
||||
{ |
||||
code: 514104, |
||||
msg: 'Failed to start charging', |
||||
}, |
||||
{ |
||||
code: 514105, |
||||
msg: 'Failed to stop charging', |
||||
}, |
||||
{ |
||||
code: 514106, |
||||
msg: 'Failed to restart the aircraft', |
||||
}, |
||||
{ |
||||
code: 514107, |
||||
msg: 'Failed to open hatch', |
||||
}, |
||||
{ |
||||
code: 514108, |
||||
msg: 'Failed to close hatch', |
||||
}, |
||||
{ |
||||
code: 514109, |
||||
msg: 'Failed to open the plane', |
||||
}, |
||||
{ |
||||
code: 514110, |
||||
msg: 'Failed to close the plane', |
||||
}, |
||||
{ |
||||
code: 514111, |
||||
msg: 'The aircraft failed to turn on the slow-rotating propeller in the cabin', |
||||
}, |
||||
{ |
||||
code: 514112, |
||||
msg: 'The aircraft failed to stop the slow-rotating propeller in the cabin', |
||||
}, |
||||
{ |
||||
code: 514113, |
||||
msg: 'Failed to establish wired connection with aircraft', |
||||
}, |
||||
{ |
||||
code: 514114, |
||||
msg: 'Get aircraft power status, command timed out, or return code is not 0', |
||||
}, |
||||
{ |
||||
code: 514116, |
||||
msg: 'The DJI Dock is busy and other control orders are being executed at the DJI Dock', |
||||
}, |
||||
{ |
||||
code: 514117, |
||||
msg: 'Check hatch status failed', |
||||
}, |
||||
{ |
||||
code: 514118, |
||||
msg: 'Check putter status failed', |
||||
}, |
||||
{ |
||||
code: 514120, |
||||
msg: 'DJI Dock and aircraft SDR connection failed', |
||||
}, |
||||
{ |
||||
code: 514121, |
||||
msg: 'Emergency stop state', |
||||
}, |
||||
{ |
||||
code: 514122, |
||||
msg: 'Failed to get the charging status of the aircraft (Failed to get the charging status, the flight mission can be executed, affecting charging and remote troubleshooting)', |
||||
}, |
||||
{ |
||||
code: 514123, |
||||
msg: 'Unable to power on due to low battery', |
||||
}, |
||||
{ |
||||
code: 514124, |
||||
msg: 'Failed to get battery information', |
||||
}, |
||||
{ |
||||
code: 514125, |
||||
msg: 'The battery is fully charged and cannot be charged', |
||||
}, |
||||
{ |
||||
code: 514145, |
||||
msg: 'Can not work while debugging on site', |
||||
}, |
||||
{ |
||||
code: 514146, |
||||
msg: 'Unable to work in remote debugging', |
||||
}, |
||||
{ |
||||
code: 514147, |
||||
msg: 'Unable to work in upgrade state', |
||||
}, |
||||
{ |
||||
code: 514148, |
||||
msg: 'Unable to execute new tasks in job state', |
||||
}, |
||||
{ |
||||
code: 514150, |
||||
msg: 'DJI Dock is automatically restarting', |
||||
}, |
||||
] |
Loading…
Reference in new issue