Vue large file video slice upload processing method

When the front-end uploads large files and videos, there will be timeouts, too large, very slow, etc. In order to solve this problem, a slicing function has been created in cooperation with the back-end.

My slicing function is based on minion, and the backend will put the file on the minion server. Specifically look at the backend how to do it

1. Create a js file upload.js in the file home  of the project's util (this folder is created by yourself, if there is no one in the project),    add the following code in the js file:

import axios from 'axios';
import md5 from 'js-md5' //引入MD5加密
export const uploadByPieces = ({ urlList, file, pieceSize, progress, beforeSuccess, success, error }) => {
    // 如果文件传入为空直接 return 返回
    if (!file) return
    let fileMD5 = ''// 总文件列表
    const chunkSize = pieceSize * 1024 * 1024 // 5MB一片
    const chunkCount = Math.ceil(file.size / chunkSize - 1) // 总片数
    // 获取md5
    const readFileMD5 = () => {
        // 读取视频文件的md5
        // console.log("获取文件的MD5值")
        let fileRederInstance = new FileReader()
        // console.log('file', file)
        fileRederInstance.readAsBinaryString(file)
        fileRederInstance.addEventListener('load', e => {
        let fileBolb = e.target.result
        fileMD5 = md5(fileBolb)
        // console.log('fileMD5', fileMD5)
        // console.log("文件未被上传,将分片上传")
        readChunkMD5()

        })
    }
    const getChunkInfo = (file, currentChunk, chunkSize) => {
        let start = currentChunk * chunkSize
        let end = Math.min(file.size, start + chunkSize)
        let chunk = file.slice(start, end)
        return { start, end, chunk }
    }
    // 针对每个文件进行chunk处理
    const readChunkMD5 = () => {
        // 针对单个文件进行chunk上传
        for (var i = 0; i < chunkCount; i++) {
            const { chunk } = getChunkInfo(file, i, chunkSize)
            // console.log("切片地址123" + urlList)
            // console.log("总片数" + chunkCount)
            // console.log("分片后的数据---测试:" + i)
            // console.log(chunk)
            let fileUrl = urlList[i];
            // console.log(fileUrl,'地址');
            uploadChunk({ chunk, currentChunk: i, chunkCount, fileUrl })
        }
    }
    const uploadChunk = (chunkInfo) => {
        // 上传请求方式1 (根据自身情况自行选择)
        // console.log(chunkInfo.chunk,'chunkInfochunkInfo');
        let files = chunkInfo.chunk
        axios.put(chunkInfo.fileUrl,files).then((res) => {
            // console.log("分片上传返回信息:"+ res)
            if (res.status == 200) {
                // 下面如果在项目中没有用到可以不用打开注释
                if (chunkInfo.currentChunk < chunkInfo.chunkCount - 1) {
                    beforeSuccess()
                } else {
                    // 当总数大于等于分片个数的时候
                    if ((chunkInfo.currentChunk + 1) == chunkInfo.chunkCount) {
                        // console.log("文件开始------合并成功")
                        success(res.data[0])
                    }
                }
            }
        }).catch((e) => {
            console.log('失败!');
            error && error(e)
        })
    }
    readFileMD5() // 开始执行代码
}

If js-md5 is not available, you need to install it in the project yourself:

npm install js-md5

2. Create a public component for uploading video files, which is convenient for reference in different places, as follows:

<template>
	<div class="container" style="display:inline-block;width: 200px;">
		<el-upload
			class="upload-demo"
			action="#"
			:multiple="false"
			:auto-upload="false"
			accept=".mp4"
			:on-change="handleChange"
			:show-file-list="false">
			<el-button slot="trigger" size="small" type="primary" :disabled="isUploadVideo">选择视频</el-button>
			<!-- <el-button size="small" type="primary" @click="uploadVideo()" style="margin-left: 10px;">开始上传</el-button> -->
		</el-upload>
		<!-- 进度条 -->
		<el-progress v-if="progressFlag" :percentage="loadProgress"></el-progress>
	</div>
