无人机管理后台前端(已迁走)
罗广辉
2025-12-02 f38d736bb48c2bdef300f571c28b73f96be4de8b
Merge remote-tracking branch 'origin/feature/v8.0/8.0.4' into feature/v8.0/8.0.4
9 files modified
1 files added
233 ■■■■■ changed files
src/assets/images/layerManagement/disabled.svg 23 ●●●●● patch | view | raw | blame | history
src/views/algorithmMange/algorithmMange.vue 3 ●●●● patch | view | raw | blame | history
src/views/dataCenter/dataCenter.vue 2 ●●● patch | view | raw | blame | history
src/views/device/airport.vue 26 ●●●● patch | view | raw | blame | history
src/views/job/components/DeviceJobDetails.vue 47 ●●●● patch | view | raw | blame | history
src/views/job/components/SearchBox.vue 40 ●●●● patch | view | raw | blame | history
src/views/layerManagement/components/leftList.vue 14 ●●●● patch | view | raw | blame | history
src/views/layerManagement/components/rightEdit.vue 11 ●●●●● patch | view | raw | blame | history
src/views/layerManagement/index.vue 15 ●●●● patch | view | raw | blame | history
src/views/resource/patchManagement.vue 52 ●●●● patch | view | raw | blame | history
src/assets/images/layerManagement/disabled.svg
New file
@@ -0,0 +1,23 @@
<svg width="133" height="47" viewBox="0 0 133 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 1321316177">
<g id="Rectangle 34624973" filter="url(#filter0_d_2810_2521)">
<rect x="4" width="125" height="39" rx="4" fill="#A4A4A4"/>
</g>
<path id="&#228;&#191;&#157;&#229;&#173;&#152;" d="M65.584 13.17L67.124 13.674C66.76 14.584 66.326 15.536 65.822 16.432V26.19H64.24V18.868C63.89 19.316 63.54 19.736 63.176 20.114C63.022 19.708 62.56 18.812 62.28 18.406C63.582 17.146 64.856 15.158 65.584 13.17ZM68.986 15.214V17.09H73.088V15.214H68.986ZM75.44 21.332H72.64C73.466 22.55 74.67 23.698 75.846 24.384C75.468 24.706 74.936 25.294 74.67 25.714C73.648 24.986 72.626 23.852 71.828 22.606V26.218H70.148V22.676C69.294 23.908 68.23 24.972 67.124 25.686C66.872 25.28 66.354 24.678 65.976 24.356C67.236 23.698 68.482 22.564 69.35 21.332H66.48V19.82H70.148V18.56H67.404V13.758H74.754V18.56H71.828V19.82H75.44V21.332ZM89.23 16.544H81.768C81.292 17.552 80.732 18.518 80.074 19.414V26.19H78.394V21.304C77.974 21.682 77.554 22.018 77.078 22.34C76.91 21.906 76.546 21.164 76.294 20.744C77.806 19.75 79.024 18.224 79.878 16.544H76.798V14.948H80.592C80.816 14.332 81.012 13.73 81.166 13.128L82.902 13.548C82.762 14.024 82.594 14.472 82.426 14.948H89.23V16.544ZM89.44 21.15V22.704H86.122V24.454C86.122 25.294 85.982 25.728 85.38 25.98C84.792 26.204 83.966 26.232 82.846 26.218C82.79 25.742 82.594 25.098 82.384 24.622C83.084 24.664 83.91 24.664 84.134 24.664C84.372 24.65 84.442 24.594 84.442 24.412V22.704H80.886V21.15H84.442V20.17C84.876 19.904 85.338 19.526 85.772 19.134H81.978V17.636H87.298L87.648 17.538L88.698 18.392C87.984 19.148 87.046 19.974 86.122 20.618V21.15H89.44Z" fill="white"/>
<g id="Frame">
<path id="Vector" d="M47.3855 24.4975C47.1585 24.4975 46.9402 24.4126 46.7756 24.2584L42.0787 19.8785C41.7269 19.551 41.7148 19.007 42.0509 18.664C42.387 18.3209 42.9467 18.3105 43.2984 18.638L47.3093 22.3786L54.5843 13.7695C54.8944 13.4039 55.4506 13.3502 55.8266 13.6517C56.2025 13.9531 56.2562 14.4937 55.9478 14.861L48.0681 24.1857C47.9122 24.371 47.6835 24.4837 47.4392 24.4975H47.3855Z" fill="white"/>
</g>
</g>
<defs>
<filter id="filter0_d_2810_2521" x="0" y="0" width="133" height="47" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2810_2521"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2810_2521" result="shape"/>
</filter>
</defs>
</svg>
src/views/algorithmMange/algorithmMange.vue
@@ -25,7 +25,7 @@
    <div class="mange-table">
            <el-table border :data="tableList" class="ztzf-table-mange">
                <el-table-column label="序号" type="index" width="60"></el-table-column>
        <el-table-column prop="model_name" label="算法名称" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="alg_name" label="算法名称" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="alg_type" label="算法类型" align="center"></el-table-column>
                <el-table-column prop="qua_rate" label="最低准确率" align="center">
          <template #header>
