From 763e39bd71d83a6501ebdebf0d53130797bd5d73 Mon Sep 17 00:00:00 2001
From: sean.zhou <sean.zhou@dji.com>
Date: Thu, 18 May 2023 16:26:09 +0800
Subject: [PATCH] Merge branch 'v1.5.0' What's new? 1. Add new model: DJI Matrices 350 RTK. 2. Fixed some issues.

---
 src/types/task.ts                                    |    9 +
 src/components/g-map/use-mqtt.ts                     |    2 
 src/components/g-map/use-manual-control.ts           |    7 +
 src/types/device.ts                                  |    4 +
 src/store/index.ts                                   |    1 
 src/components/g-map/use-drone-control-ws-event.ts   |    6 -
 src/pages/page-pilot/pilot-home.vue                  |   15 ++-
 src/components/task/CreatePlan.vue                   |   48 ++++++-----
 src/components/livestream-agora.vue                  |   36 ++++----
 src/types/drc.ts                                     |   13 +-
 package.json                                         |    1 
 src/components/g-map/use-drone-control-mqtt-event.ts |   17 ++++
 src/pages/page-web/projects/workspace.vue            |    1 
 src/components/livestream-others.vue                 |    2 
 src/components/g-map/DroneControlPanel.vue           |   32 +++++--
 15 files changed, 121 insertions(+), 73 deletions(-)

diff --git a/package.json b/package.json
index 34c4aa0..4a82dd0 100644
--- a/package.json
+++ b/package.json
@@ -95,6 +95,7 @@
         "ant-design-vue/es/switch/style/css",
         "ant-design-vue/es/table/style/css",
         "ant-design-vue/es/tag/style/css",
+        "ant-design-vue/es/time-picker/style/css",
         "ant-design-vue/es/tooltip/style/css",
         "ant-design-vue/es/tree/style/css",
         "ant-design-vue/es/upload/style/css",
diff --git a/src/components/g-map/DroneControlPanel.vue b/src/components/g-map/DroneControlPanel.vue
index af2311f..ea8956a 100644
--- a/src/components/g-map/DroneControlPanel.vue
+++ b/src/components/g-map/DroneControlPanel.vue
@@ -118,7 +118,7 @@
               <span>Take off</span>
             </Button>
           </DroneControlPopover>
-          <Button :loading="cmdItem.loading" size="small" ghost @click="sendControlCmd(cmdItem, index)">
+          <Button :loading="cmdItem.loading" size="small" ghost @click="sendControlCmd(cmdItem, 0)">
           {{ cmdItem.operateText }}
           </Button>
         </div>
@@ -269,7 +269,7 @@
   return store.state.clientId
 })
 
-const initCmdList = baseCmdList.find(item => item.cmdKey === DeviceCmd.ReturnHome)
+const initCmdList = baseCmdList.find(item => item.cmdKey === DeviceCmd.ReturnHome) as DeviceCmdItem
 const cmdItem = ref(initCmdList)
 
 const {
@@ -284,7 +284,10 @@
     action: cmdItem.action
   }, false)
   if (result && flightController.value) {
+    message.success('Return home successful')
     exitFlightCOntrol()
+  } else {
+    message.error('Failed to return home')
   }
   cmdItem.loading = false
 }
@@ -346,7 +349,7 @@
   maxSpeed: MAX_SPEED,
   rthAltitude: null as null | number,
   rcLostAction: LostControlActionInCommandFLight.RETURN_HOME,