</template>

<script>
import {mapGetters} from "vuex"; 
import { uploadByPieces } from '@/util/upload-video'
import api from "@/api/mes2/index-lhj"
export default {
	data() {
		return {
			isUploadVideo: false,
			uploadId: '', // 切片视频的唯一id(后端返回)
			fileNameVal: '', // 文件名称(后端返回)
			listUrl: [], // 切片路径集合
			loadProgress: 0, // 动态显示进度条
			progressFlag: false, // 关闭进度条
		}
	},
	created(){
		
	},
	computed: {   
		...mapGetters(["userInfo"]),   
	}, 
	props:{
		paramsData: {
			type: Object,
			default: {}
		}
	},
	methods: {
		// 选择视频
		handleChange(file, fileList) {
			this.isUploadVideo = true;
			this.progressFlag = true; // 显示进度条
			this.loadProgress = 10; // 动态获取文件上传进度
			let fileSizeVal = file.size / 1024 / 1024;
			let numVal = null;
			if(fileSizeVal <= 20){
				numVal = 1;
			}else{
				numVal = Math.ceil(file.size / (10 * 1024 * 1024));
			}
			let params = {
				fileName: file.name,
				partCount: numVal - 1,
				tenantId: this.userInfo.tenant_id,
				fileType: "mp4",
				fileSize: file.size,
				sourceId: this.paramsData.id,
				sourceType: this.paramsData.inspectionType,
				sourceSystem: "MES2",
				hierarchyCode:"MES2"
			}
			api.queryUploadBigFileUrl(params).then((res) => {
				this.loadProgress = 20;
				this.listUrl = res.data.data.partUrlList;
				this.uploadId = res.data.data.uploadId;
				this.fileNameVal = res.data.data.fileName
				// 调用切片方法
				uploadByPieces({
					urlList: this.listUrl,
					file: file.raw, // 视频实体
					pieceSize: 10, // 分片大小
					beforeSuccess: data => {
						// 进度数 / 切片总数
						let progress = Math.floor(70 / (numVal - 1)); // 计算进度
						this.loadProgress += progress;
					},
					success: data => {
						// console.log('分片上传视频成功', data)
						this.getFileAll(numVal)
					},
					error: e => {
						console.log('分片上传视频失败', e)
						this.$message.error('视频切片上传失败,请重新上传!')
						this.progressFlag = false
					}
				})
			}).catch(() => {
				this.$message.error('发生错误,请重新上传!')
				this.progressFlag = false
			})
		},
		// 整合切片文件
		getFileAll(numVal){
			let params = {
				partCount: numVal - 1,
				tenantId: this.userInfo.tenant_id,
				uploadId: this.uploadId,
				fileName: this.fileNameVal,
			}
			this.loadProgress = 95;
			api.queryUploadBigFile(params).then((res) => {
				if(res.data.data === false){
					this.isUploadVideo = false;
					this.$message.error('视频切片合并失败,请重新上传!')
					setTimeout( () => {this.progressFlag = false}, 1000) // 一秒后关闭进度条
				}else{
					this.loadProgress = 100;
					this.isUploadVideo = false;
					this.$message.success('视频上传成功!')
					this.$emit('uploadVideoData');
					if (this.loadProgress >= 100) {
						this.loadProgress = 100
						setTimeout( () => {this.progressFlag = false}, 1000) // 一秒后关闭进度条
					}
				}
			}).catch(() => {
				this.isUploadVideo = false;
				this.$message.error('视频合并上传失败,请重新上传!')
			})
		},
	},
}
</script>

<style scoped lang="scss">

</style>

You can modify it according to your actual situation!

That's it! ! !

The test works! ! ! Thanks for the support! ! !

Guess you like

Origin blog.csdn.net/qq_38543537/article/details/132212026