最近遇到一个项目,使用vue开发后台管理系统,其中有一个需求是需要上传附件(Word、PPT、excel、图片格式、PDF、压缩包)
如图:
// 上传接口
uploadFile: (params, onUploadProgress) => upload('/sync_api/api/v1/upload/uploadFile', params, onUploadProgress),
<!-- 上传附件 -->
<div v-loading="fileUploading">
<div class="title-box">
<h3 style="width: 120px">
<span class="required">*</span>
上传附件
</h3>
<p>可上传Word、PPT、excel、图片格式、PDF、压缩包;总内容不超过500MB</p>
<!-- input上传 -->
<input
ref="fileUpload"
class="upload-input"
type="file"
title=""
multiple="multiple"
@change="fileChange($event, 0, 500, 0, ['word', 'ppt', 'excel', 'image', 'pdf', 'zip'], fileSuc)"
/>
<el-button class="add-btn" @click="add('fileUpload')">
<img alt="" class="imgIcon" src="@/assets/image/icon/addIcon1.png" />
新增
</el-button>
</div>
<div class="file-list" style="padding-left: 120px">
<div v-for="(item, index) in fileList" :key="index" class="file-box">
<div class="file-icon">
<!-- 删除icon图片 -->
<img
class="file-del"
src="@/assets/image/icon/icon-file-del.png"
alt=""
@click="fileList.splice(index, 1)"
/>
<img
v-if="typeList.image.includes(getSuffix(item.originalFileName))"
class="file-img"
src="@/assets/image/icon/icon-image.png"
alt=""
@click="download(item)"
/>
<img
v-else-if="typeList.word.includes(getSuffix(item.originalFileName))"
class="file-img"
src="@/assets/image/icon/icon-word.png"
alt=""
@click="download(item)"
/>
<img
v-else-if="typeList.ppt.includes(getSuffix(item.originalFileName))"
class="file-img"
src="@/assets/image/icon/icon-ppt.png"
alt=""
@click="download(item)"
/>
<img
v-else-if="typeList.excel.includes(getSuffix(item.originalFileName))"
class="file-img"
src="@/assets/image/icon/icon-excel.png"
alt=""
@click="download(item)"
/>
<img
v-else-if="typeList.pdf.includes(getSuffix(item.originalFileName))"
class="file-img"
src="@/assets/image/icon/icon-pdf.png"
alt=""
@click="download(item)"
/>
<img
v-else-if="typeList.zip.includes(getSuffix(item.originalFileName))"
class="file-img"
src="@/assets/image/icon/icon-zip.png"
alt=""
@click="download(item)"
/>
</div>
//文件名称
<p class="file-name">{{ item.originalFileName }}</p>
<el-button class="file-btn" @click="add('fileUpload', index)">
<img src="@/assets/image/icon/changeIcon.png" alt="" />
修改
</el-button>
</div>
</div>
</div>
<style>
.upload-input {
height: 0;
width: 0;
opacity: 0;
}
</style>
<script>
import { Message } from 'element-ui'
export default {
components: {},
data: () => ({
// 对应类型的名称(上传提示时需要)
typeName: {
image: '图片',
word: 'Word',
ppt: 'PPT',
excel: 'Excel',
zip: '压缩包',
pdf: 'PDF',
video: '视频'
},
typeList: {
// 支持上传的后缀名
image: ['png', 'jpg', 'jpeg', 'gif', 'bmp'], // 图片
word: ['doc', 'docx'], // Word
ppt: ['ppt', 'pptx'], // PPT
excel: ['xls', 'xlsx'], // Excel
zip: ['zip', 'rar', '7z'], // 压缩包
pdf: ['pdf'], // PDF
video: ['mp4', 'mov']
},
fileList: [], // 附件列表
fileUploading: false, // 上传附件Loading
editIndex: null, // 编辑中的Index
}),
watch: { },
created() { },
mounted() {},
methods: {
/**
* 下载
* @param file 下载的文件
*/
download(file) {
this.$download(file.filePath, file.originalFileName)
},
/**
* 上传点击事件
* @param ref
* @param editIndex
*/
add(ref, editIndex) {
this.editIndex = editIndex
this.$refs[ref].value = ''
this.$refs[ref].dispatchEvent(new MouseEvent('click'))
},
/**
* 上传附件文件回调
* @param fileArr
* @returns {Promise}
*/
async fileSuc(fileArr) {
this.fileUploading = true
const data = await this.uploadFile(fileArr, 'system').catch(() => {
this.fileUploading = false
})
this.fileUploading = false
if (this.editIndex != null) {
this.fileList.splice(this.editIndex, 1, ...data)
} else {
this.fileList.push(...data)
}
},
/**
* input获取文件事件
* @param e event
* @param fileSize 限制大小,单位MB
* @param totalSize 限制总大小,单位MB
* @param limit 限制数量
* @param typeList 支持的格式列表
* @param sucFun 成功回调
*/
fileChange(e, fileSize, totalSize, limit, typeList, sucFun) {
const files = e.target.files
const fileArr = []
let hasFile = false // 是否有可上传的文件
const msgList = [] // 消息队列
let total = 0
for (const file of files) {
if (fileArr.length >= limit && limit !== 0) {
msgList.push(`超过${limit}个文件,剩余文件跳过上传`)
break
}
if (file.size / 1024 / 1024 > fileSize && fileSize !== 0) {
if (fileSize > 1024) {
msgList.push(`${file.name}大于${fileSize / 1024}GB,跳过上传`)
} else {
msgList.push(`${file.name}大于${fileSize}MB,跳过上传`)
}
continue
}
total += file.size / 1024 / 1024
if (total > totalSize && totalSize !== 0) {
msgList.push(`超过${totalSize}MB,剩余文件跳过上传`)
break
}
let has = false
// 循环遍历支持下载后缀,不支持的文件则跳过
for (const k of typeList) {
const list = this.typeList[k]
if (list.includes(this.getSuffix(file.name))) {
has = true
break
}
}
if (!has) {
const msgTypeList = []
for (const k of typeList) {
msgTypeList.push(this.typeName[k])
}
msgList.push(`${file.name}不是${msgTypeList.join('、')},跳过上传`)
continue
}
fileArr.push(file)
hasFile = true
}
// 文件都被跳过,取消上传
if (!hasFile) {
msgList.push('没有可上传的文件')
this.msgTick(msgList)
return
}
this.msgTick(msgList) // 处理消息队列
sucFun(fileArr)
},
/**
* 多消息事件处理,避免同时弹出覆盖显示
* @param list 消息列表
* @param index 当前进行显示的下标
*/
msgTick(list, index = 0) {
if (!list[index]) {
return
}
setTimeout(
function() {
Message.error(list[index])
this.msgTick(list, index + 1)
}.bind(this),
300
)
},
/**
* 获取后缀名
* @param name 文件名
* @returns {string} 后缀名
*/
getSuffix(name) {
return name.substring(name.lastIndexOf('.') + 1).toLowerCase()
},
/**
* 上传
* @param fileList 文件列表
* @param type 类型
* @returns {Promise<*>}
*/
async uploadFile(fileList, type = 'system') {
const formData = new FormData()
formData.append('type', type)
fileList.forEach(item => formData.append('files', item))
const { data } = await this.$http.uploadFile(formData)
return data
}
}
}
</script>
至此,附件上传分享完毕