-  exitWaylineWhenRcLost: WaylineLostControlActionInCommandFlight.RETURN_HOME
+  exitWaylineWhenRcLost: WaylineLostControlActionInCommandFlight.EXEC_LOST_ACTION
 })
 
 function onShowTakeoffToPointPopover () {
@@ -357,7 +360,7 @@
   takeoffToPointPopoverData.securityTakeoffHeight = null
   takeoffToPointPopoverData.rthAltitude = null
   takeoffToPointPopoverData.rcLostAction = LostControlActionInCommandFLight.RETURN_HOME
-  takeoffToPointPopoverData.exitWaylineWhenRcLost = WaylineLostControlActionInCommandFlight.RETURN_HOME
+  takeoffToPointPopoverData.exitWaylineWhenRcLost = WaylineLostControlActionInCommandFlight.EXEC_LOST_ACTION
 }
 
 async function onTakeoffToPointConfirm (confirm: boolean) {
@@ -396,10 +399,10 @@
 useMqtt(deviceTopicInfo)
 
 // 飞行控制
-const drcState = computed(() => {
-  return store.state.deviceState?.dockInfo[props.sn]?.link_osd?.drc_state === DrcStateEnum.CONNECTED
-})
-const flightController = ref(drcState.value)
+// const drcState = computed(() => {
+//   return store.state.deviceState?.dockInfo[props.sn]?.link_osd?.drc_state === DrcStateEnum.CONNECTED
+// })
+const flightController = ref(false)
 
 async function onClickFightControl () {
   if (flightController.value) {
@@ -452,7 +455,7 @@
 }
 
 // drc mqtt message
-const { drcInfo } = useDroneControlMqttEvent(props.sn)
+const { drcInfo, errorInfo } = useDroneControlMqttEvent(props.sn)
 
 const {
   handleKeyup,
@@ -688,6 +691,17 @@
   }
   cameraAimPopoverData.visible = false
 }
+
+watch(() => errorInfo, (errorInfo) => {
+  if (errorInfo.value) {
+    message.error(errorInfo.value)
+    console.error(errorInfo.value)
+    errorInfo.value = ''
+  }
+}, {
+  immediate: true,
+  deep: true
+})
 </script>
 
 <style lang='scss' scoped>
diff --git a/src/components/g-map/use-drone-control-mqtt-event.ts b/src/components/g-map/use-drone-control-mqtt-event.ts
index 4a3d299..63ade36 100644
--- a/src/components/g-map/use-drone-control-mqtt-event.ts
+++ b/src/components/g-map/use-drone-control-mqtt-event.ts
@@ -5,6 +5,7 @@
   DRCHsiInfo,
   DRCOsdInfo,
   DRCDelayTimeInfo,
+  DrcResponseInfo,
 } from '/@/types/drc'
 
 export function useDroneControlMqttEvent (sn: string) {
@@ -12,6 +13,7 @@
   const hsiInfo = ref('')
   const osdInfo = ref('')
   const delayInfo = ref('')
+  const errorInfo = ref('')
 
   function handleHsiInfo (data: DRCHsiInfo) {
     hsiInfo.value = `method: ${DRC_METHOD.HSI_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n `
@@ -23,6 +25,13 @@
 
   function handleDelayTimeInfo (data: DRCDelayTimeInfo) {
     delayInfo.value = `method: ${DRC_METHOD.DELAY_TIME_INFO_PUSH}\r\n ${JSON.stringify(data)}\r\n `
+  }
+
+  function handleDroneControlErrorInfo (data: DrcResponseInfo) {
+    if (!data.result) {
+      return
+    }
+    errorInfo.value = `Drc error code: ${data.result}, seq: ${data.output?.seq}`
   }
 
   function handleDroneControlMqttEvent (payload: any) {
@@ -43,6 +52,11 @@
         handleDelayTimeInfo(payload.data)
         break
       }
+      case DRC_METHOD.DRONE_EMERGENCY_STOP:
+      case DRC_METHOD.DRONE_CONTROL: {
+        handleDroneControlErrorInfo(payload.data)
+        break
+      }
     }
     drcInfo.value = hsiInfo.value + osdInfo.value + delayInfo.value
   }
@@ -56,6 +70,7 @@
   })
 
   return {
-    drcInfo: drcInfo
+    drcInfo: drcInfo,
+    errorInfo: errorInfo
   }
 }
diff --git a/src/components/g-map/use-drone-control-ws-event.ts b/src/components/g-map/use-drone-control-ws-event.ts
index 34981c2..cfcb1d3 100644
--- a/src/components/g-map/use-drone-control-ws-event.ts
+++ b/src/components/g-map/use-drone-control-ws-event.ts
@@ -19,12 +19,11 @@
     }
     if (data.type === ControlSourceChangeType.Payload && data.sn === payloadSn) {
       payloadControlSource.value = data.control_source
-      message.info(`Payload control is changed to ${ payloadControlSource.value }.`)
-      return
+      message.info(`Payload control is changed to ${payloadControlSource.value}.`)
     }
   }
 
