The main reference for this article is this article, and the backend is also completed with django.
Large file upload (second pass/breakpoint continue transmission)_Use Vue-Simple-Uploader plug-in --Vue/Django full implementationhttps:///article/
Reference code address:/ClearlightY/FileUpload
vue-simple-upload documentation:/simple-uploader/Uploader
<template> <div id='global-uploader'> <uploader ref='uploader' :options='options' :autoStart='false' :file-status-text='statusText' @file-added='onFileAdded' @file-success='onFileSuccess' @file-progress='onFileProgress' @file-error='onFileError' @file-removed='onfileRemoved' class='uploader-app' > <uploader-unsupport></uploader-unsupport> <!-- File drag and drop upload area--> <uploader-drop id='global-uploader-drop'> <uploader-btn id='global-uploader-btn' :attrs='attrs' ref='uploadBtn'> <div class='hzs-upload-icon'> <svg viewBox='0 0 1024 1024' data-icon='inbox' width='1em' height='1em' fill='currentColor' aria-hidden='true' focusable='false' class=''> <path d='M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0 0 60.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z'></path> </svg> </div> <p class='hzs-upload-title'>Click or drag file(.zip) to this area to upload datasets</p> <p class='hzs-upload-description'>Just support for a single file, multiple uploads will be overwritten by the latter.</p> </uploader-btn> </uploader-drop> <!--File list--> <uploader-list> <div class='file-panel' slot-scope='props'> <ul class='file-list' ref='fileList'> <li v-for='file in ' :key=''> <uploader-file :class="'file_' + " ref='files' :file='file' :list='true'></uploader-file> <!-- <!&ndash; Not important&ndash;>--> <!-- <div class='query_check' v-if='queryBtnShow'>--> <!-- <button @click='queryCheck(uuid)'>Verification query</button>--> <!-- <!&ndash; <input type="button" v-on="queryCheck(uuid)" value="school"/> &ndash;>--> <!-- <!&ndash; <div v-if="queryCheckStatus">The file is being uploaded</div> &ndash;>--> <!-- <span class='queryCheckShow' v-if='queryCheckShow'>{{ checkStatus }}</span>--> <!-- </div>--> <!-- <div class='save-result' v-if='saveBtnShow'>--> <!-- <button @click='download_check_result(file_path)'>Verification and Save</button>--> <!-- </div>--> </li> <div class='no-file' v-if='!'> Empty </div> </ul> </div> </uploader-list> </uploader> </div> </template> <script> import SparkMD5 from 'spark-md5' import { ACCEPT_FILE_CONFIG } from '@/config/defaultSettings' import { checkResult, isFileExist, mergeFile, textCheck } from '@/api/uploadTool' // import storage from 'store' // /simple-uploader/Uploader#events export default { data() { return { options: { target: '/api/upload/upload/', // Target upload URL testChunks: true, chunkSize: '2048000', // chunkSize: "10240000", // When dividing chunks, it is divided according to this value fileParameterName: 'file', // The parameter name of the file when uploading the file maxChunkRetries: 3, // Maximum number of automatic failures and retry uploads // Due to my own business reasons, I added a verification query function, and I cannot control it during querying. // Corresponding to the uploaded file id, so multiple file uploads have been removed // Comment it out here to achieve multiple files upload // singleFile: true, // single file upload // Before uploading the shard, a get request will be sent to the backend first. This function responds to this get request checkChunkUploadedByResponse: function(chunk, message) { ('Before uploading the shard, a get request will be sent to the backend first, and the function will respond to this get request') (chunk) (message) let objMessage = (message) ('objMessage:', objMessage) //----------------------------------------------------------------------------------------------------------------------------- // Uncomment here, and the parameters sent from the backend can be transmitted in seconds. I still need to make a verification request after uploading. // Here I will cut off the instant transfer function... //----------------------------- // Here we can determine whether it is a second pass based on the return value // if ( === "true") { // return true; // } // Judging which shards do not need to be uploaded based on the returned array content return ( || []).indexOf( + 1) >= 0 }, parseTimeRemaining: function(timeRemaining, parsedTimeRemaining) { return parsedTimeRemaining .replace(/\syears?/, 'years') .replace(/\days?/, 'days') .replace(/\shours?/, 'hours') .replace(/\sminutes?/, 'minutes') .replace(/\sseconds?/, 'seconds') } }, attrs: { accept: ACCEPT_FILE_CONFIG.getAll() }, statusText: { success: 'success', error: 'network error', uploading: 'uploading', typeError: 'typeError', emptyError: 'emptyError', paused: 'paused', waiting: 'waiting', cmd5: 'calculate md5', merging: 'merging' }, fileStatusText: (status, response) => { return [status] }, saveBtnShow: false, queryBtnShow: true, queryCheckShow: false, // queryCheckStatus: false, checkStatus: 'checking...', uuid: '', file_path: '' } }, mounted() { // this.$bus.$on('openUploader', query => { // = query || {} // if (this.$) { // ('#global-uploader-btn').click() // } // }) }, computed: { //Uploader instance uploader() { return this.$ } }, methods: { onFileAdded(file, event) { (file) (event) () () this.$emit('canGoToNextStep', false) this.$emit('canGoToPreStep', false) // () //Pause file upload () // // = true; = false = false = false (, 'md5') this.computedMD5(file) // setTimeout(() => { // this.computedMD5(file) // }, 5000) // Bus.$emit("fileAdded"); // () // () }, onFileProgress(rootFile, file, chunk) { ( `uploading ${},chunk:${ / 1024 / 1024} ~ ${ / 1024 / 1024}` ) }, async onFileSuccess(rootFile, file, response, chunk) { ('onFileSuccess') (file) let res = (response) = true // File upload is completed, file merge flag if ( === 'true') { (, 'merging') let formData = new FormData() ('filename', ) ('identifier', arguments[0].uniqueIdentifier) ('totalSize', ) ('timeStamp', ) ('formData') try { // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- let res = await mergeFile(formData) // Processing of merge failure // if ( !== 200) { // this.$({ // message: 'Error', // description: 'An error occurred during the inspection, please try again' // }) // () // return // } // File upload successfully ui update () (, 'success') // = true // this.$bus.$emit('fileSuccess') // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // let formData2 = new FormData() // ('fpath', ) // ('fname', ) // let res2 = await textCheck(formData2) // if ( !== 200) { // this.$({ // message: 'Error', // description: 'An error occurred during the inspection, please try again' // }) // () // } // = // this.file_path = res2.file_path // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- // () // (, 'finish checking') // Collect file-related data (file) this.$('ADD_FILE_LIST', file) // It's time to go to the next step this.$({ message: 'Success', description: 'Successfully upload, go to next step to finish.' }) this.$emit('canGoToNextStep', true) this.$emit('canGoToPreStep', true) // // (, "checking"); // // // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ // // Send requests regularly to see if the verification is completed // let interval = setInterval(() => { // setTimeout(async () => { // let formData3 = new FormData() // ('file_uuid', ) // // let res3 = await checkResult(formData3) // ('Checking, please wait...') // if ( == 200) { // ('Check is completed') // clearInterval(interval) // // (); // // (, "checkSuccess"); // = 'finish checking' // = true // } // }, 0) // }, 1000) // // // ---------------------------------------------------------------------------------------------------------------------------- } catch (e) { this.$({ message: 'Error', description: 'An error occurred during the inspection, please try again' }) () } } }, onFileError(rootFile, file, response, chunk) { this.$({ message: 'Error', description: 'Please try again' }) }, onfileRemoved(file) { this.$(`${} 's upload had been canceled`) }, /** * Calculate md5 of uploaded file, realize breakpoint continuous transmission and second transmission */ computedMD5(file) { let fileReader = new FileReader() let time = new Date().getTime() let blobSlice = || || let currentChunk = 0 const chunkSize = 10 * 1024 * 1000 let chunks = ( / chunkSize) let spark = new () // (, 'md5') // $('.uploader-file-action').css('display', 'none'); loadNext() = e => { () currentChunk++ if (currentChunk < chunks) { // ( // `The ${currentChunk} shard parsing is completed, and the ${currentChunk + starts // 1} / ${chunks} shard analysis` // ) loadNext() // Show MD5's calculation progress in real time setTimeout(() => { (`.myStatus_${}`).textContent = 'verify MD5 ' + ((currentChunk / chunks) * 100).toFixed(0) + '%' // () // ('Check MD5' + ((currentChunk / chunks) * 100).toFixed(0) + '%') // ((`.myStatus_${}`)) // (`.myStatus_${}`).textContent = 'Check MD5' + ((currentChunk / chunks) * 100).toFixed(0) + '%' }, 20) } else { let md5 = () this.computeMD5Success(md5, file) () // Release the cache ( `MD5Calculation is complete:${} \nMD5:${md5} \nSharding:${chunks} size:${ } Time to use:${new Date().getTime() - time} ms` ) } } = function() { (`document${}Read error,请检查该document`) () } function loadNext() { let start = currentChunk * chunkSize let end = start + chunkSize >= ? : start + chunkSize ((, start, end)) } }, // Calculate md5 successfully async computeMD5Success(md5, file) { = md5 // Assign file md5 to file unique identifier () // () ('computeMD5Success') (file) // Pass the md5 verification result to the backend to check whether this file exists let that = this try { let res = await isFileExist({ md5, fileName: }) if () { // The file does not exist in s3 if (res['is_exist'] === false) { this.$confirm({ title: 'Are you sure to upload it?', content: h => , okText: 'yes', onOk() { // An action to start file upload // Set whether to force upload in the form to false file['is_force_process'] = false () }, onCancel() { that.$emit('canGoToPreStep', true) () } }) } else { // Is it necessary to upload force this.$confirm({ title: 'The file had existed, are you sure to recover it?', content: h => , okText: 'yes', onOk() { // An action to start file upload // Set whether to force upload in the form to false file['is_force_process'] = true () }, onCancel() { that.$emit('canGoToPreStep', true) () } }) } } else { () } } catch (e) { () } }, // Display file list // fileListShow() { // // let $list = $('#global-uploader .file-list') // let $list = this.$ // // if ($(':visible')) { // $() // } else { // $() // } // }, close() { () }, /** * New custom status: 'md5', 'transcoding', 'failed' * @param id * @param status */ statusSet(id, status) { let statusMap = { md5: { text: 'verify MD5', bgc: '#fff' }, merging: { text: 'merging', bgc: '#e2eeff' }, transcoding: { text: 'transcoding', bgc: '#e2eeff' }, failed: { text: 'fail to upload', bgc: '#e2eeff' }, success: { text: 'successfully upload', bgc: '#e2eeff' }, checking: { text: 'checking', bgc: '#e2eeff' }, checkSuccess: { text: 'check ok', bgc: '#e2eeff' } } setTimeout(() => { let p = ('p') = `myStatus_${id}` let father = (`.file_${id} .uploader-file-status`) ('style', `position: absolute; top:-16px;left: 0;right: 0; bottom: 0;zIndex: 1; backgroundColor: ${statusMap[status].bgc}`) (statusMap[status].text) (p) }) }, statusRemove(id) { // ("statusRemove") // (id) this.$nextTick(() => { let node = (`.myStatus_${id}`) (node) }) }, error(msg) { this.$({ message: 'Error', description: msg }) }, // Query each block queryCheck: function(uuid) { ('uuid::', uuid) ('file_path::--------', this.file_path) // if (uuid === "") { // = true; // return; // } let formData = new FormData() ('file_uuid', uuid) const instance = this.$({ headers: { 'Content-Type': 'multipart/form-data' } }) instance .post('http://127.0.0.1:8000/fileUpload/check_result', formData) .then(res => { // ("Clicked the query check status button"); if ( == '200') { // = false; = 'check ok' = true } else { = 'checking...' = true } }) }, // Download the verification results download_check_result() { let formData = new FormData() ('file_path', this.file_path) const instance = this.$({ headers: { 'Content-Type': 'multipart/form-data' }, responseType: 'blob' }) instance .post('http://127.0.0.1:8000/fileUpload/file_download', formData) .then(response => { if (!response) { return } let url = (new Blob([])) let link = ('a') = 'none' = url ('download', '') (link) () }) } }, watch: {}, destroyed() { // this.$bus.$off('openUploader') } } </script> <style scoped lang='less'> #global-uploader { // position: fixed; z-index: 20; max-width: 1000px; margin: 10px auto; background: #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 4); //padding: 10px; h2 { padding: 30px 0; text-align: center; font-size: 20px; } .uploader-app { //width: 880px; //padding: 15px; //margin: 20px auto 0; font-size: 14px; } ul li { list-style-type: none; } li div { //left: -19px; } } .file-panel { background-color: #fff; border: 1px solid #e2e2e2; border-radius: 7px 7px 0 0; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); .file-title { display: flex; height: 40px; // line-height: 40px; padding: 0 15px; border-bottom: 1px solid #ddd; .operate { flex: 1; text-align: right; } } .file-list { position: relative; height: 240px; overflow-x: hidden; overflow-y: auto; background-color: #fff; //border: 1px solid black; padding: 0; > li { background-color: #fff; } } &.collapse { .file-title { background-color: #e7ecf2; } } } .no-file { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 16px; } .uploader-btn { margin-right: 4px; color: #fff; padding: 6px 16px; } #global-uploader-btn { //border: 1px solid #409eff; //background: #409eff; border: 0; width: 100%; //height: 100px; padding: 15px; color: #F5222D; display: flex; flex-direction: column; align-items: center; p { padding: 0; margin: 10px; } .hzs-upload-icon { font-size: 40px; } .hzs-upload-title { font-size: 20px; } .hzs-upload-description { font-size: 16px; color: rgba(0, 0, 0, 0.45) } } #global-uploader-btn:hover { background: none; } #global-uploader-drop { //height: 150px; padding: 0; } #global-uploader-drop:hover { border: 1px dashed #F5222D; } #global-uploader-dir-btn { border: 1px solid #67c23a; background: #67c23a; } .save-result { position: absolute; margin-top: -24px; margin-left: 700px; z-index: 10; } .query_check { position: absolute; margin-left: 700px; margin-top: -50px; z-index: 10; } .queryCheckShow { margin-left: 10px; color: red; font-size: 12px; } </style>
Call
<MyUploaderBox @canGoToNextStep='canGoToNextStep' @canGoToPreStep='canGoToPreStep' ></MyUploaderBox>
refer to
Vue realizes shard upload/AIfurture/article/details/103975897
ByteDance Interviewer: Please implement a large file upload and breakpoint renewal/post/6844904046436843527
Experience of using vue-simple-uploader component/p/da8ad489095e
Large file upload (second pass/breakpoint continue transmission)_Use Vue-Simple-Uploader plug-in --Vue/Django full implementation/qq_36852780/article/details/107437875
Related code and documentation:
/ClearlightY/FileUpload
/shady-xia/Blog/tree/master/vue-simple-uploader
/simple-uploader/Uploader
This is the article about the file shard upload component based on vue-simple-upload in vue2. For more related contents of vue-simple-upload file shard upload, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!