多租户商城-商户端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

372 lines
9.4 KiB

<!--
* @FileDescription: index
* @Author: kahu
* @Date: 2022/12/14
* @LastEditors: kahu
* @LastEditTime: 2022/12/14
-->
<template>
<div class="content">
<el-upload
v-loading="isUploading"
:disabled="componentError"
class="upload-demo"
drag
:headers="headers"
:file-list="viewFileList"
:name="name"
:show-file-list="showFileList"
:list-type="showFileListType"
:multiple="multiple"
:action="uploadUrl"
:limit="limit"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:before-remove="handleBeforeRemove"
:on-remove="handleRemove"
:on-preview="handlePreviewOpen"
>
<i class="el-icon-upload"></i>
<div
class="el-upload__text"
v-if="!componentError"
>将文件拖到此处,或<em>点击上传</em></div>
<div
class="error-text"
v-else
> 组件配置错误,请查看控制台
</div>
<div
class="el-upload__tip"
slot="tip"
>
文件大小不超过{{ limitSize }}m,文件类型为{{ types.toString() }}
</div>
</el-upload>
<!-- 预览 -->
<el-dialog
title="预览"
:visible.sync="previewObj.show"
width="60%"
:before-close="handlePreviewClose"
>
<div class="preview-content">
<template v-if="previewObj.file && previewObj.file.type.includes('image')">
<el-image class="preview-item" :src="previewObj.file.url" />
</template>
<template v-if="previewObj.file && previewObj.file.type.includes('video')">
<video class="preview-item" controls :src="previewObj.file.url" />
</template>
</div>
</el-dialog>
</div>
</template>
<script>
import mime from 'mime'
let fullLoading = null
const baseURL = process.env.VUE_APP_DOMAIN_PREFIX
export default {
name: "Upload",
props: {
headers:{
type:Object,
default:()=>({})
},
/** 上传时候表单的KEY */
name: {
type: String,
default: () => "file"
},
/** 限制上传数量 */
limit: {
type: Number,
default: () => 5
},
/** 限制的那张大小 单位M */
limitSize: {
type: Number,
default: () => 5
},
/** 是否多选 */
multiple: {
type: Boolean,
default: () => true
},
/** 是否展示文件列表 */
showFileList: {
type: Boolean,
default: () => true
},
/** 文件展示方式 text/picture/picture-card */
showFileListType:{
type:String,
default:()=>'text'
},
/** 允许上传的文件尾缀 string[] */
types: {
type: Array,
default: () => (['jpg', 'png', 'gif'])
},
/** 默认的文件列表 string[] */
defaultFileList: {
type: Array,
default: () => ([])
},
/** 上传成功后端返回的字段名称 */
responseFileName: {
type: String,
default: () => 'url'
},
/** 是否需要全屏loading */
needFullScreenLoading:{
type:Boolean,
default:()=>true
}
},
data() {
return {
uploadUrl: `${ baseURL }/file/upload`,
// 真实文件列表
fileList: [],
// 默认展示的list,解决多上传只回调success一次的问题
viewFileList:[],
// 组件是否部署错误
componentError: false,
// 是否正在上传
isUploading:false,
// 预览对象
previewObj:{
show:false,
file:null
}
}
},
watch: {
defaultFileList: {
handler() {
// 判断类型
const flag = Object.prototype.toString.call(this.defaultFileList) === '[object Array]'
&& this.defaultFileList.length > 0 &&
Object.prototype.toString.call(this.defaultFileList[0]) !== '[object String]'
if (flag) {
this.componentError = true
throw new Error('defaultFileList格式错误,应为string[]格式')
}else{
this.componentError = false
}
this.viewFileList = this.defaultFileList.map(defaultFilePath => ({name: defaultFilePath, url: defaultFilePath}))
this.viewFileList.forEach(item=>{
this.fileList.push(item)
})
},
deep: true,
immediate: true
},
fileList:{
handler(){
this.handleNotifyFather()
},
deep:true,
immediate:false
}
},
methods: {
/**
* 检查type是否符合types的mime
* @param type 文件后缀
* @param types 可用文件后缀集合
*/
handleCheckFileMime(type, types) {
const typeMimes = types.map(item => mime.getType(item))
return typeMimes.includes(type)
},
handleCheckFileSize(fileSize, limitSize) {
const limitByteSize = limitSize * 1024 * 1024
return limitByteSize > fileSize
},
/**
* 上传之前的钩子
* @param file
* @return {undefined}
*/
handleBeforeUpload(file) {
// 检查mime
const fileType = file.type || mime.getType(file.name.slice(file.name.lastIndexOf('.') + 1))
const checkFileMime = this.handleCheckFileMime(fileType, this.types)
const checkFileSize = this.handleCheckFileSize(file.size, this.limitSize);
!checkFileSize ? file.isJumpRemove = true : undefined
!checkFileSize ? this.$notify.warning(`文件大小不得超出${ this.limitSize }m`) : undefined
!checkFileMime ? file.isJumpRemove = true : undefined
!checkFileMime ? this.$notify.warning(`文件类型不在合法列表 ${ this.types }`) : undefined
if(checkFileSize && checkFileMime){
// 开启loading
this.isUploading = true
if(this.needFullScreenLoading){
fullLoading = this.$loading({
background:`rgba(255,255,255,0.5)`,
text:'上传中',
fullscreen:true
})
}
}
return checkFileSize && checkFileMime
},
/**
* 上传成功钩子
* @param response
* @param file
* @param fileList
*/
handleUploadSuccess(response, file, fileList) {
this.isUploading = false
if(this.needFullScreenLoading){
fullLoading?.close()
}
const successObj = {
url: response.data[this.responseFileName],
name: file.name
}
file.url = response.data[this.responseFileName]
this.fileList.push(successObj)
},
/**
* 上传失败的钩子
* @param err
* @param file
* @param fileList
*/
handleUploadError(err, file, fileList) {
},
/**
* 超出数量的钩子
* @param files
* @param fileList
*/
handleExceed(files, fileList) {
this.$notify.warning(`文件总数大于可上传数量 ${ this.limit }`)
},
/**
* 文件即将移除的钩子
* @param file
* @param fileList
*/
async handleBeforeRemove(file, fileList) {
// 如果是超出文件大小调用,放行
if (file?.raw?.isJumpRemove) {
return true
}
return await this.$confirm('此操作将会删除已上传的文件, 是否继续?', '提示', {
confirmButtonText: this.$t('common.sure'),
cancelButtonText: this.$t('common.cancel'),
type: 'warning'
})
},
/**
* 移除文件的钩子
*/
handleRemove(file, fileList) {
if (file?.raw?.isJumpRemove) {
return
}
this.fileList.splice(this.fileList.findIndex(fileItem => file?.response?.data[this.responseFileName] === fileItem.url || file.url === fileItem.url), 1)
},
/**
* 通知父组件
*/
handleNotifyFather(){
this.$emit('change',this.fileList)
},
/**
* 预览
* 图片视频直接预览,其他下载
* @param file
*/
handlePreviewOpen(file){
if(!file.type){
file.type = mime.getType(file?.url?.slice(file?.url?.lastIndexOf('.')+1)) || mime.getType(file?.name?.slice(file?.name.lastIndexOf('.')+1)) || undefined
}
if(file.type.includes('image') || file.type.includes('video')){
this.previewObj.file = file
this.previewObj.show = true
}else{
this.$confirm('需要下载才能预览此文件, 是否继续?', '提示', {
confirmButtonText: this.$t('common.sure'),
cancelButtonText: this.$t('common.cancel'),
type: 'warning'
}).then(() => {
let htmlAnchorElement = document.createElement('a');
htmlAnchorElement.download = file?.url.slice(file?.url.lastIndexOf('/')+1)
htmlAnchorElement.target='_bank'
htmlAnchorElement.href = file?.url
htmlAnchorElement.click()
htmlAnchorElement = null
}).catch(() => {
});
}
},
handlePreviewClose(){
this.previewObj.file = null
this.previewObj.show = false
}
}
}
</script>
<style
lang="scss"
scoped
>
::v-deep .el-upload {
width: 100% !important;
.el-upload-dragger {
width: 100% !important;
}
}
.error-text {
font-size: 18px;
font-weight: bolder;
color: red;
animation: error-animation 2.5s ease-in-out infinite;
}
@keyframes error-animation {
0%, 100% {
font-size: 18px;
color: red;
}
25%, 75% {
font-size: 16px;
color: #b9b1b1;
}
50% {
font-size: 18px;
color: #500000;
}
}
.preview-content{
display: flex;
align-items: center;
justify-content: center;
.preview-item{
min-width: 800px;
}
}
</style>