利用 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);
}
};