@alibarbar/common 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/algorithm.js +1 -0
- package/dist/algorithm.mjs +1 -0
- package/dist/array.js +1 -0
- package/dist/array.mjs +1 -0
- package/dist/{chunk-R5ZEPV3P.js → chunk-FEBKPX5A.js} +67 -112
- package/dist/chunk-FEBKPX5A.js.map +1 -0
- package/dist/chunk-FJ6ZGZIA.mjs +39 -0
- package/dist/chunk-FJ6ZGZIA.mjs.map +1 -0
- package/dist/{chunk-ICCDFVFG.mjs → chunk-NJARVI6X.mjs} +67 -113
- package/dist/chunk-NJARVI6X.mjs.map +1 -0
- package/dist/{chunk-HME2N3VY.mjs → chunk-OIXQ3E6W.mjs} +2 -2
- package/dist/{chunk-HME2N3VY.mjs.map → chunk-OIXQ3E6W.mjs.map} +1 -1
- package/dist/chunk-PR4QN5HX.js +44 -0
- package/dist/chunk-PR4QN5HX.js.map +1 -0
- package/dist/{chunk-XVUE53T3.js → chunk-WZDOPUJW.js} +2 -2
- package/dist/{chunk-XVUE53T3.js.map → chunk-WZDOPUJW.js.map} +1 -1
- package/dist/color.js +1 -0
- package/dist/color.mjs +1 -0
- package/dist/crypto.js +1 -0
- package/dist/crypto.mjs +1 -0
- package/dist/data-structure.js +1 -0
- package/dist/data-structure.mjs +1 -0
- package/dist/date.js +1 -0
- package/dist/date.mjs +1 -0
- package/dist/dom.js +1 -0
- package/dist/dom.mjs +1 -0
- package/dist/file.js +1 -0
- package/dist/file.mjs +1 -0
- package/dist/i18n.js +1 -0
- package/dist/i18n.mjs +1 -0
- package/dist/index.d.mts +160 -2
- package/dist/index.d.ts +160 -2
- package/dist/index.js +17156 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +17135 -2
- package/dist/index.mjs.map +1 -1
- package/dist/network.js +1 -0
- package/dist/network.mjs +1 -0
- package/dist/number.js +1 -0
- package/dist/number.mjs +1 -0
- package/dist/object.js +1 -0
- package/dist/object.mjs +1 -0
- package/dist/performance.js +1 -0
- package/dist/performance.mjs +1 -0
- package/dist/storage.js +8 -7
- package/dist/storage.mjs +2 -1
- package/dist/string.js +1 -0
- package/dist/string.mjs +1 -0
- package/dist/tracking.js +1 -0
- package/dist/tracking.mjs +1 -0
- package/dist/transform.js +1 -0
- package/dist/transform.mjs +1 -0
- package/dist/{upload-StSeeRRa.d.mts → upload-DchqyDBQ.d.mts} +38 -13
- package/dist/{upload-StSeeRRa.d.ts → upload-DchqyDBQ.d.ts} +38 -13
- package/dist/upload.d.mts +1 -1
- package/dist/upload.d.ts +1 -1
- package/dist/upload.js +8 -3
- package/dist/upload.mjs +2 -1
- package/dist/url.js +1 -0
- package/dist/url.mjs +1 -0
- package/dist/validation.js +1 -0
- package/dist/validation.mjs +1 -0
- package/package.json +4 -1
- package/dist/chunk-ICCDFVFG.mjs.map +0 -1
- package/dist/chunk-R5ZEPV3P.js.map +0 -1
package/dist/algorithm.js
CHANGED
package/dist/algorithm.mjs
CHANGED
package/dist/array.js
CHANGED
package/dist/array.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { chunk, compact, difference, drop, dropWhile, findIndexBy, flatten, groupBy, intersection, partition, sample, shuffle, sortBy, take, takeWhile, union, unique, unzip, zip } from './chunk-2R2QWFJC.mjs';
|
|
2
|
+
import './chunk-FJ6ZGZIA.mjs';
|
|
2
3
|
//# sourceMappingURL=array.mjs.map
|
|
3
4
|
//# sourceMappingURL=array.mjs.map
|
|
@@ -21,7 +21,6 @@ var ChunkUploader = class {
|
|
|
21
21
|
this.uploadedChunks = /* @__PURE__ */ new Set();
|
|
22
22
|
this.status = "pending" /* PENDING */;
|
|
23
23
|
this.abortController = null;
|
|
24
|
-
this.initResponse = null;
|
|
25
24
|
this.file = file;
|
|
26
25
|
this.options = {
|
|
27
26
|
chunkSize: options.chunkSize || 2 * 1024 * 1024,
|
|
@@ -64,7 +63,7 @@ var ChunkUploader = class {
|
|
|
64
63
|
return response.data;
|
|
65
64
|
}
|
|
66
65
|
/**
|
|
67
|
-
* 计算文件MD5
|
|
66
|
+
* 计算文件MD5
|
|
68
67
|
*/
|
|
69
68
|
async calculateFileMD5() {
|
|
70
69
|
const chunks = chunk7V5UQXIO_js.splitFileIntoChunks(this.file, this.options.chunkSize);
|
|
@@ -87,7 +86,7 @@ var ChunkUploader = class {
|
|
|
87
86
|
}));
|
|
88
87
|
}
|
|
89
88
|
/**
|
|
90
|
-
*
|
|
89
|
+
* 获取已上传的分片列表(用于断点续传)
|
|
91
90
|
*/
|
|
92
91
|
async getUploadedChunks() {
|
|
93
92
|
if (!this.taskId) return [];
|
|
@@ -129,7 +128,7 @@ var ChunkUploader = class {
|
|
|
129
128
|
});
|
|
130
129
|
if (response.code === 200 && response.data.success) {
|
|
131
130
|
this.uploadedChunks.add(chunkInfo.index);
|
|
132
|
-
this.updateProgress();
|
|
131
|
+
await this.updateProgress();
|
|
133
132
|
} else {
|
|
134
133
|
throw new Error(response.message || "\u5206\u7247\u4E0A\u4F20\u5931\u8D25");
|
|
135
134
|
}
|
|
@@ -150,8 +149,6 @@ var ChunkUploader = class {
|
|
|
150
149
|
return;
|
|
151
150
|
}
|
|
152
151
|
let currentIndex = 0;
|
|
153
|
-
const semaphore = new Array(this.options.concurrency).fill(null);
|
|
154
|
-
const allUploadPromises = [];
|
|
155
152
|
const uploadNext = async () => {
|
|
156
153
|
while (this.status === "uploading" /* UPLOADING */) {
|
|
157
154
|
const chunkIndex = currentIndex++;
|
|
@@ -159,26 +156,34 @@ var ChunkUploader = class {
|
|
|
159
156
|
break;
|
|
160
157
|
}
|
|
161
158
|
const chunk = chunksToUpload[chunkIndex];
|
|
162
|
-
|
|
163
|
-
allUploadPromises.push(uploadPromise);
|
|
164
|
-
await uploadPromise;
|
|
159
|
+
await this.uploadChunk(chunk);
|
|
165
160
|
}
|
|
166
161
|
};
|
|
167
|
-
const
|
|
168
|
-
await Promise.all(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
162
|
+
const tasks = Array(this.options.concurrency).fill(null).map(() => uploadNext());
|
|
163
|
+
await Promise.all(tasks);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 更新上传进度(仅用于回调前端显示)
|
|
167
|
+
*/
|
|
168
|
+
async updateProgress() {
|
|
169
|
+
if (!this.taskId) return;
|
|
170
|
+
try {
|
|
171
|
+
const response = await this.request(
|
|
172
|
+
`/api/files/common/progress/${this.taskId}`,
|
|
173
|
+
{
|
|
174
|
+
method: "GET",
|
|
175
|
+
headers: this.options.headers
|
|
176
|
+
}
|
|
176
177
|
);
|
|
178
|
+
if (response.code === 200 && response.data) {
|
|
179
|
+
this.options.onProgress(response.data);
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.warn("\u83B7\u53D6\u4E0A\u4F20\u8FDB\u5EA6\u5931\u8D25:", error);
|
|
177
183
|
}
|
|
178
184
|
}
|
|
179
185
|
/**
|
|
180
186
|
* 获取上传进度
|
|
181
|
-
* 当进度达到100%时,会自动调用完成接口
|
|
182
187
|
*/
|
|
183
188
|
async getUploadProgress() {
|
|
184
189
|
if (!this.taskId) {
|
|
@@ -193,23 +198,7 @@ var ChunkUploader = class {
|
|
|
193
198
|
}
|
|
194
199
|
);
|
|
195
200
|
if (response.code === 200 && response.data) {
|
|
196
|
-
console.log("[\
|
|
197
|
-
percentage: response.data.percentage,
|
|
198
|
-
status: response.data.status,
|
|
199
|
-
uploadedChunks: response.data.uploadedChunks,
|
|
200
|
-
totalChunks: response.data.totalChunks,
|
|
201
|
-
currentStatus: this.status
|
|
202
|
-
});
|
|
203
|
-
if (response.data.percentage >= 100) {
|
|
204
|
-
console.log("[\u89E6\u53D1\u5B8C\u6210] \u8FDB\u5EA6\u5DF2\u8FBE\u5230100%\uFF0C\u51C6\u5907\u8C03\u7528\u5B8C\u6210\u63A5\u53E3");
|
|
205
|
-
try {
|
|
206
|
-
await this.completeUpload();
|
|
207
|
-
console.log("[\u5B8C\u6210\u6210\u529F] \u5DF2\u6210\u529F\u8C03\u7528\u5B8C\u6210\u63A5\u53E3");
|
|
208
|
-
} catch (error) {
|
|
209
|
-
console.error("[\u5B8C\u6210\u5931\u8D25] \u8C03\u7528\u5B8C\u6210\u63A5\u53E3\u65F6\u51FA\u9519:", error);
|
|
210
|
-
throw error;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
201
|
+
console.log("[\u83B7\u53D6\u8FDB\u5EA6]", response.data);
|
|
213
202
|
return response.data;
|
|
214
203
|
}
|
|
215
204
|
} catch (error) {
|
|
@@ -219,33 +208,12 @@ var ChunkUploader = class {
|
|
|
219
208
|
}
|
|
220
209
|
/**
|
|
221
210
|
* 完成上传(调用后端合并分片接口)
|
|
222
|
-
*
|
|
223
|
-
* 只有在进度为 100% 时才会被调用
|
|
224
211
|
*/
|
|
225
212
|
async completeUpload() {
|
|
226
|
-
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u5F00\u59CB\u8C03\u7528\u5B8C\u6210\u63A5\u53E3", {
|
|
227
|
-
taskId: this.taskId,
|
|
228
|
-
currentStatus: this.status
|
|
229
|
-
});
|
|
230
213
|
if (!this.taskId) {
|
|
231
214
|
throw new Error("\u4EFB\u52A1ID\u4E0D\u5B58\u5728");
|
|
232
215
|
}
|
|
233
|
-
|
|
234
|
-
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u5DF2\u7ECF\u662F\u5B8C\u6210\u72B6\u6001\uFF0C\u8DF3\u8FC7\u91CD\u590D\u8C03\u7528");
|
|
235
|
-
if (this.initResponse?.fileUrl) {
|
|
236
|
-
return {
|
|
237
|
-
taskId: this.taskId,
|
|
238
|
-
fileUrl: this.initResponse.fileUrl,
|
|
239
|
-
fileName: this.file.name,
|
|
240
|
-
fileSize: this.file.size,
|
|
241
|
-
fileMd5: "",
|
|
242
|
-
success: true,
|
|
243
|
-
message: "\u4E0A\u4F20\u5DF2\u5B8C\u6210"
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
throw new Error("\u4E0A\u4F20\u5DF2\u5B8C\u6210\u4F46\u7F3A\u5C11\u6587\u4EF6\u4FE1\u606F");
|
|
247
|
-
}
|
|
248
|
-
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u6B63\u5728\u8BF7\u6C42\u5B8C\u6210\u63A5\u53E3:", `/api/files/common/complete/${this.taskId}`);
|
|
216
|
+
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u8C03\u7528\u5B8C\u6210\u63A5\u53E3:", `/api/files/common/complete/${this.taskId}`);
|
|
249
217
|
const response = await this.request(
|
|
250
218
|
`/api/files/common/complete/${this.taskId}`,
|
|
251
219
|
{
|
|
@@ -253,39 +221,12 @@ var ChunkUploader = class {
|
|
|
253
221
|
headers: this.options.headers
|
|
254
222
|
}
|
|
255
223
|
);
|
|
256
|
-
console.log("[\u5B8C\u6210\u4E0A\u4F20] \
|
|
224
|
+
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u63A5\u53E3\u54CD\u5E94:", response);
|
|
257
225
|
if (response.code !== 200) {
|
|
258
226
|
throw new Error(response.message || "\u5B8C\u6210\u4E0A\u4F20\u5931\u8D25");
|
|
259
227
|
}
|
|
260
|
-
this.status = "completed" /* COMPLETED */;
|
|
261
|
-
this.options.onComplete(response.data);
|
|
262
|
-
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u4E0A\u4F20\u5B8C\u6210\uFF0C\u72B6\u6001\u5DF2\u66F4\u65B0\u4E3A COMPLETED");
|
|
263
228
|
return response.data;
|
|
264
229
|
}
|
|
265
|
-
/**
|
|
266
|
-
* 更新上传进度(用于回调前端显示)
|
|
267
|
-
* 每次上传完一个分片后调用
|
|
268
|
-
*/
|
|
269
|
-
async updateProgress() {
|
|
270
|
-
if (!this.taskId) return;
|
|
271
|
-
try {
|
|
272
|
-
const response = await this.request(
|
|
273
|
-
`/api/files/common/progress/${this.taskId}`,
|
|
274
|
-
{
|
|
275
|
-
method: "GET",
|
|
276
|
-
headers: this.options.headers
|
|
277
|
-
}
|
|
278
|
-
);
|
|
279
|
-
if (response.code === 200 && response.data) {
|
|
280
|
-
this.options.onProgress(response.data);
|
|
281
|
-
if (response.data.percentage >= 100) {
|
|
282
|
-
await this.completeUpload();
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
} catch (error) {
|
|
286
|
-
console.warn("\u83B7\u53D6\u4E0A\u4F20\u8FDB\u5EA6\u5931\u8D25:", error);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
230
|
/**
|
|
290
231
|
* 开始上传
|
|
291
232
|
*/
|
|
@@ -293,13 +234,15 @@ var ChunkUploader = class {
|
|
|
293
234
|
try {
|
|
294
235
|
this.status = "uploading" /* UPLOADING */;
|
|
295
236
|
this.abortController = new AbortController();
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
237
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 1. \u521D\u59CB\u5316\u4E0A\u4F20");
|
|
238
|
+
const initResponse = await this.initUpload();
|
|
239
|
+
this.taskId = initResponse.taskId;
|
|
240
|
+
if (initResponse.instantUpload && initResponse.fileUrl) {
|
|
241
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] \u79D2\u4F20\u6210\u529F");
|
|
299
242
|
this.status = "completed" /* COMPLETED */;
|
|
300
243
|
const result = {
|
|
301
244
|
taskId: this.taskId,
|
|
302
|
-
fileUrl:
|
|
245
|
+
fileUrl: initResponse.fileUrl,
|
|
303
246
|
fileName: this.file.name,
|
|
304
247
|
fileSize: this.file.size,
|
|
305
248
|
fileMd5: "",
|
|
@@ -309,41 +252,48 @@ var ChunkUploader = class {
|
|
|
309
252
|
this.options.onComplete(result);
|
|
310
253
|
return result;
|
|
311
254
|
}
|
|
255
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 2. \u51C6\u5907\u5206\u7247");
|
|
312
256
|
this.prepareChunks();
|
|
257
|
+
const totalChunks = this.chunks.length;
|
|
258
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] \u5171 ${totalChunks} \u4E2A\u5206\u7247`);
|
|
259
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 3. \u68C0\u67E5\u5DF2\u4E0A\u4F20\u5206\u7247");
|
|
313
260
|
const existingChunks = await this.getUploadedChunks();
|
|
314
261
|
existingChunks.forEach((index) => this.uploadedChunks.add(index));
|
|
262
|
+
console.log(
|
|
263
|
+
`[\u4E0A\u4F20\u6D41\u7A0B] \u5DF2\u4E0A\u4F20 ${existingChunks.length} \u4E2A\u5206\u7247\uFF0C\u8FD8\u9700\u4E0A\u4F20 ${totalChunks - existingChunks.length} \u4E2A`
|
|
264
|
+
);
|
|
265
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 4. \u5F00\u59CB\u4E0A\u4F20\u5206\u7247");
|
|
315
266
|
await this.uploadChunksConcurrently();
|
|
316
|
-
|
|
267
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 5. \u6240\u6709\u5206\u7247\u4E0A\u4F20\u5B8C\u6210");
|
|
317
268
|
const uploadedCount = this.uploadedChunks.size;
|
|
318
269
|
if (uploadedCount < totalChunks) {
|
|
319
|
-
throw new Error(
|
|
320
|
-
`\u4E0A\u4F20\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5DF2\u4E0A\u4F20 ${uploadedCount}/${totalChunks} \u4E2A\u5206\u7247\uFF0C\u65E0\u6CD5\u5B8C\u6210\u4E0A\u4F20`
|
|
321
|
-
);
|
|
270
|
+
throw new Error(`\u4E0A\u4F20\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5DF2\u4E0A\u4F20 ${uploadedCount}/${totalChunks} \u4E2A\u5206\u7247`);
|
|
322
271
|
}
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
fileMd5: "",
|
|
333
|
-
success: true,
|
|
334
|
-
message: "\u4E0A\u4F20\u5B8C\u6210"
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
const finalPercentage = progress?.percentage ?? localPercentage;
|
|
272
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] 6. \u9A8C\u8BC1\u901A\u8FC7\uFF1A${uploadedCount}/${totalChunks} \u4E2A\u5206\u7247\u5DF2\u4E0A\u4F20`);
|
|
273
|
+
const localPercentage = Math.round(uploadedCount / totalChunks * 100);
|
|
274
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] 7. \u672C\u5730\u8FDB\u5EA6\uFF1A${localPercentage}%`);
|
|
275
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 8. \u83B7\u53D6\u670D\u52A1\u7AEF\u8FDB\u5EA6");
|
|
276
|
+
const serverProgress = await this.getUploadProgress();
|
|
277
|
+
const serverPercentage = serverProgress?.percentage ?? 0;
|
|
278
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] \u670D\u52A1\u7AEF\u8FDB\u5EA6\uFF1A${serverPercentage}%`);
|
|
279
|
+
const finalPercentage = serverProgress?.percentage ?? localPercentage;
|
|
280
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] 9. \u6700\u7EC8\u8FDB\u5EA6\uFF1A${finalPercentage}%`);
|
|
338
281
|
if (finalPercentage >= 100) {
|
|
282
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 10. \u2705 \u8FDB\u5EA6\u8FBE\u5230100%\uFF0C\u8C03\u7528\u5B8C\u6210\u63A5\u53E3");
|
|
339
283
|
const result = await this.completeUpload();
|
|
284
|
+
this.status = "completed" /* COMPLETED */;
|
|
285
|
+
this.options.onComplete(result);
|
|
286
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] \u2705 \u4E0A\u4F20\u5B8C\u6210");
|
|
340
287
|
return result;
|
|
288
|
+
} else {
|
|
289
|
+
console.error(`[\u4E0A\u4F20\u6D41\u7A0B] \u274C \u8FDB\u5EA6\u4E0D\u8DB3100%\uFF1A${finalPercentage}%`);
|
|
290
|
+
throw new Error(`\u4E0A\u4F20\u672A\u5B8C\u6210\uFF1A\u5F53\u524D\u8FDB\u5EA6 ${finalPercentage.toFixed(2)}%`);
|
|
341
291
|
}
|
|
342
|
-
throw new Error(`\u4E0A\u4F20\u672A\u5B8C\u6210\uFF1A\u5F53\u524D\u8FDB\u5EA6 ${finalPercentage.toFixed(2)}%`);
|
|
343
292
|
} catch (error) {
|
|
344
293
|
this.status = "failed" /* FAILED */;
|
|
345
294
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
346
295
|
this.options.onError(err);
|
|
296
|
+
console.error("[\u4E0A\u4F20\u6D41\u7A0B] \u274C \u4E0A\u4F20\u5931\u8D25:", err);
|
|
347
297
|
throw err;
|
|
348
298
|
}
|
|
349
299
|
}
|
|
@@ -423,9 +373,14 @@ var ChunkUploader = class {
|
|
|
423
373
|
function createUploader(file, options) {
|
|
424
374
|
return new ChunkUploader(file, options);
|
|
425
375
|
}
|
|
376
|
+
async function uploadFile(file, options) {
|
|
377
|
+
const uploader = createUploader(file, options);
|
|
378
|
+
return uploader.upload();
|
|
379
|
+
}
|
|
426
380
|
|
|
427
381
|
exports.ChunkUploader = ChunkUploader;
|
|
428
382
|
exports.UploadStatus = UploadStatus;
|
|
429
383
|
exports.createUploader = createUploader;
|
|
430
|
-
|
|
431
|
-
//# sourceMappingURL=chunk-
|
|
384
|
+
exports.uploadFile = uploadFile;
|
|
385
|
+
//# sourceMappingURL=chunk-FEBKPX5A.js.map
|
|
386
|
+
//# sourceMappingURL=chunk-FEBKPX5A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/upload.ts","../src/browser/upload.ts"],"names":["UploadStatus","splitFileIntoChunks","calculateBlobMD5"],"mappings":"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","file":"chunk-FEBKPX5A.js","sourcesContent":["/**\n * 文件上传相关类型定义\n */\n\n/**\n * 上传初始化请求参数\n */\nexport interface UploadInitRequest {\n fileName: string;\n fileSize: number;\n fileMd5: string;\n chunkSize?: number;\n}\n\n/**\n * 上传初始化响应\n */\nexport interface UploadInitResponse {\n taskId: string;\n totalChunks: number;\n existingChunks: number[];\n instantUpload: boolean;\n fileUrl?: string;\n chunkSize: number;\n}\n\n/**\n * 分片上传响应\n */\nexport interface ChunkUploadResponse {\n chunkIndex: number;\n success: boolean;\n message: string;\n chunkMd5: string;\n}\n\n/**\n * 完成上传响应\n */\nexport interface CompleteUploadResponse {\n taskId: string;\n fileUrl: string;\n fileName: string;\n fileSize: number;\n fileMd5: string;\n success: boolean;\n message: string;\n}\n\n/**\n * 上传进度信息\n */\nexport interface UploadProgress {\n taskId: string;\n fileName: string;\n fileSize: number;\n totalChunks: number;\n uploadedChunks: number;\n percentage: number;\n status: string;\n uploadedSize: number;\n}\n\n/**\n * API响应包装类型\n */\nexport interface ApiResponse<T> {\n code: number;\n message: string;\n data: T;\n timestamp: number;\n}\n\n/**\n * 上传配置选项\n */\nexport interface UploadOptions {\n /** 分片大小(字节),默认 2MB */\n chunkSize?: number;\n /** 并发上传数量,默认 3 */\n concurrency?: number;\n /** 重试次数,默认 3 */\n retryCount?: number;\n /** 重试延迟(毫秒),默认 1000 */\n retryDelay?: number;\n /** 基础API地址 */\n baseURL?: string;\n /** 请求头 */\n headers?: Record<string, string>;\n /** 上传进度回调 */\n onProgress?: (progress: UploadProgress) => void;\n /** 上传完成回调 */\n onComplete?: (result: CompleteUploadResponse) => void;\n /** 上传错误回调 */\n onError?: (error: Error) => void;\n}\n\n/**\n * 上传状态\n */\nexport enum UploadStatus {\n PENDING = 'pending',\n UPLOADING = 'uploading',\n PAUSED = 'paused',\n COMPLETED = 'completed',\n FAILED = 'failed',\n CANCELLED = 'cancelled',\n}\n\n/**\n * 文件分片信息\n */\nexport interface ChunkInfo {\n index: number;\n start: number;\n end: number;\n blob: Blob;\n md5?: string;\n}\n","/**\n * 文件分片上传工具类\n * 支持分片上传、断点续传、进度追踪、暂停/恢复/取消\n *\n * @example\n * ```typescript\n * import { createUploader } from '@alibarbar/common/upload';\n *\n * const uploader = createUploader(file, {\n * chunkSize: 2 * 1024 * 1024, // 2MB\n * concurrency: 3,\n * baseURL: 'https://api.example.com',\n * onProgress: (progress) => {\n * console.log(`进度:${progress.percentage}%`);\n * },\n * onComplete: (result) => {\n * console.log('上传完成:', result.fileUrl);\n * },\n * onError: (error) => {\n * console.error('上传失败:', error);\n * }\n * });\n *\n * // 开始上传\n * await uploader.upload();\n * ```\n */\n\nimport {\n UploadOptions,\n UploadInitRequest,\n UploadInitResponse,\n ChunkUploadResponse,\n CompleteUploadResponse,\n UploadProgress,\n UploadStatus,\n ChunkInfo,\n ApiResponse,\n} from '../types/upload';\nimport { calculateBlobMD5, splitFileIntoChunks } from './file';\n\n/**\n * 文件上传器类\n */\nexport class ChunkUploader {\n private file: File;\n private options: Required<UploadOptions>;\n private taskId: string | null = null;\n private chunks: ChunkInfo[] = [];\n private uploadedChunks: Set<number> = new Set();\n private status: UploadStatus = UploadStatus.PENDING;\n private abortController: AbortController | null = null;\n\n constructor(file: File, options: UploadOptions = {}) {\n this.file = file;\n this.options = {\n chunkSize: options.chunkSize || 2 * 1024 * 1024, // 默认2MB\n concurrency: options.concurrency || 3,\n retryCount: options.retryCount || 3,\n retryDelay: options.retryDelay || 1000,\n baseURL: options.baseURL || '',\n headers: options.headers || {},\n onProgress: options.onProgress || (() => {}),\n onComplete: options.onComplete || (() => {}),\n onError: options.onError || (() => {}),\n };\n }\n\n /**\n * 初始化上传\n */\n private async initUpload(): Promise<UploadInitResponse> {\n const fileMd5 = await this.calculateFileMD5();\n const request: UploadInitRequest = {\n fileName: this.file.name,\n fileSize: this.file.size,\n fileMd5,\n chunkSize: this.options.chunkSize,\n };\n\n const response = await this.request<ApiResponse<UploadInitResponse>>('/api/files/common/init', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.options.headers,\n },\n body: JSON.stringify(request),\n });\n\n if (response.code !== 200) {\n throw new Error(response.message || '初始化上传失败');\n }\n\n return response.data;\n }\n\n /**\n * 计算文件MD5\n */\n private async calculateFileMD5(): Promise<string> {\n const chunks = splitFileIntoChunks(this.file, this.options.chunkSize);\n const md5Promises = chunks.map((chunk, index) =>\n calculateBlobMD5(chunk).then(md5 => ({ index, md5 }))\n );\n const md5Results = await Promise.all(md5Promises);\n return md5Results.map(r => r.md5).join('');\n }\n\n /**\n * 准备分片\n */\n private prepareChunks(): void {\n const blobChunks = splitFileIntoChunks(this.file, this.options.chunkSize);\n this.chunks = blobChunks.map((blob, index) => ({\n index,\n start: index * this.options.chunkSize,\n end: Math.min((index + 1) * this.options.chunkSize, this.file.size),\n blob,\n }));\n }\n\n /**\n * 获取已上传的分片列表(用于断点续传)\n */\n private async getUploadedChunks(): Promise<number[]> {\n if (!this.taskId) return [];\n\n try {\n const response = await this.request<ApiResponse<number[]>>(\n `/api/files/common/chunks/${this.taskId}`,\n {\n method: 'GET',\n headers: this.options.headers,\n }\n );\n\n if (response.code === 200) {\n return response.data || [];\n }\n } catch (error) {\n console.warn('获取已上传分片失败:', error);\n }\n\n return [];\n }\n\n /**\n * 上传单个分片\n */\n private async uploadChunk(chunkInfo: ChunkInfo, retryCount = 0): Promise<void> {\n if (!this.taskId) {\n throw new Error('任务ID不存在');\n }\n\n if (this.uploadedChunks.has(chunkInfo.index)) {\n return; // 已上传,跳过\n }\n\n try {\n const chunkMd5 = await calculateBlobMD5(chunkInfo.blob);\n const formData = new FormData();\n formData.append('file', chunkInfo.blob, this.file.name);\n\n const url = `/api/files/common/chunk?taskId=${this.taskId}&chunkIndex=${chunkInfo.index}&chunkMd5=${chunkMd5}`;\n\n const response = await this.request<ApiResponse<ChunkUploadResponse>>(url, {\n method: 'POST',\n headers: this.options.headers,\n body: formData,\n });\n\n if (response.code === 200 && response.data.success) {\n this.uploadedChunks.add(chunkInfo.index);\n // 每上传一个分片,更新进度\n await this.updateProgress();\n } else {\n throw new Error(response.message || '分片上传失败');\n }\n } catch (error) {\n if (retryCount < this.options.retryCount) {\n await this.delay(this.options.retryDelay);\n return this.uploadChunk(chunkInfo, retryCount + 1);\n }\n throw error;\n }\n }\n\n /**\n * 并发上传分片\n */\n private async uploadChunksConcurrently(): Promise<void> {\n const chunksToUpload = this.chunks.filter(chunk => !this.uploadedChunks.has(chunk.index));\n\n if (chunksToUpload.length === 0) {\n return; // 所有分片已上传\n }\n\n let currentIndex = 0;\n const uploadNext = async (): Promise<void> => {\n while (this.status === UploadStatus.UPLOADING) {\n const chunkIndex = currentIndex++;\n if (chunkIndex >= chunksToUpload.length) {\n break;\n }\n const chunk = chunksToUpload[chunkIndex];\n await this.uploadChunk(chunk);\n }\n };\n\n // 启动并发任务\n const tasks = Array(this.options.concurrency)\n .fill(null)\n .map(() => uploadNext());\n await Promise.all(tasks);\n }\n\n /**\n * 更新上传进度(仅用于回调前端显示)\n */\n private async updateProgress(): Promise<void> {\n if (!this.taskId) return;\n\n try {\n const response = await this.request<ApiResponse<UploadProgress>>(\n `/api/files/common/progress/${this.taskId}`,\n {\n method: 'GET',\n headers: this.options.headers,\n }\n );\n\n if (response.code === 200 && response.data) {\n this.options.onProgress(response.data);\n }\n } catch (error) {\n console.warn('获取上传进度失败:', error);\n }\n }\n\n /**\n * 获取上传进度\n */\n private async getUploadProgress(): Promise<UploadProgress | null> {\n if (!this.taskId) {\n return null;\n }\n\n try {\n const response = await this.request<ApiResponse<UploadProgress>>(\n `/api/files/common/progress/${this.taskId}`,\n {\n method: 'GET',\n headers: this.options.headers,\n }\n );\n\n if (response.code === 200 && response.data) {\n console.log('[获取进度]', response.data);\n return response.data;\n }\n } catch (error) {\n console.warn('获取上传进度失败:', error);\n }\n\n return null;\n }\n\n /**\n * 完成上传(调用后端合并分片接口)\n */\n private async completeUpload(): Promise<CompleteUploadResponse> {\n if (!this.taskId) {\n throw new Error('任务ID不存在');\n }\n\n console.log('[完成上传] 调用完成接口:', `/api/files/common/complete/${this.taskId}`);\n\n const response = await this.request<ApiResponse<CompleteUploadResponse>>(\n `/api/files/common/complete/${this.taskId}`,\n {\n method: 'POST',\n headers: this.options.headers,\n }\n );\n\n console.log('[完成上传] 接口响应:', response);\n\n if (response.code !== 200) {\n throw new Error(response.message || '完成上传失败');\n }\n\n return response.data;\n }\n\n /**\n * 开始上传\n */\n async upload(): Promise<CompleteUploadResponse> {\n try {\n this.status = UploadStatus.UPLOADING;\n this.abortController = new AbortController();\n\n // 1. 初始化上传\n console.log('[上传流程] 1. 初始化上传');\n const initResponse = await this.initUpload();\n this.taskId = initResponse.taskId;\n\n // 2. 检查是否秒传\n if (initResponse.instantUpload && initResponse.fileUrl) {\n console.log('[上传流程] 秒传成功');\n this.status = UploadStatus.COMPLETED;\n const result: CompleteUploadResponse = {\n taskId: this.taskId,\n fileUrl: initResponse.fileUrl,\n fileName: this.file.name,\n fileSize: this.file.size,\n fileMd5: '',\n success: true,\n message: '文件已存在,秒传成功',\n };\n this.options.onComplete(result);\n return result;\n }\n\n // 3. 准备分片\n console.log('[上传流程] 2. 准备分片');\n this.prepareChunks();\n const totalChunks = this.chunks.length;\n console.log(`[上传流程] 共 ${totalChunks} 个分片`);\n\n // 4. 获取已上传的分片(断点续传)\n console.log('[上传流程] 3. 检查已上传分片');\n const existingChunks = await this.getUploadedChunks();\n existingChunks.forEach(index => this.uploadedChunks.add(index));\n console.log(\n `[上传流程] 已上传 ${existingChunks.length} 个分片,还需上传 ${totalChunks - existingChunks.length} 个`\n );\n\n // 5. 上传分片\n console.log('[上传流程] 4. 开始上传分片');\n await this.uploadChunksConcurrently();\n console.log('[上传流程] 5. 所有分片上传完成');\n\n // 6. 验证所有分片都已上传\n const uploadedCount = this.uploadedChunks.size;\n if (uploadedCount < totalChunks) {\n throw new Error(`上传验证失败:已上传 ${uploadedCount}/${totalChunks} 个分片`);\n }\n console.log(`[上传流程] 6. 验证通过:${uploadedCount}/${totalChunks} 个分片已上传`);\n\n // 7. 计算本地进度\n const localPercentage = Math.round((uploadedCount / totalChunks) * 100);\n console.log(`[上传流程] 7. 本地进度:${localPercentage}%`);\n\n // 8. 获取服务端进度\n console.log('[上传流程] 8. 获取服务端进度');\n const serverProgress = await this.getUploadProgress();\n const serverPercentage = serverProgress?.percentage ?? 0;\n console.log(`[上传流程] 服务端进度:${serverPercentage}%`);\n\n // 9. 计算最终进度(优先使用服务端进度)\n const finalPercentage = serverProgress?.percentage ?? localPercentage;\n console.log(`[上传流程] 9. 最终进度:${finalPercentage}%`);\n\n // 10. 判断是否可以调用完成接口\n if (finalPercentage >= 100) {\n console.log('[上传流程] 10. ✅ 进度达到100%,调用完成接口');\n const result = await this.completeUpload();\n\n this.status = UploadStatus.COMPLETED;\n this.options.onComplete(result);\n\n console.log('[上传流程] ✅ 上传完成');\n return result;\n } else {\n console.error(`[上传流程] ❌ 进度不足100%:${finalPercentage}%`);\n throw new Error(`上传未完成:当前进度 ${finalPercentage.toFixed(2)}%`);\n }\n } catch (error) {\n this.status = UploadStatus.FAILED;\n const err = error instanceof Error ? error : new Error(String(error));\n this.options.onError(err);\n console.error('[上传流程] ❌ 上传失败:', err);\n throw err;\n }\n }\n\n /**\n * 暂停上传\n */\n pause(): void {\n if (this.status === UploadStatus.UPLOADING) {\n this.status = UploadStatus.PAUSED;\n if (this.abortController) {\n this.abortController.abort();\n }\n }\n }\n\n /**\n * 恢复上传\n */\n async resume(): Promise<CompleteUploadResponse> {\n if (this.status === UploadStatus.PAUSED) {\n return this.upload();\n }\n throw new Error('当前状态无法恢复上传');\n }\n\n /**\n * 取消上传\n */\n async cancel(): Promise<void> {\n if (this.taskId && this.status === UploadStatus.UPLOADING) {\n try {\n await this.request<ApiResponse<null>>(`/api/files/common/cancel/${this.taskId}`, {\n method: 'POST',\n headers: this.options.headers,\n });\n } catch (error) {\n console.warn('取消上传失败:', error);\n }\n }\n\n this.status = UploadStatus.CANCELLED;\n if (this.abortController) {\n this.abortController.abort();\n }\n }\n\n /**\n * 获取当前状态\n */\n getStatus(): UploadStatus {\n return this.status;\n }\n\n /**\n * 获取任务ID\n */\n getTaskId(): string | null {\n return this.taskId;\n }\n\n /**\n * HTTP请求封装\n */\n private async request<T>(url: string, options: RequestInit = {}): Promise<T> {\n const fullUrl = `${this.options.baseURL}${url}`;\n const signal = this.abortController?.signal;\n\n const response = await fetch(fullUrl, {\n ...options,\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP错误: ${response.status} ${response.statusText}`);\n }\n\n return response.json();\n }\n\n /**\n * 延迟函数\n */\n private delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n\n/**\n * 创建文件上传器实例\n * @param file - 文件对象\n * @param options - 上传配置选项\n * @returns 上传器实例\n */\nexport function createUploader(file: File, options?: UploadOptions): ChunkUploader {\n return new ChunkUploader(file, options);\n}\n\n/**\n * 简单的文件上传函数(Promise风格)\n * @param file - 文件对象\n * @param options - 上传配置选项\n * @returns Promise<CompleteUploadResponse>\n */\nexport async function uploadFile(\n file: File,\n options?: UploadOptions\n): Promise<CompleteUploadResponse> {\n const uploader = createUploader(file, options);\n return uploader.upload();\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
|
|
37
|
+
export { __commonJS, __export, __require, __toESM };
|
|
38
|
+
//# sourceMappingURL=chunk-FJ6ZGZIA.mjs.map
|
|
39
|
+
//# sourceMappingURL=chunk-FJ6ZGZIA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-FJ6ZGZIA.mjs"}
|