From d516e08ace187d792b99440223dcf5eaf3f6f36b Mon Sep 17 00:00:00 2001
From: 罗广辉 <guanghui.luo@foxmail.com>
Date: Wed, 13 Aug 2025 15:56:29 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/feature/v5.0/5.0.3' into feature/v5.0/5.0.3

---
 .env.development                                  |    2 
 src/permission.js                                 |   18 +
 src/views/dataCenter/components/searchData.vue    |   36 ++++
 src/hooks/components/EventPopUpBox.vue            |   69 ++++++---
 src/utils/util.js                                 |   10 +
 src/views/dataCenter/dataCenter.vue               |  221 ++++++++++++++++++++++++++----
 src/views/job/components/JobRelatedEvents.vue     |    2 
 src/views/dataCenter/components/dataCenterMap.vue |    1 
 src/api/dataCenter/dataCenter.js                  |   16 ++
 src/assets/images/dataCenter/filePackage.png      |    0 
 10 files changed, 307 insertions(+), 68 deletions(-)

diff --git a/.env.development b/.env.development
index e35d854..09780be 100644
--- a/.env.development
+++ b/.env.development
@@ -21,7 +21,7 @@
 
 # 服务地址
 VITE_APP_URL = https://wrj.shuixiongit.com/api
-#VITE_APP_URL= http://192.168.1.168 rjg
+#VITE_APP_URL= http://192.168.1.168 
 #VITE_APP_URL= http://192.168.1.33
 #新大屏地址
 VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/'
diff --git a/src/api/dataCenter/dataCenter.js b/src/api/dataCenter/dataCenter.js
index 996ac7f..0dd0dd0 100644
--- a/src/api/dataCenter/dataCenter.js
+++ b/src/api/dataCenter/dataCenter.js
@@ -81,3 +81,19 @@
 		  },
 	})
 }
+// 获取机场下的文件夹
+export const getJobIdsBySnApi = (params, dockSn) => {
+	return request({
+		url: `/drone-device-core/wayline/api/v1/workspaces/getJobIdsBySn`,
+		method: 'get',
+		params,
+	})
+}
+// 附件下载
+export const attachDownload = (data) => {
+	return request({
+		url: `/blade-resource/attach/download`,
+		method: 'post',
+		data
+	})
+}
\ No newline at end of file
diff --git a/src/assets/images/dataCenter/filePackage.png b/src/assets/images/dataCenter/filePackage.png
new file mode 100644
index 0000000..a7daa97
--- /dev/null
+++ b/src/assets/images/dataCenter/filePackage.png
Binary files differ
diff --git a/src/hooks/components/EventPopUpBox.vue b/src/hooks/components/EventPopUpBox.vue
index a0a084f..24a4ad6 100644
--- a/src/hooks/components/EventPopUpBox.vue
+++ b/src/hooks/components/EventPopUpBox.vue
@@ -1,11 +1,28 @@
 <template>
   <div class="mapPopUpBox">
     <div class="title">
-      <span>{{ info.event_name }}</span>
-      <el-icon class="header-close" @click.stop="props.detailClick"><Warning /></el-icon>
+     <el-tooltip
+				v-if="infoList.resultType === 2"
+				effect="dark"
+				:content="infoList.eventName"
+				placement="top"
+				:disabled="!shouldShowTooltip"
+			>
+				<span ref="titleSpan" class="title-text">
+					{{ infoList.eventName?infoList.eventName:'--' }}
+				</span>
+			</el-tooltip>
+			<el-tooltip v-else effect="dark" :content="infoList.nickName" placement="top" :disabled="!shouldShowTooltip">
+				<span ref="titleSpan" class="title-text" >
+					{{ infoList.nickName }}
+				</span>
+			</el-tooltip>
+   <div>
+       <el-icon class="header-close" @click.stop="props.detailClick"><Warning /></el-icon>
       <el-icon class="header-close" @click.stop="props.removeLabel">
         <Close />
       </el-icon>
