400 lines
7.8 KiB
Vue
400 lines
7.8 KiB
Vue
|
<!--
|
||
|
filename: AssetsUpload.vue
|
||
|
author: liubin
|
||
|
date: 2023-10-12 16:40:14
|
||
|
description: 上传资料/图片 组件
|
||
|
-->
|
||
|
|
||
|
<template>
|
||
|
<div class="assets-upload">
|
||
|
<section class="operations">
|
||
|
<el-button type="text" class="expand-btn" @click="expand = !expand">
|
||
|
<i class="el-icon-folder-opened" v-if="expand"></i>
|
||
|
<i class="el-icon-folder" v-else></i>
|
||
|
展开
|
||
|
</el-button>
|
||
|
<!-- <div class="preview-btn">
|
||
|
<i class="el-icon-view"></i>
|
||
|
预览
|
||
|
</div> -->
|
||
|
</section>
|
||
|
<section
|
||
|
class="file-area"
|
||
|
:style="{
|
||
|
height: expand ? 'auto' : isPicMode ? '180px' : '152px',
|
||
|
gap: isPicMode ? '0 24px' : '24px',
|
||
|
gridAutoRows: isPicMode ? '180px' : '152px',
|
||
|
}">
|
||
|
<el-upload
|
||
|
class="equipment-upload"
|
||
|
:disabled="disabled"
|
||
|
drag
|
||
|
:action="uploadUrl"
|
||
|
:headers="headers"
|
||
|
multiple
|
||
|
:show-file-list="false"
|
||
|
:before-upload="beforeUpload"
|
||
|
:on-success="handleSuccess">
|
||
|
<i class="el-icon-upload"></i>
|
||
|
<div class="el-upload__text">
|
||
|
<span>将文件拖到此处或</span>
|
||
|
<em>点击上传</em>
|
||
|
</div>
|
||
|
<div class="el-upload__tip" slot="tip">
|
||
|
{{
|
||
|
isPicMode ? '仅支持上传 .jpg .png 格式文件, 且' : ''
|
||
|
}}文件大小不超过2MB
|
||
|
</div>
|
||
|
</el-upload>
|
||
|
<div
|
||
|
v-for="(file, index) in files"
|
||
|
:key="file.fileName"
|
||
|
style="width: 100%">
|
||
|
<div
|
||
|
class="file-list__item"
|
||
|
v-if="!isPicMode"
|
||
|
:style="{
|
||
|
background: isPicMode
|
||
|
? `url(${file.fileUrl}) no-repeat`
|
||
|
: `url(${defaultBg}) no-repeat`,
|
||
|
backgroundSize: isPicMode ? '100% 100%' : '64px',
|
||
|
backgroundPosition: isPicMode ? '0% 0%' : 'center',
|
||
|
}"
|
||
|
@click="handleDownload(file)"
|
||
|
:data-name="file.fileName">
|
||
|
<el-button
|
||
|
v-if="!disabled"
|
||
|
type="text"
|
||
|
class="el-icon-delete"
|
||
|
style="padding: 0"
|
||
|
@click="(e) => handleDelete(file)" />
|
||
|
</div>
|
||
|
|
||
|
<el-image
|
||
|
v-else
|
||
|
class="file-list__item"
|
||
|
style="width: 100%"
|
||
|
:src="file.fileUrl"
|
||
|
:preview-src-list="files.map((item) => item.fileUrl)"></el-image>
|
||
|
</div>
|
||
|
</section>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import { getAccessToken } from '@/utils/auth';
|
||
|
import defaultBg from '../../../assets/images/default-file-icon.png';
|
||
|
|
||
|
function checkSize(file, message) {
|
||
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
||
|
if (!isLt2M) {
|
||
|
message.error('上传文件大小不能超过 2MB!');
|
||
|
}
|
||
|
return isLt2M;
|
||
|
}
|
||
|
|
||
|
function checkPic(file, message) {
|
||
|
const isJPG = file.type === 'image/jpeg';
|
||
|
const isPNG = file.type === 'image/png';
|
||
|
const isPic = isJPG || isPNG;
|
||
|
if (!isPic) {
|
||
|
message.error('上传图片只能是 JPG/PNG 格式!');
|
||
|
}
|
||
|
return isPic;
|
||
|
}
|
||
|
|
||
|
export default {
|
||
|
name: 'AssetsUpload',
|
||
|
components: {},
|
||
|
model: {
|
||
|
prop: 'dataSource',
|
||
|
event: 'update',
|
||
|
},
|
||
|
props: {
|
||
|
type: {
|
||
|
type: String,
|
||
|
default: 'image',
|
||
|
},
|
||
|
dataSource: {
|
||
|
type: Array,
|
||
|
default: () => [],
|
||
|
},
|
||
|
equipmentId: {
|
||
|
type: String,
|
||
|
default: '',
|
||
|
},
|
||
|
isPicMode: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
disabled: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
},
|
||
|
emits: ['update-filelist'],
|
||
|
data() {
|
||
|
return {
|
||
|
defaultBg,
|
||
|
expand: false,
|
||
|
headers: { Authorization: 'Bearer ' + getAccessToken() }, // 设置上传的请求头部
|
||
|
fileList: [],
|
||
|
uploadUrl: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload',
|
||
|
files: [],
|
||
|
updateTimer: null,
|
||
|
};
|
||
|
},
|
||
|
watch: {
|
||
|
dataSource: {
|
||
|
handler(val) {
|
||
|
this.files = JSON.parse(JSON.stringify(val));
|
||
|
},
|
||
|
immediate: true,
|
||
|
deep: true,
|
||
|
},
|
||
|
},
|
||
|
mounted() {},
|
||
|
methods: {
|
||
|
// handle success, per file!
|
||
|
handleSuccess(response, file, fileList) {
|
||
|
this.$notify({
|
||
|
title: '成功',
|
||
|
message: '上传成功! 点击确认保存上传结果',
|
||
|
type: 'success',
|
||
|
});
|
||
|
if (
|
||
|
response == null ||
|
||
|
!('data' in response) ||
|
||
|
response.data == null ||
|
||
|
response.data.trim() == ''
|
||
|
) {
|
||
|
this.$message.error('上传出错了!');
|
||
|
return;
|
||
|
}
|
||
|
this.files.push({
|
||
|
fileName: file.name,
|
||
|
fileUrl: response.data,
|
||
|
fileType: this.isPicMode ? 1 : 2,
|
||
|
});
|
||
|
// debugger;
|
||
|
|
||
|
// 延时更新
|
||
|
if (this.updateTimer) {
|
||
|
clearTimeout(this.updateTimer);
|
||
|
}
|
||
|
this.updateTimer = setTimeout(() => {
|
||
|
// console.log('[AssetsUpload] 更新上传列表');
|
||
|
this.emitFilelist();
|
||
|
clearTimeout(this.updateTimer);
|
||
|
this.updateTimer = null;
|
||
|
}, 500);
|
||
|
},
|
||
|
|
||
|
async handleDownload(file) {
|
||
|
if (this.isPicMode) {
|
||
|
// this.$emit('preview', file);
|
||
|
const link = document.createElement('a');
|
||
|
link.href = file.fileUrl;
|
||
|
link.target = '_blank';
|
||
|
document.body.appendChild(link);
|
||
|
link.click();
|
||
|
document.body.removeChild(link);
|
||
|
} else {
|
||
|
// this.$emit('download', file);
|
||
|
const data = await this.$axios({
|
||
|
url: file.fileUrl,
|
||
|
method: 'get',
|
||
|
responseType: 'blob',
|
||
|
});
|
||
|
const link = document.createElement('a');
|
||
|
link.href = window.URL.createObjectURL(new Blob([data]));
|
||
|
link.download = file.fileName;
|
||
|
document.body.appendChild(link);
|
||
|
link.click();
|
||
|
document.body.removeChild(link);
|
||
|
window.URL.revokeObjectURL(link.href);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
emitFilelist() {
|
||
|
this.$emit('update', this.files);
|
||
|
},
|
||
|
|
||
|
handleRemove(file, fileList) {
|
||
|
debugger;
|
||
|
},
|
||
|
|
||
|
handleDelete(file) {
|
||
|
// fileName fileType 都可能一样,但 fileUrl 一定不一样
|
||
|
this.files = this.files.filter((item) => item.fileUrl != file.fileUrl);
|
||
|
this.$notify({
|
||
|
title: '成功',
|
||
|
message: '删除成功! 需点击确认保存删除结果',
|
||
|
type: 'success',
|
||
|
});
|
||
|
this.emitFilelist();
|
||
|
},
|
||
|
|
||
|
beforeUpload(file) {
|
||
|
if (this.isPicMode) {
|
||
|
return checkPic(file, this.$message) && checkSize(file, this.$message);
|
||
|
}
|
||
|
return checkSize(file, this.$message);
|
||
|
},
|
||
|
|
||
|
handleUpload() {
|
||
|
switch (this.type) {
|
||
|
case 'image':
|
||
|
break;
|
||
|
case 'asset':
|
||
|
break;
|
||
|
}
|
||
|
},
|
||
|
updateFileList(appendFilelist) {
|
||
|
// Array
|
||
|
this.$emit('update-filelist', this.appendFilelist);
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
.assets-upload {
|
||
|
position: relative;
|
||
|
}
|
||
|
|
||
|
.operations {
|
||
|
position: absolute;
|
||
|
top: -36px;
|
||
|
right: 0;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
.expand-btn,
|
||
|
.preview-btn {
|
||
|
font-size: 14px;
|
||
|
line-height: 1.2;
|
||
|
display: inline-block;
|
||
|
padding-left: 20px;
|
||
|
cursor: pointer;
|
||
|
z-index: 1000;
|
||
|
}
|
||
|
|
||
|
.expand-btn {
|
||
|
margin-right: 12px;
|
||
|
}
|
||
|
|
||
|
.preview-btn {
|
||
|
color: #ccc;
|
||
|
}
|
||
|
|
||
|
.expand-btn,
|
||
|
.preview-btn:hover,
|
||
|
.preview-btn.active {
|
||
|
// color: #0042d0;
|
||
|
color: #0b58ff;
|
||
|
}
|
||
|
|
||
|
:deep(.equipment-upload) {
|
||
|
.el-upload-dragger {
|
||
|
width: 188px;
|
||
|
height: 128px;
|
||
|
}
|
||
|
|
||
|
.el-icon-upload {
|
||
|
margin: 12px 0;
|
||
|
font-size: 48px;
|
||
|
}
|
||
|
|
||
|
.el-upload__text {
|
||
|
font-size: 12px;
|
||
|
line-height: 2px;
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
|
||
|
em {
|
||
|
margin-top: 12px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.el-upload__tip {
|
||
|
font-size: 12px;
|
||
|
line-height: 1.5;
|
||
|
color: #d1d1d1;
|
||
|
margin: 0 0 12px;
|
||
|
transform: translateY(-12px);
|
||
|
user-select: none;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.equipment-upload {
|
||
|
margin-bottom: 24px;
|
||
|
}
|
||
|
|
||
|
.file-list {
|
||
|
padding: 12px;
|
||
|
border: 1px solid #ccc;
|
||
|
}
|
||
|
|
||
|
// custom
|
||
|
.file-area {
|
||
|
display: grid;
|
||
|
grid-template-columns: repeat(auto-fill, 188px);
|
||
|
grid-auto-rows: 152px;
|
||
|
gap: 48px 24px;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
|
||
|
.file-list__item {
|
||
|
height: 128px;
|
||
|
background-color: #fff;
|
||
|
border: 1px dashed #d9d9d9;
|
||
|
border-radius: 6px;
|
||
|
-webkit-box-sizing: border-box;
|
||
|
box-sizing: border-box;
|
||
|
text-align: center;
|
||
|
cursor: pointer;
|
||
|
position: relative;
|
||
|
// overflow: hidden;
|
||
|
|
||
|
&:hover {
|
||
|
.el-icon-delete {
|
||
|
display: block;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.el-icon-delete {
|
||
|
color: #ccc;
|
||
|
position: absolute;
|
||
|
top: 8px;
|
||
|
right: 8px;
|
||
|
display: none;
|
||
|
|
||
|
&:hover {
|
||
|
color: rgb(210, 41, 41);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.file-list__item:hover {
|
||
|
border-color: #0b58ff;
|
||
|
}
|
||
|
|
||
|
.file-list__item::after {
|
||
|
content: attr(data-name);
|
||
|
position: absolute;
|
||
|
left: 0;
|
||
|
bottom: -26px;
|
||
|
font-size: 14px;
|
||
|
line-height: 2;
|
||
|
color: #616161;
|
||
|
}
|
||
|
|
||
|
.default-icon {
|
||
|
background: url(../../../assets/images/default-file-icon.png) no-repeat;
|
||
|
background-position: center;
|
||
|
background-size: 64px;
|
||
|
}
|
||
|
</style>
|