Ver Fonte

✨perf: Upload last chunk after others for better progress

Shinohara Haruna há 6 meses atrás
pai
commit
0cc8de431f

+ 33 - 17
smsb-plus-ui/src/components/SmsbFileUpload/SmsbFileUploader.vue

@@ -244,7 +244,6 @@ async function uploadFileChunks(file: any) {
   }
   const fileUid = file.uid;
   const totalChunks = Math.ceil(rawFile.size / CHUNK_SIZE);
-  // 使用 ossId 作为 uploadId
   const uploadId = ossId.value || fileUid;
   uploadStates[fileUid] = {
     ...uploadStates[fileUid],
@@ -256,8 +255,9 @@ async function uploadFileChunks(file: any) {
     uploadedChunks: new Set(),
     finalUrl: null,
   };
+  // 先上传前 N-1 个分片
   const chunkPromises: Promise<void>[] = [];
-  for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
+  for (let chunkIndex = 0; chunkIndex < totalChunks - 1; chunkIndex++) {
     const start = chunkIndex * CHUNK_SIZE;
     const end = Math.min(start + CHUNK_SIZE, rawFile.size);
     const chunk = rawFile.slice(start, end);
@@ -281,30 +281,46 @@ async function uploadFileChunks(file: any) {
     chunkPromises.push(sendChunkRequest(formData, fileUid, chunkIndex, file));
   }
   try {
+    // 等待前 N-1 个分片全部上传
     const results = await Promise.allSettled(chunkPromises);
     const failedChunk = results.find((result) => result.status === "rejected");
     if (failedChunk) {
       uploadStates[fileUid].status = "error";
       uploadStates[fileUid].errorMessage = uploadStates[fileUid].errorMessage || "一个或多个分片上传失败";
       ElMessage.error(`${file.name} 上传失败: ${uploadStates[fileUid]?.errorMessage}`);
-    } else {
-      const finalState = uploadStates[fileUid];
-      if (finalState && finalState.status === "uploading") {
-        if (finalState.uploadedChunks!.size === totalChunks) {
-          finalState.status = "success";
-          finalState.progress = 100;
-          // 上传成功后移除 fileList 中的该文件,防止再次被上传
-          const fileIndex = fileList.value.findIndex(f => f.uid === fileUid);
-          if (fileIndex !== -1) fileList.value.splice(fileIndex, 1);
-        } else {
-          finalState.status = "error";
-          finalState.errorMessage = "内部状态不一致";
-        }
-      } else if (finalState && (finalState.status === "success" || finalState.status === "merging")) {
-        // 已完成,但确保移除 fileList 中的该文件
+      return;
+    }
+    // 前 N-1 个分片全部成功后,上传最后一个分片
+    const lastChunkIndex = totalChunks - 1;
+    const start = lastChunkIndex * CHUNK_SIZE;
+    const end = Math.min(start + CHUNK_SIZE, rawFile.size);
+    const lastChunk = rawFile.slice(start, end);
+    const lastFormData = new FormData();
+    lastFormData.append("file", lastChunk, `${file.name}.chunk${lastChunkIndex}`);
+    lastFormData.append("filename", file.name);
+    lastFormData.append("chunkIndex", String(lastChunkIndex));
+    lastFormData.append("totalChunks", String(totalChunks));
+    lastFormData.append("fileSize", String(rawFile.size));
+    lastFormData.append("fileType", rawFile.type || "application/octet-stream");
+    lastFormData.append("uploadId", uploadId);
+    await sendChunkRequest(lastFormData, fileUid, lastChunkIndex, file);
+    // 判断所有分片是否都上传成功
+    const finalState = uploadStates[fileUid];
+    if (finalState && finalState.status === "uploading") {
+      if (finalState.uploadedChunks!.size === totalChunks) {
+        finalState.status = "success";
+        finalState.progress = 100;
+        // 上传成功后移除 fileList 中的该文件,防止再次被上传
         const fileIndex = fileList.value.findIndex(f => f.uid === fileUid);
         if (fileIndex !== -1) fileList.value.splice(fileIndex, 1);
+      } else {
+        finalState.status = "error";
+        finalState.errorMessage = "内部状态不一致";
       }
+    } else if (finalState && (finalState.status === "success" || finalState.status === "merging")) {
+      // 已完成,但确保移除 fileList 中的该文件
+      const fileIndex = fileList.value.findIndex(f => f.uid === fileUid);
+      if (fileIndex !== -1) fileList.value.splice(fileIndex, 1);
     }
   } catch (error) {
     uploadStates[fileUid].status = "error";