1.html
<a-upload-dragger
style="margin: 0 auto"
name="file"
:show-upload-list="false"
:data="{ isup: 1 }"
:before-upload="videobeforeUpload"
:customRequest="ImgSplitUpload"
:action="$config.http.baseUrl + baseUrl"
:disabled="this.value != 0 || this.addForm.videoUrl != null"
v-model="addForm.videoUrl"
>
<div>
<div v-if="value == 0 && addForm.videoUrl == null">
<p style="margin-top: 20px">
<a-button>选择文件</a-button>
</p>
</div>
<div v-else-if="value != 0 && addForm.videoUrl == null">
<a-spin
tip="正在上传请稍等!"
:spinning="addForm.videoUrl == null"
>
<!-- <a-progress type="circle" :percent="value">
<span>上传{{ value }}%</span>
</a-progress> 进度条-->
</a-spin>
</div>
<div v-else-if="value != 0 && addForm.videoUrl">
<video
:src="addForm.videoUrl"
style="height: 200px; width: 200px"
></video>
</div>
</div>
</a-upload-dragger>
2.data()
data(){
return {
baseUrl: "Img/SplitUpload",
value: 0, // 进度条值
// 转码进度
videoTime: null,
addForm: {
videoUrl: null,
},
}
}
3.方法 methods
(1)上传前校验
// 文件上传前校验
// 视频--video/mp4 图片--image/jpeg或image/png 文档--application/pdf
// 软件-- application/x-zip-compressed或application/x-msdownload
videobeforeUpload(file) {
const isMP4 = file.type === "video/mp4";
if (!isMP4) {
this.$message.error("视频格式错误,请上传mp4格式");
}
// 文件大小1G
const isLt1G = file.size / 1024 / 1024 < 1024;
if (!isLt1G) {
this.$message.error("视频大小要小于1GB!");
}
return isMP4 && isLt1G;
},
(2)上传视频
// 上传视频
async ImgSplitUpload(option) {
const that = this;
console.log(option);
// this.returnFileInf.name = option.file.name;
const fileReader = new FileReader(); // 文件读取类
const action = option.action; // 文件上传上传路径
const chunkSize = 1024 * 10; // 单个分片大小,这里测试用1m
const optionFile = option.file; // 需要分片的文件
let fileChunkedList = []; // 文件分片完成之后的数组
const percentage = []; // 文件上传进度的数组,单项就是一个分片的进度
if (option.file.size > 1024 * 50) {
let data1 = option.file.slice(0, 1024 * 50);
//将文件进行分块 file.slice(start,length)
fileReader.readAsBinaryString(data1); //将文件读取为二进制码
} else {
fileReader.readAsBinaryString(option.file);
}
console.log("fileReader", fileReader);
// 文件开始分片,push到fileChunkedList数组中
for (let i = 0; i < optionFile.size; i = i + chunkSize) {
const tmp = optionFile.slice(
i,
Math.min(i + chunkSize, optionFile.size)
);
if (i === 0) {
// fileReader.readAsArrayBuffer(tmp);
}
fileChunkedList.push(tmp);
}
console.log("fileChunkedList", fileChunkedList);
// 在文件读取完毕之后,开始计算文件
fileReader.onload = async (e) => {
// 将fileChunkedList转成FormData对象,并加入上传时需要的数据
fileChunkedList = fileChunkedList.map((item, index) => {
const formData = new FormData();
if (option.data) {
Object.keys(option.data).forEach((key) => {
formData.append(key, option.data[key]);
});
// 看后端需要哪些,就传哪些,也可以自己追加额外参数
formData.append(option.filename, item, option.file.name); // 文件
formData.append("chunk", index + 1); // 当前文件数
formData.append("name", option.file.name); // 文件名
formData.append("maxChunk", fileChunkedList.length); // 总块数
formData.append("guid", option.file.uid); // 临时id
formData.append("folder", "deviceVideo"); // 文件夹名称
}
return { formData: formData, index: index };
});
// 创建队列上传任务,limit是上传并发数
const sendRequest = function (chunks, limit) {
return new Promise((resolve, reject) => {
const len = chunks.length;
let counter = 0;
let isStop = false;
const start = async () => {
if (isStop) {
return;
}
const item = chunks.shift();
if (item) {
const xhr = new XMLHttpRequest();
const index = item.index;
// 分片上传失败回调
xhr.onerror = function error(e) {
isStop = true;
reject(e);
console.log("失败了");
};
// 分片上传成功回调
xhr.onload = function onload() {
if (xhr.status !== 200) {
isStop = true;
reject(getError(action, option, xhr));
}
if (counter === len - 1) {
// 最后一个上传完成
resolve(JSON.parse(this.responseText));
that.addForm.videoUrl = JSON.parse(xhr.response).filePath;
console.log("0", that.addForm.videoUrl);
} else {
counter++;
start();
}
};
// 分片上传中回调
if (xhr.upload) {
xhr.upload.onprogress = (e) => {
percentage[index] = e.loaded;
updataPercentage(e);
};
}
xhr.open("post", action, true);
if (option.withCredentials && "withCredentials" in xhr) {
xhr.withCredentials = true;
}
const headers = option.headers || {};
for (const item in headers) {
if (headers.hasOwnProperty(item) && headers[item] !== null) {
xhr.setRequestHeader(item, headers[item]);
}
}
// 文件开始上传
xhr.send(item.formData);
}
};
while (limit > 0) {
setTimeout(() => {
start();
}, Math.random() * 1000);
limit -= 1;
}
});
};
// 更新上传进度条百分比的方法
const updataPercentage = (e) => {
let loaded = 0; // 当前已经上传文件的总大小
percentage.forEach((item) => {
loaded += item;
});
e.percent = (loaded / optionFile.size) * 100;
if (
this.value > parseFloat(Number(e.percent).toFixed(0)) ||
this.value === parseFloat(Number(e.percent).toFixed(0))
)
return;
this.value = parseFloat(Number(e.percent).toFixed(0));
console.log("value", this.value);
};
try {
// 调用上传队列方法 等待所有文件上传完成
// this.returnFileInf.softwareLink = await sendRequest(
// fileChunkedList,
// 1
// );
const res = await sendRequest(fileChunkedList, 1);
this.createdSoftForm.softwareLink = res.response.filePath;
// 可以在这通知服务端合并
} catch (error) {
option.onError(error);
this.errorOccur = true;
}
};
},