+   </div>
     </div>
     <div class="content">
       <div class="medium">
@@ -27,6 +44,12 @@
       </div>
 
       <div class="details">
+        <div class="label" v-if="infoList.resultType === 2">事件编号:</div>
+        <div class="value point" v-if="infoList.resultType === 2">
+          {{
+            infoList?.eventNum ? infoList?.eventNum : '--'
+          }}
+        </div>
         <div class="label">时间:</div>
         <div class="value point">
           {{
@@ -36,8 +59,8 @@
         </div>
         <div class="label">地点:</div>
         <div class="value">
-          {{ _.round(infoList?.metadata?.shootPosition?.lng, 3) }},{{
-            _.round(infoList?.metadata?.shootPosition?.lat, 3)
+          {{ _.round(infoList?.metadata?.shootPosition?.lng, 6) }},{{
+            _.round(infoList?.metadata?.shootPosition?.lat, 6)
           }}
         </div>
       </div>
@@ -63,6 +86,8 @@
   create_time: '04/01 12:41',
 });
 const infoList = props.data;
+console.log('infoList',infoList);
+
 const clickpanorama = val => {
   // 通过事件总线发送全景参数
   EventBus.emit('open-panorama', {
@@ -78,8 +103,8 @@
 
 <style scoped lang="scss">
 .mapPopUpBox {
-  width: 271px;
-  height: 153px;
+  width: 291px;
+  height: 183px;
   // background: url('@/assets/images/dataCenter/datamap/popUpBox.png') no-repeat center / 100% 100%;
   border-radius: 20px;
   background-color: #fff;
@@ -92,19 +117,18 @@
     font-weight: 400;
     font-size: 18px;
     line-height: 16px;
-    background: linear-gradient(180deg, #a8e5fb 0%, #e6f8ff 100%);
-    -webkit-background-clip: text;
-    -webkit-text-fill-color: transparent;
-    -moz-background-clip: text;
-    -moz-text-fill-color: transparent;
-    background-clip: text;
-    text-fill-color: transparent;
     margin-bottom: 10px;
     display: flex;
     align-items: center;
-    justify-content: end;
-
-    .header-close {
+    justify-content: space-between;
+   
+    .title-text {
+     color: black;
+    }
+      div{
+      display: flex;
+      align-items: center;
+      .header-close {
       width: 20px;
       height: 100%;
       line-height: 100%;
@@ -114,17 +138,19 @@
       pointer-events: all;
       cursor: pointer;
     }
+      }
+    
   }
 
   .content {
-    height: 102px;
-    width: 240px;
+    height: 132px;
+    // width: 240px;
     display: flex;
     align-items: center;
 
     .medium {
-      height: 102px;
-      width: 120px;
+      height: 122px;
+      width: 140px;
       margin-right: 10px;
 
       > img,
@@ -152,10 +178,11 @@
         color: black;
         line-height: 16px;
         margin-bottom: 2px;
+        white-space: nowrap;
       }
 
       .point {
-        margin-bottom: 14px;
+        margin-bottom: 10px;
       }
     }
   }
diff --git a/src/permission.js b/src/permission.js
index 4db5ed8..36ed552 100644
--- a/src/permission.js
+++ b/src/permission.js
@@ -126,9 +126,17 @@
   }
 })
 
+// router.afterEach(to => {
+//   NProgress.done()
+//   let title = router.$avueRouter.generateTitle(to, { label: 'name' })
+//   router.$avueRouter.setTitle(title)
+//   store.commit('SET_IS_SEARCH', false)
+// })
 router.afterEach(to => {
-  NProgress.done()
-  let title = router.$avueRouter.generateTitle(to, { label: 'name' })
-  router.$avueRouter.setTitle(title)
-  store.commit('SET_IS_SEARCH', false)
-})
+	NProgress.done()
+	const isLoginPage = to.path === '/login'
+	// 根据是否登录页设置标题
+	const pageTitle = isLoginPage ? '中图智飞低空感知网平台' : '综合管理平台'
+	document.title = pageTitle
+	store.commit('SET_IS_SEARCH', false)
+})
\ No newline at end of file
diff --git a/src/utils/util.js b/src/utils/util.js
index 325dcc5..57c3536 100644
--- a/src/utils/util.js
+++ b/src/utils/util.js
@@ -459,6 +459,16 @@
 	return `${url.substring(0, lastDotIndex)}_show${url.substring(lastDotIndex)}`
 }
 
