大文件切片上传实现

 

 fileUpload.vue  子组件

<template>
  <!-- miniion  版本 -->
  <!-- 多文件分片上传Minio -->
  <div class="multipleFilePartUploadMinio">
    <el-upload
      ref="upload"
      name="files"
      action="#"
      :on-change="selectMultiplePartFileMinio"
      :on-remove="removeMultiplePartFileMinio"
      :file-list="fileList"
      :auto-upload="false"
      :show-file-list="false"
    >
      <el-button slot="trigger" size="small" type="primary">
        {{ upBtnVal }}</el-button
      >
      <el-button
        v-if="isShowButton"
        style="margin-left: 10px"
        size="small"
        type="success"
        @click="multipleFilePartUploadMinio"
        >点击上传
      </el-button>
      <el-link
        v-else
        style="margin-left: 10px"
        size="small"
        type="success"
        @click="multipleFilePartUploadMinio"
        >点击上传</el-link
      >
      <div slot="tip" class="el-upload__tip"></div>
    </el-upload>
    <el-progress
      :text-inside="true"
  :stroke-width="15"
      :percentage="filePercentage"
    ></el-progress>
    <!-- 文件列表 -->
    <transition-group
      :style="{ display: fileList.length === 0 ? 'none' : 'inline-block' }"
      class="upload-file-list el-upload-list el-upload-list--text"
      name="el-fade-in-linear"
      tag="ul"
    >
      <!-- :key="file.uid" -->
      <li
        class="el-upload-list__item ele-upload-list__item-content sNone"
        :style="{ marginBottom: fileList.length > 1 ? '10px !important' : 0 }"
        v-for="(file, index) in fileList"
        :key="index"
      >
        <!-- @click="downLoad(file)" -->
        <span class="el-icon-paperclip">
          <span class="baseColor">
            {{ file.name }}
          </span>
          ({{ formatBytes(file.size) }})
        </span>
        <span
          class="ele-upload-list__item-content-action"
          style="margin-left: 20px"
          @click="handleDelete(index)"
        >
         <!-- v-if="baseFileList.length" -->
          <i class="el-icon-close"></i>
        </span>
      </li>
    </transition-group>
  </div>
</template>

