文件切片上传

14 篇文章 0 订阅
1 篇文章 0 订阅

利用 file.slice() 方法,将文件切片
所有切片上传完成后调用 merge 接口,通知后端文件上传完成

一、组件

<a-upload-dragger
    name="file"
    v-model:fileList="fileList"
    :disabled="uploading"
    :progress="uploadProgress"
    :before-upload="beforeUpload"
    :custom-request="handlePreview"
>
    <p class="ant-upload-drag-icon">
        <inbox-outlined />
    </p>
    <p class="ant-upload-text">
        单击或拖动文件到此区域进行上传
    </p>
</a-upload-dragger>

二、初始值

import { UploadProps } from 'ant-design-vue/lib';
import {
    requestUploadChunk,     // 上传切片接口
    requestMerge,           // 切片上传完成后提交
} from '... 封装好的请求地址 ';

const fileList: any = ref([]);
const uploading = ref<boolean>(false);
const uploadQueue: Ref<Chunk[]> = ref([]);
const concurrentUploads: Ref<number> = ref(0);
const maxConcurrentUploads = 5;
const totalChunks: Ref<number> = ref(0);
const uploadedChunks: Ref<number> = ref(0);

const state = reactive({
    file: {
        status: 'uploading',
        percent: 0,
        name: '',
    },
});

// 组件进度条
const uploadProgress = reactive({
    strokeColor: {
        '0%': '#108ee9',
        '100%': '#87d068',
    },
    strokeWidth: 3,
    format: (percent: number) => {
        if (percent >= 100) {
            for (let i = 0, r = fileList.value.length; i < r; i++) {
                fileList.value[i].status = 'done';
            }
        }
        return `${parseFloat(percent.toFixed(0))}%`;
    },
});

/**
 * 文件上传预处理:规则校验
 * @param file 文件类型
 */
const beforeUpload: UploadProps['beforeUpload'] = (file: any) => {
    
    state.file = file;
    // ... 省略文件校验细节
    return true;
};

三、完整示例

const handlePreview = () => {
    const params = {
        file: state.file,
    };
    createChunkAsync(params);
};

// 文件切片
const createChunkAsync = (params: { file: any }) => {
    const chunkSize: number = 1024 * 1024 * 50; // 每个块50MB
    let cur = 0;
    const file = params.file;
    totalChunks.value = Math.ceil(file.size / chunkSize);
    uploadedChunks.value = 0;
    const key = uuidv4();
    while (cur < file.size) {
        const chunk: Blob = file.slice(cur, cur + chunkSize);
        uploadQueue.value.push({ file: chunk, index: cur / chunkSize, key });
        cur += chunkSize;
    }
    uploadQueueAsync(params);
};

const uploadQueueAsync = (params: any) => {
    let index = 0;
    while (
        concurrentUploads.value < maxConcurrentUploads &&
        uploadQueue.value.length
    ) {
        const chunk: Chunk = uploadQueue.value.shift()!;
        concurrentUploads.value++;
        chunkAsync(chunk, params.file.name, params, index);
        index++;
    }
};

const chunkAsync = async (
    chunk: Chunk,
    filename: string,
    params: any,
    index: number,
) => {

    const result = await(requestUploadChunk({
        bodyParams: {
            ...chunk,
            filename: filename,
            chunkCount: totalChunks.value,
            length: chunk.file.size,
        },
    }));
    if (result.code == 200) {
        concurrentUploads.value--;
        uploadedChunks.value++;
        if (uploadedChunks.value === totalChunks.value) {
            const mergeResult = (await mergeFile(
                params,
            )) as ResultType;
            

            // ...文件上传完成

        } else {
            // 没有上传完成,开启新的上传
            uploadQueueAsync(params);
        }
    }
};

// Merge
const mergeFile = async (params: {
    file: { name: any };
    dataSetLoadDTO: any;
}) => {
    try {
        return requestMerge({
            bodyParams: {
                fileName: params.file.name,
                chunkCount: totalChunks.value,
            },
        });
    } catch (error) {
        console.error('Error merging file', error);
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值