基于vue-simple-uploader的断点续传

news2024/11/16 15:37:30

方案:

分片上传,再次上传时,查询已上传分片,继续上传剩余分片

实现效果: 

1. 安装uploader和spark-md5的依赖

npm install --save vue-simple-uploader

npm install --save spark-md5

2.mainjs导入uploader

import uploader from 'vue-simple-uploader'

Vue.use(uploader)

3.代码:

<template>
  <div>
    <uploader
      :autoStart="false"
      :options="options"
      :file-status-text="statusText"
      class="uploader-example"
      @file-complete="fileComplete"
      @complete="complete"
      @file-success="fileSuccess"
      @files-added="filesAdded"
    >
      <uploader-unsupport></uploader-unsupport>
      <uploader-drop>
        <p>将文件拖放到此处以上传</p>
        <uploader-btn>选择文件</uploader-btn>
        <uploader-btn :attrs="attrs">选择图片</uploader-btn>
        <uploader-btn :directory="true">选择文件夹</uploader-btn>
      </uploader-drop>
      <!-- <uploader-list></uploader-list> -->
      <uploader-files> </uploader-files>
    </uploader>
    <br />
    <el-button @click="allStart()" :disabled="disabled">全部开始</el-button>
    <el-button @click="allStop()" style="margin-left: 4px">全部暂停</el-button>
    <el-button @click="allRemove()" style="margin-left: 4px"
      >全部移除</el-button
    >
  </div>
</template>

<script>
import SparkMD5 from "spark-md5";
import { mergeChunk } from "@/api/dataset";
// import storage from "store";
// import { ACCESS_TOKEN } from "@/store/mutation-types";
export default {
  data() {
    return {
      skip: false,
      options: {
        target: process.env.VUE_APP_BASE_API + "factory/upload/chunk",
        // 开启服务端分片校验功能
        testChunks: true,
        // chunkSize: 2*1024*1024, // 默认:1M
        parseTimeRemaining: function (timeRemaining, parsedTimeRemaining) {
          return parsedTimeRemaining
            .replace(/\syears?/, "年")
            .replace(/\days?/, "天")
            .replace(/\shours?/, "小时")
            .replace(/\sminutes?/, "分钟")
            .replace(/\sseconds?/, "秒");
        },
        // 服务器分片校验函数
        checkChunkUploadedByResponse: (chunk, message) => {
          console.log("chunk校验", chunk);
          const result = JSON.parse(message);
          if (result.data.skipUpload) {
            // skipUpload为true, 是秒传,代表这个文件已经有了
            this.skip = true;
            return true;
          }
          // result.data.uploaded 表示已经上传过的分片编号
          return (result.data.uploaded || []).indexOf(chunk.offset + 1) >= 0;
        },
        headers: {
          // 在header中添加的验证,请根据实际业务来
          //   "Access-Token": storage.get(ACCESS_TOKEN),
        },
      },
      attrs: {
        accept: "image/*",
      },
      statusText: {
        success: "上传成功",
        error: "上传出错了",
        uploading: "上传中...",
        paused: "暂停中...",
        waiting: "等待中...",
        cmd5: "计算文件MD5中...",
      },
      fileList: [],
      disabled: true,
    };
  },
  watch: {
    fileList(o, n) {
      this.disabled = false;
    },
  },
  methods: {
    fileSuccess(rootFile, file, response, chunk) {
      //   console.log("rootFile", rootFile);
      //   console.log("file", file);
      //   console.log("response", response);
      //   console.log("chunk", chunk);
      const result = JSON.parse(response);
      console.log(result.code, this.skip);

      if (result.code === "0000000" && !this.skip) {
        mergeChunk({
          identifier: file.uniqueIdentifier,
          filename: file.name,
          totalChunks: chunk.offset,
          path: "mulu1/mulu2",
          datasetId: 64,
        })
          .then((res) => {
            console.log("merge返回", res);
            if (res.code === "0000000") {
              console.log("上传成功");
            } else {
              console.log(res);
            }
          })
          .catch(function (error) {
            console.log(error);
          });
      } else {
        console.log("上传成功,不需要合并");
      }
      if (this.skip) {
        this.skip = false;
      }
    },
    fileComplete(rootFile) {
      // 一个根文件(文件夹)成功上传完成。
      // console.log("fileComplete", rootFile);
      // console.log("一个根文件(文件夹)成功上传完成。");
    },
    complete() {
      // 上传完毕。
      // console.log("complete");
    },
    filesAdded(file, fileList, event) {
      // console.log(file);
      file.forEach((e) => {
        this.fileList.push(e);
        this.computeMD5(e);
      });
    },
    computeMD5(file) {
      let fileReader = new FileReader();
      let time = new Date().getTime();
      let blobSlice =
        File.prototype.slice ||
        File.prototype.mozSlice ||
        File.prototype.webkitSlice;
      let currentChunk = 0;
      const chunkSize = 1024 * 1024; // 1M
      let chunks = Math.ceil(file.size / chunkSize);
      let spark = new SparkMD5.ArrayBuffer();
      // 文件状态设为"计算MD5"
      file.cmd5 = true; //文件状态为“计算md5...”
      file.pause();
      loadNext();
      fileReader.onload = (e) => {
        spark.append(e.target.result);
        if (currentChunk < chunks) {
          currentChunk++;
          loadNext();
          // 实时展示MD5的计算进度
          console.log(
            `第${currentChunk}分片解析完成, 开始第${
              currentChunk + 1
            } / ${chunks}分片解析`
          );
        } else {
          let md5 = spark.end();
          console.log(
            `MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${
              file.size
            } 用时:${new Date().getTime() - time} ms`
          );
          spark.destroy(); //释放缓存
          file.uniqueIdentifier = md5; //将文件md5赋值给文件唯一标识
          file.cmd5 = false; //取消计算md5状态
          file.resume(); //开始上传
        }
      };
      fileReader.onerror = function () {
        this.error(`文件${file.name}读取出错,请检查该文件`);
        file.cancel();
      };
      function loadNext() {
        let start = currentChunk * chunkSize;
        let end =
          start + chunkSize >= file.size ? file.size : start + chunkSize;
        fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
      }
    },
    allStart() {
      console.log(this.fileList);
      this.fileList.map((e) => {
        if (e.paused) {
          e.resume();
        }
      });
    },
    allStop() {
      console.log(this.fileList);
      this.fileList.map((e) => {
        if (!e.paused) {
          e.pause();
        }
      });
    },
    allRemove() {
      this.fileList.map((e) => {
        e.cancel();
      });
      this.fileList = [];
    },
  },
};
</script>

