Files
td_official/src/views/drone/components/medium/mediumHomeAi.vue
2025-05-14 18:31:25 +08:00

610 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="medium-home-container">
<div class="medium-home-main">
<div class="medium-home-main-top">
<div class="medium-breadcrumb">
<div v-for="item in paths" :key="item" class="breadcrumb-item" @click="changePath(item)">
{{ item || '全部文件' }}
</div>
</div>
</div>
<div class="medium-home-top-btn">
<div>
<el-button size="small" @click="handleDelete(false)" type="danger"> 删除 </el-button>
<el-button size="small" @click="handleDownload(false)" type="success"> 下载 </el-button>
</div>
<div class="medium-check">
<div class="check-item">已选/全部</div>
<div class="check-item">{{ selectNum }}/{{ totle }}</div>
</div>
</div>
<div class="medium-home-main-table">
<el-table
ref="multipleTable"
:data="fileList"
tooltip-effect="dark"
stripe
size="small"
height="600"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column prop="fileName" label="文件名称">
<template slot-scope="scope">
<div
class="file-name-wrapper"
style="display: flex; align-items: center; cursor: pointer"
@click="handleSelectFile(scope.row.path, scope.row)"
>
<img :src="scope.row.img" alt="" style="width: 16px; height: 16px; transform: translateY(-1px); margin-right: 2px" />
<div class="file-name">{{ scope.row.name ? scope.row.name : scope.row.fileName }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="size" label="大小" width="80" show-overflow-tooltip> </el-table-column>
<el-table-column prop="creatTime" label="创建时间">
<template slot-scope="scope">{{ scope.row.creatTime }}</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="120">
<template slot-scope="scope">
<div class="opration-btns">
<el-tooltip v-if="scope.row.size !== 'N/A'" class="item" content="下载" effect="dark">
<!-- v-if="scope.row.size !== 'N/A'" -->
<span class="opration-btn" style="display: inline-block; cursor: pointer" @click="handleDownload(scope.row)">
<img :src="require('../../images/medium/down-load.png')" srcset="" />
</span>
</el-tooltip>
<el-tooltip v-if="scope.row.size !== 'N/A'" class="item" content="预览" effect="dark">
<span class="opration-btn" style="display: inline-block; cursor: pointer" @click="handlePreview(scope.row)">
<img :src="require('../../images/medium/prview-icon.png')" srcset="" />
</span>
</el-tooltip>
<el-tooltip class="item" content="删除" effect="dark">
<span class="opration-btn" style="display: inline-block; cursor: pointer" @click="handleDelete(scope.row)">
<img :src="require('../../images/medium/delete.png')" srcset="" />
</span>
</el-tooltip>
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="shade" v-if="loading">
<el-progress type="circle" :percentage="percentage"></el-progress>
<!-- <div
style="white-space: pre-line;text-align: center;color: aqua;color: aqua; display: flex; flex-direction: column;">
<img src="../../images/loadingdow.gif" alt="">
<span style="display: inline-block;position: absolute;left: 50%;top:50%;transform: translate(-50%, -50%);">{{
this.text }}</span>
</div> -->
</div>
</div>
</template>
<script>
import axios from 'axios';
import JSZip from 'jszip';
import { getAiFiles, deleteAiFile, getAiUrlList } from '@/api/fileMangement';
import Preview from './preview.vue';
import { useAirStore } from '@/store/modules/drone';
export default {
components: { Preview },
data() {
return {
percentage: 0,
info: {},
paths: [''],
fileList: [
// {
// fileName: item,
// size: list[item].size,
// creatTime: list[item].creation_time,
// path:''
// img: ''
// },
],
totle: 0,
selectNum: 0,
length: 0,
sn: '',
currentPath: '',
searchName: '', // 搜索关键字
dateTime: [new Date(), new Date()], // 初始时间范围为今日至今日
typeOptions: [
{
value: '选项1',
label: '选项1'
},
{
value: '选项2',
label: '选项2'
}
],
typeValue: '',
loadOptions: [
{
value: '选项1',
label: '选项1'
},
{
value: '选项2',
label: '选项2'
}
],
loadValue: '',
selectList: [],
loading: false,
gateWay: useAirStore().gateWay,
text: ''
};
},
watch: {
// 监听 Vuex 中的状态变化
'useAirStore().gateWay': {
handler(newValue, oldVal) {
this.gateWay = newValue;
this.getFileList(this.gateWay.gateway);
},
deep: true
}
},
methods: {
handleSelectionChange(datas) {
// console.log("datas: ", datas);
this.selectList = datas;
this.selectNum = datas.length;
},
isEmptyObject(obj) {
return Object.keys(obj).length === 0;
},
// 获取文件列表
async getFileList(gateway, path = '') {
this.fileList = [];
const list = await getAiFiles({ gateway, itemPath: path });
// console.log("文件列表1-------", list);
if (Object.keys(list).length === 0) {
return;
}
this.paths = [
'',
...Object.keys(list)[0]
.split('/')
.filter((path) => path !== '')
.slice(0, -1)
];
this.fileList = Object.keys(list).map((item) => {
const pathList = item.split('/').filter((path) => path !== '');
let img = require('../../images/medium/files-icon.png');
let type = 'file';
// console.log("item----------", item);
// console.log("list----------", list[item]);
// 文件缩略图
if (list[item].size !== 'N/A') {
type = item.split('.')[1];
if (item.split('.')[1] !== 'mp4') {
img = list[item].download_url;
} else {
img = require('../../images/medium/video-icon.png');
}
}
return {
name: list[item].missionName,
fileName: pathList[pathList.length - 1],
size: list[item].size,
creatTime: list[item].creation_time,
path: item,
img,
type,
url: list[item].download_url,
fileLength: list[item].length
};
});
this.totle = this.fileList.length;
this.length = this.fileList.fileLength;
// console.log("文件列表2-------", this.fileList);
},
// 文件夹点击进入文件夹
handleSelectFile(path, data) {
console.log('path11111111111', path);
if (data && data.size !== 'N/A') {
// console.log("文件------------");
} else {
this.currentPath = path;
const { gateway } = this.gateWay;
this.getFileList(gateway, path);
}
},
// 路径变化
changePath(path) {
if (path) {
// console.log("currentPath", this.currentPath);
this.currentPath = this.currentPath.split(path)[0] + path;
// console.log("path", path);
// 跳转到该路径
this.handleSelectFile(this.currentPath);
} else {
this.handleSelectFile('');
}
},
// 删除
handleDelete(row) {
// console.log("删除---------", row);
let params = { itemPaths: [row.path], gateway: this.gateWay.gateway };
if (!row) {
if (this.selectList.length === 0) {
this.$message.warning('请先选择要删除的文件');
this.loading = false;
return;
}
const pathList = this.selectList.map((item) => item.path);
params = { itemPaths: pathList, gateway: this.gateWay.gateway };
}
this.$confirm('此操作将删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
customClass: 'customMessageBox',
confirmButtonClass: 'customConfirm',
cancelButtonClass: 'customCancel'
}).then(() => {
deleteAiFile(params).then((res) => {
this.$message.success(res.msg);
this.$sendChanel('mediumDel');
// 过滤掉删除的文件
this.fileList = this.fileList.filter((file) => {
return !params.itemPaths.includes(file.path);
});
if (this.fileList.length === 0) {
// 如果列表为空跳转到根路径
this.handleSelectFile('');
}
});
});
},
// 下载
handleDownload(row) {
this.loading = true;
// console.log("下载---------", row);
let params = { itemPath: row.path, gateway: this.gateWay.gateway };
if (!row) {
if (this.selectList.length === 0) {
this.$message.warning('请先选择要下载的文件');
this.loading = false;
return;
}
let pathList = [];
// 定义是否是文件夹
let isFile = false;
// console.log("this.selectList", this.selectList);
this.selectList.forEach((item) => {
if (item.type === 'file') {
isFile = true;
}
});
if (isFile) {
const { gateway } = this.gateWay;
// this.selectList.forEach((item) => {
// const params = { gateway, itemPath: item.path };
// getUrlList(params).then((res) => {
// pathList.push(...res);
// });
// });
// console.log("pathList1", pathList);
// // 并行下载文件并压缩为 zip
// this.downloadAndZipFiles(pathList);
const promises = this.selectList.map((item) => {
const params = { gateway, itemPath: item.path };
return getAiUrlList(params).then((res) => {
pathList.push(...res); // 将结果合并到 pathList
});
});
// 等待所有异步操作完成后,再执行下载操作
Promise.all(promises)
.then(() => {
// console.log("pathList1", pathList);
// 确保 pathList 有值后再调用下载方法
this.downloadAndZipFiles(pathList);
})
.catch((error) => {
console.error('获取文件路径列表时出错:', error);
});
} else {
pathList = this.selectList.map((item) => item.url);
// console.log("pathList2", pathList);
// 并行下载文件并压缩为 zip
this.downloadAndZipFiles(pathList);
}
} else {
this.downloadAndZipFiles([row.url], row);
}
},
async downloadAndZipFiles(fileUrls, file) {
try {
const zip = new JSZip();
const fileSizeMap = new Map();
let fileTotal = 0;
if (file) {
fileTotal = file.fileLength;
} else {
this.selectList.forEach((item) => {
fileTotal += item.fileLength;
});
}
// console.log("file-----", fileTotal);l
// 并行下载所有文件
const downloadPromises = fileUrls.map((url) =>
axios({
url: url,
method: 'get',
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
const { loaded, total } = progressEvent;
fileSizeMap.set(url, loaded);
const totalFileSize = [...fileSizeMap.values()].reduce((acc, value) => acc + value, 0);
const progress = Math.round((totalFileSize / fileTotal) * 100); // 计算下载进度百分比
// console.log("progressEvent", progressEvent);
// console.log("overallProgress", progress);
// this.percentage = progress; // 更新进度百分比
if (progress == 100) {
this.text = `${99}%\n 正在打包中`;
} else {
this.text = `${progress}%\n 下载中`;
}
}
}).then((response) => {
console.log('Response:', response); // 在这里打印 response 对象
console.log('url:', url); // 在这里打印 response 对象
console.log('flie:', file); // 在这里打印 response 对象
const regex = /\/(DJI_[^\/]+\/DJI_[^\/]+\.[^\/?]+)(?=\?)/;
// 提取匹配的部分
const match = url.match(regex);
let extractedString = response.data.size + '.jpg';
if (match) {
extractedString = match[1]; // 捕获的字符串
}
// 打印文件名和文件数据
const fileName = file ? file.fileName : extractedString; // 获取文件名
const fileData = response.data; // 保存文件数据
// 获取文件大小:使用 Blob 的 size 属性
const fileSize = fileData.size; // 单位为字节bytes
// console.log("File size:", fileSize);
// 返回一个对象,继续后续操作
return { fileName, fileData };
})
);
// 等待所有文件下载完成
const downloadedFiles = await Promise.all(downloadPromises);
if (file) {
// console.log("Downloading", downloadedFiles);
const url = window.URL.createObjectURL(downloadedFiles[0].fileData);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', downloadedFiles[0].fileName); // 设置下载的文件名
document.body.appendChild(link);
link.click();
link.remove();
this.loading = false;
this.percentage = 0; // 下载完进度百分比清零
return;
}
// 将每个文件添加到 zip 中
downloadedFiles.forEach(({ fileName, fileData }) => {
// console.log("File Name:", fileName);
zip.file(fileName, fileData); // 添加文件到 zip
});
// 生成 zip 文件并触发下载
const zipBlob = await zip.generateAsync({ type: 'blob' });
const url = window.URL.createObjectURL(zipBlob);
const link = document.createElement('a');
link.href = url;
const temp = new Date().getTime();
link.setAttribute('download', `文件${temp}.zip`); // 设置下载的文件名
document.body.appendChild(link);
link.click();
link.remove();
this.loading = false;
this.percentage = 0; // 下载完进度百分比清零
} catch (error) {
// console.error("Error downloading or zipping files:", error);
this.loading = false;
this.percentage = 0; // 下载完进度百分比清零
}
},
// 预览
handlePreview(row) {
const list = this.fileList;
// console.log("预览---------", row);
// console.log("list---------", list);
const index = list.findIndex((item) => item === row);
const data = { list, detail: row, index };
this.$sendChanel('previewBus', data);
}
},
created() {},
mounted() {
this.getFileList(this.gateWay.gateway);
}
};
</script>
<style lang="scss">
.medium-home-container {
height: 100%;
width: 100%;
position: relative;
background-color: antiquewhite;
.medium-home-search-wrapper {
width: 100%;
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
> .el-date-editor {
width: 38%;
}
> .el-select {
width: 18%;
}
> .el-input {
width: 18%;
}
> .el-button {
width: 32px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
img {
width: 20px;
height: 20px;
}
}
}
.medium-home-main {
height: calc(100%);
background: #fff;
.medium-home-main-top {
display: flex;
justify-content: space-between;
line-height: 40px;
padding: 0 16px;
font-size: 12px;
width: 100%;
.medium-breadcrumb {
display: flex;
.breadcrumb-item {
// margin-right: 20px;
color: #909399;
cursor: pointer;
&::after {
content: '/';
display: inline-block;
margin: 0 3px;
}
}
.breadcrumb-item:last-child {
color: #000;
&::after {
content: '';
display: inline-block;
}
}
}
.file-name-wrapper {
display: flex;
.file-img-wrapper {
height: 20px !important;
width: 20px !important;
img {
width: 100%;
height: 100%;
}
}
}
.el-table {
.el-checkbox {
margin-left: 8px !important;
}
}
}
.medium-home-top-btn {
width: 100%;
height: 40px;
padding: 0 16px;
display: flex;
align-items: center;
font-size: 12px;
justify-content: space-between;
.medium-check {
display: flex;
align-items: center;
color: #000;
}
}
.medium-home-main-table {
overflow-y: auto;
height: calc(100% - 80px);
width: 100%;
}
.el-checkbox__input {
margin-left: 8px !important;
}
}
.shade {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 10;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
.el-progress__text {
color: aqua !important;
white-space: pre-line;
line-height: 20px;
}
}
.el-picker-panel {
background: rgba(255, 255, 255, 1) !important;
color: #606266 !important;
filter: drop-shadow(2px 4px 6px black);
}
.opration-btns {
display: flex;
justify-content: start;
align-items: center;
// background-color: #606266;
.opration-btn {
width: 16px;
height: 16px;
display: flex;
justify-content: center;
align-items: center;
margin-left: 10px;
cursor: pointer;
img {
width: 12px;
height: 12px;
}
&:hover {
// background: #e6e6e6;
}
}
}
}
</style>