@@ -48,6 +48,7 @@
            {{ scope.row.event_type == 0 ? '常规类' : '紧急类' }}
          </template>
        </el-table-column>
        <el-table-column prop="version" label="算法版本" align="center"/>
                <el-table-column prop="remark" label="算法描述" show-overflow-tooltip />
                <el-table-column label="操作" width="180" align="center">
                    <template #default="scope">
src/views/dataCenter/dataCenter.vue
@@ -304,7 +304,7 @@
      >
        <div class="video-container">
          <video
            style="width: 100%"
            style="width: 100%;height: 500px"
            class="videoBox"
            ref="videoRefs"
            controls
src/views/device/airport.vue
@@ -64,31 +64,33 @@
            </el-icon>更多</el-button>
          <template #dropdown v-if="scope.row.domain == 3">
            <el-dropdown-menu teleported>
              <el-dropdown-item command="a">
                <el-button type="primary" text icon="el-icon-paperclip" v-if="permission.oss_set"
              <el-dropdown-item command="a" v-if="permission.oss_set">
                <el-button type="primary" text icon="el-icon-paperclip"
                  @click.stop="handleOpenOssSet(scope.row, scope.index)">存储配置</el-button>
              </el-dropdown-item>
              <el-dropdown-item command="b">
                <el-button type="primary" text icon="el-icon-share" v-if="permission.per_share && scope.row.domain == 3"
              <el-dropdown-item command="b" v-if="permission.per_share && scope.row.domain == 3">
                <el-button type="primary" text icon="el-icon-share"
                  @click.stop="handleOpenDevicePerShare(scope.row, scope.index)">机场授权</el-button>
              </el-dropdown-item>
              <el-dropdown-item command="c"> <el-button type="primary" text icon="el-icon-position"
                  :disabled="!scope.row.status" v-if="permission.rang_con && scope.row.domain == 3"
              <el-dropdown-item command="c" v-if="permission.rang_con && scope.row.domain == 3">
                <el-button type="primary" text icon="el-icon-position"
                  :disabled="!scope.row.status"
                  @click.stop="handleOpenRemoteDebugging(scope.row, scope.index)">远程调试</el-button>
              </el-dropdown-item>
              <el-dropdown-item command="d"><el-button type="primary" text icon="el-icon-collection"
                  v-if="permission.fly_device_offline" @click.stop="rollFirmware(scope.row)">固件版本管理</el-button>
              <el-dropdown-item command="d" v-if="permission.fly_device_offline">
                <el-button type="primary" text icon="el-icon-collection"
                   @click.stop="rollFirmware(scope.row)">固件版本管理</el-button>
              </el-dropdown-item>
              <el-dropdown-item command="d" v-if="!scope.row.status">
                <el-button type="primary" text icon="el-icon-collection" @click.stop="dockNotLine(scope.row)">
                  {{ scope.row.hidden_flag === 1 ? '设备上线' : '设备下线' }}
                </el-button>
              </el-dropdown-item>
              <el-dropdown-item command="e"><el-button type="primary" text icon="el-icon-document-delete"
                  v-if="permission.fly_device_offline && scope.row.mode_code !==0" @click.stop="handleDeviceOffline(scope.row)">注销</el-button>
              <el-dropdown-item command="e" v-if="permission.fly_device_offline && scope.row.mode_code !==0">
                <el-button type="primary" text icon="el-icon-document-delete" @click.stop="handleDeviceOffline(scope.row)">注销</el-button>
              </el-dropdown-item>
              <el-dropdown-item command="e">
                <el-button type="primary" text icon="el-icon-document-delete" v-if="permission.fly_device_offline"
              <el-dropdown-item command="e" v-if="permission.fly_device_offline">
                <el-button type="primary" text icon="el-icon-document-delete"
                  :disabled="scope.row.dem_status === 1" @click.stop="handleStatus(scope.row)">
                  {{ scope.row.dem_status === 0 ? '初始化地形' : (scope.row.dem_status === 1 ? '初始化中' : '更新地形') }}
                </el-button>
