切片上传(抄袭)

2023-01-29  本文已影响0人  糖醋里脊120625

<template>
    <div class="info">
   <el-input v-model="currentFileName" clearable class="info-content" @clear="resetFile" />
      <input
        id="file-upload"
        ref="fileUpload"
        type="file"
        @input="uploadFile"
      />
      <el-button size="small" class="file-btn" @click="uploadClick">选择</el-button>
      <div class="info-tips">仅支持XLS、CSV格式文件,小于等于500M</div>
    </div>

    <div v-if="fileObj.state" class="uploadChunksPanel">
      <div class="progressWrap">
        <el-progress text-inside :stroke-width="14" :format="format" :percentage="uploadProgress" />
      </div>
      <div class="tipsWrap">
        <div class="leftBox">
          <span :class="[fileObj.state === 3 ? 'blue' : '']">
            <i v-if="fileObj.state === 2" class="el-icon-loading"></i>
            <i v-if="fileObj.state === 3" class="el-icon-success"></i>
            {{ fileObj.tips }}
          </span>
        </div>
        <div v-if="fileObj.name" class="rightBox">
          {{ fileObj.name }}<span class="line">/</span>
          {{ fileObj.size }}<span v-if="speedStr" class="line">/</span>{{ speedStr }}
        </div>
      </div>
    </div>
</template>

<script lang="ts" setup>
import { computed, onMounted, ref, unref } from "vue";

const uploadProgress = ref(0); // 上传进度
const fileObj = ref({
  name: '',
  size: '',
  state: 0,
  tips: ''
});
const speedStr = ref('');

import BMF from 'browser-md5-file';

// 计算MD5
const toHandleMd5 = (file) => {
  return new Promise((resolve, reject) => {
    const bmf = new BMF();
    bmf.md5(file, (err, md5) => {
      err ? reject(err) : resolve(md5);
    },
    progress => {
      fileObj.value.tips = `玩命计算中 ${parseInt(progress * 100)}%,即将开始上传`;
    }
    );
  });
};

// 格式化字节
 function formatBytes(value) {
  let bytes = '-';
  if (value < 1024 * 1024) {
    bytes = parseFloat(value / 1024).toFixed(2) + ' KB';
  } else if (value >= 1024 * 1024 && value < 1024 * 1024 * 1024) {
    bytes = parseFloat(value / (1024 * 1024)).toFixed(2) + ' MB';
  } else if (value >= 1024 * 1024 * 1024 && value < 1024 * 1024 * 1024 * 1024) {
    bytes = parseFloat(value / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
  } else if (value >= 1024 * 1024 * 1024 * 1024) {
    bytes = parseFloat(value / (1024 * 1024 * 1024 * 1024)).toFixed(2) + ' TB';
  }
  return bytes;
}

const uploadFile = async(e) => {
  const file = e.target.files[0];
  const { size: fileSize, name: fileName } = file;
  const maxFileSize = 500 * 1024 * 1024;   // 限制文件上传大小 500MB

  if (fileSize <= maxFileSize) {
    fileObj.value.state = 1;
    fileObj.value.name = fileName;
    fileObj.value.size = formatBytes(fileSize);
    const fileMd5 = await toHandleMd5(file);
    fileObj.value.tips = '文件上传中...';
    fileObj.value.state = 2;

    const sliceSize = 5 * 1024 * 1024; // 切片大小 5MB
    const totalChunks = Math.ceil(fileSize / sliceSize); // 总共切片数量  Math.ceil(x) 向上取整

    for (let i = 0; i < totalChunks; i++) {
      const start = i * sliceSize;
      const chunk = file.slice(start, Math.min(fileSize, start + sliceSize)); // Math.min 返回最小的数
      const fileIndex = i + 1;

      const formData = new FormData();
      formData.append('file', chunk);  // 当前切片的文件
      formData.append('file_name', fileName); // 文件名
      formData.append('file_size', fileSize); // 文件总大小
      formData.append('file_index', fileIndex); // 当前上传的切片下标,起始1
      formData.append('total_chunks', totalChunks); // 切片总数
      formData.append('file_md5', fileMd5); // 文件md5值

      // 最后一个切片上传时
      if (fileIndex + 1 === totalChunks) fileObj.value.tips = '文件合并转存中...';

      const sTime = new Date().getTime();
      const result = await toUpload(formData); // 上传事件
      console.log(result)
      const eTime = new Date().getTime();
      const speed = sliceSize / ((eTime - sTime) / 1000); // 单个切片上传速度
      if (speed < (1024 * 1024)) {
        speedStr.value = parseFloat(speed / 1024).toFixed(2) + ' KB/s';
      } else if (speed >= (1024 * 1024) && speed < (1024 * 1024 * 1024)) {
        speedStr.value = parseFloat(speed / (1024 * 1024)).toFixed(2) + ' MB/s';
      }

      // 正常操作
      if (result?.status) {
        uploadProgress.value = Number(((fileIndex / totalChunks) * 100).toFixed(2));
        if (result?.data?.is_complete === 1) { // 是否完成 0未完成 1完成
          speedStr.value = '';
          fileObj.value.tips = '文件上传完成!';
          fileObj.value.state = 3;

          currentFilePath.value = result?.data?.file_path; // 上传完成时返回的文件路径 用于另一个接口
          currentFileName.value = fileName;
        }
      } else {
        resetParams();
        console.log('上传失败,请重新上传!');
        break;
      }
    }
  } else {
    console.log('文件大小超出500MB');
    resetParams();
  }
};

// 上传
const toUpload = (fileObj) => {
  console.log(fileObj)

  return
  return new Promise((resolve, reject) => {
    // uploadChunk 上传接口
    uploadChunk(fileObj).then(res => {
      resolve(res);
    });
  });
};

// 重置
const resetParams = () => {
  uploadProgress.value = 0;
  fileObj.value = {
    name: '',
    size: '',
    state: 0,
    tips: ''
  };
  speedStr.value = '';
};


const fileUpload = ref(null);

const resetFile = () => {
  currentFileName.value = '';
  currentFilePath.value = '';
  fileUpload.value.value = ''; // 清空input选中文件
  resetParams();
};

</script>
上一篇下一篇

猜你喜欢

热点阅读