<style>
.uploader-example {
  width: 100%;
  padding: 15px;
  margin: 0px auto 0;
  font-size: 12px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
}
.uploader-example .uploader-btn {
  margin-right: 4px;
}
.uploader-example .uploader-list {
  max-height: 440px;
  overflow: auto;
  overflow-x: hidden;
  overflow-y: auto;
}
</style>

 参考:

vue-simple-uploader地址

GitHub - simple-uploader/vue-uploader: A Vue.js upload component powered by simple-uploader.js

或者:

README_zh-CN.md · master · mirrors / simple-uploader / vue-uploader · GitCode

simple-uploader.js文档

Uploader/README_zh-CN.md at develop · simple-uploader/Uploader · GitHub

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

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

相关文章

日期格式化 YYYY-MM-DD 出现时间偏移量

在js中&#xff0c;很多时候需要把日期字符串转换为一个 Date 对象。 如果得到的日期字符串有时间还好办&#xff0c;如果没有时间&#xff0c;只有日期的格式&#xff0c;例如 2022-12-01 这样的字符串呢&#xff1f; 大部分人可能什么都没想&#xff0c;直接就调用了 new D…

MyBatis-Plus分页查询(快速上手运用)

系列文章目录 Mybatis-Plus知识点[MyBatisMyBatis-Plus的基础运用]_心态还需努力呀的博客-CSDN博客 Mybatis-PlusSpringBoot结合运用_心态还需努力呀的博客-CSDN博客MyBaits-Plus中TableField和TableId用法_心态还需努力呀的博客-CSDN博客 MyBatis-Plus中的更新操作&#…

【实操篇】Linux实用指令总结

目录 1.运行级别类 ●运行级别 ●指定运行级别 2.帮助指令类 ●帮助指令 1.man获得帮助信息 2.help指令 3.文件目录类 ●pwd指令 ●ls指令 ●cd指令 ●mkdir指令 ●rmdir指令 ●touch指令 ●cp指令 ●rm指令 ●mv指令 ●cat指令 ●more指令 ●less指令 ●>指令和>>…

如此简单的K8S,来玩下pv和pvc,利用nfs来实现持久化存储(内网环境,非常详细)

如此简单的K8S,来玩下pv和pvc&#xff0c;利用nfs来实现持久化存储(内网环境&#xff0c;非常详细) k8s很简单&#xff0c;怎么个简单法呢&#xff0c;来给小编一起再来复习一边吧。今天主要来了解下pv和pvc的概念&#xff0c;小编也是当过多次的面试官&#xff0c;小编悄悄的告…

低代码助力制造型企业管理:项目管理系统

制造业企业经过近两个世纪的发展&#xff0c;已经成为世界各国经济发展的支柱产业&#xff0c;要增强一个国家的综合国力&#xff0c;就必须首先建设一个强大的制造业。因此&#xff0c;在一些率先进入知识经济的工业发达国家&#xff0c;汽车、航空、装备等制造业依然保持支柱…

QT QSpinBox 整数计数器控件 使用详解

