|
|
@@ -0,0 +1,85 @@
|
|
|
+import { chunkUploadApi } from '@/apis/upload';
|
|
|
+import calculateMD5 from './calculateMD5';
|
|
|
+
|
|
|
+interface Chunk {
|
|
|
+ file: Blob;
|
|
|
+ index: number;
|
|
|
+}
|
|
|
+
|
|
|
+interface UploadPartResponse {
|
|
|
+ code?: number;
|
|
|
+ message?: string;
|
|
|
+ data?: any;
|
|
|
+}
|
|
|
+
|
|
|
+const CHUNK_SIZE = 2 * 1024 * 1024; // 2MB per chunk
|
|
|
+
|
|
|
+export const chunkUpload = async (
|
|
|
+ file: File,
|
|
|
+ onProgress?: (progress: number) => void,
|
|
|
+ abortSignal?: AbortSignal
|
|
|
+): Promise<string> => {
|
|
|
+ const chunks: Chunk[] = [];
|
|
|
+ const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
|
|
|
+ const fileKey = await calculateMD5(file);
|
|
|
+
|
|
|
+ // 创建分片
|
|
|
+ for (let i = 0; i < totalChunks; i++) {
|
|
|
+ const start = i * CHUNK_SIZE;
|
|
|
+ const end = Math.min(start + CHUNK_SIZE, file.size);
|
|
|
+ const chunk = file.slice(start, end);
|
|
|
+
|
|
|
+ chunks.push({
|
|
|
+ file: chunk,
|
|
|
+ index: i + 1
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上传进度跟踪
|
|
|
+ let uploadedChunks = 0;
|
|
|
+
|
|
|
+ const uploadPromises = chunks.map(chunk => {
|
|
|
+ return uploadChunk(
|
|
|
+ chunk.file,
|
|
|
+ fileKey,
|
|
|
+ chunk.index,
|
|
|
+ totalChunks,
|
|
|
+ onProgress ? () => {
|
|
|
+ uploadedChunks++;
|
|
|
+ const progress = Math.round((uploadedChunks / totalChunks) * 100);
|
|
|
+ onProgress(progress);
|
|
|
+ } : undefined
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ // 等待所有分片上传完成
|
|
|
+ await Promise.all(uploadPromises);
|
|
|
+
|
|
|
+ return `分片上传完成,文件标识: ${fileKey}`;
|
|
|
+};
|
|
|
+
|
|
|
+const uploadChunk = async (
|
|
|
+ chunk: Blob,
|
|
|
+ fileKey: string,
|
|
|
+ chunkNumber: number,
|
|
|
+ totalChunks: number,
|
|
|
+ onProgress?: () => void
|
|
|
+): Promise<UploadPartResponse> => {
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append('file', chunk);
|
|
|
+ formData.append('fileKey', fileKey);
|
|
|
+ formData.append('chunkNumber', chunkNumber.toString());
|
|
|
+ formData.append('totalChunks', totalChunks.toString());
|
|
|
+
|
|
|
+ try {
|
|
|
+ const response = await chunkUploadApi(formData)
|
|
|
+ if (onProgress) {
|
|
|
+ onProgress();
|
|
|
+ }
|
|
|
+
|
|
|
+ return { message: response.data.message || '上传成功' };
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error(`分片 ${chunkNumber} 上传失败:`, error);
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+}
|