<script>
import { initFile, mergeFile, uploadFile } from "@/api/common";
import Axios from "axios";
export default {
  props: {
    upBtnVal: {
      type: String,
      default: "选取文件",
    },
    isShowButton: {
      type: Boolean,
      default: true,
    },
    // 是否展示
    fileShow: {
      type: Boolean,
      default: false,
    },
    baseFileList: {
      type: Array,
      default: () => [],
    },
  },
name: "JsPage",

  data() {
    return {
   
     headers: {
        "Content-Type": "application/x-www-form-urlencoded",
     
      },
      filePercentage: 0,
      fileList: [],
      isUploadSuccess: true,
      timerId: null,
      callCount: 0,
    };
  },
  mounted() {},
 watch: {
    baseFileList: {
      handler(newVal) {
        this.fileList = newVal;
      },
      deep: true,
      immediate: true,
    },
  },
  /* 组件销毁时清除定时器 */
  destroyed() {
    this.timerId = null;
  },
  methods: {
    // 删除文件
    handleDelete(index) {
      this.fileList.splice(index, 1);
      this.$emit("input", this.fileList);
    },
// 下面多文件分片上传Minio的一些方法
    selectMultiplePartFileMinio(file, fileList) {
      this.filePercentage = 0;
      this.fileList.push(file);
    },
    /* 移除文件 */
    removeMultiplePartFileMinio(file, fileList) {
      this.fileList = this.fileList.filter((item) => item.uid != file.uid);
      this.filePercentage = 0;
    },

    // 上传
    async multipleFilePartUploadMinio() {
      if (!this.fileList.length) {
        this.$modal.msgWarning("请选择需要上传的文件");
        return;
      }
   this.filePercentage = 0;
      let fileUploadCount = 0;
      let partSize = 20; //MB
      let fileList = this.fileList.filter((item) => item.raw);
      for (let i = 0; i < fileList.length; i++) {
        let partNum = Math.ceil(this.fileList[i].size / 1024 / 1024 / partSize);
        if (partNum > 1) {
          let partFileIndex = {
            filename: fileList[i].name,
            partCount: partNum,
            partIndex: "",
          };
          const res = await initFile(partFileIndex);
          if (res.uploadId) {
            let urlList = res.uploadUrls;
            let urlUploadId = res.uploadId;
            for (let j = 0; j < partNum; j++) {
              partFileIndex.partIndex = j;
         
            
               let file=fileList[i].raw.slice(
                  j * 1024 * 1024 * partSize,
                  (j + 1) * 1024 * 1024 * partSize
                )
        Axios.put(urlList[j], file, this.headers).then(
                async (response) => {
                  fileUploadCount++;
                  this.filePercentage = Math.round(
                    (fileUploadCount / partNum) * 100
                  );
                  if (fileUploadCount == partNum) {
                    let mergeData = {
                      objectName:
                        this.dateColumnFormatNotDash("", "", new Date()) +
                        "/" +
                        this.fileList[i].name, //这个是"日期/文件名"
                      uploadId: urlUploadId, //这个是调第一个接口生成的id
                    };
                    const resMerge = await mergeFile(mergeData);
                    if (resMerge.success) {
                      // 合并文件成功后,将url返回给fileList
                      this.$modal.msgSuccess("上传成功");
                      // 将url结果返回给filelist
                      this.fileList[i].fileUrl = resMerge.fileUrl;
                      this.$emit("fileChildList", [...this.fileList]);
                      this.isUploadSuccess = false;
                      this.$emit("isUploadSuccess", this.isUploadSuccess);
                    }
              }
                }
              );
            }
          }
        } else {
          // 调取之前的上传
          let partFileIndex = {
            fileName: fileList[i].name,
            fileUid: fileList[i].uid,
          };
          let fileParam = new FormData();
          fileParam.append("file", fileList[i].raw);
  fileParam.append("partFileIndex", JSON.stringify(partFileIndex));
          const resFile = await uploadFile(fileParam);
          if (resFile.code == 200 || resFile.code == 2000) {
            this.filePercentage = 100;
            // 合并文件成功后,将url返回给fileList
            this.$modal.msgSuccess("上传成功");
            // 将url结果返回给filelist
            this.fileList[i].fileUrl = resFile.msg;
            this.$emit("fileChildList", [...this.fileList]);
            this.isUploadSuccess = false;
            this.$emit("isUploadSuccess", this.isUploadSuccess);
          } else {
            this.$modal.msgError("上传失败,请重试");
          }
  this.timer = setInterval(() => {
            this.filePercentage++;
            if (this.filePercentage > 90) {
              clearInterval(this.timer);
              this.timer = null;
            }
          }, 900);
        }
      }
    },
  },
};
</script>

<style lang="scss" scoped>
::v-deep .el-progress-bar__innerText {
  margin-top: -7px;
}
.upload-file-list {
  display: inline-block;
}
.upload-file-list .el-upload-list__item {
  line-height: 2;
  margin-bottom: 10px;
  position: relative;
}

.ele-upload-list__item-content-action .el-link {
  margin-right: 10px;
}
.sNone:hover {
  background-color: inherit !important;
}
.sNone {
  line-height: 0 !important;
  margin-bottom: 0 !important;
  margin-top: 0 !important;
}
.el-icon-close {
  top: 1px;
}
.pointer {
  cursor: pointer;
}
</style>

      

父组件

  <file-upload
                @fileChildList="getFileList"
                @isUploadSuccess="isUploadSuccess"
                :baseFileList="fileList"
                :isShowButton="true"
              />

api接口

//初始化
export function initFile(data) {
  return request({
    url: "/fileApi/multipart/init",
    method: "post",
    data,
  });
}
// 文件合并
export function mergeFile(data) {
  return request({
    url: "/fileApi/multipart/complete",
    method: "put",
    data,
  });
}
// 上传文件
export function uploadFile(data) {
  return request({
    url: "/fileApi/uploadFile",
    method: "post",
    data,
    headers: {
      "Content-Type": "multipart/form-data;charset=utf-8",
    },
  });
}

上传成功拿到文件信息进行业务提交

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值