无人机管理后台前端(已迁走)
张含笑
2025-08-22 ec1f38facb39dec5ac1d172a9518bda46a1ab9f6
Merge remote-tracking branch 'origin/feature/v5.0/5.0.4' into feature/v5.0/5.0.4
11 files modified
239 ■■■■ changed files
src/api/dataCenter/dataCenter.js 3 ●●●● patch | view | raw | blame | history
src/axios.js 2 ●●● patch | view | raw | blame | history
src/page/index/setting.vue 4 ●●●● patch | view | raw | blame | history
src/views/dataCenter/components/dataCenterMap.vue 20 ●●●●● patch | view | raw | blame | history
src/views/dataCenter/components/searchData.vue 46 ●●●●● patch | view | raw | blame | history
src/views/dataCenter/dataCenter.vue 42 ●●●● patch | view | raw | blame | history
src/views/job/components/JobRelatedEvents.vue 4 ●●●● patch | view | raw | blame | history
src/views/job/components/SearchBox.vue 55 ●●●●● patch | view | raw | blame | history
src/views/job/components/TaskTop/TaskTime.vue 2 ●●●●● patch | view | raw | blame | history
src/views/tickets/orderLog.vue 9 ●●●●● patch | view | raw | blame | history
src/views/tickets/ticket.vue 52 ●●●● patch | view | raw | blame | history
src/api/dataCenter/dataCenter.js
@@ -87,6 +87,7 @@
        url: `/drone-device-core/wayline/api/v1/workspaces/getJobIdsBySn`,
        method: 'get',
        params,
        customize: params.areaCode
    })
}
// 附件下载
@@ -104,4 +105,4 @@
        method: 'post',
        data: data,
    })
}
}
src/axios.js
@@ -41,7 +41,7 @@
      config.url = baseUrl + config.url;
    }
    //安全请求header
    config.headers['areaCode'] = store?.state?.user?.userInfo?.detail?.areaCode;
    config.headers['areaCode'] = config?.params?.areaCode || store?.state?.user?.userInfo?.detail?.areaCode;
    config.headers['Blade-Requested-With'] = 'BladeHttpRequest';
    //headers判断是否需要
    const authorization = config.authorization === false;
src/page/index/setting.vue
@@ -1,11 +1,11 @@
<template>
  <el-button
<!--  <el-button
    @click="show = true"
    class="setting-icon"
    type="primary"
    icon="el-icon-setting"
    circle
  ></el-button>
  ></el-button>-->
  <el-drawer append-to-body :with-header="false" v-model="show" size="30%">
    <div class="setting">
<!--      <h5>导航模式</h5>
src/views/dataCenter/components/dataCenterMap.vue
@@ -1,5 +1,10 @@
<template>
  <el-dialog modal-class="mapDialog" v-model="isShow" width="80%">
  <el-dialog modal-class="mapDialog"  v-model="isShow" width="80%">
     <template #header="{ titleId, titleClass }">
          <div class="my-header">
            <h4 :id="titleId" :class="titleClass">定位</h4>
          </div>
        </template>
    <div class="mapBox">
      <div v-if="isShow" id="dataCenterMap" class="ztzf-cesium"></div>
    </div>
@@ -318,4 +323,17 @@
    height: 100%;
  }
}
.my-header :deep(.el-dialog__title) {
  margin: 0 !important;
  height: 19px;
}
.my-header {
  display: flex;
  align-items: center;
  .el-button {
    margin-left: 20px;
  }
}
</style>
src/views/dataCenter/components/searchData.vue
@@ -3,8 +3,8 @@
    <el-form :model="searchForm" inline>
      <div class="search-first">
        <el-form-item label="行政区划:" >
          <el-tree-select
          :disabled="foldersDisabled"
          <el-tree-select
          :disabled="viewDetailsDisabled"
            popper-class="custom-tree-select"
            v-model="searchForm.areaCode"
            :data="deptTreeData"
@@ -17,7 +17,7 @@
        </el-form-item>
        <el-form-item label="所属机巢:">
          <el-select
          :disabled="foldersDisabled"
          :disabled="viewDetailsDisabled"
            :teleported="false"
            v-model="searchForm.deviceSn"
            placeholder="请选择"