+/**
+ * 获取正射路径
+ * @param url
+ * @returns {string}
+ */
+export const getzsShowImg = url => {
+	if (!url) return ''
+	const lastDotIndex = url.lastIndexOf('.')
+	return `${url.substring(0, lastDotIndex)}_show.jpeg`
+}
 // key驼峰转换为下划线
 export function camelToSnake (obj) {
   if (typeof obj !== 'object' || obj === null) {
diff --git a/src/views/dataCenter/components/dataCenterMap.vue b/src/views/dataCenter/components/dataCenterMap.vue
index cc787c7..2715f26 100644
--- a/src/views/dataCenter/components/dataCenterMap.vue
+++ b/src/views/dataCenter/components/dataCenterMap.vue
@@ -232,7 +232,6 @@
   try {
     const res = await getMapInfoAPI(ids);
     dataPointList.value = res.data.data || [];
-   
     if (isMapInitialized.value && viewer) {
       renderDataPoint(dataPointList.value);
     }
diff --git a/src/views/dataCenter/components/searchData.vue b/src/views/dataCenter/components/searchData.vue
index a0c557d..fc5052f 100644
--- a/src/views/dataCenter/components/searchData.vue
+++ b/src/views/dataCenter/components/searchData.vue
@@ -2,8 +2,9 @@
   <div class="search-box-test">
     <el-form :model="searchForm" inline>
       <div class="search-first">
-        <el-form-item label="行政区划:">
+        <el-form-item label="行政区划:" >
           <el-tree-select
+          :disabled="foldersDisabled"
             popper-class="custom-tree-select"
             v-model="searchForm.areaCode"
             :data="deptTreeData"
@@ -16,6 +17,7 @@
         </el-form-item>
         <el-form-item label="所属机巢:">
           <el-select
+          :disabled="foldersDisabled"
             :teleported="false"
             v-model="searchForm.deviceSn"
             placeholder="请选择"
@@ -59,6 +61,7 @@
         </el-form-item>
         <el-form-item label="文件格式:">
           <el-select
+          :disabled="foldersDisabled"
             :teleported="false"
             v-model="searchForm.resultType"
             placeholder="请选择"
@@ -76,7 +79,8 @@
         </el-form-item>
         <el-form-item label="文件类别:">
           <el-select
-            :disabled="disabled"
+          
+            :disabled="disabled || foldersDisabled"
             :teleported="false"
             v-model="searchForm.photoType"
             placeholder="请选择"
@@ -95,7 +99,7 @@
       </div>
       <div class="search-first">
         <el-form-item label="文件名称:">
-          <el-input v-model="searchForm.name" placeholder="请输入" clearable />
+          <el-input :disabled="foldersDisabled" 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>
@@ -107,6 +111,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>
           <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">
@@ -135,13 +140,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']);
+const emit = defineEmits(['search', 'downFun', 'allDownFun','handleswitchFolders']);
 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 searchForm = reactive({
   jobName: '', //任务名称
   name: '', //文件名称
@@ -151,6 +156,7 @@
   deviceSn: '', // 所属机巢
   resultType: '', //文件格式
   photoType: '', //文件类别
+  wayLineJobId:''
 });
 const disabled = ref(false);
 const treeProps = {
@@ -207,6 +213,18 @@
   },
   { deep: true }
 );
+watch(() => props.searchjobId, (newVal) => {
+  searchForm.wayLineJobId = newVal;
+  handleSearch()
+});
+const foldersDisabled  = ref(false)
+watch(() => props.switchFolders, (newVal) => {
+if(newVal === true){
+  foldersDisabled.value = true
+}else{
+   foldersDisabled.value = false
+}
+});
 const changePhotoType =(val)=>{
 if(val === undefined){
   searchForm.photoType = ''
@@ -322,7 +340,10 @@
     ElMessage.success('取消成功')
   })
 }
-
+// 切换文件夹
+const handleswitchFolders =()=>{
+  emit('handleswitchFolders');
+}
 onMounted(() => {
   requestDockInfo();
   getDownloadStatusApi({type: 'htsjzx'}).then(res =>{
@@ -346,9 +367,12 @@
     justify-content: space-between;
 
     .search-btn {
+    display: flex;
+    align-items: center;
       margin-right: 32px;
 
       .downloadBtn{
+      margin-left: 10px;
         position: relative;
         display: flex;
         align-items: center;
diff --git a/src/views/dataCenter/dataCenter.vue b/src/views/dataCenter/dataCenter.vue
index 2ddb099..501ffe4 100644
--- a/src/views/dataCenter/dataCenter.vue
+++ b/src/views/dataCenter/dataCenter.vue
@@ -4,12 +4,30 @@
   >
     <div class="dataCenter-table">
       <searchData
+      :searchjobId="searchjobId"
+      :switchFolders="switchFolders"
         @search="searchClick"
         @downFun="downloadFile"
         @allDownFun="aLLDownloadFile"
+          @handleswitchFolders="handleswitchFolders"
       ></searchData>
+      <!-- 文件夹 -->
+      <div class="fileshow" v-if="switchFolders"  v-loading="loadings "   element-loading-text="加载中">
+          <div
+                class="filePackage"
+                v-for="(folderItem, fileIndex) in folderList"
+                :key="fileIndex"
+                @click.stop="foldersOpen(folderItem)"
+              >
+                <img :src="fileimg" alt="" />
+                <el-checkbox v-model="folderItem.checked" @click.stop />
+                <div class="itemName" :title="folderItem.name">
+                  <div>{{ folderItem.name }}</div>
+                    </div>
+          </div>
+      </div>
       <!-- 表格部分 -->
-      <div class="dataTable">
+      <div class="dataTable" v-else>
         <el-table
         border
          stripe
@@ -124,16 +142,16 @@
       </div>
       <!-- 分页 -->
       <div class="pagination">
-        <el-pagination
-          v-model:current-page="jobListParams.current"
-          v-model:page-size="jobListParams.size"
-          :page-sizes="[10, 20, 30, 40]"
-          background
-          layout="total, sizes, prev, pager, next, jumper"
-          :total="total"
-          @size-change="handleSizeChange"
-          @current-change="handleCurrentChange"
-        />
+         <el-pagination
+      :current-page="switchFolders ? FolderListParams.page : jobListParams.current"
+      :page-size="switchFolders ? FolderListParams.page_size : jobListParams.size"
+      :page-sizes="[10, 20, 30, 40]"
+      background
+       layout="total, sizes, prev, pager, next, jumper"
+      :total="total"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
       </div>
       <!-- 查看弹框 -->
       <el-dialog
@@ -278,6 +296,11 @@
 </template>
 
 <script setup>
+import fileimg from '@/assets/images/dataCenter/filePackage.png'
+import { getShowImg, getSmallImg, getzsSmallImg } from '@/utils/util';
+import { onMounted, watch } from 'vue';
+import dayjs from 'dayjs';
+import ElTooltipCopy from '@/components/ElTooltipCopy.vue';
 import videoplay from '@/assets/images/dataCenter/videoplay.png';
 import positionicon from '@/assets/images/dataCenter/positionicon.png';
 import { useStore } from 'vuex';
@@ -308,12 +331,9 @@
   deleteFileMultipleApi,
   downloadApi,
   updataTitleApi,
-  getOrthoimageInfo, getDownloadStatusApi
+  getOrthoimageInfo, getDownloadStatusApi,getJobIdsBySnApi
 } from '@/api/dataCenter/dataCenter';
-import { getShowImg, getSmallImg, getzsSmallImg } from '@/utils/util';
-import { onMounted, watch } from 'vue';
-import dayjs from 'dayjs';
-import ElTooltipCopy from '@/components/ElTooltipCopy.vue';
+const switchFolders = ref(false)
 
 function bytesToMB(bytes, decimalPlaces = 2) {
   if (typeof bytes !== 'number' || bytes < 0) return '0';
@@ -397,6 +417,14 @@
   orderByCreateTime: true,
   searchParams: { startTime: timeRange[0], endTime: timeRange[1] },
 });
+const FolderListParams = reactive({
+  page: 1,
+  page_size: 30,
+    startTime: jobListParams.searchParams.startTime?.slice(0, 10),
+    endTime: jobListParams.searchParams.endTime?.slice(0, 10),
+   waylineName:'',
+   
+});
 const tableData = ref([]);
 
 // 获取列表数据
@@ -406,7 +434,6 @@
     orderByCreateTime: jobListParams.orderByCreateTime,
     ...jobListParams.searchParams,
   };
-
   getaiImagesPageAPI(params, {
     current: jobListParams.current,
     size: jobListParams.size,
@@ -423,27 +450,86 @@
       }));
     })
     .catch(error => {
-      // 可选:这里可以添加错误处理逻辑
       console.error('获取数据失败:', error);
     })
     .finally(() => {
-      loadings.value = false; // 无论成功失败都会执行
+      loadings.value = false; 
     });
 };
