方案:
分片上传,再次上传时,查询已上传分片,继续上传剩余分片
实现效果:

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







![[附源码]Python计算机毕业设计SSM居民个人健康服务平台(程序+LW)](https://img-blog.csdnimg.cn/c7bb75a9b7974eda81efbf9f895faa17.png)






![[附源码]计算机毕业设计在线影院系统Springboot程序](https://img-blog.csdnimg.cn/d7382327a98a48d49068c649ea5bdb77.png)