@@ -33,10 +33,11 @@
          </el-select>
        </el-form-item>
        <el-form-item label="任务名称:">
          <el-input v-model="searchForm.jobName" placeholder="请输入" clearable />
          <el-input  :disabled="viewDetailsDisabled" v-model="searchForm.jobName" placeholder="请输入" clearable />
        </el-form-item>
        <el-form-item>
          <el-date-picker
           :disabled="viewDetailsDisabled"
            popper-class="custom-date-picker"
            v-model="dateRange"
            type="daterange"
@@ -61,7 +62,7 @@
        </el-form-item>
        <el-form-item label="文件格式:">
          <el-select
          :disabled="foldersDisabled"
          :disabled="foldersDisabled || viewDetailsDisabled"
            :teleported="false"
            v-model="searchForm.resultType"
            placeholder="请选择"
@@ -80,7 +81,7 @@
        <el-form-item label="文件类别:">
          <el-select
          
            :disabled="disabled || foldersDisabled"
            :disabled="disabled || foldersDisabled || viewDetailsDisabled"
            :teleported="false"
            v-model="searchForm.photoType"
            placeholder="请选择"
@@ -99,11 +100,11 @@
      </div>
      <div class="search-first">
        <el-form-item label="文件名称:">
          <el-input :disabled="foldersDisabled" v-model="searchForm.name" placeholder="请输入" clearable />
          <el-input :disabled="foldersDisabled || viewDetailsDisabled" v-model="searchForm.name" placeholder="请输入" clearable />
        </el-form-item>
        <div class="search-btn">
          <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
          <el-button icon="el-icon-refresh" @click="handleReset">清空</el-button>
          <el-button  type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
          <el-button  icon="el-icon-refresh" @click="handleReset">清空</el-button>
        </div>
      </div>
      <div class="search-first">
@@ -111,7 +112,7 @@
<!--          <el-button type="primary" icon="el-icon-download" @click="allDownloadFun"-->
<!--            >全部下载</el-button-->
<!--          >-->
        <el-button type="primary" plain  @click="handleswitchFolders" ><el-icon><FolderOpened /></el-icon></el-button>
        <el-button v-if="!viewDetailsDisabled" type="primary" plain  @click="handleswitchFolders" ><el-icon><FolderOpened /></el-icon></el-button>
          <div class="downloadBtn" @click="htsjzx === 100 && downloadFun()">
            <el-progress v-if="htsjzx !== 100" :percentage="htsjzx" :show-text="false" striped striped-flow :duration="1" />
            <div class="downloadBtnText">
@@ -121,6 +122,7 @@
              </template>
            </div>
          </div>
           <el-button v-if="viewDetailsDisabled" type="primary" plain  @click="handleBack" >返回</el-button>
        </div>
      </div>
    </el-form>