本文详细的介绍了QSpinBox控件的各种操作&#xff0c;例如&#xff1a;获取数值、设置前后缀、设置最大/小值、进制转换、关联信号槽、优化信号、QSS优化、文件源码、样式表 、效果&#xff1a;可以设置背景、边框、向上按钮、向下按钮 等等操作。 本文作者原创&#xff0c;转载…

安装dolphinscheduler

四种安装方式&#xff0c;机器有限&#xff0c;最后选的伪集群安装&#xff0c;所有都装在一台机器上。 安装手册 需要依次安装 JDK&#xff1a;下载JDK (1.8)&#xff0c;安装并配置 JAVA_HOME 环境变量&#xff0c;并将其下的 bin 目录追加到 PATH环境变量中。如果你的环境…

[附源码]Python计算机毕业设计SSM居民个人健康服务平台(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

能耗物联网的入口—计量监测解决方案价值解析

能耗物联网的入口—计量监测解决方案价值解析 在双碳政策支持下&#xff0c;有着众多头部企业的引领&#xff0c;能源物联网呈现蓬勃发展势头。 然而作为该领域内占有重要位置的海量用电设备&#xff0c;其运行状态、设备利用率均是未知的&#xff0c;绝大多数用电设备仍未联网…

CTFHUB-web-文件上传

无验证 上传一句话木马 <?php eval($_POST[attack]) ?>蚁剑添加数据&#xff0c;密码为attack 成功连接 找到flag flag&#xff1a; ctfhub{5d24093c73fddbba912490b6} 前端验证 还是传那个一句话木马&#xff0c;不允许上传 只能上传指定后缀的文件&#xff0c;所以可…

如何在Centos8中添加附加的IP

有时可能需要为 CentOS 8 系统上的单个网卡分配附加的 IP 地址。例如应用程序要求或 SSL 证书的安装。在本文中&#xff0c;我们将解释如何在 CentOS 7/8 中添加附加或多个 IP 地址。 方法一&#xff1a;手动添加附加IP 在原网卡配置文件中添加附加IP 在继续配置辅助 IP 之前…

Kotlin高仿微信-第32篇-支付-我的零钱

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

opencv入门笔记(一)

目录图像处理基本操作图像读取图像显示图像保存图像翻转图像缩放如何绘制简单的图形绘制线段示例&#xff08;在画布上绘制线段&#xff09;绘制矩形示例&#xff08;标记图片中的花朵位置&#xff09;绘制圆形示例&#xff08;同心圆绘制&#xff09;绘制多边形示例&#xff0…

Linux4._冯•诺依曼体系结构

文章目录[toc]1. 硬件结构2. 工作方式3. 存储器结构4. 局部性原理5. 实例分析早期的 ENIAC 计算机存储容量很小&#xff0c;编程采用线路连接方式&#xff0c;很不方便。1946年&#xff0c;数学家 冯•诺依曼 提出了以存储程序为核心的计算机模型&#xff0c;该计算机模型一直沿…

[附源码]计算机毕业设计在线影院系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Java8用Stream流一行代码实现数据分组统计,排序,最大值、最小值、平均值、总数、合计

Java8对数据处理可谓十分流畅&#xff0c;既不改变数据&#xff0c;又能对数据进行很好的处理&#xff0c;今天给大家演示下&#xff0c;用Java8的Stream如何对数据进行分组统计&#xff0c;排序&#xff0c;求和等 汇总统计方法 找到汇总统计的方法。这些方法属于java 8的汇…

wsl2如何安装systemctl命令,已成功!

打开powershell&#xff0c; 输入wsl 进入子系统(或者以你自己的方式进入子系统) apt install policykit-1 apt install build-essential apt install daemonize cd /tmp git clone http://github.com/bmc/daemonize.git cd daemonize sh configure make sudo make ins…

论文笔记:OpenPrompt: An Open-source Framework for Prompt-learning

论文来源&#xff1a;ACL2022 论文地址&#xff1a;https://aclanthology.org/2022.acl-demo.10.pdf 论文代码&#xff1a;https://github.com/thunlp/OpenPrompt 笔记仅供参考&#xff0c;撰写不易&#xff0c;请勿恶意转载抄袭&#xff01; Abstract 目前&#xff0c;还没…

Flink系列之Flink中Source_Transform_Sink整理和实战

title: Flink系列 二、Flink Source 整理和实战 Flink Source 是程序的数据源输入&#xff0c;可以通过 StreamExecutionEnvironment.addSource(sourceFunction) 来为你的程序添加一个 Source。 Flink 提供了大量的已经实现好的 source 方法&#xff0c;也可以自定义 source&…

译文 | A poor man‘s API

作者&#xff1a;Nicolas Frnkel 翻译&#xff1a;Sylvia https://blog.frankel.ch/poor-man-api/ 在 API 日渐流行的年代&#xff0c;越来越多的非技术人员也希望能从 API 的使用中获利&#xff0c;而创建一套成熟的 API 方案需要时间成本和金钱两方面的资源加持。在这个过程中…