src/views/job/components/DeviceJobDetails.vue
@@ -99,28 +99,7 @@
                fit="cover"
              />
              <el-dialog
                class="ztzf-dialog"
                append-to-body
                modal-class="detailsOfHistoricalTasks"
                v-model="VideoShow"
                :width="pxToRem(1600)"
                :close-on-click-modal="false"
                :destroy-on-close="true"
              >
                <div class="fullscreen">
                  <video
                    ref="fullscreenVideo"
                    class="fullscreen-video"
                    :src="currentVideoUrl"
                    :style="{ width: pxToRem(1567), height: '80vh' }"
                    controls
                    preload="auto"
                    @play="handleVideoPlay"
                    @ended="handleVideoEnded"
                  ></video>
                </div>
              </el-dialog>
            </div>
          </template>
@@ -145,6 +124,28 @@
      </div>
    </div>
  </el-dialog>
    <el-dialog
        class="ztzf-dialog"
        append-to-body
        modal-class="detailsOfHistoricalTasks"
        v-model="VideoShow"
        :width="pxToRem(1600)"
        :close-on-click-modal="false"
        :destroy-on-close="true"
      >
        <div class="fullscreen">
          <video
            ref="fullscreenVideo"
            class="fullscreen-video"
            :src="currentVideoUrl"
            :style="{ width: pxToRem(1567), height: '80vh' }"
            controls
            preload="auto"
            @play="handleVideoPlay"
            @ended="handleVideoEnded"
          ></video>
        </div>
      </el-dialog>
  <!-- 全景360 -->
  <PanoramaPopup
    v-if="'全景'"
