大文件上传,前端vue 做分片上传

html – 以弹窗的形式

<!-- 上传算法文件 -->
<el-dialog title="上传算法文件" :visible.sync="uploadPop" width="60%" :close-on-click-modal="false" :before-close="closeUploadPop" append-to-body custom-class="upload_box"><div class="upload_btn_box"><el-uploadclass="upload-demo"ref="upload"action="":show-file-list="false":http-request="requestFile":before-upload = "checkFileType"v-if="isShowUploadBtn"><el-button>上传压缩包</el-button></el-upload><el-button v-else :loading="true">上传压缩包</el-button></div><div class="tip_box"><span class="tips_text">1、请上传文件类型为zip的算法文件;2、上传可能需要一些时间,上传过程中建议不要关闭弹窗。</span></div><div class="file_box"><div class="upload_list" v-if="isShowUpload"><div id="progress-bar-container" class="list_box" :class="{'isSuccess': uploadAllData.isSuccess}"><span style="width: 14px"><i class="el-icon-folder"></i></span><span style="width: 30%">{{ uploadAllData.name }}</span><span style="width: 12%">{{ uploadAllData.type == 1? '算法文件': '测试集文件' }}</span><span style="width: 10%">{{ uploadAllData.size }}</span><span style="width: 16%">{{ uploadAllData.isSuccess?uploadAllData.msg: uploadAllData.isStop? '暂停中': uploadAllData.percent+'%' + ' ' + uploadAllData.speed + '/s' }}</span><span class="action_btn" v-if="!uploadAllData.isSuccess" @click="changeStop">{{ uploadAllData.isStop?'▶': '‖' }}</span><span class="action_btn" v-if="!uploadAllData.isSuccess" @click="changeClose">✖</span><div id="progress-bar" class="progress-bar" :style="{ width: progressBarWidth }"></div></div></div></div>
</el-dialog>

js – 初始化数据

// 初始化数据
initUpload() {this.fileData = null;this.chunks = [];this.isShowUpload = false;this.uploadAllData = {id: null,isSuccess: false,isStop: false,msg: '',name: '',size: '0',speed: "0",percent: 0,type: 1,};this.progressBarWidth = '0%';this.fileData = null;this.chunkSize = 0;this.fileSize = 0;this.isShowUploadBtn = true;this.uploadedChunks = 0;
},

js – 上传前判断文件类型

// 上传前判断
checkFileType(file) {// 先初始化,预防在上传过程中继续点击上传this.initUpload();// 禁止继续点击上传this.isShowUploadBtn = false;// 判断只能上传.zip压缩包const allowedExtensions = ['zip']; // 允许的文件后缀名列表const extension = file.name.split('.').pop().toLowerCase(); // 获取文件的后缀名if (allowedExtensions.indexOf(extension) === -1) {this.$message.error('只允许上传zip格式的文件');this.isShowUploadBtn = true;return false; // 阻止文件上传}return true; // 允许文件上传
},

js – 上传前准备、获取传输任务(旧)
!说明: 因为后台需要文件的md5校验文件的完整性,所以需要读取文件,但是文件太大的时候,导致前端读取的时候就需要很长时间了,经协调,去掉参数md5

