From 73e5d0d8bd018cde09c541988d82e6bbb880f133 Mon Sep 17 00:00:00 2001
From: 张含笑 <zhx18749296735@163.com>
Date: Wed, 13 Aug 2025 09:08:19 +0800
Subject: [PATCH] feat:成果数据展示所有数据
---
src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue | 4
src/api/job/task.js | 7 +
src/views/job/components/DeviceJobDetailsMap.vue | 14 -
src/views/job/components/DeviceJobDetails.vue | 358 ++++++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 320 insertions(+), 63 deletions(-)
diff --git a/src/api/job/task.js b/src/api/job/task.js
index fda4ed7..b1eb8fb 100644
--- a/src/api/job/task.js
+++ b/src/api/job/task.js
@@ -239,3 +239,10 @@
},
})
}
+export const getJobsAllFiles = data => {
+ return request({
+ url: `/blade-resource/attach/aiImagesPage?current=1&size=9999`,
+ method: 'post',
+ data: data,
+ })
+}
\ No newline at end of file
diff --git a/src/views/job/components/DeviceJobDetails.vue b/src/views/job/components/DeviceJobDetails.vue
index d31673a..3b0e909 100644
--- a/src/views/job/components/DeviceJobDetails.vue
+++ b/src/views/job/components/DeviceJobDetails.vue
@@ -11,7 +11,7 @@
<div class="itemBox">
<div class="itemTitle">{{ item.name }}:</div>
<div truncated class="itemValue" v-if="item.name !== '飞行事件' && item.name !== '任务执行次数'">{{
- item.value ? item.value : '--' }}</div>
+ item.value ? item.value : '--' }}</div>
<div class="itemValue" v-if="item.name === '任务执行次数'">{{ item.value ? item.value : '0'
}}次</div>
<!-- 飞行事件 -->
@@ -34,49 +34,133 @@
<span>{{ total }}</span>
个
</p>
- <p class="more" @click="jumpMore">更多</p>
+ <div class="rightBox">
+ <div class="downloadBtn" @click="htlsrwxq === 100 && downloadFun()">
+ <el-progress v-if="htlsrwxq !== 100" :percentage="htlsrwxq" :show-text="false" striped striped-flow :duration="1" />
+ <div class="downloadBtnText">
+ <span v-if="htlsrwxq === 100">下载</span>
+ <template v-else>
+ 处理中<el-icon @click="cancelDownload"><CircleClose /></el-icon>
+ </template>
+ </div>
+ </div>
+ <div class="downloadBtn" @click="showAll = !showAll" v-if="total > 5">
+ {{ showAll ? '收起' : '更多' }}
+ </div>
+ </div>
</div>
<div class="imgListBox">
<!-- 图片显示 -->
- <!-- :preview-src-list="achievementList.map(i => i.url)" -->
- <template v-for="(item, index) in achievementList" :key="index">
- <el-image v-if="item.result_type === 0" class="imgItem" :src="getSmallImg(item.url)"
- :preview-src-list="achievementList.map(i => i.url)" show-progress preview-teleported
- :initial-index="index" fit="cover" />
- <div v-if="item.result_type === 1" class="videotime">
- <video ref="videoRef" class="videoDisplay" :src="item.url"></video>
- <img @click="enterFullScreen(index)" class="videobutton"
- src="@/assets/images/task/videoshow.png" alt="">
- </div>
- <el-dialog class="ztzf-dialog " append-to-body modal-class="detailsOfHistoricalTasks"
- v-model="VideoShow" width="1600" :close-on-click-modal="false"
- :destroy-on-close="true">
- <div class="fullscreen">
-
- <video ref="fullscreenVideo" class="fullscreen-video" :src="currentVideoUrl"
- :style="{ width: 1600, height: '80vh' }" controls autoplay></video>
+ <template v-for="(item, index) in achievementList.slice(0, visibleCount)" :key="index">
+ <div class="result-item">
+ <el-checkbox v-model="item.checked" />
+ <div class="itemName">{{ item.createTime }}</div>
+ <!-- 正射 -->
+ <el-image
+ v-if="item.resultType === 4"
+ :src="item.smallUrl"
+ :preview-src-list="[item.showUrl]"
+ fit="cover"
+ preview-teleported
+ />
+ <!-- 全景 -->
+ <img
+ v-else-if="item.resultType === 5"
+ class="quanjing"
+ @click="clickpanorama(item)"
+ :src="item?.smallUrl"
+ alt=""
+ />
+ <!-- 视频 -->
+ <div v-else-if="item.resultType === 1" class="videotime">
+ <img
+ class="videoDisplay"
+ :src="convertVideoUrlToThumbnail(item.link)"
+ alt=""
+ @click="enterFullScreen(index)"
+ />
+ <img
+ @click="enterFullScreen(index)"
+ class="videobutton"
+ src="@/assets/images/task/videoshow.png"
+ alt=""
+ />
</div>
-
- </el-dialog>
+ <!-- 图片 -->
+ <el-image
+ v-else
+ :src="item.smallUrl"
+ :preview-src-list="[item.showUrl]"
+ preview-teleported
+ :initial-index="index"
+ 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(1600), height: '80vh' }"
+ controls
+ autoplay
+ ></video>
+ </div>
+ </el-dialog>
+ </div>
+
</template>
</div>
</div>
- <DeviceJobDetailsMap v-if="isShow" class="contentRight" :detailsData="detailsData" />
+ <DeviceJobDetailsMap v-if="isShow" :yuanImages="yuanImages" class="contentRight" :detailsData="detailsData" />
+
</div>
</el-dialog>
-
+ <!-- 全景360 -->
+ <PanoramaPopup
+ v-if="'全景'"
+ v-model:panoramaParamsShow="panoramaParamsShow"
+ v-model:panoramaParamsUrl="panoramaParamsUrl"
+ />
</template>
<script setup>
+import PanoramaPopup from '@/components/PanoramaPopup/PanoramaPopup.vue';
+import { getShowImg, getSmallImg, getzsSmallImg,getzsShowImg } from '@/utils/util';
+import { getaiImagesPageAPI,cancelDownloadApi,getDownloadStatusApi,attachDownload} from '@/api/dataCenter/dataCenter';
import { pxToRem } from '@/utils/rem'
import JobRelatedEvents from './JobRelatedEvents.vue'
-import { getEventMediaListApi, getJobDetails, getJobInfoFiles } from '@/api/job/task'
+import { getEventMediaListApi, getJobDetails, getJobInfoFiles,getJobsAllFiles } from '@/api/job/task'
import DeviceJobDetailsMap from './DeviceJobDetailsMap.vue'
import { droneEventList } from '../const/drc'
-import { ElMessage } from 'element-plus'
+import { ElMessage,ElLoading } from 'element-plus'
+import { useStore } from 'vuex';
+const store = useStore();
+const htlsrwxq = computed(() => store.state.common.downloadProgress?.htlsrwxq || 100)
const isShow = defineModel('show')
const VideoShow = ref(false)
+const showAll = ref(false) // 是否展示全部
+let loadingData
+// 原图
+const yuanImages = ref([])
+function convertVideoUrlToThumbnail(videoUrl) {
+ // 检查是否是有效的视频URL
+ if (!videoUrl || typeof videoUrl !== 'string') {
+ return videoUrl
+ }
+ // 替换文件扩展名
+ return videoUrl.replace(/\.mp4$/, '_small.jpg')
+}
const infoList = ref([
{ name: '任务编号', value: '', field: 'job_info_num' },
{ name: '任务名称', value: '', field: 'name' },
@@ -110,26 +194,40 @@
// 任务成果
const total = ref(0)
const achievementList = ref([])
-const props = defineProps(['wayLineJodInfoId', 'waylineJobId', 'batchNo'])
+const props = defineProps(['wayLineJodInfoId', 'waylineJobId', 'batchNo','jobId'])
const wayLineJodInfoId = computed(() => props.wayLineJodInfoId)
provide('wayLineJodInfoId', wayLineJodInfoId)
+// 可见数量
+const visibleCount = computed(() =>
+ showAll.value ? achievementList.value.length : Math.min(5, achievementList.value.length)
+)
const getAchievement = () => {
- if (!props.wayLineJodInfoId) return
- const params = {
- "way_line_jod_info_id": props.wayLineJodInfoId,
- "batch_no": props.batchNo
+ if (!props.jobId) return
+
+ const attachmentsParams = {
+ 'wayLineJobId': props.jobId,
+ 'resultTypes': [0, 1, 3, 4, 5],
+ 'orderByCreateTime': true,
}
- getEventMediaListApi(params).then(res => {
- achievementList.value = res.data.data.slice(0, 5)
- total.value = res.data.data.length
+ const pageParams = {
+ current: 1,
+ size: 2000,
+ }
+ getaiImagesPageAPI(attachmentsParams,pageParams ).then(res => {
+ achievementList.value = res.data.data.records.map(i => ({
+ ...i,
+ checked: false,
+ smallUrl: i.resultType === 4 ? getzsSmallImg(i.link) : getSmallImg(i.link),
+ showUrl: i.resultType === 4 ? getzsShowImg(i.link) : getShowImg(i.link),
+ }))
+ total.value = res.data.data.total
+ console.log('成果数据', res.data.data)
})
}
const jumpMore = () => {
ElMessage.warning('正在加急开发中...')
}
-const getSmallImg = url => {
- return url ? url.substring(0, url.lastIndexOf('.')) + '_small' + url.substring(url.lastIndexOf('.')) : ''
-}
+
const flightEvents = ref([])
const jobTimes = ref([])
const getDetails = () => {
@@ -141,7 +239,6 @@
getJobDetails(params).then(res => {
detailsData.value = res.data.data
jobTimes.value = res.data.data.job_times
-
infoList.value.forEach(item => {
if (item.name === '任务频次') {
const { rep_rule_type = '', rep_rule_val = '' } = detailsData?.value || {}
@@ -155,6 +252,15 @@
droneEventList.filter(({ value }) => actionActuatorFunc === value)
)
}
+ getJobsAllFiles({
+ wayLineJobId: detailsData.value.way_lines.map(item => item.job_id).join(','),
+ resultTypes: [0, 2, 4, 5],
+ }).then(result => {
+ if (result.data.code !== 200) return
+ yuanImages.value = result.data.data.records
+ console.log('ssssss',yuanImages.value);
+
+ })
})
// flystatus.value = res.data.data.ai_type_str
})
@@ -169,7 +275,7 @@
}
// 计算当前视频URL
const currentVideoUrl = computed(() => {
- return achievementList.value[currentVideoIndex.value]?.url || ''
+ return achievementList.value[currentVideoIndex.value]?.link || ''
})
// 关闭弹窗处理
const handleClose = () => {
@@ -178,7 +284,41 @@
fullscreenVideo.value.currentTime = 0
}
}
-
+// 下载
+const downloadFun = async () => {
+ const list = achievementList.value.filter(i => i.checked)
+ console.log('list',list);
+ if (!list?.length) return ElMessage.warning('请选择文件')
+ if (list.length === 1) {
+ list.forEach((item, index) => {
+ const suffix = item.url.split('.').pop()
+ aLinkDownloadUtil(item.url, item.nickName + '.' + suffix)
+ })
+ } else {
+ loadingData = ElLoading.service({ background: 'rgba(0, 0, 0, 0.5)', text: '打包中,请稍等...' })
+ const fileIds = list.map(i => i.id)
+ const res = await getDownloadStatusApi({type: 'htlsrwxq'})
+ if (!['CANCELLED','COMPLETED'].includes(res.data.data?.status || 'COMPLETED')){
+ return ElMessage.warning('还有正在处理的')
+ }
+ attachDownload({ attachIds: fileIds,type:'htlsrwxq' }).finally(()=>{
+ loadingData.close()
+ })
+ }
+}
+// 全景预览
+const panoramaParamsShow = ref(false)
+const panoramaParamsUrl = ref(null)
+const clickpanorama = val => {
+ panoramaParamsShow.value = true
+ panoramaParamsUrl.value = val.link
+}
+// 取消下载
+function cancelDownload() {
+ cancelDownloadApi({ type:'htlsrwxq' }).then(res =>{
+ ElMessage.success('取消成功')
+ })
+}
onMounted(() => {
getDetails()
getAchievement()
@@ -235,7 +375,52 @@
display: flex;
justify-content: space-between;
align-content: center;
+.rightBox{
+ display: flex;
+ align-items: center;
+ padding-right: 10px;
+ gap: 0 10px;
+ .downloadBtn{
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 28px;
+ padding: 0 15px;
+ background: rgba(28, 92, 255, 0.14);
+ border-radius: 4px 4px 4px 4px;
+ border: 1px solid #1c5cff;
+ cursor: pointer;
+ color: #1C5CFF;
+
+ .downloadBtnText{
+ display: flex;
+ align-items: center;
+ gap: 5px;
+ z-index: 5;
+ }
+ .el-progress{
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+
+ :deep(){
+ .el-progress-bar__outer{
+ height: 26px !important;
+ border-radius: 0 !important;
+ background: transparent !important;
+
+ .el-progress-bar__inner{
+ border-radius: 0 !important;
+ }
+ }
+ }
+ }
+
+ }
+ }
p {
display: inline-block;
margin-left: 30px;
@@ -333,8 +518,92 @@
grid-template-columns: repeat(5, 1fr);
gap: 10px;
margin-bottom: 49px;
+
+ > * {
+ width: 100%;
+ height: 200px;
+ position: relative;
+ border-radius: 0px 0px 4px 4px;
+ overflow: hidden;
+ }
+ :deep(.el-checkbox__inner) {
+ width: 17px !important;
+ height: 17px !important;
+ background: rgba(37, 36, 36, 0.63) !important;
+ border-radius: 4px 4px 4px 4px;
+ border: 1px solid #ffffff !important;
+ }
+ .el-checkbox {
+ position: absolute;
+ top: 0;
+ left: 6px;
+ }
+ :deep(.el-checkbox__inner:after) {
+ position: absolute;
+ left: 50% !important;
+ top: 40% !important;
+ transform: translate(-50%, -50%) rotate(45deg) !important;
+ }
+ :deep(.el-checkbox.is-checked .el-checkbox__inner) {
+ background-color: #09297b !important;
+ border-color: #1c5cff !important;
+ }
+ .el-image {
+ width: 100%;
+ height: 100%;
+ cursor: pointer;
+ position: relative;
+ }
+
+ .quanjing {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ cursor: pointer;
+ position: relative;
+ }
+
+ .videotime {
+ width: 100%;
+ height: 100%;
+ position: relative;
+
+ .videoDisplay {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ }
+ .itemName {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ height: 23px;
+ width: 100%;
+ background: rgba(22, 22, 22, 0.68);
+ 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;
+ z-index: 9;
+ padding: 0 6px;
+ }
}
+.videobutton {
+ position: absolute;
+ top: 40%;
+ left: 50%;
+ transform: translate(-50%);
+ cursor: pointer;
+ width: 40px;
+ height: 40px;
+ display: inline-block;
+ background: #999;
+ border-radius: 50%;
+ }
.videoDisplay {
display: flex;
flex-wrap: wrap;
@@ -346,17 +615,6 @@
.videotime {
position: relative;
}
-
- // .videobutton {
- // position: absolute;
- // top: 40%;
- // left: 45%;
- // transform: translate(-50%);
- // cursor: pointer;
- // width: 40px;
- // height: 40px;
- // display: inline-block;
- // }
}
.contentRight {
diff --git a/src/views/job/components/DeviceJobDetailsMap.vue b/src/views/job/components/DeviceJobDetailsMap.vue
index 1c6cdb5..2bc98ee 100644
--- a/src/views/job/components/DeviceJobDetailsMap.vue
+++ b/src/views/job/components/DeviceJobDetailsMap.vue
@@ -1,13 +1,3 @@
-<!--
- * @Author : yuan
- * @Date : 2025-05-26 17:30:33
- * @LastEditors : yuan
- * @LastEditTime : 2025-06-10 15:46:18
- * @FilePath : \src\views\job\components\DeviceJobDetailsMap.vue
- * @Description :
- * Copyright 2025 OBKoro1, All Rights Reserved.
- * 2025-05-26 17:30:33
--->
<template>
<div id="deviceJobDetailsMap" class="ztzf-cesium">
<PlanarRouteLineList :curRouteLineData="curRouteLineData" @routeLineListClick="routeLineListClick" />
@@ -18,8 +8,8 @@
import { PublicCesium } from '@/utils/cesium/publicCesium'
-const props = defineProps(['detailsData'])
-
+const props = defineProps(['detailsData','yuanImages'])
+console.log('props.yua',props.yuanImages);
import { useRouteLine } from '@/hooks/useRouteLine/useRouteLine.js'
// 加载航线hook
diff --git a/src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue b/src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue
index 8a16eff..c8e910a 100644
--- a/src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue
+++ b/src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue
@@ -104,7 +104,7 @@
/> -->
<!-- 历史任务详情 -->
<DeviceJobDetails v-if="isShowDeviceJobDetails" v-model:show="isShowDeviceJobDetails" :wayLineJodInfoId="rowData.id"
- :batchNo="rowData.batch_no" />
+ :batchNo="rowData.batch_no" :jobId="jobId"/>
<CancelTaskDialog ref="cancelTaskDialogRef" v-model:isShowCancelTask="isShowCancelTask" :row-data="rowData"
@refresh="getJobList" />
</template>
@@ -166,10 +166,12 @@
// 查看当前任务详情 如果是一台机则显示详情 如果是多台机则进入集群调度(暂未开发)
let rowData = ref({})
+const jobId = ref('')
const handleDetail = row => {
if (!row.device_sns.length) return ElMessage.warning('没有device_sns')
if (row.device_sns.length !== 1) return ElMessage.success('即将跳转到集群调度')
rowData.value = row ? row : {}
+jobId.value = rowData.value?.job_id
if (row.status === 2 || row.status === 1) {
// isShowCurrentTaskDetails.value = true
// 跳转大屏当前任务详情
--
Gitblit v1.9.3