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 |  623 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 600 insertions(+), 23 deletions(-)

diff --git a/src/views/device/airport.vue b/src/views/device/airport.vue
index 5b630a2..e751aec 100644
--- a/src/views/device/airport.vue
+++ b/src/views/device/airport.vue
@@ -57,43 +57,89 @@
       <template #firmware_status="{ row }">
         <div
           v-if="row.firmware_status == 1"
-          style="display: flex; flex-direction: row; align-items: center"
+          style="display: flex; flex-direction: column; align-items: center"
         >
-          <div style="background-color: #f1f1f1; border-radius: 4px">无需升级</div>
+          <el-tag type="info">无需升级</el-tag>
+          <el-tag type="primary" effect="dark" class="active-element" @click="rollFirmware(row)"
+            >版本管理</el-tag
+          >
+          <!-- <div style="background-color: #f1f1f1; border-radius: 4px">无需升级</div> -->
         </div>
         <div
           v-if="row.firmware_status == 2"
-          style="display: flex; flex-direction: row; align-items: center"
+          style="display: flex; flex-direction: column; align-items: center"
         >
-          <div @click="updateFirmware(row)" class="firmware_status">升级固件</div>
+          <!-- <el-tag type="success" effect="dark" class="active-element" @click="updateFirmware(row)"
+            >升级固件</el-tag
+          > -->
+          <el-tag type="primary" effect="dark" class="active-element" @click="rollFirmware(row)"
+            >版本管理</el-tag
+          >
+          <!-- <div @click="updateFirmware(row)" class="firmware_status">升级固件</div> -->
         </div>
         <div
           v-if="row.firmware_status == 3"
           style="display: flex; flex-direction: row; align-items: center"
         >
-          <span style="margin-left: 5px">一致性升级</span>
+          <el-tag type="success" effect="dark" class="active-element" @click="updateFirmware(row)"
+            >一致性升级</el-tag
+          >
+          <!-- <div @click="updateFirmware(row)" class="firmware_status">一致性升级</div> -->
         </div>
         <div
           v-if="row.firmware_status == 4"
           style="display: flex; flex-direction: row; align-items: center"
         >
-          <div style="background-color: #a8cbfb; border-radius: 4px">
-            升级中
-            <el-progress  v-if="row.firmware_progress>0 && row.firmware_progress<100" :percentage="row.firmware_progress"></el-progress>
-          </div>
+          <el-tag effect="dark" class="active-element" @click="updateFirmware(row)">升级中</el-tag>
+          <el-progress
+            v-if="row.firmware_progress > 0 && row.firmware_progress < 100"
+            :percentage="row.firmware_progress"
+          ></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"
+          text
+          icon="el-icon-share"
+          v-if="permission.per_share && scope.row.domain == 3"
+          @click.stop="handleOpenDevicePerShare(scope.row, scope.index)"
+          >机场授权
+        </el-button>
+
+        <el-button
+          type="primary"
+          text
+          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>
       </template>
+      <!-- 添加行政区划显示模板 -->
+      <template #area_code="{ row }">
+        <span>{{ row.area_name }}</span>
+      </template>
     </avue-crud>
+
     <el-dialog title="固件升级" append-to-body v-model="firmwareBox" width="455px">
       <div>升级固件版本:{{ firmwareVersion }}</div>
       <template #footer>
@@ -103,14 +149,84 @@
         </span>
       </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">
+        固件版本升级/回退:
+        <el-select
+          v-model="rollFirmVersion"
+          clearable
+          placeholder="请选择固件版本"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="item in firmList"
+            :key="item.firmware_version"
+            :label="item.firmware_version"
+            :value="item.firmware_version"
+          />
+        </el-select>
+      </div>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="rollFirmwareBox = false">取 消</el-button>
+          <el-button type="primary" @click="rollFirmwareConfirm">确 定</el-button>
+        </span>
+      </template>
+    </el-dialog>
+
     <el-drawer
-      title="固件管理"
+      title="机场授权管理"
       size="60%"
       append-to-body
-      v-model="firmwareManageVisible"
+      v-model="devicePerShareVisible"
       :direction="'rtl'"
     >
