610 lines
19 KiB
Vue
610 lines
19 KiB
Vue
|
<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>
|