<template>
|
<div id="app">
|
<!-- 上传组件 -->
|
<!-- :action="uploadUrl" -->
|
<el-upload
|
ref="upload"
|
action
|
:multiple="true"
|
:show-file-list="true"
|
:auto-upload="false"
|
:http-request="uploadSectionFile"
|
:on-error="onError"
|
:on-change="changeFiles"
|
name="file"
|
:accept="acceptString"
|
>
|
<el-button class="button_box" slot="trigger" size="small" type="default"
|
>选择数据</el-button
|
></el-upload
|
>
|
<!-- 进度显示 -->
|
<!-- <div class="progress-box">
|
<span>上传进度:{{ percent.toFixed() }}%</span>
|
<el-button type="primary" size="mini" @click="handleClickBtn">{{
|
upload | btnTextFilter
|
}}</el-button>
|
</div> -->
|
</div>
|
</template>
|
|
<script>
|
import SparkMD5 from "spark-md5";
|
import axios from "axios";
|
|
export default {
|
name: "App3",
|
props: ["acceptString"],
|
filters: {
|
btnTextFilter(val) {
|
return val ? "暂停" : "继续";
|
},
|
},
|
data() {
|
return {
|
uploadFileList: [],
|
uploadNum: 0,
|
percent: 0,
|
videoUrl: "",
|
upload: true,
|
percentCount: 0,
|
};
|
},
|
methods: {
|
submitUpload() {
|
this.$refs.upload.submit();
|
},
|
cancelUpload() {
|
this.$refs.upload.clearFiles();
|
this.uploadNum = 0;
|
this.uploadFileList = [];
|
},
|
uploadSectionFile(param) {
|
let that = this;
|
const file = param.file;
|
let fsize = file.size / 1024 / 1024;
|
if (fsize > 100) {
|
//数据大于100M,执行分卷上传
|
this.handleBigFileUpload(file);
|
} else {
|
//小文件直接上传
|
const formData = new FormData();
|
formData.append("chunk", file);
|
formData.append("filename", file.name);
|
//服务端上传接口,后期对接
|
this.$axios({
|
url: "/datainsert/upload",
|
method: "post",
|
headers: { "Content-Type": "multipart/form-data" },
|
data: formData,
|
}).then((res) => {
|
alert("upload small file success!");
|
that.uploadNum++;
|
if (that.uploadNum === that.uploadFileList.length) {
|
that.$refs.upload.clearFiles();
|
that.uploadNum = 0;
|
that.uploadFileList = [];
|
}
|
});
|
}
|
},
|
changeFiles(file, fileList) {
|
this.uploadFileList = fileList;
|
},
|
onError(err, file, fileList) {
|
this.$alert("文件上传失败,请重试", "错误", {
|
confirmButtonText: "确定",
|
});
|
},
|
async handleBigFileUpload(file) {
|
if (!file) return;
|
let buffer;
|
try {
|
buffer = await this.fileToBuffer(file);
|
} catch (e) {
|
console.log(e);
|
}
|
// 将文件按固定大小(5M)进行切片,注意此处同时声明了多个常量
|
const chunkSize = 50 * 1024 * 1024,
|
chunkList = [], // 保存所有切片的数组
|
chunkListLength = Math.ceil(file.size / chunkSize), // 计算总共多个切片
|
suffix = /\.([0-9A-z]+)$/.exec(file.name)[1]; // 文件后缀名
|
|
// 根据文件内容生成 hash 值
|
const spark = new SparkMD5.ArrayBuffer();
|
spark.append(buffer);
|
const hash = spark.end();
|
|
// 生成切片,这里后端要求传递的参数为字节数据块(chunk)和每个数据块的文件名(fileName)
|
let curChunk = 0; // 切片时的初始位置
|
for (let i = 0; i < chunkListLength; i++) {
|
const item = {
|
chunk: file.slice(curChunk, curChunk + chunkSize),
|
fileName: `${hash}_${i}.${suffix}`, // 文件名规则按照 hash_1.jpg 命名
|
};
|
curChunk += chunkSize;
|
chunkList.push(item);
|
}
|
this.chunkList = chunkList; // sendRequest 要用到
|
this.hash = hash; // sendRequest 要用到
|
this.sendRequest();
|
},
|
// 将 File 对象转为 ArrayBuffer
|
fileToBuffer(file) {
|
return new Promise((resolve, reject) => {
|
const fr = new FileReader();
|
fr.onload = (e) => {
|
resolve(e.target.result);
|
};
|
fr.readAsArrayBuffer(file);
|
fr.onerror = () => {
|
reject(new Error("转换文件格式发生错误"));
|
};
|
});
|
}, // 发送请求
|
sendRequest() {
|
let that = this;
|
const requestList = []; // 请求集合
|
this.chunkList.forEach((item, index) => {
|
const fn = () => {
|
const formData = new FormData();
|
formData.append("chunk", item.chunk);
|
formData.append("filename", item.fileName);
|
return that
|
.$axios({
|
url: "/datainsert/upload",
|
method: "post",
|
headers: { "Content-Type": "multipart/form-data" },
|
data: formData,
|
})
|
.then((res) => {
|
alert("upload chunk :" + index + " success!");
|
that.chunkList.splice(index, 1); // 一旦上传成功就删除这一个 chunk,方便断点续传
|
});
|
};
|
requestList.push(fn);
|
});
|
|
let i = 0; // 记录发送的请求个数
|
// 文件切片全部发送完毕后,需要请求 '/merge' 接口,把文件的 hash 传递给服务器
|
//递归发送异步
|
const send = async () => {
|
if (i >= requestList.length) {
|
that.uploadNum++;
|
// 发送完毕
|
that.completeUploadBigFile();
|
return;
|
}
|
await requestList[i]();
|
i++;
|
send();
|
};
|
send(); // 发送请求
|
},
|
completeUploadBigFile() {
|
let that = this;
|
//服务端上传分卷完成后,将分卷合并还原文件接口,后期对接
|
this.$axios({
|
url: "/datainsert/merge",
|
method: "post",
|
data: { hash: this.hash },
|
}).then((res) => {
|
console.log(res);
|
if (that.uploadNum === that.uploadFileList.length) {
|
that.$refs.upload.clearFiles();
|
that.uploadNum = 0;
|
that.uploadFileList = [];
|
}
|
});
|
},
|
},
|
};
|
</script>
|
|
<style scoped>
|
.progress-box {
|
box-sizing: border-box;
|
width: 360px;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-top: 10px;
|
padding: 8px 10px;
|
background-color: #ecf5ff;
|
font-size: 14px;
|
border-radius: 4px;
|
}
|
</style>
|