|
|
@@ -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";
|