<template>
|
<div>
|
<el-upload ref="upload" :class="[
|
'avatar-uploader customUploadImg',
|
fileList.length === limitNumber?'uploadTrigger':'',
|
{moreThanOneLine:isMoreThanOneLine}
|
]" :headers="headers" action="api" :on-error="handleError" :accept="accept"
|
:http-request="handleRequrst" :on-change="handleChange" multiple
|
v-customLoading="{isLoading:isLoading,percentage:percentage}" :auto-upload="false"
|
:show-file-list="false">
|
<div class="upload-list__item" :draggable="draggable" @dragstart="dragstart(item)"
|
@dragenter="dragenter(item)" @dragend="dragend(item)" v-for="(item,index) in fileList"
|
:key="item.url">
|
<video v-if="getFileType(item.url) === 'video'" :src="item.url"
|
:style="{width:thumbnailImageWidth,height:thumbnailImageHeight}" />
|
<img v-else :src="item.url"
|
:style="{width:thumbnailImageWidth,height:thumbnailImageHeight}" />
|
<slot name="appendPart" :data="{item,index}"></slot>
|
<span class="el-upload-list__item-actions"
|
:style="{width:thumbnailImageWidth,height:thumbnailImageHeight,lineHeight:thumbnailImageHeight}">
|
<span class="el-upload-list__item-preview">
|
<i class="el-icon-zoom-in" @click="handlePreview(item.url)"></i>
|
</span>
|
<span class="el-upload-list__item-delete" v-show="isHideDelete">
|
<i class="el-icon-delete" @click="handleRemove(item)"></i>
|
</span>
|
</span>
|
</div>
|
<i slot="trigger" v-show="fileList.length !== limitNumber && isHideDelete"
|
class="el-icon-plus avatar-uploader-icon"></i>
|
<div slot="tip" v-if="imageSize" class="el-upload__tip" style="color:#909399;">
|
请上传{{imageSize}}的图片</div>
|
<div slot="tip" v-if="fileTip" class="el-upload__tip" style="color:#909399;" v-html="fileTip">
|
</div>
|
<div class="clear"></div>
|
</el-upload>
|
<el-dialog :visible.sync="dialogVisible" v-if="dialogVisible" :append-to-body="isAppendTobody">
|
<video v-if='getFileType(imgShow) === "video"' autoplay controls="controls" :src="imgShow"
|
width="100%" />
|
<img v-else :src="imgShow" width="100%" />
|
</el-dialog>
|
</div>
|
</template>
|
<script>
|
import {
|
getUuid
|
} from '@/api/sm'
|
import { mapState } from 'vuex'
|
import uploadFile from '@/api/uploadFile'
|
import { getFileType } from '@/utils/getFileType'
|
|
export default {
|
props: {
|
fileList: {
|
type: Array,
|
default: function() {
|
return []
|
}
|
},
|
index: {
|
type: Number,
|
default: 0
|
},
|
keyImg: {
|
type: String,
|
default: undefined
|
},
|
isAppendTobody: {
|
type: Boolean,
|
default: false
|
},
|
accept: {
|
type: String,
|
default: '.jpg,.jpeg,.png'
|
},
|
// 图片接收类型
|
uploadPath: {
|
type: String,
|
default: 'product'
|
},
|
// 表单数据
|
form: {
|
type: Object,
|
default: function() {
|
return {}
|
}
|
},
|
// 限制图片上传个数
|
limitNumber: {
|
type: Number,
|
default: 1
|
},
|
// 是否可拖拽
|
draggable: {
|
type: Boolean,
|
default: false
|
},
|
/**
|
* 设置上传图片的大小(提示)
|
*/
|
imageSize: {
|
type: String,
|
default: null
|
},
|
/**
|
* 页面缩略展示图宽度
|
*/
|
thumbnailImageWidth: {
|
type: String,
|
default: '148px'
|
},
|
/**
|
* 页面缩略展示图高度
|
*/
|
thumbnailImageHeight: {
|
type: String,
|
default: '148px'
|
},
|
// 是否隐藏删除按钮
|
isHideDelete: {
|
type: Boolean,
|
default: true
|
},
|
// 上传图片是否超过一行
|
isMoreThanOneLine: {
|
type: Boolean,
|
default: false
|
},
|
/**
|
* 设置上传图片的大小(提示)
|
*/
|
fileTip: {
|
type: String,
|
default: null
|
}
|
},
|
created() {
|
this.businessId = getUuid().split('-').join('')
|
},
|
computed: {
|
...mapState(['token']),
|
headers() {
|
return {
|
Authorization: `Bearer ${this.token}`
|
}
|
}
|
},
|
data: function() {
|
return {
|
businessId: null,
|
imgShow: null,
|
dialogVisible: false,
|
oldNum: {},
|
newNum: {},
|
files: [],
|
count: 0,
|
percentage: null, // 进度条数值
|
isLoading: false// 是否展示进度条遮罩
|
}
|
},
|
watch: {
|
count(newValue, oldValue) {
|
if (newValue !== this.files.length) {
|
this.handleRequrst()
|
}
|
}
|
},
|
methods: {
|
// 当文件改变时获取选中的文件
|
handleChange(file, fileList) {
|
if (!this.beforeAvatarUpload(file)) return; // 限制图片上传
|
this.files.push(file.raw)
|
this.count = fileList.length
|
this.count++
|
},
|
/**
|
*上传图片
|
*/
|
async handleRequrst(param) {
|
if (this.files.length + this.fileList.length > this.limitNumber) {
|
this.$message.warning(`当前限制选择 ${this.limitNumber} 个文件,本次选择了 ${this.files.length} 个文件,请重新选择`)
|
this.files = []
|
return
|
}
|
const formData = new FormData()
|
this.files.forEach(item => {
|
formData.append('files', item)
|
})
|
formData.append('bizCode', this.businessId)
|
formData.append('path', this.uploadPath)
|
// 进度条配置
|
const config = {
|
onUploadProgress: ProgressEvent => {
|
const progressPercent = Math.round(ProgressEvent.loaded / ProgressEvent.total * 100 | 0)
|
this.percentage = progressPercent === 100 ? 99 : progressPercent
|
this.isLoading = true
|
}
|
}
|
try {
|
const res = await uploadFile.fileUpload(formData, config)
|
if (res.data instanceof Array) {
|
res.data.forEach(item => {
|
var param = {
|
url: item.like,
|
id: item.key,
|
businessId: item.bizCode
|
}
|
this.$emit('handle-success', param)
|
})
|
this.files = []
|
this.percentage = 100
|
this.isLoading = false
|
} else {
|
this.isLoading = false
|
this.files = []
|
}
|
} catch (error) {
|
this.$message.error('上传文件失败!请重新上传')
|
this.files = []
|
this.isLoading = false
|
}
|
},
|
// 获取图片宽高
|
getImgWidthHeight(file) {
|
const _URL = window.URL || window.webkitURL
|
const image = new Image()
|
try {
|
image.src.srcObject = file
|
} catch (error) {
|
image.src = _URL.createObjectURL(file)
|
}
|
return new Promise((resolve, reject) => {
|
image.onload = () => {
|
const height = image.height
|
const width = image.width
|
resolve({ width, height })
|
}
|
})
|
},
|
// 记录初始拖拽信息
|
dragstart(value) {
|
this.oldNum = value
|
},
|
// 做最终操作
|
dragend(value) {
|
if (this.oldNum !== this.newNum) {
|
const oldIndex = this.fileList.indexOf(this.oldNum)
|
const newIndex = this.fileList.indexOf(this.newNum)
|
const newItems = [...this.fileList]
|
// 删除老的节点
|
newItems.splice(oldIndex, 1)
|
// 在列表中目标位置增加新的节点
|
newItems.splice(newIndex, 0, this.oldNum)
|
// 新数组顺序
|
this.fileList = [...newItems]
|
this.$emit('handle-file-data', this.fileList)
|
}
|
},
|
// 记录移动过程中信息
|
dragenter(value) {
|
this.newNum = value
|
},
|
/**
|
* 预览
|
*/
|
handlePreview(file) {
|
this.dialogVisible = true
|
this.imgShow = file
|
},
|
/**
|
* 删除图片
|
*/
|
handleRemove(file) {
|
this.$emit('handle-remove', file)
|
},
|
handleError(e, file, fileList) {
|
this.$message.error('上传文件失败')
|
},
|
// 获取文件类型
|
getFileType(file) {
|
return getFileType(file)
|
},
|
/**
|
* 设置上传图片大小
|
*/
|
beforeAvatarUpload(file) {
|
const nameType = file.name.substring(file.name.lastIndexOf('.') + 1)
|
const fileType = this.accept.toLowerCase().includes(nameType.toLowerCase())
|
const imgSize = file.raw.type.includes('image')
|
const videoSize = file.raw.type.includes('video')
|
if (!fileType) {
|
this.$message.error(`上传失败!仅支持${this.accept}格式,请重新上传`)
|
return false
|
}
|
if (imgSize) {
|
const fileSize = file.size / 1024 / 1024 < 5
|
if (!fileSize) {
|
this.$message.error('上传失败!图片大小不能超多 5MB!请重新上传')
|
return false
|
}
|
}
|
if (videoSize) {
|
const fileSize = file.size / 1024 / 1024 < 300
|
if (!fileSize) {
|
this.$message.error('上传失败!视频大小不能超多 300MB!请重新上传')
|
return false
|
}
|
}
|
return true
|
}
|
}
|
}
|
</script>
|
<style lang="scss">
|
.customUploadImg {
|
position: relative;
|
.clear {
|
clear: both;
|
}
|
.upload-list__item {
|
position: relative;
|
display: inline-block;
|
overflow: hidden;
|
box-sizing: border-box;
|
float: left;
|
margin: 0 15px 15px 0;
|
img,
|
video {
|
border: 1px solid #c0ccda;
|
border-radius: 6px;
|
}
|
.el-upload-list__item-actions {
|
position: absolute;
|
left: 0;
|
top: 0;
|
cursor: default;
|
text-align: center;
|
color: #fff;
|
opacity: 0;
|
font-size: 20px;
|
background-color: rgba(0, 0, 0, 0.5);
|
transition: opacity 0.3s;
|
border-radius: 6px;
|
span {
|
cursor: pointer;
|
}
|
.el-upload-list__item-delete {
|
position: static;
|
font-size: inherit;
|
color: inherit;
|
}
|
span + span {
|
margin-left: 15px;
|
}
|
}
|
.el-upload-list__item-actions:hover {
|
opacity: 1;
|
span {
|
display: inline;
|
}
|
}
|
}
|
.el-upload-dragger {
|
width: 148px;
|
height: 148px;
|
}
|
}
|
.moreThanOneLine {
|
.el-upload {
|
border: none !important;
|
display: block;
|
width: 150px;
|
margin-bottom: 15px;
|
.avatar-uploader-icon {
|
border: 1px dashed #d9d9d9;
|
border-radius: 6px;
|
}
|
}
|
}
|
.uploadTrigger {
|
.el-upload {
|
display: none;
|
}
|
}
|
</style>
|