From 2dfc8dc4bcd3d3cd4aed1b6054e073e140eba9c8 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Mon, 19 May 2025 16:05:50 +0800
Subject: [PATCH] Merge branch 'master' into jiangwu

---
 src/views/device/airport.vue |  358 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 328 insertions(+), 30 deletions(-)

diff --git a/src/views/device/airport.vue b/src/views/device/airport.vue
index be48ea1..e751aec 100644
--- a/src/views/device/airport.vue
+++ b/src/views/device/airport.vue
@@ -97,14 +97,23 @@
           ></el-progress>
         </div>
       </template>
+      <template #mode_code="{ row }">
+        <span
+          class="text"
+          v-if="row.domain == 3"
+          :style="row.mode_code != '-1' ? 'color: #00ee8b' : 'color: #de5e5e'"
+        >
+          {{ getDockModeText(row.mode_code) }}
+        </span>
+      </template>
       <template #menu="scope">
         <el-button
           type="primary"
           text
-          icon="el-icon-collection-tag"
-          v-if="permission.deviceFirmware_manage"
-          @click.stop="handleOpenFirmwarm(scope.row, scope.index)"
-          >固件管理
+          icon="el-icon-paperclip"
+          v-if="permission.oss_set"
+          @click.stop="handleOpenOssSet(scope.row, scope.index)"
+          >存储配置
         </el-button>
         <el-button
           type="primary"
@@ -115,14 +124,19 @@
           >机场授权
         </el-button>
 
-        <!-- <el-button
+        <el-button
           type="primary"
           text
-          icon="el-icon-share"
-          v-if="permission.per_share && scope.row.domain == 3"
+          icon="el-icon-position"
+          :disabled="!scope.row.status"
+          v-if="permission.rang_con && scope.row.domain == 3"
           @click.stop="handleOpenRemoteDebugging(scope.row, scope.index)"
           >远程调试
-        </el-button> -->
+        </el-button>
+      </template>
+      <!-- 添加行政区划显示模板 -->
+      <template #area_code="{ row }">
+        <span>{{ row.area_name }}</span>
       </template>
     </avue-crud>
 
@@ -136,10 +150,50 @@
       </template>
     </el-dialog>
 
+    <el-dialog
+      title="存储配置"
+      append-to-body
+      v-model="ossSetBox"
+      @close="handleOssSetClose"
+      width="600px"
+    >
+      <div style="display: flex; flex-direction: row; align-items: center">
+        存储对象配置:
+        <el-select v-model="ossEnd" clearable placeholder="请选择存储对象" style="width: 450px">
+          <el-option
+            v-for="item in ossList"
+            :key="item.id"
+            :label="item.name + ': ' + item.endpoint"
+            :value="item.id"
+          >
+            <span style="float: left">{{ item.name + ': ' + item.endpoint }}</span>
+            <span v-if="item.status == 1" style="float: right; color: #8492a6; font-size: 13px">{{
+              item.categoryName
+            }}</span>
+            <span v-if="item.status == 2" style="float: right; color: #40cb8b; font-size: 13px">{{
+              item.categoryName
+            }}</span>
+          </el-option>
+        </el-select>
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="cancelOssSet">取 消</el-button>
+          <el-button type="danger" @click="cancelOssSetConfirm">取消配置</el-button>
+          <el-button type="primary" @click="ossSetConfirm">配置</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
     <el-dialog title="固件版本管理" append-to-body v-model="rollFirmwareBox" width="455px">
-      <div style="display: flex;flex-direction: row;align-items: center ">
+      <div style="display: flex; flex-direction: row; align-items: center">
         固件版本升级/回退:
-        <el-select v-model="rollFirmVersion" clearable placeholder="请选择固件版本" style="width: 240px">
+        <el-select
+          v-model="rollFirmVersion"
+          clearable
+          placeholder="请选择固件版本"
+          style="width: 240px"
+        >
           <el-option
             v-for="item in firmList"
             :key="item.firmware_version"
@@ -166,7 +220,7 @@
       <DevicePerShare ref="devicePerShare" />
     </el-drawer>
 
-    <el-drawer title="远程调试" append-to-body v-model="remoteDebuggingShow" size="40%">
+    <el-drawer :title="operateTitle" append-to-body v-model="remoteDebuggingShow" size="40%">
       <DockControlPanel
         v-if="remoteDebuggingShow"
         :sn="curDeviceInfo.device_sn"