-      <FirmwareManage ref="firmwareManage" />
+      <DevicePerShare ref="devicePerShare" />
+    </el-drawer>
+
+    <el-drawer :title="operateTitle" append-to-body v-model="remoteDebuggingShow" size="40%">
+      <DockControlPanel
+        v-if="remoteDebuggingShow"
+        :sn="curDeviceInfo.device_sn"
+        :deviceInfo="curDeviceInfo"
+      >
+      </DockControlPanel>
     </el-drawer>
   </basic-container>
 </template>
@@ -124,15 +240,45 @@
   getDetail,
   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';
+import DockControlPanel from './components/DockControlPanel.vue';
+import { getWebsocketUrl } from '@/websocket/util/config';
+import ConnectWebSocket from '@/websocket';
 export default {
   components: {
     FirmwareManage,
+    DevicePerShare,
+    DockControlPanel,
   },
   data() {
     return {
+      bindOssId: null,
+      deviceSn: '',
+      ossSetBox: false,
+      ossList: [],
+      ossEnd: '',
+      operateTitle: '',
+      rollFirmVersion: '',
+      firmList: [],
+      rollFirmwareBox: false,
+      // 用于记录已经创建的websocket,防止重复创建
+      webSocketIdSet: new Set(),
+      // 用于保存多组websocket
+      websocketMap: new Map(),
+      scheduleNum: 0,
+      webSocket: '',
+      devicePerShareVisible: false,
+      remoteDebuggingShow: false,
+      curDeviceInfo: {},
       firmwareManageVisible: false,
       percentageNum: 0,
       firmwareBox: false,
@@ -152,7 +298,7 @@
         tree: true,
         height: '460',
         calcHeight: 32,
-        dialogWidth: 950,
+        dialogWidth: 1050,
         tip: false,
         searchShow: true,
         searchMenuSpan: 6,
@@ -199,6 +345,7 @@
             label: '机巢编号',
             prop: 'machine_nest_sn',
             labelWidth: 130,
+            editDisabled: true,
             rules: [
               {
                 required: false,
@@ -306,6 +453,74 @@
             ],
           },
           {
+            label: '行政区划',
+            prop: 'area_code',
+            type: 'cascader',
+            labelWidth: 130,
+            hide: true,
+            props: {
+              label: 'title',
+              value: 'value',
+              emitPath: false,
+              checkStrictly: true,
+              multiple: false,
+              expandTrigger: 'hover',
+            },
+            dataType: 'string',
+            rules: [
+              {
+                required: true,
+                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 => ({
+                    ...ele,
+                    value: ele.value,
+                    leaf: level >= 2,
+                  }))
+                );
+              };
+
+              if (level === 0) {
+                getLazyTree('000000000000').then(res => {
+                  list = res.data.data;
+                  callback();
+                });
+              } 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();
+                });
+              } else {
+                callback();
+              }
+            },
+          },
+          {
             label: '在线时间',
             prop: 'login_time',
             type: 'date',
@@ -336,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',
               },
             ],
@@ -375,9 +606,109 @@
       return ids.join(',');
     },
   },
