<template>
<div>
<el-upload
ref="upload"
name="attach"
:accept="accept"
:multiple="multiple"
:action="uploadAc"
:show-file-list="true"
:auto-upload="false"
with-credentials
:on-remove="handleRemove"
:http-request="
debounce(() => {
uploadRequest()
})
"
:limit="multiple ? limit : 2"
:on-change="
debounce((file, fileList) => {
onChange(file, fileList)
})
"
:file-list="fileList"
:before-upload="beforeUpload"
>
<!-- :on-preview="handlePreview" -->
<!-- :limit="1" -->
<el-button slot="trigger" type="primary" size="mini">{{
zh_en('上传文件', 'Upload Files')
}}</el-button>
<!-- <el-dropdown type="primary" size="mini">
<el-button
type="primary"
size="mini"
@click="uploadFloder"
>
选择文件
<i class="el-icon-arrow-down el-icon--right" />
</el-button>
<el-dropdown-menu slot="dropdown">
<el-button
type="primary"
size="mini"
@click="uploadFloders"
>选择文件夹
</el-button>
</el-dropdown-menu>
</el-dropdown> -->
<span style="paddingLeft:10px;color:#2D8CF0;fontSize:12px;">
{{ uploadNotes }}
</span>
<span
v-if="multiple"
style="paddingLeft:10px;color:#ff4949;fontSize:12px;display:block"
>
{{
zh_en(
'建议单次选择文件数不超过300个,可多次选择例如要上传900张发票,请分3次选择,然后一起提交,这样上传速度最快。',
'It is recommended that you select no more than 300 invoices at a time. You can select multiple times .For example, to upload 900 invoices, please select them in three times and submit them together, so that the upload speed is the fastest.'
)
}}
</span>
</el-upload>
<el-dialog
:append-to-body="true"
:visible.sync="dialog.show"
center
:show-close="false"
:close-on-click-modal="false"
:close-on-press-escape="false"
class="noBackground"
>
<el-progress type="circle" :percentage="dialog.percentage" />
<p>{{ zh_en('正在上传...', 'Be uploading...') }}</p>
</el-dialog>
</div>
</template>
<script>
export default {
components: {},
props: {
accept: {
type: String,
default: '.pdf,.ofd'
},
uploadAc: {
type: String,
default: ''
},
multiple: {
type: Boolean,
default: true
},
limit: {
type: Number,
default: null
},
require: {
type: Boolean,
default: true
},
successFunction: {
type: Function,
default: () => {
return new Promise((resolve, reject) => {
console.log('success')
resolve()
})
}
},
uploadNotes: {
type: String,
default: null
}
},
data() {
return {
fileList: [],
formData: new FormData(),
token: null,
dialog: {
show: false,
percentage: 0
}
}
},
computed: {
// uploadAc() {
// return `${process.env.VUE_APP_BASE_API}/station/import`
// }
},
mounted() {},
methods: {
clear() {
this.$refs['upload'].clearFiles()
this.fileList = []
},
// 支持上传文件夹
uploadFunction() {
this.$nextTick(() => {
document.getElementsByClassName(
'el-upload__input'
)[0].webkitdirectory = true
})
},
handleRemove(val, b) {
console.log('val', val)
this.fileList = b
},
uploadFloder() {
this.$nextTick(() => {
document.getElementsByClassName(
'el-upload__input'
)[0].webkitdirectory = false
})
},
uploadFloders() {
this.$nextTick(() => {
document.getElementsByClassName(
'el-upload__input'
)[0].webkitdirectory = true
})
},
handlePreview(file) {
console.log(file)
},
// 执行压缩方法生成压缩文件
handleBefore(fileList) {
// const loading = this.$loading({
// lock: true,
// text: 'Loading',
// spinner: 'el-icon-loading',
// background: 'rgba(0, 0, 0, 0.7)'
// })
// var new_zip = new JsZip()
// const date = new Date()
// fileList.map(file => {
// new_zip.file(file.name, file.raw)
// })
// new_zip
// .generateAsync({ type: 'Blob', compression: 'DEFLATE' })
// .then(function(content) {
// loading.close()
// console.log('数量:', fileList.length, 'time:', new Date() - date)
// console.log(
// 'zip包大小:',
// (content.size / (1024 * 1024)).toFixed(2) + 'M'
// )
// // see FileSaver.js
// FileSaver(content, 'example.zip')
// })
},
onChange(file, fileList) {
// console.log(file, fileList)
// if (this.multiple) {
// const filterFileList = fileList.filter(item => {
// return (
// this.getFileType(item.name) === 'ofd' ||
// this.getFileType(item.name) === 'pdf'
// )
// })
// 单个文件上传时新的文件更新旧的文件
if (!this.multiple) {
if (fileList.length > 0) {
this.fileList = [fileList[fileList.length - 1]] // 这一步,是 展示最后一次选择文件
return
}
} else {
console.log(file)
// this.fileList = [
// ...fileList.filter(item => {
// return item.raw.name !== file.name
// }),
// file
// ]
const fullLoading = this.fullLoading()
// 过滤重复文件
this.fileList = fileList.reduce((prev, next) => {
// console.log(prev)
if (
prev.find(item => {
return item.raw.name === next.raw.name
})
) {
return prev
} else {
return [...prev, next]
}
}, [])
setTimeout(() => {
fullLoading.close()
}, 1000)
}
// }
},
getFileType(filePath) {
var startIndex = filePath.lastIndexOf('.')
if (startIndex !== -1) {
return filePath.substring(startIndex + 1, filePath.length).toLowerCase()
} else return ''
},
// throttle(callback, wait = 500) {
// let timer = null
// let startTime
// return function() {
// const ctx = this
// const args = arguments
// const now = +new Date()
// if (startTime && now < startTime + wait) {
// clearTimeout(timer)
// timer = setTimeout(function() {
// startTime = now
// callback.apply(ctx, args)
// }, wait)
// } else {
// startTime = now
// callback.apply(ctx, args)
// }
// }
// },
debounce(fn, delay) {
var timer = null
return function() {
var context = this
var args = arguments
clearTimeout(timer)
timer = setTimeout(function() {
fn.apply(context, args)
}, delay)
}
},
beforeUpload(file) {
// var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
// const accept = this.accept
// // const extension = testmsg === 'xls'
// // const extension2 = testmsg === 'xlsx'
// const isLt2M = file.size / 1024 / 1024 < 20 // 这里做文件大小限制
// const isAccept =
// accept.indexOf(testmsg) !== -1 && accept.indexOf(testmsg) !== '-1'
// if (!isAccept) {
// this.message_alert_withObject({
// message: this.zh_en(
// `上传文件只能是 ${accept}格式!`,
// `The uploaded file must be in ${accept} format only`
// ),
// type: 'error'
// })
// return false
// }
// if (!isLt2M) {
// this.message_alert_withObject({
// message: this.zh_en(
// `上传文件大小不能超过 20MB!`,
// `The uploaded file size cannot exceed 20MB!`
// ),
// type: 'error'
// })
// return false
// }
// // const formData = this.formData
// // if (this.multiple) {
// // formData.append('files', file, file.name)
// // } else {
// // formData.append('file', file, file.name)
// // }
// // return extension || (extension2 && isLt2M)
// return isLt2M && isAccept
return true
},
// 文件列表复制到上传组件中
fileListToFormData() {
const fileList = this.fileList
const formData = new FormData()
formData.append('token', this.token)
if (this.multiple) {
fileList.forEach(file => {
formData.append('files', file['raw'], file.name)
})
} else {
// ie 不支持 formData.set
formData.append('file', fileList[0]['raw'], fileList[0]['name'])
}
this.formData = formData
},
// async getToken() {
// try {
// const tokenRes = await this.$store.dispatch('file/getToken') // 获取token
// // const tokenRes = 'token' // 获取token
// this.token = tokenRes.data
// } catch (error) {
// console.log(error)
// }
// },
async uploadRequest(fileObj) {
// const formData = this.formData
this.uploadFiles()
// if (this.multiple) {
// // fileList 的赋值放到了提交之前
// if (formData.getAll('files').length === this.fileList.length) {
// this.uploadFiles()
// }
// } else {
// this.uploadFiles()
// }
},
cutArray(array, subLength) {
let index = 0
const newArr = []
while (index < array.length) {
newArr.push(array.slice(index, (index += subLength)))
}
return newArr
},
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
},
async uploadFiles() {
// const fullLoading = this.fullLoading()
try {
const formData = this.formData
const multiple = this.multiple
// const totalFileServerRes = []
let fileResponse = {}
let filesResponse = []
this.dialog.show = true
let result = null
if (multiple) {
// const filesList = this.formData.getAll('files')
const filesList = this.fileList
// 每次最大文件上传数量
const maxRequest = 10
// 并发请求数量
const maxConcurrency = 6
// 接收 上传文件列表,返回size 合计20M以内的数量
const checkSizeNumber = list => {
let number = 0
let filesSize = 0
for (const file of list) {
filesSize += file.size
if (filesSize / 1024 / 1024 < 20 && number < maxRequest) {
number++
}
}
return number
}
const doMutilRequest = async list => {
return new Promise((resolve, reject) => {
const requestPromise = []
const cutArrayResult = this.cutArray(list, checkSizeNumber(list))
for (const items of cutArrayResult) {
const formDataList = new FormData()
formDataList.append('token', this.token)
// fileList 与 formData中的files不同
items.map(file => {
formDataList.append('files', file['raw'], file.name)
})
requestPromise.push(
new Promise((res, rej) => {
// this.sleep(Math.random() * 1000).then(r => {
// res(['1', '2', '3', '4', 5, 6, 7, 8, 9, 0])
// })
this.$store
.dispatch('file/multiUploadFiles', formDataList)
.then(urls => {
res(urls.split(','))
// res(['1', '2', '3', '4', 5, 6, 7, 8, 9, 0])
})
.catch(error => {
rej(error)
})
})
)
}
Promise.all(requestPromise)
.then(urlsArray => {
resolve(
urlsArray.reduce((a, b) => {
return [...a, ...b]
}, [])
)
})
.catch(error => {
reject(error)
})
})
}
const checkRequestNumber = (list, receiveUrls) => {
return new Promise((resolve, reject) => {
// 更新进度条状态
this.dialog.percentage =
parseInt((receiveUrls.length * 10000) / filesList.length) / 100
// 上传文件数量超过预定限制,分批次请求
doMutilRequest(list.slice(0, maxRequest * maxConcurrency))
.then(urls => {
if (list.length > maxRequest * maxConcurrency) {
const undealList = list.slice(maxRequest * maxConcurrency)
checkRequestNumber(undealList, [...receiveUrls, ...urls])
.then(r => {
resolve(r)
})
.catch(error => {
reject(error)
})
} else {
// 更新进度条状态
this.dialog.percentage = 100
resolve({
list: list,
receiveUrls: [...receiveUrls, ...urls]
})
}
})
.catch(error => {
reject(error)
})
})
}
const res = await checkRequestNumber(filesList, [])
const filePaths = res.receiveUrls
filesResponse = filesList.map((it, index) => {
const item = {}
item.scale = filesList[index].size
item.storeName = filePaths[index]
item.displayName = filesList[index].name
return item
})
result = filesResponse
} else {
const fileServerRes = await this.$store.dispatch(
'file/uploadFile',
formData
)
// IE 11 不支持formData.get方法
// const file = formData.get('file')
const file = this.fileList[0]
fileResponse = {
scale: file.size,
storeName: fileServerRes,
displayName: file.name
}
result = fileResponse
}
await new Promise((resolve, reject) => {
this.successFunction(result)
.then(resolve())
.catch(err => {
console.log(err)
this.$confirm(
this.zh_en('出现错误,再试一次?', 'Error occurred,try again?'),
this.zh_en('提示', 'Warning'),
{
confirmButtonText: this.zh_en('重试', 'Retry'),
cancelButtonText: this.zh_en('取消', 'Cancel'),
type: 'warning'
}
)
.then(_ => {
// this.$emit('close', this.selected)
this.successFunction(result)
.then(resolve())
.catch(err => {
reject(err)
})
})
.catch(_ => {
this.message_alert(this.zh_en('取消!', 'Cancel!'))
reject('取消!')
})
})
})
this.dialog.show = false
// 完成后formData置空
// this.formData = new FormData()
// this.fileList = []
} catch (error) {
console.log(error)
this.dialog.show = false
if (this.$refs['upload']) {
// console.log('清空文件')
// this.$refs['upload'].clearFiles()
}
} finally {
console.log('close dialog')
// this.dialog.show = false
// fullLoading.close()
}
},
async submit() {
// 判断是否是必选,若为必选则判断fileList是否为空
const fileList = this.fileList
if (this.require && !(fileList && fileList.length)) {
this.message_alert(
this.zh_en('请选择上载文件', 'Please choose upload file')
)
return false
}
const accept = this.accept
const isAccept = fileList.every(file => {
var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
const result = accept.includes(testmsg.toLowerCase())
return result
})
if (!isAccept) {
this.message_alert_withObject({
message: this.zh_en(
`上传文件只能是 ${accept}格式!`,
`The uploaded file must be in ${accept} format only`
),
type: 'error'
})
return
}
const isLt2M = fileList.every(file => {
const result = file.size / 1024 / 1024 < 20
return result
})
if (!isLt2M) {
this.message_alert_withObject({
message: this.zh_en(
`上传文件大小不能超过 20MB!`,
`The uploaded file size cannot exceed 20MB!`
),
type: 'error'
})
return false
}
const fullLoading = this.fullLoading()
try {
// this.btnLoading = true
const tokenRes = await this.$store.dispatch('file/getToken') // 获取token
this.token = tokenRes.data
this.fileListToFormData()
this.$refs['upload'].submit()
// 解决上传后无法继续上传的问题
// if (
// formData.getAll('files').length === this.fileList.length ||
// formData.get('file')
// ) {
// this.uploadRequest()
// } else {
// this.$refs['upload'].submit()
// }
} catch (error) {
console.log(error)
} finally {
// this.btnLoading = false
fullLoading.close()
}
}
}
}
</script>
<style lang="scss" scoped>
/deep/ .noBackground {
.el-dialog {
background: none;
box-shadow: none;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
position: absolute;
margin-top: 0 !important;
p {
color: #409eff;
}
}
.el-dialog__body {
text-align: center;
border: none;
}
}
</style>