基于el-upload 封装的文件上传
vue
<div>
<el-upload
class="ape-uploader"
:class="{'ape-uploader-image':isImage, 'ape-uploader-disabled':disabledUpload}"
name="file"
:action="uploadToken.host"
:headers="uploadHeaders"
:data="uploadData"
:on-preview="handlePictureCardPreview"
:before-upload="beforeUpload"
:on-success="afterUpload"
:on-remove="removeUpload"
:list-type="listType"
:on-error="onError"
:file-list="uploadFileList"
:limit="limit"
:on-exceed="onExceed"
>
<el-button v-if="listType === 'text' && !disabledUpload" size="mini" type="success" icon="el-icon-upload" plain>点击上传</el-button>
<i v-if="listType === 'picture-card' && !disabledUpload" class="el-icon-plus"></i>
</el-upload>
<div slot="tip" class="el-upload__tip">{{ uploadTip ? uploadTip : `提示:单次可上传1个文件,单个文件≤50M,最多可上传${limit}个` }}</div>
<el-dialog :visible.sync="dialogVisible" append-to-body>
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</div>
javascript
import Cookies from 'js-cookie'
export default {
model: {
prop: 'value',
event: 'update'
},
props: {
value: {
type: Array,
required: true,
default: () => []
},
isImage: {
type: Boolean,
default: false
},
limit: {
type: Number,
default: 1
},
uploadTip: {
type: String,
default: ''
},
allowTypeList: {
type: Array,
default: function() {
//支持格式:doc .docx .pdf .xls .xlsx .csv .ppt .pptx .txt .xmind .mmap .zip .jpeg .png
return [
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'text/csv',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'text/plain',
'application/x-zip-compressed',
'application/zip',
'application/x-zip',
'image/jpeg',
'image/png',
'application/wps-office.doc',
'application/wps-office.xlsx',
'application/wps-office.docx',
'application/wps-office.pptx',
'application/wps-office.ppt',
'application/wps-office.xls',
'application/wps-office.xlsx'
]
}
},
allowSize: {
type: Number,
default: 1024 * 1024 * 50 //默认50MB
}
},
data() {
return {
uploadFileList: [],
imageUrl: '',
fileType: '',
dialogVisible: false,
dialogImageUrl: '',
uploadHeaders: {},
uploadData: {},
uploadToken: {
accessid: '',
host: '',
policy: '',
signature: '',
expire: 0,
callback: '',
dir: '',
upload_save: 'local',
filename: ''
}
}
},
created() {
},
computed: {
listType: function() {
if (this.isImage) {
return 'picture-card'
} else {
return 'text'
}
},
disabledUpload() {
return this.uploadFileList.length >= this.limit
}
},
methods: {
/**
* 点击文件列表中已上传的文件时的钩子
*/
handlePictureCardPreview(file) {
if (this.isImage) {
this.dialogImageUrl = file.url
this.dialogVisible = true
}
},
/**
* 超过文件最多数量
*/
onExceed(files, fileList) {
let length = fileList.length
let msg = '最多上传' + length + '个文件'
this.$message.error(msg)
},
/**
* 获取上传凭证
*/
async getOssToken() {
// this.uploadToken = await this.$api.getOssToken()
//开发环境,正向代理使用
const BASE_API = process.env.NODE_ENV === 'production' ? localStorage.getItem('BASE_API') : process.env.VUE_APP_BASE_API
this.uploadToken.host = BASE_API + 'common/file/upload'
},
/**
* 上传完成
*/
afterUpload(res, file, fileList) {
console.log(res)
console.log(file)
console.log(fileList)
if (res.code === 200) {
// this.imageUrl = URL.createObjectURL(file.raw)
// this.$emit('handleUploadSuccess', res.data[0], this.formatFileList(fileList))
const arr = fileList.map(item => {
return item.response?.data ?? {}
})
this.uploadFileList = fileList
this.$emit('update', arr)
} else {
this.$message.error(res.message)
this.uploadFileList = fileList.filter(item => {
return item['uid'] !== file['uid']
})
}
},
/**
* 删除文件
*/
removeUpload(file, fileList) {
const arr = fileList.map(item => {
return item.response?.data ?? {}
})
this.uploadFileList = fileList
this.$emit('update', arr)
// this.$emit('handleUploadRemove', file, this.formatFileList(fileList))
},
/**
* 上传失败
*/
onError(err, file, fileList) {
this.$message.error(err)
// this.$emit('handleUploadError', err, file, fileList)
},
/**
* 上传前
*/
async beforeUpload(file) {
let checkType = this.allowTypeList.includes(file.type)
let checkSize = file.size > this.allowSize
if (!checkType) {
this.$message.error('文件类型不合法,支持格式:doc .docx .pdf .xls .xlsx .csv .ppt .pptx .txt .zip .jpeg .png')
throw '文件类型不合法'
}
if (checkSize) {
this.$message.error('文件大小超过限制')
throw '文件大小超过限制'
}
const suffix_index = file.name.lastIndexOf('.')
this.fileType = file.name.substring(suffix_index)
//上传配置
await this.setOssParams()
await this.$emit('handleUploadBefore', file)
return true
},
/**
* 设置上传参数
*/
async setOssParams() {
await this.getOssToken()
const urlInfo = JSON.parse(Cookies.get('urlInfo'))
let fileKey = this.uploadToken.dir + this.uploadToken.filename
if (this.fileType) {
fileKey += this.fileType
}
if (this.uploadToken.upload_save === 'oss') {
this.uploadData = {
key: fileKey,
policy: this.uploadToken.policy,
OSSAccessKeyId: this.uploadToken.accessid,
success_action_status: '200', //让服务端返回200,不然,默认会返回204
callback: this.uploadToken.callback,
signature: this.uploadToken.signature
}
}
if (this.uploadToken.upload_save === 'local') {
this.uploadHeaders = {
'Authorization': `Bearer ${urlInfo.token}`,
'systemCode': urlInfo.systemCode
}
// this.uploadData = {
// upload_path: this.uploadToken.dir
// }
}
},
/**
* 格式化文件列表
*/
formatFileList(fileList) {
let result = []
for (let i = 0; i < fileList.length; i++) {
if (fileList[i].response === undefined) {
result.push(fileList[i])
} else {
let resData = fileList[i].response.data[0]
let item = {
id: resData.id,
name: resData.title,
path: resData.path,
url: resData.full_path,
size: resData.size
}
result.push(item)
}
}
return result
}
}
}
text
<style rel="stylesheet/scss" lang="scss" scoped>
//按钮宽度
$icon-width: 100px;
//按钮高度
$icon-height: 100px;
.ape-uploader-image {
.el-upload-dragger {
width: $icon-width;
height: $icon-height;
}
}
.ape-uploader-image {
.el-upload--picture-card {
width: $icon-width;
height: $icon-height;
line-height: $icon-height;
}
}
.ape-uploader-image {
.el-upload-list--picture-card {
.el-upload-list__item {
width: $icon-width;
height: $icon-height;
}
}
}
.ape-uploader-disabled {
.el-upload--picture-card {
display: none;
}
}
.el-progress--circle {
width: 80px !important;
}
.el-progress-circle {
width: 80px !important;
height: 80px !important;
}
</style>
基于原生组件+element样式的上传组件
vue
// 使用
<el-form-item label="附件" prop="file">
<file-upload v-model="Form.file" ref="upload" :limit="1" :voucherNumber="voucherNumber" @restart="onClose"></file-upload>
</el-form-item>
vue
<!--组件-->
<template>
<div>
<form enctype="multipart/form-data">
<label for="file" class="filelabel el-button el-button--mini el-button--success">
<el-icon class="el-icon-upload"></el-icon>
选择文件
</label>
<input type="file"
ref="input_file"
id="file"
style="display: none"
@change="handleFileChange"
/>
<div class="info" v-if="value">
<div>{{ value }}</div>
<el-icon class="el-icon-close info-icon" @click.native="close"></el-icon>
</div>
</form>
</div>
</template>
<script>
import { apiUploadFile } from '@/api/finacial'
export default {
model: {
prop: 'value',
event: 'update'
},
props: {
value: {
type: String,
required: true,
default: ''
},
limit: {
type: Number,
default: 1
},
uploadTip: {
type: String,
default: ''
},
voucherNumber: {
type: String,
default: ''
},
allowTypeList: {
type: Array,
default: function() {
//支持格式:doc .docx .pdf .xls .xlsx .csv .ppt .pptx .xmind .mmap .zip .jpeg .png
return [
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'text/csv',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/x-zip-compressed',
'application/zip',
'application/x-zip',
'image/jpeg',
'image/png',
'application/wps-office.doc',
'application/wps-office.xlsx',
'application/wps-office.docx',
'application/wps-office.pptx',
'application/wps-office.ppt',
'application/wps-office.xls',
'application/wps-office.xlsx'
]
}
},
allowSize: {
type: Number,
default: 1024 * 1024 * 10 //默认10MB
},
userOptions: {
type: Array,
default: () => []
},
permissions: {
type: Boolean,
default: false
}
},
data() {
return {
query:undefined
}
},
created() {
},
computed: {
listType: function() {
if (this.isImage) {
return 'picture-card'
} else {
return 'text'
}
}
},
methods: {
close() {
this.$emit('update','')
},
check(file) {
let checkType = this.allowTypeList.includes(file.type)
let checkSize = file.size > 1024 * 1024 * 10 //默认10MB
// let length = fileList.length
// let msg = '最多上传' + length + '个文件'
// this.$message.error(msg)
if (!checkType) {
throw '文件类型不合法,支持格式:doc .docx .pdf .xls .xlsx .csv .ppt .pptx .zip .jpeg .png'
}
if (checkSize) {
throw '文件大小超过限制'
}
},
async handleFileChange(e) {
const files = e.target.files[0]
try {
await this.check(files)
this.query = await this.setOssParams(files)
this.$emit('update',files.name)
this.$refs.input_file.value = ''
} catch (e) {
this.$message.error(e)
}
},
// 参数组装
setOssParams(files) {
let query = new FormData()
query.append('file', files)
query.append('voucherNumber', this.voucherNumber)
return query
},
/**
* 上传完成
*/
afterUpload(res, file, fileList) {
console.log(res)
console.log(file)
console.log(fileList)
if (res.code === '000000') {
// const arr = fileList.map(item => {
// if (item['uid'] === file['uid'] && this.permissions) {
// item['response']['data']['permission'] = {
// 'type': 0, //0=》默认所有上级可见,1 =》360评估人可见,2=》指定用户可见
// 'designate_user': [] //当type=2时存在并必须有值
// }
// }
// return item.response?.data ?? {}
// })
this.uploadFileList = fileList
// this.$emit('update', arr)
this.$emit('restart')
} else {
this.$message.error(res.message)
this.uploadFileList = fileList.filter(item => {
return item['uid'] !== file['uid']
})
}
},
/**
* 删除文件
*/
submit() {
apiUploadFile(this.query).then(res => {
this.$message.success(res.message)
this.$emit('restart')
}).catch(err=>{
this.$message.error(err.message)
}).finally(()=>{
this.close()
})
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.info{
background-color: #f4f4f5;
color: #909399;
padding: 0 4px;
color: #909399;
opacity: 1;
display: flex;
justify-content: space-between;
align-items: center;
transition: opacity .2s;
.info-icon{
cursor: pointer;
}
}
</style>