import SparkMD5 from 'spark-md5';
// 上传算法文件
requestFile(file) {this.fileData = file.file;const reader = new FileReader();console.log('开始分片任务!');reader.onload = (event) => {const fileObj = event.target.result;const spark = new SparkMD5.ArrayBuffer(); // 获取文件的md5 哈希值 -- 后台用于验证文件的完整性console.log(spark, 'md5');spark.append(fileObj);let md5Hash = spark.end();console.log(md5Hash, 'md5');spark.destroy(); //释放缓存// 将文件分片this.chunkSize = 1024 * 1024 * 20 // 每个分片的大小20Mthis.fileSize = this.fileData.size; // 文件总大小this.chunkCount = Math.ceil(this.fileSize / this.chunkSize) // 分片数量this.uploadedChunks = 0 // 重置已上传的分片数量this.startTime = new Date().getTime() // 记录上传开始时间// 逐个上传分片for (let index = 0; index < this.chunkCount; index++) {const start = index * this.chunkSizeconst end = Math.min(start + this.chunkSize, this.fileSize)const chunk = this.fileData.slice(start, end)this.chunks.push(chunk)}console.log(this.chunks);console.log(this.fileData);// 整合上传前的参数,请求获取idlet beforeUpload = {belongsId: this.algorithmVersionId,chunkNumberCount: this.chunkCount,fileSavePath: "",fileType: 1, // 1为算法文件; 2为测试集md5: md5Hash,pauseOffset: 0,status: 1,transmitType: 1,uploaded: this.uploadedChunks,fileName: this.fileData.name}console.log(beforeUpload, '参数整合');httpPost('/api/v1/acctm_file_transmit_task', beforeUpload) // 文件分片传输任务表.then(res => {if(res.code == '10000') {this.currentUploadId = res.data;let num = (this.fileSize/(1024*1024)).toFixed(2); // B => MBlet fileSizeStr = "";if(num >= 1024) {fileSizeStr = num + 'GB'} else if(1 <= num < 1024 ) {fileSizeStr = num + 'MB'} else {fileSizeStr = this.fileSize + 'KB'}this.uploadChunk(this.chunks, 0, this.chunkSize, this.fileData.name, fileSizeStr)} else {this.isShowUploadBtn = true;this.$message({type: 'error',message: '文件分片传输失败!'})}}).catch(() => {console.log('到这人了?');})};reader.readAsArrayBuffer(this.fileData);将文件分片this.chunkSize = 1024 * 1024 * 20 // 每个分片的大小20Mthis.fileSize = this.fileData.size; // 文件总大小this.chunkCount = Math.ceil(this.fileSize / this.chunkSize) // 分片数量this.uploadedChunks = 0 // 重置已上传的分片数量this.startTime = new Date().getTime() // 记录上传开始时间// 逐个上传分片for (let index = 0; index < this.chunkCount; index++) {const start = index * this.chunkSizeconst end = Math.min(start + this.chunkSize, this.fileSize)const chunk = this.fileData.slice(start, end)this.chunks.push(chunk)}let beforeUpload = {belongsId: this.algorithmVersionId,chunkNumberCount: this.chunkCount,fileSavePath: "",fileType: 1, // 1为算法文件; 2为测试集pauseOffset: 0,status: 1,transmitType: 1,uploaded: this.uploadedChunks,fileName: this.fileData.name}httpPost('/api/v1/acctm_file_transmit_task', beforeUpload) // 文件分片传输任务表.then(res => {if(res && res.code == '10000') {this.currentUploadId = res.data;let num = (this.fileSize/(1024*1024)).toFixed(2); // B => MBlet fileSizeStr = "";if(num >= 1024) {fileSizeStr = (num/1024).toFixed(2) + 'GB'} else if(1 <= num && num < 1024 ) {fileSizeStr = num + 'MB'} else {fileSizeStr = (num*1024).toFixed(2) + 'KB'}this.uploadChunk(this.chunks, 0, this.chunkSize, this.fileData.name, fileSizeStr)} else {this.isShowUploadBtn = true;}}).catch(() => {console.log('开始分片任务失败!');})
},

js – 上传前准备、获取传输任务(目前采用)

// 上传算法文件
requestFile(file) {this.fileData = file.file;// 将文件分片this.chunkSize = 1024 * 1024 * 20 // 每个分片的大小20Mthis.fileSize = this.fileData.size; // 文件总大小this.chunkCount = Math.ceil(this.fileSize / this.chunkSize) // 分片数量this.uploadedChunks = 0 // 重置已上传的分片数量this.startTime = new Date().getTime() // 记录上传开始时间// 逐个上传分片for (let index = 0; index < this.chunkCount; index++) {const start = index * this.chunkSizeconst end = Math.min(start + this.chunkSize, this.fileSize)const chunk = this.fileData.slice(start, end)this.chunks.push(chunk)}let beforeUpload = {belongsId: this.activeRouter.id,chunkNumberCount: this.chunkCount,fileSavePath: "",fileType: 2, // 1为算法文件; 2为测试集pauseOffset: 0,status: 1,transmitType: 1,uploaded: this.uploadedChunks,fileName: this.fileData.name}httpPost('/api/v1/acctm_file_transmit_task', beforeUpload) // 文件分片传输任务表.then(res => {if(res && res.code == '10000') {this.currentUploadId = res.data;let num = (this.fileSize/(1024*1024)).toFixed(2); // B => MBlet fileSizeStr = "";if(num >= 1024) {fileSizeStr = (num/1024).toFixed(2) + 'GB'} else if(1 <= num && num < 1024 ) {fileSizeStr = num + 'MB'} else {fileSizeStr = (num*1024).toFixed(2) + 'KB'}this.uploadChunk(this.chunks, 0, this.chunkSize, this.fileData.name, fileSizeStr)} else {this.isShowUploadBtn = true;}}).catch(() => {console.log('开始分片任务失败!');})
},

js – 开始分片上传
!注意:自己封装的axios 请求触发不了onUploadProgress事件

//  上传分片
uploadChunk(chunks, index, chunkSize, name, fileSize) {console.log(chunks, index);this.isShowUpload = true;this.isShowUploadBtn = true; // 显示加载文件后放开上传的按钮this.progressBar = document.getElementById('progress-bar');if (index >= chunks.length) {// 全部分片上传完成this.uploadAllData = {id: this.currentUploadId,isStop: false,isSuccess: true,msg: '上传完成',name: name,size: fileSize,speed: '0',percent: 0,type: 1}// 重置数据this.chunks = [];this.progressBarWidth = '0%';this.fileData = null;this.chunkSize = 0;this.fileSize = 0;this.uploadedChunks = 0;return}let chunk = chunks[index]; // 当前文件的分片数据// 整合参数const formData = new FormData()formData.append('chunkSize', chunkSize)formData.append('file', chunk, index+1) // 文件的分片,从1开始 -- 与后台协商,文件的命名formData.append('chunkNumber', index+1); // 分片序号,从1开始 -- 与后台协商formData.append('chunkNumberCount', this.chunkCount)formData.append('transmitTaskId', this.currentUploadId)// 发送分片请求let url = process.env.VUE_APP_BASE_API;axios.post(url + '/api/v1/acctm_file_transmit_task/chunkUpload', formData, { // 文件分片信息表headers: {'Content-Type': 'multipart/form-data','Authorization': sessionStorage.getItem('token') || ""},onUploadProgress: (progressEvent) => {const uploaded = progressEvent.loaded// const total = progressEvent.total// 更新上传进度this.progress = Math.round(((index + 1) / this.chunkCount) * 100)// this.progress = Math.round((uploaded / total) * 100)// 计算上传速度const currentTime = new Date().getTime()const elapsedTime = (currentTime - this.startTime) / 1000 // 经过的时间(秒)this.speed = Math.round((uploaded - this.uploadedSize) / elapsedTime / 1024) // 上传速度(KB/s)// console.log(this.speed);// 更新已上传大小this.uploadedSize = uploaded;// 转换单位,超过1M,显示M,超过G,显示Glet number = (this.speed/1024).toFixed(2); // KB => MB// console.log(1 <= number < 1024);let speedStr = ""if(number >= 1024) {speedStr = (number/1024).toFixed(2) + 'GB'} else if(1 <= number && number < 1024) {speedStr = number + 'MB'} else if(number < 0 || this.speed < 0) {speedStr = 0 + 'KB';} else {speedStr = (this.speed).toFixed(2) + 'KB'}this.uploadAllData = {id: this.currentUploadId,isStop: false,isSuccess: false,msg: '正在下载',name: name,size: fileSize,speed: speedStr,percent: this.progress == 100? 99: this.progress,type: 1};this.progressBarWidth = `${this.progress}%`}}).then((res) => {// console.log(res);if(res && res.data && res.data.code == '10000' && res.data.data) {if(this.timer) {clearTimeout(this.timer)}this.uploadedChunks++// 上传下一个分片this.uploadChunk(chunks, this.uploadedChunks, chunkSize, name, fileSize);} else if(res && res.data && res.data.code == '10000' && !res.data.data) { // 重新上传当前分片this.uploadChunk(chunks, this.uploadedChunks, chunkSize, name, fileSize);} else if(res && res.data && res.data.code == '40004') {this.uploadAllData.isStop = !this.uploadAllData.isStop;return} else if(res && res.data && res.data.code == '50010') {this.uploadAllData.isStop = !this.uploadAllData.isStop;return} else {// 一般是网络问题,隔几秒继续上传this.timer = setTimeout(() => {this.uploadChunk(chunks, this.uploadedChunks, chunkSize, name, fileSize);}, 2000);}}).catch((error) => {// 处理上传错误console.log('上传错误', error)})
},

js – 暂停\启动
!说明:因为前端不能做到真正的把请求暂停,只能调用接口,然后后台去实际暂停上传的接口

// 暂停、启动
changeStop() {if(this.timer) {clearTimeout(this.timer)}this.uploadAllData.isStop = !this.uploadAllData.isStop;if(this.uploadAllData.isStop) { // 点击了启动图标,触发暂停httpGet("/api/v1/acctm_file_transmit_task/pauseStart/" + this.currentUploadId).then(res => {if(res && res.code == '10000' && !res.data) {// console.log('暂停成功!');}})} else { // 点击了暂停图标,触发启动httpGet("/api/v1/acctm_file_transmit_task/pauseStart/" + this.currentUploadId).then(res => {if(res && res.code == '10000') {let num = (this.fileSize/(1024*1024)).toFixed(2); // B => MBlet fileSizeStr = "";if(num >= 1024) {fileSizeStr = (num/1024).toFixed(2) + 'GB'} else if(1 <= num && num < 1024 ) {fileSizeStr = num + 'MB'} else {fileSizeStr = (num*1024).toFixed(2) + 'KB'}// 从之前的分片this.uploadChunk(this.chunks, this.uploadedChunks+1, this.chunkSize, this.fileData.name, fileSizeStr);}})}
},

js – 删除任务

changeClose() {if(this.timer) {clearTimeout(this.timer)}httpDeleter('/api/v1/acctm_file_transmit_task/' + this.currentUploadId).then(res => {if(res && res.code == '10000') {this.$message({type: 'success',message: '删除成功!'});this.initUpload();}})
},

js – 关闭弹窗
!说明: 由于上传的文件比较大,本地文件存储的位置获取不到,所以如果半路退出,则不能再继续获取到上一次的文件

closeUploadPop() {if(this.timer) {clearTimeout(this.timer)}// 判断是否上传完成if(this.fileData && !this.uploadAllData.isSuccess) {this.$confirm('文件上传未完成,关闭弹窗则上传无效,是否确定关闭?', '温馨提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(async() => {let res = await httpDeleter('/api/v1/acctm_file_transmit_task/' + this.currentUploadId)if(res && res.code == '10000') {this.uploadPop = false;this.initUpload();if(this.activeName == "1"){this.getCloudData(1,10,1,this.algorithmId);} else {this.getCloudData(1,10,2,this.algorithmId);}}}).catch(() => {})} else {this.uploadPop = false;// 格式化数据this.initUpload();if(this.activeName == "1"){this.getCloudData(1,10,1,this.algorithmId);} else {this.getCloudData(1,10,2,this.algorithmId);}}
},

完成、效果展示
正在上传
在这里插入图片描述
暂停
在这里插入图片描述
退出
在这里插入图片描述
完成
在这里插入图片描述

中秋国庆的八天假 迎来了七天的搬砖!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/96732.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023.10.07

#include <iostream>using namespace std;int main() {string str;cout << "请输入字符串&#xff1a;";getline(cin,str);int big0,little0,spac0,num0,sym0;int sizestr.size();for(int i0;i<size;i){if((int)str.at(i)<6526 && (int)st…

如何开发一款高效便捷的搬家服务小程序

随着互联网的发展&#xff0c;小程序已成为各行各业重要的业务推广和用户服务平台。对于搬家行业而言&#xff0c;开发一款高效便捷的搬家服务小程序具有巨大的市场潜力。本文将为您详细介绍如何开发一款这样的搬家服务小程序。 一、进入乔拓云网后台 在开始制作搬家服务小程序…

ICE综述

ICE综述 ICE(Internet Communications Engine)是ZeroC提供的一款高性能的中间件&#xff0c;基于ICE可以实现电信级的解决方案。在设计网站架构的时候可以使用ICE实现对网站应用的基础对象操作&#xff0c;将基础对象操作和数据库操作封装在这一层&#xff0c;在业务逻辑层以及…

Pyside6 安装和简单界面开发

Pyside6 安装和简单界面开发 Pyside6介绍Pysied6开发环境搭建Python安装Pysied6安装 Pyside6界面开发简单界面设计界面设计界面编译 编写界面初始化代码软件打包 Pyside6介绍 对于Python的GUI开发来说&#xff0c;Python自带的可视化编程模块的功能较弱&#xff0c;PySide是跨…

【11】c++设计模式——>单例模式

单例模式是什么 在一个项目中&#xff0c;全局范围内&#xff0c;某个类的实例有且仅有一个&#xff08;只能new一次&#xff09;&#xff0c;通过这个唯一的实例向其他模块提供数据的全局访问&#xff0c;这种模式就叫单例模式。单例模式的典型应用就是任务队列。 为什么要使…

12P2532X162-233A KJ3222X1-BA1 CE4003S2B3 EMERSON CONTROLLER

12P2532X162-233A KJ3222X1-BA1 CE4003S2B3 EMERSON CONTROLLER EDGEBoost I/O模块是一种可扩展的模块化解决方案&#xff0c;集成到Premio的工业计算机中&#xff0c;通过即插即用的可扩展性提供增强的可靠性。这些附加模块有助于解决在加固边缘出现的设计限制和兼容性问题。…

JDBC-day01(JDBC概述,获取数据库连接)

一&#xff1a;JDBC概述 1.数据持久化 持久化(persistence)&#xff1a;把数据保存到可掉电式存储设备中以供之后使用。大多数情况下&#xff0c;数据持久化意味着将内存中的数据保存到硬盘上加以”固化”&#xff0c;而持久化的实现过程大多通过各种关系数据库来完成。简单来…

gorm 自定义时间、字符串数组类型

文章目录 自定义时间类型自定义字符串数组测试与完整代码测试代码测试结果 GORM 是GO语言中一款强大友好的ORM框架&#xff0c;但在使用过程中内置的数据类型不能满足以下两个需求&#xff0c;如下&#xff1a; time.Time类型返回的是 2023-10-03T09:12:08.5352808:00这种字符串…

美国各流域边界下载,并利用arcgis提取与处理

一、边界数据的下载 一般使用最普遍的流域边界数据是从HydroSHEDS官网下载: HydroBASINS代表一系列矢量多边形图层&#xff0c;以全球尺度呈现次级流域边界。该产品的目标是提供一种无缝的全球覆盖&#xff0c;其中包含了不同尺度&#xff08;从数十到数百万平方千米&#xf…

Zygote Secondary:加速应用启动的未来之路

Zygote Secondary&#xff1a;加速应用启动的未来之路 1. 引言 在现代的移动应用开发中&#xff0c;启动速度和响应性能是用户体验的重要方面。然而&#xff0c;传统的 Android 进程管理方式在启动应用时会出现性能瓶颈&#xff0c;导致启动时间过长和资源占用过多。为了解决…

Linux基本指令(中)——“Linux”

各位CSDN的uu们好呀&#xff0c;今天&#xff0c;小雅兰的内容是Linux基本指令呀&#xff01;&#xff01;&#xff01;下面&#xff0c;让我们进入Linux的世界吧&#xff01;&#xff01;&#xff01; cp指令&#xff08;重要&#xff09; mv指令&#xff08;重要&#xff09…

“益路同行”栏目专访 第06期—小星星关爱联盟创始人魏洁荣老师

中国善网在本届&#xff08;第十届&#xff09;慈展会上特别推出了《益路同行》采访栏目&#xff0c;《益路同行》栏目旨在寻觅公益之路上同行者的故事&#xff0c;挖掘公益更深层次的内涵&#xff0c;探索新时代公益发展道路。希望公益企业、人物、故事被更多人看到&#xff0…

外卖小程序源码vs定制开发:何时选择哪种方式?

在数字餐饮行业的蓬勃发展中&#xff0c;外卖应用程序已经成为餐厅和创业者的必备工具。然而&#xff0c;当涉及到开发外卖应用程序时&#xff0c;您会面临一个重要的决策&#xff1a;是使用外卖小程序源码还是进行定制开发&#xff1f;这两种方法各有优势和劣势&#xff0c;取…

【刷题笔记10.5】LeetCode:排序链表

LeetCode&#xff1a;排序链表 一、题目描述 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 二、分析 这题咱们默认要求&#xff1a;空间复杂度为O(1)。所以这把咱们用自底向上的方法实现归并排序&#xff0c;则可以达到O(1) 的空间复杂…

【itext7】使用itext7将多个PDF文件、图片合并成一个PDF文件,图片旋转、图片缩放

这篇文章&#xff0c;主要介绍使用itext7将多个PDF文件、图片合并成一个PDF文件&#xff0c;图片旋转、图片缩放。 目录 一、itext7合并PDF 1.1、引入依赖 1.2、合并PDF介绍 1.3、采用字节数组方式读取PDF文件 1.4、合并多个PDF文件 1.5、合并图片到PDF文件 1.6、旋转图…

王杰C++day1

#include <iostream>using namespace std;int main() {cout << "输入一个字符串&#xff1a;" << endl;string str;int a 0,b 0,c 0,d 0,e 0;getline(cin,str);for(int i 0;i < (int)str.size();i){if(str[i] > A && str[i] &…

接口自动化测试介入项目管理流程

上图为接口自动化测试介入梧桐项目管理流程图 前景和目标&#xff1a; 现在公司的项目流程都是全部开发完成后提交到测试环境进行测试&#xff0c;导致测试人员在开发编码过程中相对清闲&#xff0c;除了完成测试用例之外没有其他事情可做&#xff0c;而当进入测试阶段又会变…

兽药经营小程序微信商城的作用是什么

无论家宠还是畜牧养殖&#xff0c;生病杀虫总是不可少的&#xff0c;尤其对铲屎官们来说&#xff0c;宠物的健康状况很重要&#xff0c;以此花费百元千元也并不觉心疼&#xff0c;兽药的需求度也是非常高&#xff0c;那么对相关从业商家来说&#xff0c;遇到的难题有哪些&#…

Sql server 使用DBCC Shrinkfile 收缩日志文件

磁盘空间有限&#xff0c;需要收缩日志文件释放空间。 数据库名称上右击属性->文件,逻辑名称日志文件默认名称为“_log”结尾。 alter database 数据库 set recovery simple dbcc shrinkfile(XXX_log,2,truncateonly) alter database 数据库 set recovery full

安全基础 --- MySQL数据库的《锁》解析

MySQL的ACID &#xff08;1&#xff09;ACID是衡量事务的四个特性 原子性&#xff08;Atomicity&#xff0c;或称不可分割性&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;Durability&#xff09; &…