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.
137 lines
3.9 KiB
137 lines
3.9 KiB
<template>
|
|
<div>
|
|
<!--上传组件-->
|
|
<el-upload
|
|
class="upload-demo"
|
|
:action="uploadUrl"
|
|
:auto-upload="false"
|
|
:on-change="handleChange"
|
|
:before-upload="handleBeforeUpload"
|
|
:on-progress="handleProgress"
|
|
>
|
|
<el-button slot="trigger">选取文件</el-button>
|
|
<!--上传文件按钮-->
|
|
<el-button style="margin-left: 10px" type="primary" :loading="uploading" :disabled="files.length === 0" @click="handleUpload">
|
|
上传文件
|
|
</el-button>
|
|
<el-progress :percentage="percent" />
|
|
</el-upload>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapGetters } from 'vuex'
|
|
import axios from 'axios'
|
|
|
|
export default {
|
|
data() {
|
|
return {
|
|
files: [], // 选中的文件列表
|
|
uploading: false, // 是否正在上传
|
|
percent: 0, // 上传进度
|
|
uploadUrl: this.baseApi + '/api/collect/uploadFiles' // 上传地址
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters([
|
|
'baseApi'
|
|
])
|
|
},
|
|
methods: {
|
|
// 切片上传
|
|
async upload(file) {
|
|
const chunkSize = 1024 * 1024 // 每个块的大小为 1MB
|
|
const fileSize = file.size // 文件大小
|
|
const chunks = Math.ceil(fileSize / chunkSize) // 总块数
|
|
const tasks = [] // 上传任务数组
|
|
let uploaded = 0 // 已上传块数
|
|
|
|
// 文件切割
|
|
for (let i = 0; i < chunks; i++) {
|
|
const start = i * chunkSize
|
|
const end = Math.min(start + chunkSize, fileSize)
|
|
|
|
tasks.push(
|
|
new Promise((resolve, reject) => {
|
|
const formData = new FormData()
|
|
formData.append('chunk_index', i) // 块编号
|
|
formData.append('chunk_count', chunks) // 总块数
|
|
formData.append('file_id', file.id) // 文件ID
|
|
formData.append('chunk_data', file.slice(start, end)) // 块数据
|
|
|
|
axios
|
|
.post(this.uploadUrl, formData) // 上传块数据
|
|
.then(res => {
|
|
uploaded++
|
|
this.percent = Math.floor((uploaded / chunks) * 100)
|
|
console.log(this.percent)
|
|
resolve()
|
|
})
|
|
.catch(err => {
|
|
reject(err)
|
|
})
|
|
})
|
|
)
|
|
}
|
|
|
|
// 待所有块上传完成后,发送合并请求
|
|
await Promise.all(tasks)
|
|
const res = await axios.post(this.uploadUrl, { file_id: file.id, chunks })
|
|
|
|
// 上传成功,返回文件URL
|
|
if (res.status === 200) {
|
|
return `${this.uploadUrl}/${file.id}`
|
|
} else {
|
|
throw new Error(res.data.message)
|
|
}
|
|
},
|
|
handleChange(files) {
|
|
this.files = files
|
|
},
|
|
async handleUpload() {
|
|
console.log('handleUpload')
|
|
try {
|
|
console.log('handleUpload2')
|
|
this.uploading = true
|
|
console.log(this.files)
|
|
const url = await this.upload(this.files)
|
|
// 文件上传成功,将url展示给用户
|
|
this.$message.success(`文件${this.files.name}上传成功!URL:${url}`)
|
|
// for (let i = 0; i < this.files.length; i++) {
|
|
// const file = this.files[i]
|
|
// console.log('file', file)
|
|
|
|
// }
|
|
} catch (err) {
|
|
console.log('handleUpload3')
|
|
this.$message.error(`文件上传失败!${err.message}`)
|
|
} finally {
|
|
console.log('handleUpload4')
|
|
this.uploading = false
|
|
}
|
|
},
|
|
handleBeforeUpload() {
|
|
// TODO: 检查文件大小、类型等
|
|
},
|
|
handleProgress(event, file) {
|
|
// 显示上传进度
|
|
this.percent = Math.floor((event.loaded / event.total) * 100)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.upload-demo{
|
|
position: relative;
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 120px;
|
|
margin: 20px 0 30px 0;
|
|
.el-progress{
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: -20px;
|
|
}
|
|
}
|
|
</style>
|