+const folderList = ref([])
+// 获取文件夹数据
+const getFolderList=()=>{
+ 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  
+		})
+		.finally(() => {
+		  loadings.value = false; 
+		})
+}
+const searchjobId = ref('')
+const foldersOpen = (val)=>{
+    loadings.value = true;
+    tableData.value=[]
+    searchjobId.value = val.job_id
+    switchFolders.value = false
+
+}
+// 获取数据时使用各自的分页参数
+const fetchData = () => {
+ loadings.value = true;
+  if (switchFolders.value) {
+    getFolderList();
+  } else {
+    getaiImagesPage();  
+  }
+};
+// 切换文件夹
+ const handleswitchFolders = () => {
+     switchFolders.value = !switchFolders.value;
+     jobListParams.current = 1;
+     FolderListParams.page = 1;
+     fetchData();
+   };
 // 查询
 const searchClick = params => {
-  jobListParams.current = 1;
-  jobListParams.size = 10;
-  jobListParams.searchParams = params;
-  getaiImagesPage();
+  if(switchFolders.value){
+    FolderListParams.page = 1;
+    FolderListParams.page_size = 30;
+    FolderListParams.startTime = params.startTime?.slice(0, 10); 
+    FolderListParams.endTime = params.endTime?.slice(0, 10);
+    FolderListParams.waylineName=params.jobName,
+    getFolderList()
+  }else{
+     jobListParams.current = 1;
+      jobListParams.size = 10;
+      jobListParams.searchParams = {
+      ...jobListParams.searchParams, 
+      ...params 
+    };
+    getaiImagesPage()
+  }
 };