@@ -140,13 +142,13 @@
const userAreaCode = computed(() => store.getters.userInfo.detail.areaCode);
const selectedAreaCode = computed(() => store.state.user.selectedAreaCode);
const htsjzx = computed(() => store.state.common.downloadProgress?.htsjzx || 100)
const emit = defineEmits(['search', 'downFun', 'allDownFun','handleswitchFolders']);
const emit = defineEmits(['search', 'Reset','downFun', 'allDownFun','handleswitchFolders','handleBack']);
const startTime = dayjs().subtract(6, 'day').startOf('day');
const endTime = dayjs().endOf('day');
const timeRange = [startTime.format('YYYY-MM-DD HH:mm:ss'), endTime.format('YYYY-MM-DD HH:mm:ss')];
const dateRange = ref(timeRange);
const timeFormat = 'YYYY-MM-DD HH:mm:ss';
const props = defineProps(['searchjobId','switchFolders'])
const props = defineProps(['searchjobId','switchFolders','viewDetails'])
const searchForm = reactive({
  jobName: '', //任务名称
  name: '', //文件名称
@@ -223,6 +225,14 @@
  foldersDisabled.value = true
}else{
   foldersDisabled.value = false
}
});
const viewDetailsDisabled  = ref(false)
watch(() => props.viewDetails, (newVal) => {
if(newVal === true){
  viewDetailsDisabled.value = true
}else{
   viewDetailsDisabled.value = false
}
});
const changePhotoType =(val)=>{
@@ -323,6 +333,7 @@
  searchForm.wayLineJobId=''
  handleNodeClick({ id: userAreaCode.value });
  handleSearch();
   emit('Reset', searchForm);
};
// 下载
const downloadFun = () => {
@@ -342,7 +353,10 @@
const handleswitchFolders =()=>{
  emit('handleswitchFolders'); 
}
// 返回按钮
const handleBack = ()=>{
  emit('handleBack');
}
onMounted(() => {
  requestDockInfo();
  getDownloadStatusApi({type: 'htsjzx'}).then(res =>{
@@ -352,7 +366,9 @@
  })
});
defineExpose({
  handleReset,
});
</script>
<style scoped lang="scss">
@@ -373,7 +389,7 @@
      margin-right: 32px;
      .downloadBtn{
      margin-left: 10px;
      margin:0 10px;
        position: relative;
        display: flex;
        align-items: center;
src/views/dataCenter/dataCenter.vue
@@ -4,13 +4,16 @@
  >
    <div class="dataCenter-table">
      <searchData
      ref="searchBoxRef"
      :searchjobId="searchjobId"
      :switchFolders="switchFolders"
        @search="searchClick"
        @downFun="downloadFile"
        @allDownFun="aLLDownloadFile"
        @handleswitchFolders="handleswitchFolders"
        @handleBack ="handleBack"
       :viewDetails ="viewDetails"
      ></searchData>
      <!-- 文件夹 -->
      <div v-if="switchFolders" class="dataTable">
@@ -35,7 +38,7 @@
          <el-table-column property="name" label="任务名称" show-overflow-tooltip />    
           <el-table-column property="regionName" label="所属区域">
             <template #default="scope">
              <span>{{scope.row.regionName ? scope.row.regionName :'--'}}</span>
              <span>{{scope.row.city_name ? scope.row.city_name :'--'}},{{scope.row.area_name ? scope.row.area_name :'--'}}</span>
            </template>
            </el-table-column>   
          <el-table-column property="nickname" label="所属机巢" >
@@ -447,7 +450,8 @@
    startTime: jobListParams.searchParams.startTime?.slice(0, 10),
    endTime: jobListParams.searchParams.endTime?.slice(0, 10),
     waylineName:'',
    dockSn:'',
    areaCode:''
});
const tableData = ref([]);
// 获取列表数据
@@ -486,11 +490,11 @@
const folderList = ref([])
// 获取文件夹数据
const getFolderList=()=>{
 loadings.value = true;
 const apiParams = {
    ...FolderListParams,
  };
  getJobIdsBySnApi(apiParams)
    loadings.value = true;
    const apiParams = {
      ...FolderListParams,
      };
    getJobIdsBySnApi(apiParams)
        .then(res => {
    folderList.value = res.data.data.records.map(i => ({ ...i, checked: false }))
    total.value = res.data.data.total  
@@ -500,12 +504,14 @@
        })
}
const searchjobId = ref('')
const viewDetails = ref('')
// 文件夹查看
const foldersOpen = (val)=>{
    loadings.value = true;
    tableData.value=[]
    searchjobId.value = val.job_id
    switchFolders.value = false
    viewDetails.value = true
}
// 获取数据时使用各自的分页参数
const fetchData = () => {
@@ -516,14 +522,26 @@
  }
};
// 切换文件夹
 const handleswitchFolders = (val) => {
 const handleswitchFolders = () => {
 searchjobId.value = ''
     switchFolders.value = !switchFolders.value;
     jobListParams.current = 1;
     FolderListParams.page = 1;
     fetchData();
     searchBoxRef.value?.handleReset();
      fetchData();
   };
   const handleBack =()=>{
    searchjobId.value = ''
    switchFolders.value = true
    viewDetails.value = false
    jobListParams.current = 1;
    FolderListParams.page = 1;
     fetchData();
   }
   const searchBoxRef = ref(null);
// 查询
const searchClick = params => {
  if(switchFolders.value){
@@ -532,6 +550,8 @@
    FolderListParams.startTime = params?.startTime?.slice(0, 10); 
    FolderListParams.endTime = params?.endTime?.slice(0, 10);
    FolderListParams.waylineName=params?.jobName,
   FolderListParams.dockSn = params?.deviceSn
   FolderListParams.areaCode = params?.areaCode
    getFolderList()
  }else{
     jobListParams.current = 1;
src/views/job/components/JobRelatedEvents.vue
@@ -13,7 +13,7 @@
                <div class="itemchild">模糊查询:</div>
                <el-input v-model="params.event_name" placeholder="请输入事件名称" clearable></el-input>
            </div>
            <div class="item">
            <!-- <div class="item">
                <div class="itemchild">任务执行日期:</div>
                <el-date-picker
                    popper-class="custom-date-picker"
@@ -25,7 +25,7 @@
                    :disabled-date="disabledDate"
                    @change="changeselect"
                />
            </div>
            </div> -->
            <div class="item">
                <div class="itemchild">关联算法:</div>
                <TaskAlgorithmBusiness :setWidth="186" :showAlgorithm="true" @algorithmChange="algorithmChange" />
src/views/job/components/SearchBox.vue
@@ -61,13 +61,9 @@
        <div class="more" v-if="isExpand" @click="toggleExpand">收起</div>
        <div class="more" v-else @click="toggleExpand">更多</div>
        <div class="search-btn" :style="{ bottom: isExpand ? '5px' : '-3px' }">
          <div class="btn clear" @click="handleReset">
            <img src="@/assets/images/task/clear.png" />重置
          </div>
          <div class="btn search" @click="handleSearch">
            <img src="@/assets/images/task/search.png" />搜索
          </div>
          <!-- <div class="btn add" @click="addTask"><img src="@/assets/images/task/add.png"/>新增</div> -->
          <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button>
          <el-button icon="el-icon-refresh" @click="handleReset">清空</el-button>
        </div>
        <el-form-item label="任务算法:" v-if="isExpand" class="taskAlgorithm">
          <!-- <TaskAlgorithmBusiness
@@ -77,17 +73,25 @@
            @algorithmChange="algorithmChange"
          /> -->
          <el-tree-select
              popper-class="custom-tree-select"
              :style="{ width: pxToRem(186) }"
              v-model="dictKey"
              :data="dataList"
              :default-expanded-keys="[dictKey]"
              check-strictly
              node-key="id"
              :props="treePropsSF"
              @node-click="handleSFNodeClick"
              clearable
              @clear="handleClear"
          style="z-index: 1000"
            :teleported="false"
            class="custom-tree-select"
            :style="{ width: pxToRem(186) }"
            v-model="dictKey"
            :data="dataList"
            :default-expanded-keys="[dictKey]"
            :props="treePropsSF"
            :render-after-expand="false"
            :default-checked-keys="checkedKeys"
            node-key="id"
            multiple
            show-checkbox
            collapse-tags
            collapse-tags-tooltip
            clearable
            @node-click="handleNodeClick"
            @check="handleCheck"
            @clear="handleClear"
          />
        </el-form-item>
        <!-- <el-form-item label="所属部门:" v-if="isExpand">
@@ -107,6 +111,7 @@
        </el-form-item> -->
        <el-form-item label="任务状态:" v-if="isExpand">
          <el-select
          style="z-index: 1000"
            :teleported="false"
            v-model="searchForm.status"
            placeholder="请选择"
@@ -351,7 +356,9 @@
  searchForm.area_code = userAreaCode.value;
  checked.value = 'month';
  signDevice_sn.value = ''
    algorithmRef.value?.clear()
  // 清除算法
  dictKey.value = '';
    // algorithmRef.value?.clear()
  handleNodeClick({ id: userAreaCode.value });
  handleSearch();
};
@@ -392,6 +399,16 @@
//   { immediate: true, deep: true }
// );
const checkedKeys = ref([])
const handleCheck = (data, { checkedKeys, checkedNodes }) => {
    dictKey.value = checkedKeys
    // 获取所有选中节点的 dictKey
    const selectedDictKeys = checkedNodes.map(node => node.dictKey).filter(Boolean)
  searchForm.ai_types = selectedDictKeys
  handleSearch()
}
onBeforeUnmount(() => {
  checked.value = 'today';
  searchForm.date_enum = 'TODAY';
src/views/job/components/TaskTop/TaskTime.vue
@@ -31,6 +31,8 @@
        formatter: '{b}: {c} 件',
    },
    legend: {
        itemWidth: 8,
        itemHeight: 12,
        top: '2%',
        textStyle: {
            color: '#6B90B5',
src/views/tickets/orderLog.vue
@@ -159,7 +159,7 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="关联航线" prop="file_id">
              <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy">
              <el-select v-model="form.file_id" placeholder="请选择航线" filterable @change="getFlyingNestBy">
                <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name"
                  :value="item.wayline_id" />
              </el-select>
@@ -169,7 +169,7 @@
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="关联机巢" prop="device_sns">
              <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple>
              <el-select v-model="form.device_sns" placeholder="请选择机巢" multiple :disabled="!device_sns.length">
                <el-option v-for="item in device_sns" :key="item.device_sn" :label="item.nickname"
                  :value="item.device_sn" />
              </el-select>
@@ -271,7 +271,7 @@
          </el-col>
          <el-col :span="12">
            <el-form-item label="关联航线" prop="file_id">
              <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy" :disabled="detailTitle === '工单详情'">
              <el-select v-model="form.file_id" placeholder="请选择航线" @change="getFlyingNestBy" filterable :disabled="detailTitle === '工单详情'">
                <el-option v-for="item in wayLineList" :key="item.wayline_id" :label="item.name"
                  :value="item.wayline_id" />
              </el-select>
@@ -663,7 +663,6 @@
        ],
        file_id: [{ required: true, message: '需要选择航线', trigger: 'change' }],
        device_sns: [{ required: true, message: '请选择机巢', trigger: 'change' }],
        ai_types: [{ required: true, message: '请选择算法', trigger: 'change' }],
        content: [
          { required: true, message: '请输入工单内容', trigger: 'blur' },
          { max: 255, message: '工单内容不能超过255个字', trigger: 'blur' },
@@ -888,8 +887,8 @@
          const submitData = {
            ...this.form,
            status: status,
            ai_types: this.form.ai_types?.length ? this.form.ai_types : [],
          }
          // 判断该值this.form.date_range[0] 周几 和rep_fre_type 是不是相等
          // if (this.form.deal_time) {
src/views/tickets/ticket.vue
@@ -83,7 +83,7 @@
                :value="item.dict_key"
              />
            </el-select> -->
            <el-tree-select
            <!-- <el-tree-select
              popper-class="custom-tree-select"
              :style="{ width: pxToRem(186) }"
              placeholder="请选择关联算法"
@@ -96,7 +96,28 @@
              @node-click="handleSFNodeClick"
              clearable
              @clear="handleClear"
          />
            /> -->
            <el-tree-select
              style="z-index: 1000"
              :teleported="false"
              class="custom-tree-select"
              :style="{ width: pxToRem(186) }"
              v-model="dictKey"
              :data="dataList"
              :default-expanded-keys="[dictKey]"
              :props="treePropsSF"
              :render-after-expand="false"
              :default-checked-keys="checkedKeys"
              node-key="id"
              multiple
              show-checkbox
              collapse-tags
              collapse-tags-tooltip
              clearable
              @check="handleCheck"
              @node-click="handleSFNodeClick"
              @clear="handleClear"
            />
            <el-select
              v-model="filters.isReview"
              placeholder="请选择复核状态"
@@ -1133,6 +1154,7 @@
      },
      dictKey: '',
      dataList: [],
      checkedKeys: [],
    };
  },
  created() {
@@ -1416,6 +1438,13 @@
  },
  methods: {
    handleCheck(data, { checkedKeys, checkedNodes }) {
      this.checkedKeys = checkedKeys
      // 获取所有选中节点的 dictKey
      const selectedDictKeys = checkedNodes.map(node => node.dictKey).filter(Boolean)
      this.filters.type = selectedDictKeys
      this.fetchTableData();
    },
    // 算法
    getAlgorithmList() {
      getSFDictionaryTree({code:'SF'}).then((res) => {
@@ -1439,16 +1468,12 @@
    },
    handleSFNodeClick(data) {
      console.log(data.dictKey, '666666666')
      this.filters.type = ''
      this.filters.algorithm = ''
        if (data.children && data.children.length) {
            // 获取子节点dictKey
            this.filters.type = data.dictKey
        } else {
            this.filters.algorithm = data.dictKey
        }
        // 更新列表请求
        this.fetchTableData();
      this.filters.type = data.dictKey
      // 更新列表请求
      this.fetchTableData();
    },
    handleClear() {
        this.dictKey = ''
@@ -1677,7 +1702,7 @@
      try {
        const currentTab = this.tabs.find(tab => tab.name === this.activeTab);
        const params = {
          word_order_type: this.filters.type || undefined,
          word_order_types: this.filters.type || undefined,
          status:
            currentTab?.name === 'myTickets'
              ? undefined
@@ -2014,6 +2039,7 @@
    },
    handleReset() {
      this.dictKey = '';
      this.filters = {
        keyword: '',
        department: '',
@@ -3101,11 +3127,11 @@
  gap: 8px; // 使用 gap 统一设置间距
  .filter-item {
    width: 160px; // 减小宽度
    width: 280px; // 减小宽度
  }
  .date-picker {
    width: 240px; // 日期选择器宽度适当调整
    // width: 240px; // 日期选择器宽度适当调整
  }
  .el-button {