+  destroyed() {
+    this.websocketMap.forEach((k, v) => {
+      if (null != v) {
+        v.close();
+        this.websocketMap.delete(k);
+        this.webSocketIdSet.delete(k);
+      }
+    });
+  },
   methods: {
+    getDockModeText(value) {
+      return EDockModeText[value] || '';
+    },
+    // 关闭所有的webscoket
+    closeAllWebsoket() {
+      this.websocketMap.forEach((k, v) => {
+        if (null != v) {
+          v.close();
+          this.websocketMap.delete(k);
+          this.webSocketIdSet.delete(k);
+        }
+      });
+    },
+    // 连接webSocket
+    connectWebSocket(data) {
+      const webSocketId = data.workspace_id;
+      if (!this.webSocketIdSet.has(webSocketId)) {
+        // 防止重复连接
+        this.webSocketIdSet.add(webSocketId);
+        const webSorketUrl = getWebsocketUrl() + '&workspace-id=' + data.workspace_id;
+        // 监听ws 消息
+        this.useConnectWebSocket(webSocketId, webSorketUrl);
+      }
+    },
+    useConnectWebSocket(webSocketId, url) {
+      const websocket = new ConnectWebSocket(url);
+      // 加入 webscoket map
+      this.websocketMap.set(webSocketId, websocket);
+      websocket?.registerMessageHandler(this.messageHandler);
+      websocket?.initSocket();
+    },
+    async messageHandler(payload) {
+      if (!payload) {
+        return;
+      }
+      if (payload.biz_code != 'ota_progress') {
+        return;
+      }
+      var data = payload.data;
+      this.data.forEach(e => {
+        if (e.device_sn == data.sn && data.output.status == 'in_progress') {
+          e.firmware_progress = data.output.progress.percent;
+        }
+
+        if (e.device_sn == data.sn && data.output.status == 'ok') {
+          // 升级完成修改状态
+          e.firmware_status = 1;
+          const webscoket = this.websocketMap.get(e.workspace_id);
+          // 关闭
+          webscoket?.close();
+          //删除对应的webscoket
+          this.websocketMap.delete(e.workspace_id);
+          this.webSocketIdSet.delete(e.workspace_id);
+        }
+      });
+    },
     init() {
-      this.onLoad(this.page);
+      (this.page = {
+        pageSize: 10,
+        currentPage: 1,
+        total: 0,
+      }),
+        this.onLoad(this.page);
+    },
+    // 打开权限分享页面
+    handleOpenDevicePerShare(row) {
+      var that = this;
+      this.devicePerShareVisible = true;
+      this.$nextTick(() => {
+        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) {
@@ -385,6 +716,144 @@
       this.firmwareManageVisible = true;
       this.$nextTick(() => {
         that.$refs.firmwareManage.init(row);
+      });
+    },
+    // 版本回退点击事件
+    rollFirmware(row) {
+      if (row.status == 0) {
+        this.$message({
+          type: 'warning',
+          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;
+      const param = {
+        device_name: row.device_name,
+      };
+      // 获取固件最新版本信息
+      getDeviceFirmwareList(1, 20, param).then(res => {
+        that.firmList = [];
+        const data = res.data.data.records;
+        if (data.length === 0) {
+          return;
+        }
+        data.forEach(e => {
+          if (e.firmware_version != row.firmware_version) {
+            that.firmList.push(e);
+          }
+        });
+        that.firmwareInfo['device_name'] = row.device_name;
+        that.firmwareInfo['sn'] = row.device_sn;
+        // 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 == '') {
+        this.$message({
+          type: 'warning',
+          message: '请先选择回退的固件版本!',
+        });
+        return;
+      }
+      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 = {};
+        that.rollFirmwareBox = false;
+        this.$message({
+          type: 'success',
+          message: '操作成功!',
+        });
+        this.onLoad(this.page);
+        done();
       });
     },
     // 升级固件按钮事件
@@ -411,7 +880,7 @@
         that.firmwareInfo['device_name'] = row.device_name;
         that.firmwareInfo['sn'] = row.device_sn;
         that.firmwareInfo['product_version'] = data[0].product_version;
-        // 1-普通升级,2-一致性升级;
+        // 3-普通升级,2-一致性升级;
         that.firmwareInfo['firmware_upgrade_type'] =
           row.firmware_status === that.DeviceFirmwareStatusEnum.ToUpgraded
             ? that.DeviceFirmwareTypeEnum.ToUpgraded
@@ -436,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);
@@ -453,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({
@@ -524,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();
@@ -542,6 +1106,7 @@
       this.onLoad(this.page, this.query);
     },
     onLoad(page, params = {}) {
+      // this.closeAllWebsoket();
       const { releaseTimeRange } = this.query;
       let values = {
         ...params,
@@ -562,6 +1127,9 @@
         this.page.total = data.total;
         data.records.forEach(e => {
           e['hasChildren'] = e.has_children;
+          if (e.firmware_status == 4) {
+            this.connectWebSocket(e);
+          }
         });
         this.data = data.records;
         this.loading = false;
@@ -573,14 +1141,15 @@
         childSn: tree.child_sn,
       };
       getList(1, 10, params).then(res => {
-        resolve(res.data.data.records);
+        const data = res.data.data.records;
+        resolve(data);
       });
     },
   },
 };
 </script>
 
-<style>
+<style lang="scss" scoped>
 .firmware_status {
   background-color: aqua;
   border-radius: 4px;
@@ -589,4 +1158,12 @@
   cursor: pointer;
   /* color: aqua; */
 }
+
+.active-element {
+  cursor: pointer;
+  &:hover {
+    background-color: #409eff;
+    border-color: #409eff;
+  }
+}
 </style>

--
Gitblit v1.9.3