-const handleSizeChange = val => {
-  jobListParams.size = val;
-  getaiImagesPage();
+const handleSizeChange = (val) => {
+  if (switchFolders.value) {
+    FolderListParams.page_size = val;  
+  } else {
+    jobListParams.size = val; 
+  }
+  fetchData();
 };
-const handleCurrentChange = val => {
-  jobListParams.current = val;
-  getaiImagesPage();
+const handleCurrentChange = (val) => {
+  if (switchFolders.value) {
+    FolderListParams.page = val;
+  } else {
+    jobListParams.current = val;
+  }
+  fetchData();
 };
 // 多选
 const selectedRows = ref([]);
@@ -517,9 +603,20 @@
     });
   }
 };
+// 文件夹打包下载
+async function folderDownload() {
+	const jobId = folderList.value.filter(i => i.checked).map(i => i.job_id)
+	if (!jobId?.length) return ElMessage.warning('请选择文件夹')
+	const res = await getDownloadStatusApi({type: 'dpsjzx'})
+	if (!['CANCELLED','COMPLETED'].includes(res.data.data?.status || 'COMPLETED')){
+		return ElMessage.warning('还有正在处理的')
+	}
+	await downloadApi({ wayLineJobIds:jobId, withFolder: true, resultType: 0, type:'htsjzx' })
+}
 // 下载
 const downloadFile = () => {
-  fileDownload();
+
+ switchFolders.value?folderDownload(): fileDownload();
 };
 const detailDownLoad = val => {
   const suffix = val.link?.split('.').pop();
@@ -724,7 +821,6 @@
   isMapInitialized.value = false;
 }
 function handleCellClick(row, column) {
-  console.log(row,column.no)
   if (column.no === 5) {
     navigator.clipboard.writeText(row.nickName).then(() => {
       ElMessage.success('复制文件名称成功')
@@ -746,7 +842,6 @@
   viewInstance.value?.viewerDestroy();
 });
 </script>
-
 <style scoped lang="scss">
 .dataCenter-table {
   height: 0;
@@ -781,7 +876,67 @@
       cursor: pointer;
     }
   }
+	.fileshow {
+		 display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
+  gap: 10px;
+  overflow: auto;
+  flex: 1;
+  min-height: 0; /* 关键:解决 flex 容器中的最小高度问题 */
+  align-content: flex-start; /* 让内容从顶部开始排列 */
+			.filePackage {
+          display: flex;
+    justify-content: center;
+				width: 260px;
+				height: 146px;
+				border-radius: 4px 4px 4px 4px;
+				position: relative;
+				background: #ddd;
+				cursor: pointer;
+				img {
+					width: 111px;
+					height: 111px;
+			
+				}
 
+				.el-checkbox {
+					position: absolute;
+					top: 0;
+					left: 6px;
+				}
+
+				.itemName {
+					position: absolute;
+					bottom: 0;
+					left: 0;
+					height: 23px;
+					width: 100%;
+          padding: 0 10px;
+          box-sizing: border-box;
+					background: rgba(22, 56, 101, 0.3);
+					border-radius: 0px 0px 4px 4px;
+					font-family: Source Han Sans CN, Source Han Sans CN;
+					font-weight: 400;
+					font-size: 14px;
+					color: #ffffff;
+					line-height: 23px;
+				
+					display: flex;
+					align-items: center;
+					justify-content: space-between;
+
+					div {
+						white-space: nowrap;
+					}
+
+					img {
+						width: 14px;
+						height: 14px;
+						cursor: pointer;
+					}
+				}
+			}
+		}
   .pagination {
     display: flex;
     justify-content: end;
@@ -938,4 +1093,4 @@
     }
   }
 }
-</style>
+</style>
\ No newline at end of file
diff --git a/src/views/job/components/JobRelatedEvents.vue b/src/views/job/components/JobRelatedEvents.vue
index 6826bef..632db4f 100644
--- a/src/views/job/components/JobRelatedEvents.vue
+++ b/src/views/job/components/JobRelatedEvents.vue
@@ -222,7 +222,7 @@
 }
 // 处理中
 .processing {
-	color: #ffff61;
+	color: #FFC300;
 }
 // 已完成
 .done {

--
Gitblit v1.9.3