-  function handleProgress(key: string, message: string, error: number) {
+  function handleProgress (key: string, message: string, error: number) {
     if (error !== 0) {
       notification.error({
         key: key,
@@ -72,7 +71,6 @@
       }
       case EBizCode.DrcStatusNotify: {
         const { sn: deviceSn, result, message: msg } = payload.data as DrcStatusNotifyMessage
-        if (deviceSn !== sn) return
         // handleProgress(EBizCode.DrcStatusNotify, `device(sn: ${deviceSn}) ${msg}`, result)
 
         break
diff --git a/src/components/g-map/use-manual-control.ts b/src/components/g-map/use-manual-control.ts
index eb178a8..96055d1 100644
--- a/src/components/g-map/use-manual-control.ts
+++ b/src/components/g-map/use-manual-control.ts
@@ -30,7 +30,7 @@
 export function useManualControl (deviceTopicInfo: DeviceTopicInfo, isCurrentFlightController: Ref<boolean>) {
   const activeCodeKey = ref(null) as Ref<KeyCode | null>
   const mqttHooks = useMqtt(deviceTopicInfo)
-
+  let seq = 0
   function handlePublish (params: DroneControlProtocol) {
     const body = {
       method: DRC_METHOD.DRONE_CONTROL,
@@ -38,8 +38,9 @@
     }
     handleClearInterval()
     myInterval = setInterval(() => {
+      body.data.seq = seq++
+      seq++
       window.console.log('keyCode>>>>', activeCodeKey.value, body)
-      body.data.seq = new Date().getTime()
       mqttHooks?.publishMqtt(deviceTopicInfo.pubTopic, body, { qos: 0 })
     }, 50)
   }
@@ -52,6 +53,7 @@
     const SPEED = 5 //  check
     const HEIGHT = 5 //  check
     const W_SPEED = 20 // 机头角速度
+    seq = 0
     switch (keyCode) {
       case 'KeyA':
         if (activeCodeKey.value === keyCode) return
@@ -105,6 +107,7 @@
 
   function resetControlState () {
     activeCodeKey.value = null
+    seq = 0
     handleClearInterval()
   }
 
diff --git a/src/components/g-map/use-mqtt.ts b/src/components/g-map/use-mqtt.ts
index c02f537..d5bfa68 100644
--- a/src/components/g-map/use-mqtt.ts
+++ b/src/components/g-map/use-mqtt.ts
@@ -60,6 +60,8 @@
         case DRC_METHOD.DELAY_TIME_INFO_PUSH:
         case DRC_METHOD.HSI_INFO_PUSH:
         case DRC_METHOD.OSD_INFO_PUSH:
+        case DRC_METHOD.DRONE_CONTROL:
+        case DRC_METHOD.DRONE_EMERGENCY_STOP:
           EventBus.emit('droneControlMqttInfo', payloadObj)
           break
         default:
diff --git a/src/components/livestream-agora.vue b/src/components/livestream-agora.vue
index b1c0d05..dd435ab 100644
--- a/src/components/livestream-agora.vue
+++ b/src/components/livestream-agora.vue
@@ -76,7 +76,6 @@
         class="ml10"
         v-model:value="agoraPara.token"
         placeholder="Token"
-        @change="encodeToken"
       ></a-input>
       <span class="ml10">Channel:</span>
       <a-input
@@ -169,7 +168,6 @@
   liveState: false
 })
 const nonSwitchable = 'normal'
-
 const onRefresh = async () => {
   dronePara.droneList = []
   dronePara.cameraList = []
@@ -204,8 +202,11 @@
 
 onMounted(() => {
   onRefresh()
-  agoraPara.token = encodeURIComponent(agoraPara.token)
   agoraClient = AgoraRTC.createClient({ mode: 'live', codec: 'vp8' })
+  agoraClient.setClientRole('audience', { level: 2 })
+  if (agoraClient.connectionState === 'DISCONNECTED') {
+    agoraClient.join(agoraPara.appid, agoraPara.channel, agoraPara.token)
+  }
   // Subscribe when a remote user publishes a stream
   agoraClient.on('user-joined', async (user: IAgoraRTCRemoteUser) => {
     message.info('user[' + user.uid + '] join')
@@ -217,9 +218,7 @@
       // Get `RemoteVideoTrack` in the `user` object.
       const remoteVideoTrack = user.videoTrack!
       // Dynamically create a container in the form of a DIV element for playing the remote video track.
-      const remotePlayerContainer: any = document.getElementById('player')
-      remotePlayerContainer.id = user.uid.toString()
-      remoteVideoTrack.play(remotePlayerContainer)
+      remoteVideoTrack.play(document.getElementById('player') as HTMLElement)
     }
   })
   agoraClient.on('user-unpublished', async (user: any) => {
@@ -231,15 +230,11 @@
     message.error(e.msg)
   })
 })
-
 const handleError = (err: any) => {
   console.error(err)
 }
 const handleJoinChannel = (uid: any) => {
   agoraPara.uid = uid
-}
-const encodeToken = (e: any) => {
-  agoraPara.token = encodeURIComponent(agoraPara.token)
 }
 const onStart = async () => {
   const that = this
@@ -262,8 +257,7 @@
   }
   agoraClient.setClientRole('audience', { level: 2 })
   if (agoraClient.connectionState === 'DISCONNECTED') {
-    agoraClient
-      .join(agoraPara.appid, agoraPara.channel, agoraPara.token)
+    await agoraClient.join(agoraPara.appid, agoraPara.channel, agoraPara.token)
   }
   livePara.videoId =
     dronePara.droneSelected +
@@ -277,7 +271,7 @@
     '&sn=' +
     dronePara.droneSelected +
     '&token=' +
-    agoraPara.token +
+    encodeURIComponent(agoraPara.token) +
     '&uid=' +
     agoraPara.uid
 
@@ -298,6 +292,14 @@
     })
 }
 const onStop = async () => {
+  if (
+    dronePara.droneSelected == null ||
+    dronePara.cameraSelected == null ||
+    dronePara.claritySelected == null
+  ) {
+    message.warn('waring: not select live para!!!')
+    return
+  }
   livePara.videoId =
     dronePara.droneSelected +
     '/' +
@@ -308,10 +310,10 @@
   }).then(res => {
     if (res.code === 0) {
       message.success(res.message)
+      livePara.liveState = false
+      dronePara.lensSelected = ''
+      console.log('stop play livestream')
     }
-    livePara.liveState = false
-    dronePara.lensSelected = ''
-    console.log('stop play livestream')
   })
 }
 const onDroneSelect = (val: SelectOption) => {
@@ -350,7 +352,7 @@
   dronePara.videoSelected = firstVideo.value
   dronePara.lensList = firstVideo.more
   dronePara.lensSelected = firstVideo.label
-  dronePara.isDockLive = dronePara.lensList.length > 0
+  dronePara.isDockLive = dronePara.lensList?.length > 0
 }
 const onVideoSelect = (val: SelectOption) => {
   dronePara.videoSelected = val.value
diff --git a/src/components/livestream-others.vue b/src/components/livestream-others.vue
index 16b0bb3..754f556 100644
--- a/src/components/livestream-others.vue
+++ b/src/components/livestream-others.vue
@@ -388,7 +388,7 @@
   videoSelected.value = firstVideo.value
   lensList.value = firstVideo.more
   lensSelected.value = firstVideo.label
-  isDockLive.value = lensList.value.length > 0
+  isDockLive.value = lensList.value?.length > 0
 }
 const onVideoSelect = (val: SelectOption) => {
   videoSelected.value = val.value
diff --git a/src/components/task/CreatePlan.vue b/src/components/task/CreatePlan.vue
index becc1be..21006d8 100644
--- a/src/components/task/CreatePlan.vue
+++ b/src/components/task/CreatePlan.vue
@@ -4,8 +4,8 @@
       Create Plan
     </div>
     <div class="content">
-      <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody">
-        <a-form-item label="Plan Name" name="name" :labelCol="{span: 24}">
+      <a-form ref="valueRef" layout="horizontal" :hideRequiredMark="true" :rules="rules" :model="planBody" labelAlign="left">
+        <a-form-item label="Plan Name" name="name" :labelCol="{span: 23}">
           <a-input style="background: black;"  placeholder="Please enter plan name" v-model:value="planBody.name"/>
         </a-form-item>
         <!-- 航线 -->
@@ -62,31 +62,29 @@
           </div>
         </a-form-item>
         <!-- 任务类型 -->
-        <a-form-item label="Plan Timer" class="plan-timer-form-item">
+        <a-form-item label="Plan Timer" class="plan-timer-form-item" :labelCol="{span: 23}">
           <div style="white-space: nowrap;">
             <a-radio-group v-model:value="planBody.task_type" button-style="solid">
-              <a-radio-button :value="TaskType.Immediate">Immediate</a-radio-button>
-              <a-radio-button :value="TaskType.Single">Timed&One-Time</a-radio-button>
+              <a-radio-button v-for="type in TaskTypeOptions" :value="type.value" :key="type.value">{{ type.label }}</a-radio-button>
             </a-radio-group>
           </div>
         </a-form-item>
         <!-- 执行时间 -->
-        <a-form-item label="Start Time" v-if="planBody.task_type === TaskType.Single" name="select_execute_time">
+        <a-form-item label="Start Time" v-if="planBody.task_type === TaskType.Timed" name="select_execute_time" :labelCol="{span: 23}">
           <a-date-picker
             v-model:value="planBody.select_execute_time"
             format="YYYY-MM-DD HH:mm:ss"
-            show-time
+              show-time
             placeholder="Select Time"
-            style="width: 280px;"
-          />
+            />
         </a-form-item>
         <!-- RTH Altitude Relative to Dock -->
-        <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{span: 24}" name="rth_altitude">
-          <a-input v-model:value="planBody.rth_altitude" style="background: black !important;">
-          </a-input>
+        <a-form-item label="RTH Altitude Relative to Dock (m)" :labelCol="{span: 23}" name="rth_altitude">
+          <a-input-number v-model:value="planBody.rth_altitude" :min="20" :max="1500" class="width-100" required>
+          </a-input-number>
         </a-form-item>
         <!-- Lost Action -->
-        <a-form-item label="Lost Action" :labelCol="{span: 24}" name="out_of_control_action">
+        <a-form-item label="Lost Action" :labelCol="{span: 23}" name="out_of_control_action">
           <div style="white-space: nowrap;">
             <a-radio-group v-model:value="planBody.out_of_control_action" button-style="solid">
               <a-radio-button v-for="action in OutOfControlActionOptions" :value="action.value" :key="action.value">
@@ -95,7 +93,7 @@
             </a-radio-group>
           </div>
         </a-form-item>
-        <a-form-item style="width: 280px;">
+        <a-form-item class="width-100" style="margin-bottom: 40px;">
           <div class="footer">
             <a-button class="mr10" style="background: #3c3c3c;" @click="closePlan">Cancel
             </a-button>
@@ -106,7 +104,7 @@
       </a-form>
     </div>
   </div>
-  <div v-if="drawerVisible" style="position: absolute; left: 330px; width: 280px; height: 100vh; float: right; top: 0; z-index: 1000; color: white; background: #282828;">
+  <div v-if="drawerVisible" style="position: absolute; left: 335px; width: 280px; height: 100vh; float: right; top: 0; z-index: 1000; color: white; background: #282828;">
     <div>
       <router-view :name="routeName"/>
     </div>
@@ -118,14 +116,14 @@
 
 <script lang="ts" setup>
 import { computed, onMounted, onUnmounted, reactive, ref, toRaw, UnwrapRef } from 'vue'
-import { CloseOutlined, RocketOutlined, CameraFilled, UserOutlined } from '@ant-design/icons-vue'
+import { CloseOutlined, RocketOutlined, CameraFilled, UserOutlined, PlusCircleOutlined, MinusCircleOutlined } from '@ant-design/icons-vue'
 import { ELocalStorageKey, ERouterName } from '/@/types'
 import { useMyStore } from '/@/store'
 import { WaylineType, WaylineFile } from '/@/types/wayline'
 import { Device, EDeviceType } from '/@/types/device'
 import { createPlan, CreatePlan } from '/@/api/wayline'
 import { getRoot } from '/@/root'
-import { TaskType, OutOfControlActionOptions, OutOfControlAction } from '/@/types/task'
+import { TaskType, OutOfControlActionOptions, OutOfControlAction, TaskTypeOptions } from '/@/types/task'
 import moment, { Moment } from 'moment'
 import { RuleObject } from 'ant-design-vue/es/form/interface'
 
@@ -192,9 +190,7 @@
     // console.log('planBody', createPlanBody)
     createPlan(workspaceId, createPlanBody)
       .then(res => {
-        setTimeout(() => {
-          disabled.value = false
-        }, 1500)
+        disabled.value = false
       }).finally(() => {
         closePlan()
       })
@@ -231,6 +227,7 @@
   height: 100vh;
   display: flex;
   flex-direction: column;
+  width: 285px;
 
   .header {
     height: 52px;
@@ -242,6 +239,10 @@
     align-items: center;
   }
 
+  ::-webkit-scrollbar {
+    display: none;
+  }
+
   .content {
     height: calc(100% - 54px);
     overflow-y: auto;
@@ -250,7 +251,8 @@
       margin: 10px;
     }
 
-    form label, input {
+    form label, input, .ant-input, .ant-calendar-range-picker-separator,
+    .ant-input:hover, .ant-time-picker .anticon, .ant-calendar-picker .anticon {
       background-color: #232323;
       color: #fff;
     }
@@ -260,12 +262,12 @@
     }
 
     .plan-timer-form-item {
-      // flex-direction: column;
 
       .ant-radio-button-wrapper{
         background-color: #232323;
         color: #fff;
-
+        width: 80%;
+        text-align: center;
         &.ant-radio-button-wrapper-checked{
           background-color: #1890ff;
         }
diff --git a/src/pages/page-pilot/pilot-home.vue b/src/pages/page-pilot/pilot-home.vue
index b12de0d..0b86139 100644
--- a/src/pages/page-pilot/pilot-home.vue
+++ b/src/pages/page-pilot/pilot-home.vue
@@ -67,7 +67,7 @@
             <span style="color: #737373">{{ device.data.gateway_sn }}</span>
           </a-col>
         </a-row>
-        <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" v-if="device.data.online_status">
+        <a-row style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" v-if="device.data.online_status && device.data.sn">
           <a-col :span="1"></a-col>
           <a-col :span="9">Aircraft Sn</a-col>
           <a-col :span="13" class="flex-align-end flex-column" >
@@ -79,7 +79,7 @@
         <span class="ml5" style="color: #939393;">Settings</span>
       </div>
       <div class="fz16" style="background-color: white; border-radius: 4px;">
-        <a-row v-if="device.data.online_status" style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="bindingDevice">
+        <a-row v-if="device.data.online_status && device.data.sn" style="border-bottom: 1px solid #f4f8f9; height: 45px;" align="middle" @click="bindingDevice">
           <a-col :span="1"></a-col>
           <a-col :span="11">
             Device Binding
@@ -251,6 +251,10 @@
 onMounted(() => {
   apiPilot.onBackClickReg()
   apiPilot.onStopPlatform()
+  const oldDevice = localStorage.getItem(ELocalStorageKey.Device)
+  if (oldDevice) {
+    device.data = JSON.parse(oldDevice)
+  }
 
   window.connectCallback = (arg: any) => {
     connectCallback(arg)
@@ -263,10 +267,7 @@
     message.warn('Data is not available, please restart the remote control.')
     return
   }
-  const oldDevice = localStorage.getItem(ELocalStorageKey.Device)
-  if (oldDevice) {
-    device.data = JSON.parse(oldDevice)
-  }
+
   device.data.sn = apiPilot.getAircraftSN()
   getDeviceInfo()
 
@@ -486,7 +487,7 @@
 }
 
 function getDeviceInfo () {
-  if (device.data.sn === EStatusValue.DISCONNECT) {
+  if (!device.data.sn || device.data.sn === EStatusValue.DISCONNECT) {
     return
   }
   getDeviceBySn(bindParam.workspace_id, device.data.sn).then(res => {
diff --git a/src/pages/page-web/projects/workspace.vue b/src/pages/page-web/projects/workspace.vue
index d302112..752f861 100644
--- a/src/pages/page-web/projects/workspace.vue
+++ b/src/pages/page-web/projects/workspace.vue
@@ -136,6 +136,7 @@
     .main-content {
       flex: 1;
       color: $text-white-basic;
+      width: 285px;
     }
   }
 
diff --git a/src/store/index.ts b/src/store/index.ts
index 6dbf7ba..d3964db 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -130,7 +130,6 @@
     }
     if (info.host.job_number !== undefined) {
       dock.work_osd = info.host
-      return
     }
   },
   SET_DRAW_VISIBLE_INFO (state, bool) {
diff --git a/src/types/device.ts b/src/types/device.ts
index fdbeb67..d220acc 100644
--- a/src/types/device.ts
+++ b/src/types/device.ts
@@ -23,6 +23,7 @@
   M30 = 67,
   M300 = 60,
   Mavic3EnterpriseAdvanced= 77,
+  M350 = 89,
 }
 
 // DJI负载类型枚举值
@@ -74,6 +75,7 @@
   M3T: `${DOMAIN.DRONE}-${DRONE_TYPE.Mavic3EnterpriseAdvanced}-${DEVICE_SUB_TYPE.ONE}`,
 
   M300: `${DOMAIN.DRONE}-${DRONE_TYPE.M300}-${DEVICE_SUB_TYPE.ZERO}`,
+  M350: `${DOMAIN.DRONE}-${DRONE_TYPE.M350}-${DEVICE_SUB_TYPE.ZERO}`,
 
   FPV: `${DOMAIN.PAYLOAD}-${PAYLOAD_TYPE.FPV}-${DEVICE_SUB_TYPE.ZERO}`,
   H20: `${DOMAIN.PAYLOAD}-${PAYLOAD_TYPE.H20}-${DEVICE_SUB_TYPE.ZERO}`,
@@ -107,6 +109,7 @@
   [DEVICE_MODEL_KEY.M3T]: 'Mavic 3T',
   // [DEVICE_MODEL_KEY.M3M]: 'Mavic 3M',
   [DEVICE_MODEL_KEY.M300]: 'M300 RTK',
+  [DEVICE_MODEL_KEY.M350]: 'M350 RTK',
 
   // payload
   [DEVICE_MODEL_KEY.FPV]: 'FPV',
@@ -464,6 +467,7 @@
   M30 = '0-67-0' as any,
   M30T = '0-67-1' as any,
   M300 = '0-60-0' as any,
+  M350 = DEVICE_MODEL_KEY.M350 as any,
   Z30 = '1-20-0' as any,
   XT2 = '1-26-0' as any,
   FPV = '1-39-0' as any,
diff --git a/src/types/drc.ts b/src/types/drc.ts
index e31b55f..ae83404 100644
--- a/src/types/drc.ts
+++ b/src/types/drc.ts
@@ -13,13 +13,7 @@
   y?: number; // 前进后退方向速度,正值为W指令  负值为S指令 单位:m/s
   h?: number;// 上下高度值,正值为上升指令  负值为下降指令 单位:m
   w?: number; // 机头角速度,正值为顺时针,负值为逆时针 单位:degree/s   (web端暂无此设计)
-  step_x?: number; // 水平方向步长
-  step_y?: number; // 前后方向步长
-  step_h?: number; // 高度方向步长
-  step_w?: number; // 机头转向步长
   seq?: number; // 从0计时
-  freq?: number; // 指令发送频率
-  delay_time?: number; // 指令从发送到设备端接收可容忍的时间 发送频率+链路传输时长
 }
 
 // 低延时osd
@@ -69,3 +63,10 @@
   sdr_cmd_delay: number; // sdr链路命令延时,单位:ms
   liveview_delay_list: LiveViewDelayItem[];
 }
+
+export interface DrcResponseInfo {
+  result: number;
+  output: {
+    seq: number
+  }
+}
diff --git a/src/types/task.ts b/src/types/task.ts
index a37fe73..b0cf295 100644
--- a/src/types/task.ts
+++ b/src/types/task.ts
@@ -3,14 +3,19 @@
 // 任务类型
 export enum TaskType {
   Immediate = 0, // 立即执行
-  Single = 1, // 单次定时任务
+  Timed = 1, // 单次定时任务
 }
 
 export const TaskTypeMap = {
   [TaskType.Immediate]: 'Immediate',
-  [TaskType.Single]: 'Timed & One-Time',
+  [TaskType.Timed]: 'Timed',
 }
 
+export const TaskTypeOptions = [
+  { value: TaskType.Immediate, label: TaskTypeMap[TaskType.Immediate] },
+  { value: TaskType.Timed, label: TaskTypeMap[TaskType.Timed] },
+]
+
 // 失控动作
 export enum OutOfControlAction {
   ReturnToHome = 0,

--
Gitblit v1.9.3