无人机系统
This commit is contained in:
609
src/views/drone/components/medium/mediumHomeAi.vue
Normal file
609
src/views/drone/components/medium/mediumHomeAi.vue
Normal file
@ -0,0 +1,609 @@
|
||||
<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>
|
Reference in New Issue
Block a user