SOURCE

import axios from "axios";
import { getToken } from "@/utils/auth";
import { computed, ref } from "vue";

let fileSize;
const chunkList = ref([]);

export const getPercentage = computed(() => {
  if (chunkList.value.length === 0) return 0;

  const isAllSettled = chunkList.value.every((item) => item.percentage === 100);
  if (isAllSettled) return 100;

  const loaded = chunkList.value
    .map((item) => item.size * item.percentage)
    .reduce((arr, cur) => arr + cur);

  return parseInt((loaded / fileSize).toFixed(2));
});

export const uploadSepcialFileByPieces = (url, { file, uploadId }) => {
  const chunkSize = 5 * 1024 * 1024;
  const chunkCount = Math.ceil(file.size / chunkSize);
  fileSize = file.size;

  const getChunkInfo = (file, index, chunkSize) => {
    const start = index * chunkSize;
    const end = Math.min(file.size, start + chunkSize);
    const chunk = file.slice(start, end);
    return { start, end, chunk };
  };

  const getFetchFormByReadChunk = (file, index, chunkSize, uploadId) => {
    const { chunk } = getChunkInfo(file, index, chunkSize);
    const fetchForm = new FormData();
    fetchForm.append("file", chunk);
    fetchForm.append("partNumber", +index + 1); // 分片数从 1 开始
    fetchForm.append("uploadId", uploadId);
    return fetchForm;
  };

  const uploadFile = (formData, i) => {
    return axios({
      url,
      method: "post",
      data: formData,
      headers: {
        Authorization: "Bearer " + getToken(),
        "Content-Type": "multipart/form-data",
      },
      onUploadProgress: (data) => {
        const { loaded, total } = data;
        chunkList.value[i].percentage = parseInt((loaded / total) * 100);
      },
    });
  };

  const concurRequest = (uploadFile, forms, maxNum = 5) => {
    return new Promise((resolve, reject) => {
      const len = forms.length;
      let index = 0;
      let counter = 0;
      const result = [];
      const _request = async () => {
        while (index < len && maxNum > 0) {
          maxNum--;
          const i = index;
          const { formData, idx } = forms[index];
          index++;
          try {
            const {
              data: { code, msg, data },
            } = await uploadFile(formData, idx);
            result[i] = { code, msg };
            if (code === 200) result[i].data = data;
          } catch (error) {
            reject(error);
          } finally {
            counter++;
            maxNum++;
            if (counter === len) {
              const isAllSettled = result.every((item) => item.code === 200);
              isAllSettled ? resolve(result) : reject(result);
            } else {
              _request();
            }
          }
        }
      };
      _request();
    });
  };

  return new Promise(async (resolve, reject) => {
    try {
      const formDataList = [];
      for (let i = 0; i < chunkCount; i++) {
        formDataList[i] = {
          formData: getFetchFormByReadChunk(file, i, chunkSize, uploadId),
          idx: i,
        };
        chunkList.value[i] = { size: chunkSize, percentage: 0 };
      }
      const result = await concurRequest(uploadFile, formDataList, 5);
      resolve(result);
    } catch (error) {
      reject(error);
    }
  });
};
console 命令行工具 X clear

                    
>
console