|
|
@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
|
|
|
<div class="upload-file">
|
|
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
|
|
:action="uploadFileUrl"
|
|
|
|
|
|
|
|
:before-upload="handleBeforeUpload"
|
|
|
|
|
|
|
|
:on-error="handleUploadError"
|
|
|
|
|
|
|
|
:on-success="handleUploadSuccess"
|
|
|
|
|
|
|
|
:limit="limit"
|
|
|
|
|
|
|
|
:headers="headers"
|
|
|
|
|
|
|
|
:file-list="fileList"
|
|
|
|
|
|
|
|
:show-file-list="false"
|
|
|
|
|
|
|
|
class="cover-upload"
|
|
|
|
|
|
|
|
drag
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<!-- 显示已上传图片 -->
|
|
|
|
|
|
|
|
<div v-if="imageUrl" class="image-preview">
|
|
|
|
|
|
|
|
<img :src="baseUrl + imageUrl" class="preview-img">
|
|
|
|
|
|
|
|
<div class="image-actions">
|
|
|
|
|
|
|
|
<i class="el-icon-delete" @click.stop="handleDelete"></i>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 上传区域 -->
|
|
|
|
|
|
|
|
<div v-else class="upload-content">
|
|
|
|
|
|
|
|
<icon class="el-icon-upload" />
|
|
|
|
|
|
|
|
<div class="upload-text">上传图片 或拖拽到此处</div>
|
|
|
|
|
|
|
|
<div class="upload-tip">PNG, JPG, GIF 最大 10MB</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
|
|
import { getToken } from "@/utils/auth";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
|
|
name: "FileUpload",
|
|
|
|
|
|
|
|
props: {
|
|
|
|
|
|
|
|
// 值
|
|
|
|
|
|
|
|
value: [String, Object, Array],
|
|
|
|
|
|
|
|
// 数量限制
|
|
|
|
|
|
|
|
limit: {
|
|
|
|
|
|
|
|
type: Number,
|
|
|
|
|
|
|
|
default: 1,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// 大小限制(MB)
|
|
|
|
|
|
|
|
fileSize: {
|
|
|
|
|
|
|
|
type: Number,
|
|
|
|
|
|
|
|
default: 10,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// 文件类型, 例如['png', 'jpg', 'jpeg']
|
|
|
|
|
|
|
|
fileType: {
|
|
|
|
|
|
|
|
type: Array,
|
|
|
|
|
|
|
|
default: () => ["png", "jpg", "jpeg", "gif"],
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
data() {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
uploadList: [],
|
|
|
|
|
|
|
|
baseUrl: process.env.VUE_APP_BASE_API,
|
|
|
|
|
|
|
|
uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传文件服务器地址
|
|
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
|
|
Authorization: "Bearer " + getToken(),
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
fileList: [],
|
|
|
|
|
|
|
|
imageUrl: '',
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
|
|
value: {
|
|
|
|
|
|
|
|
handler(val) {
|
|
|
|
|
|
|
|
if (val) {
|
|
|
|
|
|
|
|
// 如果是字符串,直接设置imageUrl
|
|
|
|
|
|
|
|
if (typeof val === 'string') {
|
|
|
|
|
|
|
|
this.imageUrl = val;
|
|
|
|
|
|
|
|
// 同时更新fileList以确保el-upload组件状态同步
|
|
|
|
|
|
|
|
this.fileList = [{ name: val, url: val }];
|
|
|
|
|
|
|
|
} else if (Array.isArray(val) && val.length > 0) {
|
|
|
|
|
|
|
|
// 如果是数组,取第一项
|
|
|
|
|
|
|
|
const item = val[0];
|
|
|
|
|
|
|
|
this.imageUrl = typeof item === 'string' ? item : item.url;
|
|
|
|
|
|
|
|
this.fileList = [{ name: this.imageUrl, url: this.imageUrl }];
|
|
|
|
|
|
|
|
} else if (val.url) {
|
|
|
|
|
|
|
|
// 如果是对象并且有url属性
|
|
|
|
|
|
|
|
this.imageUrl = val.url;
|
|
|
|
|
|
|
|
this.fileList = [{ name: val.name || val.url, url: val.url }];
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.imageUrl = '';
|
|
|
|
|
|
|
|
this.fileList = [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.imageUrl = '';
|
|
|
|
|
|
|
|
this.fileList = [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
deep: true,
|
|
|
|
|
|
|
|
immediate: true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
|
|
// 上传前校检格式和大小
|
|
|
|
|
|
|
|
handleBeforeUpload(file) {
|
|
|
|
|
|
|
|
// 校检文件类型
|
|
|
|
|
|
|
|
if (this.fileType) {
|
|
|
|
|
|
|
|
const fileName = file.name.split('.');
|
|
|
|
|
|
|
|
const fileExt = fileName[fileName.length - 1].toLowerCase();
|
|
|
|
|
|
|
|
const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
|
|
|
|
|
|
|
|
if (!isTypeOk) {
|
|
|
|
|
|
|
|
this.$message.error(`文件格式不正确,请上传${this.fileType.join("/")}格式文件!`);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 校检文件大小
|
|
|
|
|
|
|
|
if (this.fileSize) {
|
|
|
|
|
|
|
|
const isLt = file.size / 1024 / 1024 < this.fileSize;
|
|
|
|
|
|
|
|
if (!isLt) {
|
|
|
|
|
|
|
|
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
handleUploadError(err) {
|
|
|
|
|
|
|
|
this.$message.error("上传文件失败,请重试");
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
handleUploadSuccess(res, file) {
|
|
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
|
|
this.imageUrl = res.fileName;
|
|
|
|
|
|
|
|
this.fileList = [{ name: res.fileName, url: res.fileName }];
|
|
|
|
|
|
|
|
this.$emit("input", res.fileName);
|
|
|
|
|
|
|
|
this.$message.success("上传成功");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.$message.error(res.msg || "上传失败");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// 删除文件
|
|
|
|
|
|
|
|
handleDelete(e) {
|
|
|
|
|
|
|
|
if (e) e.stopPropagation();
|
|
|
|
|
|
|
|
this.imageUrl = '';
|
|
|
|
|
|
|
|
this.fileList = [];
|
|
|
|
|
|
|
|
this.$emit("input", '');
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
// 获取文件名称
|
|
|
|
|
|
|
|
getFileName(name) {
|
|
|
|
|
|
|
|
if (name.lastIndexOf("/") > -1) {
|
|
|
|
|
|
|
|
return name.slice(name.lastIndexOf("/") + 1);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
|
|
.upload-file {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.cover-upload {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.cover-upload ::v-deep .el-upload {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.cover-upload ::v-deep .el-upload-dragger {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
height: 180px;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
border: 1px dashed #d8d8d8;
|
|
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.upload-content {
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.upload-icon {
|
|
|
|
|
|
|
|
width: 48px;
|
|
|
|
|
|
|
|
height: 48px;
|
|
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.upload-text {
|
|
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
|
|
margin-bottom: 6px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.upload-tip {
|
|
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 图片预览样式 */
|
|
|
|
|
|
|
|
.image-preview {
|
|
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.preview-img {
|
|
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
|
|
max-height: 100%;
|
|
|
|
|
|
|
|
object-fit: contain;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.image-actions {
|
|
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
|
|
transition: opacity 0.3s;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.image-preview:hover .image-actions {
|
|
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.image-actions .el-icon-delete {
|
|
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
|
|
padding: 8px;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
</style>
|