批量上传可手动取消

在这里插入图片描述
在这里插入图片描述

说明

前端批量上传,嗯……一个一个上传
点击按钮【取消上传】可取消上传
通过将promisereject保存到外部,调用函数终止操作

核心代码

const data = new Array(100).fill(0).map((_, i) => ({ uid: i }));

type ItemType = (typeof data)[number];

let settledNum = 0;
let successList: ItemType[] = [];
let failList: ({ reason: string } & ItemType)[] = [];

// 单个文件上传
const singleUpload = (item: ItemType) => {
  console.log(item.uid);
  return new Promise((resolve, reject) => {
    if (item.uid % 3 == 0) {
      return reject();
    }
    setTimeout(() => resolve(''), 50);
  });
};

let abort: () => void;

// 批量上传处理函数
const __ = (): Promise<number | undefined> => {
  return new Promise((resolve, reject) => {
    const i = settledNum;

    abort = reject; // reject 保存到外部 用于取消批量上传
    singleUpload(data[i])
      .then(
        () => {
          successList.push(data[i]);
        },
        (err) => {
          failList.push({ ...data[i], reason: '上传失败' });
        }
      )
      .finally(() => resolve(settledNum));
  }).then(async () => {
    settledNum++;
    if (settledNum < data.length) {
      return __();
    }
  });
};

// 批量上传
const batchUpload = async () => {
  console.log('批量上传开始');
  settledNum = 0;
  successList = [];
  failList = [];
  await __();
  console.log('批量上传结束', successList, failList);
};

// 取消上传
const handleCancel = () => {
  console.log('取消上传');
  if (abort) {
    abort();
  }
  console.log('取消上传结束');
};

使用

batchUpload();
setTimeout(() => handleCancel(), 1000);

控制台输出

批量上传开始
0
1
// ...
29
取消上传
取消上传结束

栗子

文件:App.vue

<UploadLoading
  :data="tableData"
  :confirm-callback="confirmCallback"
  :cancel-callback="cancelCallback"
/>
import { ref } from 'vue';
import UploadLoading from './components/UploadLoading.vue';
import type { ConfirmData, TableData } from './components/UploadLoading.vue';

const num = 200;
const tableData = ref<TableData>(
  new Array(num).fill('').map((_, index) => ({ uid: String(index) }))
);

const confirmCallback = (val: ConfirmData) => {
  console.log('--- confirmCallback ---', val);
};
const cancelCallback = () => {
  console.log('--- cancelCallback ---');
};

组件:UploadLoading.vue

<div>
    <div>
      视频上传中
      <span>{{ settledNum }}</span>
      /
      <span>{{ total }}</span>
    </div>
    <el-progress
      :percentage="percentage"
      text-inside
      :stroke-width="20"
      status="success"
    ></el-progress>
    <div class="tip">
      温馨提示:上传过程中请勿关闭页面,否则未上传的视频将取消上传
    </div>
    <el-button @click="handleCancel">取消上传</el-button>
  </div>
import { computed, onMounted, ref } from 'vue';
import { delay, isArray } from 'lodash-es';
import { ElMessage, ElMessageBox } from 'element-plus';

export type TableData = {
  uid: string;
}[];

export type ConfirmData = { successList: TableData; failList: TableData };

interface PropsType {
  data: TableData;
  confirmCallback: (val: ConfirmData) => void;
  cancelCallback: () => void;
}

const props = withDefaults(defineProps<PropsType>(), {});

const settledNum = ref<number>(0);

const total = computed(() => props.data.length || 0);

const percentage = computed(() => {
  return Math.floor((settledNum.value / total.value) * 100);
});

const singleUpload = (item: TableData[number]) => {
  console.log('--- singleUpload ---', item.uid);
  return new Promise((resolve, reject) => {
    if (settledNum.value == 1) {
      return reject({ reason: '上传失败' });
    }
    delay(() => resolve(''), 50);
  });
};

let successList: TableData = [],
  failList: TableData = [];

const batchUpload = async () => {
  settledNum.value = 0;
  successList = [];
  failList = [];
  await __();
  props.confirmCallback({
    successList,
    failList,
  });
  ElMessage.success('上传成功');
};

let abort: () => void;

const __ = (): Promise<number | undefined> => {
  return new Promise((resolve, reject) => {
    const i = settledNum.value;

    abort = reject; // reject 保存到外部 用于取消批量上传
    singleUpload(props.data[i])
      .then(
        () => {
          successList.push(props.data[i]);
        },
        (err) => {
          failList.push(
            Object.assign({}, props.data[i], { reason: err.reason })
          );
        }
      )
      .finally(() => resolve(settledNum));
  }).then(async () => {
    settledNum.value++;
    if (settledNum.value < props.data.length) {
      return __();
    }
  });
};

const handleCancel = async () => {
  await ElMessageBox.alert('未上传的视频将停止上传,是否取消?', '提示', {
    confirmButtonText: '取消上传',
  });
  if (abort) {
    abort();
  }
  props.cancelCallback();
  ElMessage.info('已取消上传');
};

onMounted(() => {
  if (!(isArray(props.data) && props.data.length)) {
    return props.cancelCallback();
  }
  batchUpload();
});
  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值