Browse Source

优化项目工作空间

李富豪 1 year ago
parent
commit
626fef964c

+ 17 - 0
Web/src/api/custom/index.ts

@@ -2,6 +2,14 @@ import request from '/@/api/http/request';
 import { getWorkspaceId } from '/@/utils/index';
 
 // Api参数类型
+export type FetchWaylineListApiParams = Partial<{
+    order_by: string,
+    template_type: number,
+    key: string,
+    page: number,
+    page_size: number,
+}>;
+
 export type FetchDeviceFeedbackRecordListApiParams = Partial<{
     begin_time: number,
     end_time: number,
@@ -116,6 +124,7 @@ export type DeleteDirApiParams = {
 };
 
 // Api函数类型
+export type FetchWaylineListApi = (params: FetchWaylineListApiParams) => Promise<any>;
 export type FetchDeviceLogListApi = (sn: string, params: { domain_list: string }) => Promise<any>;
 export type FetchDeviceFeedbackRecordListApi = (sn: string, params: FetchDeviceFeedbackRecordListApiParams) => Promise<any>;
 export type FetchDeviceLogDetailApi = (params: { logsId: string }) => Promise<any>;
@@ -147,6 +156,13 @@ export const getUploadPath = () => {
     return `api/media/api/v1/files/${getWorkspaceId()}/file/upload`;
 }
 
+// 获取航线列表
+const fetchWaylineListApi: FetchWaylineListApi = async (params) => {
+    const url = `/wayline/api/v1/workspaces/${getWorkspaceId()}/waylines`
+    const res = await request.get(url, { params: params });
+    return res.data;
+};
+
 // 获取设备日志列表
 const fetchDeviceLogListApi: FetchDeviceLogListApi = async (sn, params) => {
     const res = await request.get(`/manage/api/v1/workspaces/${getWorkspaceId()}/devices/${sn}/logs`, { params: params });
@@ -317,6 +333,7 @@ const deleteDirApi: DeleteDirApi = async (params) => {
 };
 
 export const apis = {
+    fetchWaylineList: fetchWaylineListApi,
     fetchDeviceLogList: fetchDeviceLogListApi,
     fetchDeviceFeedbackRecordList: fetchDeviceFeedbackRecordListApi,
     fetchDeviceLogDetail: fetchDeviceLogDetailApi,

+ 3 - 3
Web/src/api/wayline.ts

@@ -78,7 +78,7 @@ export interface Task {
   rth_altitude: number // 相对机场返航高度 20 - 500
   out_of_control_action: OutOfControlAction // 失控动作
   media_count: number // 媒体数量
-  uploading:boolean // 是否正在上传媒体
+  uploading: boolean // 是否正在上传媒体
   uploaded_count: number // 已上传媒体数量
 }
 
@@ -94,7 +94,7 @@ export interface DeleteTaskParams {
 }
 
 //  删除机场任务
-export async function deleteTask (workspaceId: string, params: DeleteTaskParams): Promise<IWorkspaceResponse<{}>> {
+export async function deleteTask(workspaceId: string, params: DeleteTaskParams): Promise<IWorkspaceResponse<{}>> {
   const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/jobs`
   const result = await request.delete(url, {
     params: params
@@ -112,7 +112,7 @@ export interface UpdateTaskStatusBody {
 }
 
 // 更新机场任务状态
-export async function updateTaskStatus (workspaceId: string, body: UpdateTaskStatusBody): Promise<IWorkspaceResponse<{}>> {
+export async function updateTaskStatus(workspaceId: string, body: UpdateTaskStatusBody): Promise<IWorkspaceResponse<{}>> {
   const url = `${HTTP_PREFIX}/workspaces/${workspaceId}/jobs/${body.job_id}`
   const result = await request.put(url, {
     status: body.status

+ 20 - 12
Web/src/components/airport/components/InfoModal.vue

@@ -290,7 +290,7 @@
               <div class="content-aircraft-info-item">
                 <img style="margin-right: 5px;" :src="windSrc">
                 <div style="font-weight: bold;margin-right: 5px;">
-                  W.S
+                  {{ windDirection }}
                 </div>
                 <div>
                   {{ windSpeed }}
@@ -398,7 +398,7 @@ import DockControlPanel from '../../g-map/DockControlPanel.vue'
 import DroneControlPanel from '../../g-map/DroneControlPanel.vue'
 import { useDockControl } from '../../g-map/use-dock-control';
 import { useMyStore } from '/@/store';
-import { getTextByModeCode, getTextByDockModeCode } from '/@/utils/index'
+import { getTextByModeCode, getTextByDockModeCode, getWindDirection } from '/@/utils/index'
 import EventBus from '/@/event-bus'
 import { EModeCode, EDockModeCode } from '/@/types/device';
 
@@ -505,6 +505,15 @@ const capacity = computed(() => {
   }
 });
 
+const windDirection = computed(() => {
+  const info = props.deviceInfo?.device;
+  if (info) {
+    return getWindDirection(info.wind_direction);
+  } else {
+    return '';
+  }
+});
+
 const windSpeed = computed(() => {
   const info = props.deviceInfo?.device;
   if (info) {
@@ -693,17 +702,16 @@ const fetchLiveCapacity = async () => {
   }
 }
 
-onMounted(async () => {
-  function handleTaskWsEvent(payload: any) {
-    if (!payload) {
-      return
-    }
-    state.uploadQuantity = payload.uploaded_file_count;
-    state.uploadTotal = payload.expected_file_count;
+function handleTaskWsEvent(payload: any) {
+  if (!payload) {
+    return
   }
-  onMounted(() => {
-    EventBus.on('flightTaskWs', handleTaskWsEvent)
-  })
+  state.uploadQuantity = payload.uploaded_file_count;
+  state.uploadTotal = payload.expected_file_count;
+}
+
+onMounted(async () => {
+  EventBus.on('flightTaskWs', handleTaskWsEvent)
   await fetchLiveCapacity();
 })
 

+ 17 - 17
Web/src/components/airport/index.vue

@@ -21,21 +21,22 @@
         </div>
         <div class="content-info-left-style">
           <div class="content-info-left-style-info">
-            <img class="content-info-left-style-info-icon" :src="aircraftSrc">
+            <img class="content-info-left-style-info-icon" :src="dockSrc">
             <div class="content-info-left-style-info-text"
-              :style="deviceInfo[dock.sn] && deviceInfo[dock.sn].mode_code !== EModeCode.Disconnected ? 'color:#00EE8B' : 'color:red'">
-              {{ getTextByModeCode(deviceInfo[dock.sn] ? deviceInfo[dock.sn].mode_code : EModeCode.Disconnected) }}
+              :style="dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected ? 'color:#00EE8B' : 'color:red'">
+              {{ getTextByDockModeCode(dockInfo[dock.gateway.sn] ? dockInfo[dock.gateway.sn].basic_osd?.mode_code
+                : EDockModeCode.Disconnected) }}
             </div>
           </div>
           <div :class="[
             'content-info-left-style-other',
-            hmsInfo[dock.sn] && hmsInfo[dock.sn][0].level === 0 ? 'notice' : '',
-            hmsInfo[dock.sn] && hmsInfo[dock.sn][0].level === 1 ? 'caution' : '',
-            hmsInfo[dock.sn] && hmsInfo[dock.sn][0].level === 2 ? 'warn' : '',
+            hmsInfo[dock.gateway.sn] && hmsInfo[dock.gateway.sn][0].level === 0 ? 'notice' : '',
+            hmsInfo[dock.gateway.sn] && hmsInfo[dock.gateway.sn][0].level === 1 ? 'caution' : '',
+            hmsInfo[dock.gateway.sn] && hmsInfo[dock.gateway.sn][0].level === 2 ? 'warn' : '',
           ]">
-            <div v-if="aircraftLogInfo">
+            <div v-if="hangarLogInfo">
               <span class="word-loop">
-                {{ aircraftLogInfo }}
+                {{ hangarLogInfo }}
               </span>
             </div>
             <div v-else>
@@ -45,22 +46,21 @@
         </div>
         <div class="content-info-left-style">
           <div class="content-info-left-style-info">
-            <img class="content-info-left-style-info-icon" :src="dockSrc">
+            <img class="content-info-left-style-info-icon" :src="aircraftSrc">
             <div class="content-info-left-style-info-text"
-              :style="dockInfo[dock.gateway.sn] && dockInfo[dock.gateway.sn].basic_osd?.mode_code !== EDockModeCode.Disconnected ? 'color:#00EE8B' : 'color:red'">
-              {{ getTextByDockModeCode(dockInfo[dock.gateway.sn] ? dockInfo[dock.gateway.sn].basic_osd?.mode_code
-                : EDockModeCode.Disconnected) }}
+              :style="deviceInfo[dock.sn] && deviceInfo[dock.sn].mode_code !== EModeCode.Disconnected ? 'color:#00EE8B' : 'color:red'">
+              {{ getTextByModeCode(deviceInfo[dock.sn] ? deviceInfo[dock.sn].mode_code : EModeCode.Disconnected) }}
             </div>
           </div>
           <div :class="[
             'content-info-left-style-other',
-            hmsInfo[dock.gateway.sn] && hmsInfo[dock.gateway.sn][0].level === 0 ? 'notice' : '',
-            hmsInfo[dock.gateway.sn] && hmsInfo[dock.gateway.sn][0].level === 1 ? 'caution' : '',
-            hmsInfo[dock.gateway.sn] && hmsInfo[dock.gateway.sn][0].level === 2 ? 'warn' : '',
+            hmsInfo[dock.sn] && hmsInfo[dock.sn][0].level === 0 ? 'notice' : '',
+            hmsInfo[dock.sn] && hmsInfo[dock.sn][0].level === 1 ? 'caution' : '',
+            hmsInfo[dock.sn] && hmsInfo[dock.sn][0].level === 2 ? 'warn' : '',
           ]">
-            <div v-if="hangarLogInfo">
+            <div v-if="aircraftLogInfo">
               <span class="word-loop">
-                {{ hangarLogInfo }}
+                {{ aircraftLogInfo }}
               </span>
             </div>
             <div v-else>

+ 11 - 2
Web/src/components/onLineDevice/components/InfoModal.vue

@@ -145,7 +145,7 @@
               <div class="content-osd-info-item">
                 <img style="margin-right: 5px;" :src="windSrc">
                 <div style="font-weight: bold;margin-right: 5px;">
-                  W.S
+                  {{ windDirection }}
                 </div>
                 <div>
                   {{ windSpeed }}
@@ -231,7 +231,7 @@ import batteryFourSrc from '../icons/batteryFour.svg';
 import windSrc from '../icons/info/wind.svg';
 import homeSrc from '../icons/info/home.svg';
 import { getLiveCapacity, startLivestream, stopLivestream } from '/@/api/manage';
-import { getTextByModeCode } from '/@/utils/index'
+import { getTextByModeCode, getWindDirection } from '/@/utils/index'
 
 interface Props {
   osdInfo: any
@@ -290,6 +290,15 @@ const capacity = computed(() => {
   }
 });
 
+const windDirection = computed(() => {
+  const info = props.deviceInfo?.device;
+  if (info) {
+    return getWindDirection(info.wind_direction);
+  } else {
+    return '';
+  }
+});
+
 const windSpeed = computed(() => {
   const info = props.deviceInfo?.device;
   if (info) {

+ 0 - 3
Web/src/pages/page-web/projects/media/index/components/Search.vue

@@ -24,9 +24,6 @@
             <a-select-option :value="3">
               带状航线
             </a-select-option>
-            <a-select-option value="">
-              无
-            </a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item name="payload">

+ 1 - 5
Web/src/pages/page-web/projects/media/index/index.vue

@@ -214,9 +214,6 @@ const columns = [
         case '3':
           content = '带状航线';
           break;
-        case '4':
-          content = '无';
-          break;
         default:
           break;
       }
@@ -298,6 +295,7 @@ const onClickDownload = async (record: any) => {
   }
 }
 
+// 点击删除
 const onClickDelete = async (record: any) => {
   const data = {
     id: record.id
@@ -316,8 +314,6 @@ const onClickDelete = async (record: any) => {
       }
     },
   })
-
-
 }
 </script>
 

+ 60 - 46
Web/src/pages/page-web/projects/task/waylineList/components/Search.vue

@@ -1,62 +1,33 @@
 <template>
   <a-row style="margin-bottom: 20px;" justify="space-between">
     <a-col>
-      <a-button type="primary">
-        上传航线
-      </a-button>
+      <a-upload name="file" :multiple="false" :before-upload="beforeUpload" :show-upload-list="false"
+        :customRequest="uploadFile">
+        <a-button type="primary">
+          上传航线
+        </a-button>
+      </a-upload>
     </a-col>
     <a-col>
       <a-form ref="formRef" layout="inline" :model="formModel" :colon="false">
-        <a-form-item name="device_type">
-          <a-select style="width: 200px;" placeholder="航线类型" v-model:value="formModel.status">
-            <a-select-option :value="1">
-              上传中
-            </a-select-option>
-            <a-select-option :value="2">
-              成功
-            </a-select-option>
-            <a-select-option :value="3">
-              取消
-            </a-select-option>
-            <a-select-option :value="4">
-              失败
-            </a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item name="device_type">
-          <a-select style="width: 200px;" placeholder="飞行器型号" v-model:value="formModel.status">
-            <a-select-option :value="1">
-              上传中
-            </a-select-option>
-            <a-select-option :value="2">
-              成功
+        <a-form-item name="template_type">
+          <a-select style="width: 200px;" placeholder="航线类型" v-model:value="formModel.template_type">
+            <a-select-option :value="0">
+              航点航线
             </a-select-option>
-            <a-select-option :value="3">
-              取消
-            </a-select-option>
-            <a-select-option :value="4">
-              失败
-            </a-select-option>
-          </a-select>
-        </a-form-item>
-        <a-form-item name="device_type">
-          <a-select style="width: 200px;" placeholder="负载云台" v-model:value="formModel.status">
             <a-select-option :value="1">
-              上传中
+              二维正射
             </a-select-option>
             <a-select-option :value="2">
-              成功
+              倾斜摄影
             </a-select-option>
             <a-select-option :value="3">
-              取消
-            </a-select-option>
-            <a-select-option :value="4">
-              失败
+              带状航线
             </a-select-option>
           </a-select>
         </a-form-item>
-        <a-form-item name="search_info">
-          <a-input style="width: 200px;" placeholder="航线名称" v-model:value="formModel.search_info" />
+        <a-form-item name="key">
+          <a-input style="width: 200px;" placeholder="航线名称" v-model:value="formModel.key" />
         </a-form-item>
         <a-form-item>
           <a-button style="margin-right: 10px;" @click="handleClickSearch">
@@ -90,11 +61,54 @@ const props = withDefaults(defineProps<Props>(), {
 
 const formRef = ref();
 
+interface FileInfo {
+  file: FileItem;
+  fileList: FileItem[];
+}
+
+const fileList = ref<FileItem[]>([])
+
+
 const formModel = reactive({
-  device_type: undefined,
-  search_info: undefined,
+  template_type: undefined,
+  key: undefined,
+})
+
+
+const state = reactive({
+  buttonLoading: false,
+  fileList: []
 })
 
+
+
+const beforeUpload = (file: FileItem) => {
+  fileList.value = [file]
+  loading.value = true
+  return true
+}
+const uploadFile = async () => {
+  fileList.value.forEach(async (file: FileItem) => {
+    const fileData = new FormData()
+    fileData.append('file', file, file.name)
+    await importKmzFile(getWorkspaceId(), fileData).then((res) => {
+      if (res.code === 0) {
+        message.success(`${file.name} file uploaded successfully`)
+        canRefresh.value = true
+        pagination.total = 0
+        pagination.page = 1
+        waylinesData.data = []
+        getWaylines()
+      }
+    }).finally(() => {
+      loading.value = false
+      fileList.value = []
+    })
+  })
+}
+
+
+
 // 点击查询
 const handleClickSearch = async () => {
   const values = formRef.value?.getFieldsValue();

+ 52 - 46
Web/src/pages/page-web/projects/task/waylineList/index.vue

@@ -1,43 +1,39 @@
 <template>
-  <div class="deviceList">
+  <div class="waylineList">
     <Search :onClickSearch="onClickSearch" :onClickReset="onClickReset" />
-    <div class="deviceList-table">
-      <a-table :scroll="{ x: '100%', y: 500 }" childrenColumnName="null" rowKey="device_sn" :loading="state.listLoading"
-        :columns="columns" :dataSource="state.list" @change="refreshData" :rowClassName="rowClassName"
-        :pagination="paginationConfig">
-        <!-- 航线名称 -->
-        <template #name="{ record }">
-          <a-tooltip :title="record.name">
-            {{ record.name }}
+    <a-table :scroll="{ x: '100%', y: 500 }" rowKey="id" :loading="state.listLoading" :columns="columns"
+      :dataSource="state.list" @change="refreshData" :rowClassName="rowClassName" :pagination="paginationConfig">
+      <!-- 航线名称 -->
+      <template #name="{ record }">
+        <a-tooltip :title="record.name">
+          {{ record.name }}
+        </a-tooltip>
+      </template>
+      <!-- 操作 -->
+      <template #action="{ record }">
+        <div class="flex-align-center flex-row" style="color: #2d8cf0">
+          <a-tooltip title="下载">
+            <DownloadOutlined style="margin-right: 10px;" @click="onClickDownload(record.id, record.name)" />
           </a-tooltip>
-        </template>
-        <!-- 操作 -->
-        <template #action="{ record }">
-          <div class="flex-align-center flex-row" style="color: #2d8cf0">
-            <a-tooltip title="复制任务">
-              <CopyOutlined style="margin-right: 10px;" />
-            </a-tooltip>
-            <a-tooltip title="查看轨迹">
-              <GatewayOutlined style="margin-right: 10px;" />
-            </a-tooltip>
-            <a-tooltip title="删除">
-              <DeleteOutlined />
-            </a-tooltip>
-          </div>
-        </template>
-      </a-table>
-    </div>
+          <a-tooltip title="删除">
+            <DeleteOutlined @click="onClickDelete(record.id, record.name)" />
+          </a-tooltip>
+        </div>
+      </template>
+    </a-table>
   </div>
 </template>
 
 <script lang="ts" setup>
 import { reactive, onMounted } from 'vue';
 import { Modal } from 'ant-design-vue';
-import { CopyOutlined, GatewayOutlined, DeleteOutlined } from '@ant-design/icons-vue';
+import { DownloadOutlined, DeleteOutlined } from '@ant-design/icons-vue';
 import Search from './components/Search.vue';
-import { getWaylineFiles, importKmzFile, deleteWaylineFile, downloadWaylineFile } from '/@/api/wayline'
+import { apis } from '/@/api/custom'
+import { importKmzFile, downloadWaylineFile, deleteWaylineFile } from '/@/api/wayline'
 import { getWorkspaceId } from '/@/utils/index';
 import moment from 'moment';
+import { downloadFile } from '/@/utils/common'
 import { DEVICE_NAME } from '/@/types/device'
 
 interface State {
@@ -66,7 +62,7 @@ const paginationConfig = reactive({
 const fetchList = async () => {
   state.listLoading = true;
   try {
-    const res = await getWaylineFiles(state.workspaceId, {
+    const res = await apis.fetchWaylineList({
       ...state.query,
       order_by: 'update_time desc',
       page: paginationConfig.current,
@@ -109,7 +105,7 @@ const columns = [
     dataIndex: 'template_types',
     width: 150,
     customRender: ({ text }: any) => {
-      let content = ''
+      let content = '--';
       switch (text[0]) {
         case 0:
           content = '航点航线';
@@ -154,7 +150,8 @@ const columns = [
     title: '操作',
     dataIndex: 'actions',
     fixed: 'right',
-    width: 100,
+    align: 'center',
+    width: 60,
     slots: { customRender: 'action' },
   },
 ]
@@ -173,12 +170,6 @@ const refreshData = async (page: any) => {
   await fetchList();
 }
 
-const rowSelection = {
-  onChange: (selectedRowKeys: string[]) => {
-    state.selectedRowKeys = selectedRowKeys;
-  },
-}
-
 // 点击搜索
 const onClickSearch = async (query: any) => {
   state.query = query;
@@ -191,24 +182,39 @@ const onClickReset = async (query: any) => {
   await fetchList();
 }
 
+// 点击下载
+const onClickDownload = async (id: string, name: string) => {
+  state.listLoading = true;
+  try {
+    const res = await downloadWaylineFile(state.workspaceId, id);
+    if (!res) {
+      return;
+    }
+    const data = new Blob([res], { type: 'application/zip' });
+    downloadFile(data, name + '.kmz');
+  } catch (error) {
+    console.error(error);
+  } finally {
+    state.listLoading = false;
+  }
+}
+
 // 点击删除
-const onClickDelete = (record: any) => {
+const onClickDelete = (id: string, name: string) => {
   Modal.confirm({
-    title: '提示',
-    content: `确定删除${record.device_name}吗?`,
+    title: '删除航线',
+    content: `确定删除${name}吗?`,
+    okType: 'danger',
     onOk: async () => {
-      const res = await unbindDevice(record.device_sn);
-      if (res.code !== 0) {
-        return
-      }
+      await deleteWaylineFile(getWorkspaceId(), id);
       await fetchList();
     },
-  });
+  })
 }
 </script>
 
 <style lang="scss">
-.deviceList {
+.waylineList {
   padding: 20px;
 }
 

+ 0 - 3
Web/src/pages/page-web/projects/trajectory/components/Search.vue

@@ -19,9 +19,6 @@
             <a-select-option :value="3">
               带状航线
             </a-select-option>
-            <a-select-option value="">
-              无
-            </a-select-option>
           </a-select>
         </a-form-item>
         <a-form-item name="payload">

+ 0 - 3
Web/src/pages/page-web/projects/trajectory/index.vue

@@ -113,9 +113,6 @@ const columns = [
         case '3':
           content = '带状航线';
           break;
-        case '4':
-          content = '无';
-          break;
         default:
           break;
       }

+ 33 - 0
Web/src/utils/index.ts

@@ -129,6 +129,39 @@ export const getTextByDockTaskCode = (code: number) => {
     return text;
 }
 
+export const getWindDirection = (code: number) => {
+    let text = '';
+    switch (code) {
+        case 1:
+            text = '正北';
+            break;
+        case 2:
+            text = '东北';
+            break;
+        case 3:
+            text = '东';
+            break;
+        case 4:
+            text = '东南';
+            break;
+        case 5:
+            text = '南';
+            break;
+        case 6:
+            text = '西南';
+            break;
+        case 7:
+            text = '西';
+            break;
+        case 8:
+            text = '西北';
+            break;
+        default:
+            break;
+    }
+    return text;
+}
+
 // 获取项目ID
 export const getWorkspaceId = () => {
     return localStorage.getItem(ELocalStorageKey.WorkspaceId) || '';