@@ -187,10 +241,12 @@
   getDeviceUpgradeInfo,
   ota,
   getDeviceFirmwareList,
+  getDevices,
 } from '@/api/device/device';
-
+import { deleteByOssId, addOrUpdate as addOrUpdateOssBind } from '@/api/device/ossBind';
+import { getListPage as getOssList } from '@/api/resource/oss';
 import { getLazyTree } from '@/api/base/region';
-
+import { EDockModeText, EDockModeCode } from '@/types/device';
 import { mapGetters } from 'vuex';
 import FirmwareManage from './components/firmwareManage.vue';
 import DevicePerShare from './components/devicePerShare.vue';
@@ -203,10 +259,15 @@
     DevicePerShare,
     DockControlPanel,
   },
-
   data() {
     return {
-      rollFirmVersion:'',
+      bindOssId: null,
+      deviceSn: '',
+      ossSetBox: false,
+      ossList: [],
+      ossEnd: '',
+      operateTitle: '',
+      rollFirmVersion: '',
       firmList: [],
       rollFirmwareBox: false,
       // 用于记录已经创建的websocket,防止重复创建
@@ -400,34 +461,56 @@
             props: {
               label: 'title',
               value: 'value',
+              emitPath: false,
+              checkStrictly: true,
+              multiple: false,
+              expandTrigger: 'hover',
             },
             dataType: 'string',
             rules: [
               {
                 required: true,
-                message: '请选择所在省份',
-                trigger: 'blur',
+                message: '请选择行政区划',
+                trigger: 'change',
               },
             ],
+            change: ({ value }) => {
+              if (!value) {
+                this.form.area_code = null;
+              } else {
+                if (typeof value === 'string' && value.includes(',')) {
+                  const codes = value.split(',');
+                  this.form.area_code = codes[codes.length - 1];
+                } else {
+                  this.form.area_code = value;
+                }
+              }
+            },
             lazy: true,
             lazyLoad(node, resolve) {
               let level = node.level;
               let list = [];
               let callback = () => {
                 resolve(
-                  (list || []).map(ele => {
-                    return Object.assign(ele, {
-                      leaf: !ele.hasChildren,
-                    });
-                  })
+                  (list || []).map(ele => ({
+                    ...ele,
+                    value: ele.value,
+                    leaf: level >= 2,
+                  }))
                 );
               };
-              if (level == 0) {
+
+              if (level === 0) {
                 getLazyTree('000000000000').then(res => {
                   list = res.data.data;
                   callback();
                 });
-              } else if (level > 0 && level < 5) {
+              } else if (level === 1) {
+                getLazyTree(node.value).then(res => {
+                  list = res.data.data;
+                  callback();
+                });
+              } else if (level === 2) {
                 getLazyTree(node.value).then(res => {
                   list = res.data.data;
                   callback();
@@ -468,6 +551,22 @@
               {
                 required: true,
                 message: '请输入在线状态',
+                trigger: 'blur',
+              },
+            ],
+          },
+          {
+            label: '机场状态',
+            prop: 'mode_code',
+            addDisplay: false,
+            editDisplay: false,
+            labelWidth: 130,
+            slot: true,
+            width: 100,
+            rules: [
+              {
+                required: true,
+                message: '请输入机场状态',
                 trigger: 'blur',
               },
             ],
@@ -517,6 +616,9 @@
     });
   },
   methods: {
+    getDockModeText(value) {
+      return EDockModeText[value] || '';
+    },
     // 关闭所有的webscoket
     closeAllWebsoket() {
       this.websocketMap.forEach((k, v) => {
@@ -571,7 +673,12 @@
       });
     },
     init() {
-      this.onLoad(this.page);
+      (this.page = {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+      }),
+        this.onLoad(this.page);
     },
     // 打开权限分享页面
     handleOpenDevicePerShare(row) {
@@ -581,12 +688,28 @@
         that.$refs.devicePerShare.init(row);
       });
     },
-
+    // 打开远程调试
     handleOpenRemoteDebugging(row) {
       this.curDeviceInfo = row;
       this.remoteDebuggingShow = true;
+      this.operateTitle = row.nickname + ' - ' + row.device_sn;
     },
-
+    // 打开存储对象配置页面
+    handleOpenOssSet(row) {
+      var that = this;
+      this.deviceSn = row.device_sn;
+      this.ossSetBox = true;
+      this.bindOssId = row.oss_id;
+      this.ossEnd = row.oss_id;
+      // 查询下拉列表
+      const param = {
+        categoryKeys: "1,3,6"
+      }
+      getOssList(1, 50,param).then(res => {
+        const data = res.data.data;
+        that.ossList = data.records;
+      });
+    },
     // 打开固件管理页面
     handleOpenFirmwarm(row) {
       var that = this;
@@ -603,6 +726,16 @@
           message: '设备不在线!',
         });
         return;
+      }
+      // 如果是机场,查询飞机对应的信息
+      if (row.domain === 3) {
+        // 查询子设备名称
+        getDevices(row.workspace_id, row.child_sn).then(res => {
+          const data = res.data.data;
+          that.firmwareInfo['child_device_name'] = data.device_name;
+          that.firmwareInfo['child_version'] = data.firmware_version;
+          that.firmwareInfo['child_status'] = data.status;
+        });
       }
       var that = this;
       this.rollFirmwareBox = true;