@@ -205,11 +206,11 @@
  { name: '任务类型', value: '', field: 'industry_type_str' },
  { name: '飞行事件', value: '', field: 'event_number' },
  { name: '所属机巢', value: '', field: 'device_names' },
  { name: '创建人', value: '', field: 'creator_name' },
  { name: '所属部门', value: '', field: 'dept_name' },
  { name: '任务时间', value: '', field: 'cycle_time_value' },
  { name: '关联算法', value: '', field: 'ai_type_str' },
  { name: '自定义识别区', value: '', field: 'enable_custom_area' },
  { name: '创建人', value: '', field: 'creator_name' },
  { name: '任务描述', value: '', field: 'remark' },
  // { name: '任务执行次数', value: '', field: 'job_num' },
])
src/views/job/components/SearchBox.vue
@@ -320,27 +320,47 @@
let timeListEnum = ['TODAY', 'CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR'];
let checked = ref('month');
// 根据 周期 获取时间段
function getDateRange(date_enum) {
  // 设置对应的日期范围
  switch (date_enum) {
    case 'today':
      dateRange.value = [dayjs().startOf('day').format(timeFormat), dayjs().endOf('day').format(timeFormat)]
      break
    case 'week':
      dateRange.value = [dayjs().startOf('week').format(timeFormat), dayjs().format(timeFormat)]
      break
    case 'month':
      dateRange.value = [dayjs().startOf('month').format(timeFormat), dayjs().format(timeFormat)]
      break
    case 'year':
      dateRange.value = [dayjs().startOf('year').format(timeFormat), dayjs().format(timeFormat)]
      break
  }
}
let timeClick = (item, index) => {
  if (checked.value === item){
  if (checked.value === item) {
    checked.value = null
    searchForm.date_enum = undefined
  }else{
    dateRange.value = []
  } else {
    checked.value = item
    searchForm.date_enum = timeListEnum[index]
    getDateRange(item)
  }
  dateRange.value = []
  handleSearch()
};
}
// 搜索
const handleSearch = () => {
  if (!dateRange.value) {
    dateRange.value = [];
  }
  if (dateRange.value && dateRange.value.length) {
    // 有值时 清除 日 本周 本月 本年状态
    checked.value = '';
    searchForm.date_enum = '';
  }
  // if (dateRange.value && dateRange.value.length) {
  //   // 有值时 清除 日 本周 本月 本年状态
  //   checked.value = '';
  //   searchForm.date_enum = '';
  // }
  // 提交至store
  let params = {
    ...searchForm,
@@ -446,6 +466,8 @@
    dateRange.value = dateArray;
    const find = store.state.tags.bsTagList.find(i => i.path === '/job/jobstatistics')
          find && (find.query = {})
  } else {
    getDateRange('month')
  }
      // 查询一次
    handleSearch()
src/views/layerManagement/components/leftList.vue
@@ -127,7 +127,17 @@
    loading.value = true;
    const res = await treeDataApi();
    treeAllData.value = res.data.data;
    if(coverData.value.length===0){
       checkedKeys.value = [];
    checkedNodes.value = [];
    coverData.value = [];
     nextTick(() => {
      if (treeRef.value) {
        treeRef.value.setCheckedKeys([]);
      }
    });
    }
    setupWatch();
  } catch (error) {
    console.error('获取数据失败:', error);
@@ -213,7 +223,6 @@
  const currentCheckedKeys = [...checkedKeys.value];
  const currentCheckedNodes = [...checkedNodes.value];
  EventBus.emit('focusOnNode', node.data);
  if (node.data.level === 2) {
    const folderChildren = node.data.children || [];
    const childrenIds = folderChildren.map(child => child.id);
@@ -267,6 +276,7 @@
// 删除按钮事件
const handleDelete = node => {
  let id = node.data.id;
  ElMessageBox.confirm('确定要删除该内容吗?', '提示', {
    confirmButtonText: '确定',
src/views/layerManagement/components/rightEdit.vue
@@ -122,8 +122,9 @@
      </div>
    </div>
    <div class="btnGroups">
      <img v-if="!layerParams.editingIsProhibited" src="/src/assets/images/layerManagement/savebtn.svg" alt="" @click="submitHandle" />
     <img v-if="layerParams.editingIsProhibited" src="/src/assets/images/layerManagement/closeBtn.svg" @click="cancelHandel" alt="" />
      <img v-if="!layerParams.editingIsProhibited && layerParams.fenceArea / 1000000 > 50" src="/src/assets/images/layerManagement/disabled.svg" alt="" />
      <img v-if="!layerParams.editingIsProhibited && layerParams.fenceArea / 1000000 < 50" src="/src/assets/images/layerManagement/savebtn.svg" alt="" @click="submitHandle" />
      <img v-if="layerParams.editingIsProhibited" src="/src/assets/images/layerManagement/closeBtn.svg" @click="cancelHandel" alt="" />
      <img v-else src="/src/assets/images/layerManagement/cancelbtn.svg" @click="cancelHandel" alt="" />
      
    </div>
@@ -168,8 +169,10 @@
  () => layerParams.value.fenceArea,
  newArea => {
    if (newArea !== undefined && newArea !== null) {
      fenceArea.value = newArea;
      formData.value.area = newArea;
      if (newArea / 1000000 < 50) {
        fenceArea.value = newArea;
        formData.value.area = newArea;
      }
    }
  },
  { immediate: true }
src/views/layerManagement/index.vue
@@ -15,7 +15,7 @@
          <span class="icon">
            <el-icon><WarningFilled /></el-icon>
          </span>
          <span>测区不支持交叉面</span>
          <span>{{ showWarnToolTipText }}</span>
        </div>
         <div class="tool-tip" v-if="!isShowWaringTip && layerParams.addNest">
          {{ showToolTipText }}
@@ -72,6 +72,7 @@
const userInfo = computed(() => store.getters.userInfo);
const areaCode = userInfo.value?.detail?.areaCode || '';
const showToolTipText = ref('点击地图生成测绘区域')
const showWarnToolTipText = ref('测区不支持交叉面')
// 红色警告交叉面提示窗
const isShowWaringTip = ref(false);
const activeName = ref('自定义识别区');
@@ -417,7 +418,7 @@
  }
  if(polygon.length > 0 && !isShowWaringTip.value){
    showToolTipText.value = '测绘区域已绘制完成'
  }else {
  } else {
    showToolTipText.value = '点击地图生成测绘区域'
  }
@@ -436,13 +437,20 @@
    const closedPolygon = isClosed ? polygon : [...polygon, firstPoint];
    const turfPolygon = turf.polygon([closedPolygon]);
    const area = _.round(turf.area(turfPolygon), 2);
    layerParams.value.fenceArea = area;
    if (area / 1000000 < 50) {
      layerParams.value.fenceArea = area;
    } else {
      layerParams.value.fenceArea = area;
      isShowWaringTip.value = true
      showWarnToolTipText.value = '自定义禁飞区不能超过50平方公里'
    }
  } else {
    layerParams.value.fenceArea = 0;
  }
};
drawPolygonExample.subscribe('getShowWaringTip', data => {
  isShowWaringTip.value = data;
  showWarnToolTipText.value = '测区不支持交叉面'
  layerParams.value.crossSurface = data
});
const throttleLoadPlanarRoute = throttle(loadPlanarRoute, 200);
@@ -538,6 +546,7 @@
  });
  // 更新选中数据列表
  selectDataList.value = selectDataList.value.filter(item => item.folder_id !== folderId);
  getdataFolderApi()
};
</script>
src/views/resource/patchManagement.vue
@@ -510,44 +510,48 @@
  });
};
// 图斑上传
const uploadFlightFile = (file, t) => {
const uploadFlightFile = async (file, t) => {
  loading.value = true;
  const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1);
  if (!['kmz', 'kml', 'zip'].includes(fileSuffix)) {
    return ElMessage.error('请上传zip/kmz/kml格式的文件');
  }
  if (file) {
    box.value = false;
  }
  let data = new FormData();
  let type = t === '3' ? '' : t;
  const params = {
    file: file,
    fileName: ruleForm.name,
    LotTypeId: ruleForm.region,
  };
  try {
    const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1);
    if (!['kmz', 'kml', 'zip'].includes(fileSuffix)) {
      ElMessage.error('请上传zip/kmz/kml格式的文件');
      return;
    }
    box.value = false;
    let data = new FormData();
    let type = t === '3' ? '' : t;
    const params = {
      file: file,
      fileName: ruleForm.name,
      LotTypeId: ruleForm.region,
    };
  Object.keys(params).forEach(key => {
    data.append(key, params[key]);
  });
    Object.keys(params).forEach(key => {
      data.append(key, params[key]);
    });
  uploadManagementApi(data).then(res => {
    const res = await uploadManagementApi(data);
    if (res.data.code !== 0) {
      return ElMessage.error('上传失败');
      ElMessage.error('上传失败');
      return;
    }
    ElMessage.success('上传成功');
    loading.value = false;
    // 重置表单
    ruleForm.name = '';
    ruleForm.region = '';
    if (ruleFormRef.value) {
      ruleFormRef.value.resetFields();
    }
    searchReset();
  });
  } catch (error) {
     loading.value = false;
  } finally {
    loading.value = false;
  }
};
provide('searchReset', searchReset);
onMounted(() => {