vue中大文件上传至AWS s3组件

<template>
  <div class="minioBox">
    <el-button
      v-if="model === 'button' && fileList.length < maxLen"
      style="
        margin-right: 10px;
        color: #3f51b5;
        font-size: 14px;
        line-height: 20px;
      "
      :disabled="disabled"
      @click="getFileName"
      size="mini"
      type="text"
      >+上传</el-button
    >
    <el-button
      v-if="model === 'text' && fileList.length < maxLen"
      style="
        marginleft: 20px;
        color: #909399;
        font-size: 13px;
        line-height: 20px;
      "
      :disabled="disabled"
      @click="getFileName"
      class="el-icon-circle-plus-outline"
      size="mini"
      type="text"
      >上传文件</el-button
    >
    <input
      :accept="fileTypeList.join(',')"
      type="file"
      multiple="multiple"
      ref="minIoFile"
      v-show="false"
      @change="getFile"
    />
    <ul class="uploadFileList">
      <li v-for="(item, index) of fileList" :key="index" style="display: flex">
        <span>{{ index + 1 }}.</span>
        <el-select
          v-model="item.dataStream"
          size="mini"
          style="width: 100px; margin: 0 20px"
          v-if="updateComponent && isUpDataStream"
          placeholder="数据流"
          @change="changeItem"
        >
          <el-option
            v-for="(stream, key) in streamList"
            :key="stream + key"
            :label="stream"
            :value="stream"
          >
          </el-option>
        </el-select>
        <span class="subString">{{
          item.name.length > 10 ? item.name.substring(0, 10) + "..." : item.name
        }}</span
        >&nbsp;
        <span>({{ (item.size / 1024 / 1024).toFixed(2) }}M)</span>
        <span v-if="item.percent === 100" style="color: #4052b5"
          ><i class="el-icon-success"></i>上传成功</span
        >
        <div v-if="!isUpload" class="floatRight" style="float: right">
          <i
            class="el-icon-close"
            style="cursor: pointer"
            @click="deleteMinioFile(index)"
          ></i>
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
import AWS from "aws-sdk";
export default {
  props: {
    model: {
      type: String,
      default: "button",
    },
    maxLen: {
      type: Number,
      default: 2,
    },
    progress: {
      type: Boolean,
      default: false,
    },
    fileTypeList: {
      type: Array,
      default: [".*"],
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    isUpDataStream: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      streamList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
      fileList: [],
      fileCopyList: [],
      fileUp: false,
      isUpload: false,
      updateComponent: true,
      uploadList: [],
      timer: null,
      updateObject: {},
      usedTime: 0,
      uploadTimer: null,
      loadedTotal: 0,
      fileTotal: 0,
      s3: {},
      dataInfo: {
        accessKeyId: JSON.parse(localStorage.getItem("dataInfo")).ak,
        secretAccessKey: JSON.parse(localStorage.getItem("dataInfo")).sk,
        endpoint: JSON.parse(localStorage.getItem("dataInfo")).point,
        s3ForcePathStyle: JSON.parse(localStorage.getItem("dataInfo"))
          .s3ForcePathStyle,
        signatureVersion: "v4",
      },
    };
  },
  created() {},
  methods: {
    changeItem(item, index) {
      this.updateComponent = false;
      setTimeout(() => {
        this.updateComponent = true;
      }, 0);
    },
    selectLen() {
      let _vm = this;
      return new Promise((resolve, reject) => {
        resolve(_vm.fileList.length);
      });
    },
    upload(obj) {
      if (this.isUpDataStream) {
        let hasStream = true;
        this.fileList.forEach((item) => {
          if (!item.dataStream) {
            hasStream = false;
          }
        });
        if (!hasStream) {
          this.$message.warning("请选择数据流");
          this.$emit("hasStream", true);
          return;
        }
      }
      this.dataInfo = {
        accessKeyId: JSON.parse(localStorage.getItem("dataInfo")).ak,
        secretAccessKey: JSON.parse(localStorage.getItem("dataInfo")).sk,
        endpoint: JSON.parse(localStorage.getItem("dataInfo")).point,
        s3ForcePathStyle: JSON.parse(localStorage.getItem("dataInfo"))
          .s3ForcePathStyle,
        signatureVersion: "v4",
      };
      this.s3 = new AWS.S3(this.dataInfo);
      if (this.fileList.length === 0) {
        let nullFile = {
          type: obj,
          list: false,
        };
        this.$emit("uploadSuccess", nullFile);
      }
      this.updateObject = obj;
      this.uploadList = [];
      this.isUpload = true;
      this.timer = setInterval(() => {
        this.fileUp = !this.fileUp;
      }, 0);
      this.fileList.forEach((item) => {
        this.fileTotal += item.size;
      });
      this.fileList.map((item, index) => {
        this.uploadMinIo(item, index);
      });
    },
    clearfield() {
      this.fileList = [];
      this.uploadList = [];
      this.isUpload = false;
    },
    deleteMinioFile(index) {
      this.fileList.splice(index, 1);
      this.$refs.minIoFile.value = "";
    },
    getFileName() {
      let inputDOM = this.$refs.minIoFile;
      inputDOM.click();
    },
    getFile(event) {
      let files = this.$refs.minIoFile.files;
      let fileSwitch = true;
      if (files.length > 0) {
        for (let i = 0; i < files.length; i++) {
          if ((files[i].size / 1024 / 1024 / 1024).toFixed(2) > 6400) {
            this.$message({
              message: `${files.name}超过文件的最大长度`,
              type: "warning",
            });
            fileSwitch = false;
          }
        }
        if (fileSwitch) {
          for (let i = 0; i < files.length; i++) {
            if (this.fileList.length < this.maxLen) {
              this.fileList.push(files[i]);
              // let obj = {
              //   name: files[i].name,
              //   dataStream: "",
              //   percent: 0,
              //   size: files[i].size,
              // };
              // this.fileCopyList.push(obj);
              this.$emit("fileList", this.fileList);
            } else {
              if (this.maxLen != 1 && this.maxLen != 6) {
                this.$message.warning(`最多只能够添加6个文件`);
                return;
              } else {
                this.$message.warning(`最多只能够添加${this.maxLen}个文件`);
                return;
              }
            }
          }
        }
      }
    },
    uploadMinIo(file, index) {
      let vm = this;
      vm.uploadTimer = setInterval(() => {
        vm.usedTime += 1;
      }, 1000);
      vm.fileUp = true;
      let YY = new Date().getFullYear();
      let MM = new Date().getMonth() + 1;
      let DD = new Date().getDate();
      let fileName = file.name;
      let uuid = vm.generateUUID();
      if (file) {
        let params = {
          Bucket: JSON.parse(localStorage.getItem("dataInfo"))
            .bucketName /* required */,
          Key: `${YY}/${MM}/${DD}/${uuid}/${fileName}` /* required */,
          Body: file,
        };
        this.s3
          .upload(params, function (err, data) {
            clearInterval(vm.uploadTimer);
            if (err) {
              vm.$emit("uploadFail", err);
            } else {
              let fileObj = {
                dataFile: file.name,
                dataType: file.type,
                dataAddr: data.Location,
                dataKey: data.Key,
                bucket: data.Bucket,
                dataSize: file.size,
                dataStream: file.dataStream,
              };
              vm.uploadList.push(fileObj);
              if (vm.uploadList.length === vm.fileList.length) {
                let time = setTimeout(() => {
                  clearInterval(vm.timer);
                  vm.fileUp = true;
                  clearTimeout(time);
                }, 500);
                let obj = {
                  type: vm.updateObject,
                  list: vm.uploadList,
                };
                vm.$emit("uploadSuccess", obj);
              }
            }
          })
          .on("httpUploadProgress", (e) => {
            let per = parseInt(e.loaded, 10) / parseInt(e.total, 10);
            per = Number((per * 100).toFixed(0));
            file.percent = per;
            file.loaded = e.loaded;
            let uploadData = {
              per: per,
              time: vm.usedTime,
            };
            file.uploadData = uploadData;
            vm.getUploadTime();
          });
      }
    },
    getUploadTime() {
      this.loadedTotal = 0;
      this.fileList.forEach((item) => {
        if (item.loaded) {
          this.loadedTotal += parseInt(item.loaded);
        }
      });
      let need = 0;
      let per = (this.loadedTotal / this.fileTotal).toFixed(2) * 100;
      need = ((this.usedTime / (per / 100)) * (1 - per / 100)).toFixed(2);
      let neew = this.getRevTime(parseInt(need));
      let obj = {
        per: parseInt(per),
        needTime: neew,
      };
      this.$emit("uploadProgress", obj);
    },
    getRevTime(time) {
      if (time / 3600 > 24) {
        return `大于一天`;
      } else if (time / 3600 > 1) {
        let hh = Math.floor(time / 3600);
        let mm = Math.floor((time % 3600) / 60);
        return `大约需要${hh}时${mm}分`;
      } else if (time / 60 > 1) {
        let mm = Math.floor(time / 60);
        let ss = Math.floor(time % 60);
        return `大约需要${mm}分${ss}秒`;
      } else {
        return `大约需要${time}秒`;
      }
    },
    generateUUID() {
      var d = new Date().getTime();
      if (window.performance && typeof window.performance.now === "function") {
        d += performance.now(); // use high-precision timer if available
      }
      var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
        /[xy]/g,
        function (c) {
          var r = (d + Math.random() * 16) % 16 | 0;
          d = Math.floor(d / 16);
          return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
        }
      );
      return uuid;
    },
  },
};
</script>
<style lang="scss" scoped>
.minioBox {
  color: #000000;
  padding: 0px;
  width: 90%;
  line-height: 20px;
  min-height: 40px;
  .uploadFileList {
    width: 100%;
    list-style: none;
    margin-top: 5px;
    padding: 0;
    li {
      height: 40px;
      line-height: 26px;
      margin: 0px !important;
      span {
        vertical-align: top;
      }
      .subString {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        width: 40%;
        display: inline-block;
      }
      i {
        margin: 5px 5px 0 0;
      }
      .el-icon-close,
      .el-icon-upload-success {
        float: right;
      }
      .upload-success {
        color: green;
      }
      .upload-fail {
        color: red;
      }
    }
    li:hover {
      background-color: #f5f7fa;
    }
    li:first-child {
      margin-top: 10px;
    }
    /deep/ .progress {
      margin-top: 2px;
      width: 200px;
      height: 14px;
      margin-bottom: 10px;
      overflow: hidden;
      background-color: #f5f5f5;
      border-radius: 4px;
      -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
      box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
      display: inline-block;
      .progress-bar {
        background-color: rgb(92, 184, 92);
        background-image: linear-gradient(
          45deg,
          rgba(255, 255, 255, 0.14902) 25%,
          transparent 25%,
          transparent 50%,
          rgba(255, 255, 255, 0.14902) 50%,
          rgba(255, 255, 255, 0.14902) 75%,
          transparent 75%,
          transparent
        );
        background-size: 40px 40px;
        box-shadow: rgba(0, 0, 0, 0.14902) 0px -1px 0px 0px inset;
        box-sizing: border-box;
        color: rgb(255, 255, 255);
        display: block;
        float: left;
        font-size: 12px;
        height: 20px;
        line-height: 20px;
        text-align: center;
        transition-delay: 0s;
        transition-duration: 0.6s;
        transition-property: width;
        transition-timing-function: ease;
        width: 266.188px;
      }
    }
  }
}
</style>

 

posted @ 2022-02-22 12:58  清风园  阅读(495)  评论(0编辑  收藏  举报