@@ -626,11 +759,32 @@
         // 3-普通升级,2-一致性升级;
         that.firmwareInfo['firmware_upgrade_type'] = 3;
         that.firmwareInfo['workspaceId'] = row.workspace_id;
+        that.firmwareInfo['firmware_version'] = row.firmware_version;
+        that.firmwareInfo['status'] = row.status;
+        // domain 0:飞机  3:机场
+        that.firmwareInfo['domain'] = row.domain;
+        that.firmwareInfo['child_sn'] = row.child_sn;
+        that.firmwareInfo['now_version'] = row.firmware_version;
       });
+    },
+    // 比较版本大小
+    compare(version1, version2) {
+      let arr1 = version1.split('.');
+      let arr2 = version2.split('.');
+      let length = Math.max(arr1.length, arr2.length);
+      for (let i = 0; i < length; i++) {
+        const n1 = Number(arr1[i] || 0);
+        const n2 = Number(arr2[i] || 0);
+        // version1 > version2 返回1,如果 version1 < version2 返回-1,不然返回0
+        if (n1 > n2) return 1;
+        if (n1 < n2) return -1;
+      }
+      return 0;
     },
     // 版本回退
     rollFirmwareConfirm() {
-      if(this.rollFirmVersion==''){
+      // 无人机升级/回滚
+      if (this.rollFirmVersion == '') {
         this.$message({
           type: 'warning',
           message: '请先选择回退的固件版本!',
@@ -640,7 +794,56 @@
       var that = this;
       var arr = [];
       that.firmwareInfo['product_version'] = this.rollFirmVersion;
+      // 机场信息设置
       arr.push(that.firmwareInfo);
+      // 判断是机场升级还是飞机升级,如果是机场升级则把无人机信息一起带过去
+      if (that.firmwareInfo.domain === 3) {
+        // 判断当前机场和无人机固件版本是否一致
+        var dockFlag = this.compare(
+          this.firmwareInfo.firmware_version,
+          this.firmwareInfo.child_version
+        );
+        // 机场和无人机版本一致情况
+        if (dockFlag == 0) {
+          if (!this.firmwareInfo.status || !this.firmwareInfo.child_status) {
+            this.$message({
+              type: 'warning',
+              message: '请先更新无人机固件版本后再进行机场固件版本更新!',
+            });
+            return;
+          }
+          // 只有同时在线并且是升级才能操作
+          // 判断升级还是降级,不能降级
+          var upDownFlag = this.compare(this.rollFirmVersion, this.firmwareInfo.firmware_version);
+          if (upDownFlag == -1) {
+            this.$message({
+              type: 'warning',
+              message: '请先回滚无人机固件版本后再进行机场固件版本更新!',
+            });
+            return;
+          }
+          // 同时升级操作
+          // 无人机信息设置
+          arr.push({
+            device_name: that.firmwareInfo.child_device_name,
+            sn: that.firmwareInfo.child_sn,
+            product_version: this.rollFirmVersion,
+            firmware_upgrade_type: 3,
+          });
+        } else {
+          // 版本不一致情况
+          // 比对需要改变的版本号和无人机版本号是否一致,不一致提示不能操作
+          var verFlag = this.compare(this.rollFirmVersion, this.firmwareInfo.child_version);
+          if (verFlag == -1 || verFlag == 1) {
+            this.$message({
+              type: 'warning',
+              message: '更新版本与当前无人机固件版本不一致,请更新和无人机一致的版本!',
+            });
+            return;
+          }
+          // 需要改变的版本号和无人机版本号如果是一致,进行单独的机场升级/回滚操作
+        }
+      }
       ota(that.firmwareInfo.workspaceId, arr).then(res => {
         that.firmwareVersion = '';
         that.firmwareInfo = {};
@@ -702,7 +905,75 @@
         done();
       });
     },
+    handleOssSetClose() {
+      this.ossEnd = '';
+      this.deviceSn = '';
+      this.bindOssId = null;
+    },
+    // 存储对象配置确定
+    ossSetConfirm() {
+      var that = this;
+      // 判断是否已选择
+      if (!this.ossEnd) {
+        this.$message({
+          type: 'warning',
+          message: '请选择对于的存储对象!',
+        });
+        return;
+      }
+      // 新增或者修改操作
+      const data = {
+        oss_id: this.ossEnd,
+        sn: this.deviceSn,
+      };
+      // 新增
+      addOrUpdateOssBind(data).then(res => {
+        this.$message({
+          type: 'success',
+          message: '操作成功!',
+        });
+        that.ossSetBox = false;
+        this.onLoad(this.page);
+        done();
+      });
+    },
+    // 取消配置
+    cancelOssSetConfirm() {
+      var that = this;
+      // 判断是否已有配置
+      if (!this.bindOssId) {
+        this.$message({
+          type: 'warning',
+          message: '当前机场尚未配置存储对象信息!',
+        });
+        return;
+      }
+      deleteByOssId(this.bindOssId).then(() => {
+        that.ossSetBox = false;
+        this.onLoad(this.page);
+        this.$message({
+          type: 'success',
+          message: '操作成功!',
+        });
+      });
+    },
+    // 取消按钮 oss
+    cancelOssSet() {
+      this.ossEnd = '';
+      this.deviceSn = '';
+      this.bindOssId = null;
+      this.ossSetBox = false;
+    },
     rowSave(row, done, loading) {
+      let areaCode = row.area_code;
+      if (Array.isArray(areaCode)) {
+        areaCode = areaCode[areaCode.length - 1];
+      } else if (typeof areaCode === 'string' && areaCode.includes(',')) {
+        const codes = areaCode.split(',');
+        areaCode = codes[codes.length - 1];
+      }
+      row.area_code = areaCode || null;
+
       add(row).then(
         () => {
           this.onLoad(this.page);
@@ -719,7 +990,12 @@
       );
     },
     rowUpdate(row, index, done, loading) {
-      update(row).then(
+      const submitData = {
+        ...row,
+        area_code: row.area_code.split(',').pop(),
+      };
+
+      update(submitData).then(
         () => {
           this.onLoad(this.page);
           this.$message({
@@ -790,10 +1066,32 @@
           this.$refs.crud.toggleSelection();
         });
     },
+    getFullAreaCode(areaCode) {
+      if (!areaCode) return '';
+
+      const code = areaCode.toString();
+
+      if (code.includes(',')) return code;
+
+      if (code.endsWith('0000000000')) {
+        return code;
+      } else if (code.endsWith('00000000') && !code.endsWith('0000000000')) {
+        const provinceCode = code.substring(0, 2) + '0000000000';
+        return `${provinceCode},${code}`;
+      } else {
+        const provinceCode = code.substring(0, 2) + '0000000000';
+        const cityCode = code.substring(0, 4) + '00000000';
+        return `${provinceCode},${cityCode},${code}`;
+      }
+    },
     beforeOpen(done, type) {
       if (['edit', 'view'].includes(type)) {
         getDetail(this.form.id).then(res => {
-          this.form = res.data.data;
+          const data = res.data.data;
+          this.form = {
+            ...data,
+            area_code: this.getFullAreaCode(data.area_code),
+          };
         });
       }
       done();

--
Gitblit v1.9.3