@alibarbar/common 1.0.9 → 1.0.10
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/{chunk-O3O67R4I.js → algorithm.cjs} +0 -2
- package/dist/algorithm.js +130 -44
- package/dist/{chunk-LOAZSPGQ.js → array.cjs} +0 -2
- package/dist/array.js +135 -84
- package/dist/{chunk-Y364QIQH.js → color.cjs} +0 -2
- package/dist/color.js +127 -40
- package/dist/{chunk-DYBSRI7V.js → crypto.cjs} +0 -2
- package/dist/crypto.js +172 -60
- package/dist/{chunk-BHCRFURU.js → data-structure.cjs} +0 -2
- package/dist/data-structure.js +481 -32
- package/dist/{chunk-I3L42475.js → date.cjs} +0 -2
- package/dist/date.js +125 -72
- package/dist/{chunk-JK2SE3I2.js → dom.cjs} +0 -2
- package/dist/dom.js +84 -56
- package/dist/{chunk-7V5UQXIO.js → file.cjs} +0 -2
- package/dist/file.js +79 -32
- package/dist/{chunk-OX5PLOWB.js → i18n.cjs} +0 -2
- package/dist/i18n.js +78 -40
- package/dist/index.cjs +4132 -0
- package/dist/index.d.mts +3 -159
- package/dist/index.d.ts +3 -159
- package/dist/index.js +3364 -17427
- package/dist/{chunk-4RGXV4SJ.js → network.cjs} +0 -2
- package/dist/network.js +97 -28
- package/dist/{chunk-3FRYJPHG.js → number.cjs} +0 -2
- package/dist/number.js +77 -56
- package/dist/{chunk-27UDDVLZ.js → object.cjs} +0 -2
- package/dist/object.js +237 -80
- package/dist/{chunk-JQZBPAPO.js → performance.cjs} +0 -2
- package/dist/performance.js +145 -40
- package/dist/services.cjs +291 -0
- package/dist/services.d.mts +161 -0
- package/dist/services.d.ts +161 -0
- package/dist/services.js +281 -0
- package/dist/{chunk-WZDOPUJW.js → storage.cjs} +216 -17
- package/dist/storage.js +550 -31
- package/dist/{chunk-D7CS5EKF.js → string.cjs} +0 -2
- package/dist/string.js +91 -68
- package/dist/{chunk-56W6YECK.js → tracking.cjs} +0 -2
- package/dist/tracking.js +359 -52
- package/dist/{chunk-ZDMFMUDR.js → transform.cjs} +0 -2
- package/dist/transform.js +299 -32
- package/dist/{chunk-NJARVI6X.mjs → upload.cjs} +41 -14
- package/dist/upload.js +402 -20
- package/dist/{chunk-KGFTD255.js → url.cjs} +0 -2
- package/dist/url.js +91 -44
- package/dist/{chunk-TQN37HIN.js → validation.cjs} +0 -2
- package/dist/validation.js +77 -60
- package/package.json +7 -2
- package/dist/algorithm.js.map +0 -1
- package/dist/algorithm.mjs +0 -4
- package/dist/algorithm.mjs.map +0 -1
- package/dist/array.js.map +0 -1
- package/dist/array.mjs +0 -4
- package/dist/array.mjs.map +0 -1
- package/dist/chunk-27UDDVLZ.js.map +0 -1
- package/dist/chunk-2R2QWFJC.mjs +0 -138
- package/dist/chunk-2R2QWFJC.mjs.map +0 -1
- package/dist/chunk-3FRYJPHG.js.map +0 -1
- package/dist/chunk-4RGXV4SJ.js.map +0 -1
- package/dist/chunk-56W6YECK.js.map +0 -1
- package/dist/chunk-5BGSUGTI.mjs +0 -128
- package/dist/chunk-5BGSUGTI.mjs.map +0 -1
- package/dist/chunk-7E6GELHJ.mjs +0 -302
- package/dist/chunk-7E6GELHJ.mjs.map +0 -1
- package/dist/chunk-7V5UQXIO.js.map +0 -1
- package/dist/chunk-A4SWQXX7.mjs +0 -484
- package/dist/chunk-A4SWQXX7.mjs.map +0 -1
- package/dist/chunk-BHCRFURU.js.map +0 -1
- package/dist/chunk-CDSGEAOK.mjs +0 -80
- package/dist/chunk-CDSGEAOK.mjs.map +0 -1
- package/dist/chunk-D7CS5EKF.js.map +0 -1
- package/dist/chunk-DYBSRI7V.js.map +0 -1
- package/dist/chunk-FEBKPX5A.js +0 -386
- package/dist/chunk-FEBKPX5A.js.map +0 -1
- package/dist/chunk-FJ6ZGZIA.mjs +0 -39
- package/dist/chunk-FJ6ZGZIA.mjs.map +0 -1
- package/dist/chunk-HLDFI7R2.mjs +0 -175
- package/dist/chunk-HLDFI7R2.mjs.map +0 -1
- package/dist/chunk-I3L42475.js.map +0 -1
- package/dist/chunk-JBLX27WD.mjs +0 -240
- package/dist/chunk-JBLX27WD.mjs.map +0 -1
- package/dist/chunk-JHZ7M2MR.mjs +0 -133
- package/dist/chunk-JHZ7M2MR.mjs.map +0 -1
- package/dist/chunk-JK2SE3I2.js.map +0 -1
- package/dist/chunk-JQZBPAPO.js.map +0 -1
- package/dist/chunk-JXYGC2C5.mjs +0 -100
- package/dist/chunk-JXYGC2C5.mjs.map +0 -1
- package/dist/chunk-KGFTD255.js.map +0 -1
- package/dist/chunk-LBHBNPNJ.mjs +0 -148
- package/dist/chunk-LBHBNPNJ.mjs.map +0 -1
- package/dist/chunk-LF4CILQS.mjs +0 -87
- package/dist/chunk-LF4CILQS.mjs.map +0 -1
- package/dist/chunk-LOAZSPGQ.js.map +0 -1
- package/dist/chunk-NJARVI6X.mjs.map +0 -1
- package/dist/chunk-NSSDYX2U.mjs +0 -80
- package/dist/chunk-NSSDYX2U.mjs.map +0 -1
- package/dist/chunk-O3O67R4I.js.map +0 -1
- package/dist/chunk-OIXQ3E6W.mjs +0 -354
- package/dist/chunk-OIXQ3E6W.mjs.map +0 -1
- package/dist/chunk-OX5PLOWB.js.map +0 -1
- package/dist/chunk-PJ7UCTX4.mjs +0 -362
- package/dist/chunk-PJ7UCTX4.mjs.map +0 -1
- package/dist/chunk-PR4QN5HX.js +0 -44
- package/dist/chunk-PR4QN5HX.js.map +0 -1
- package/dist/chunk-QIBE7GVN.mjs +0 -81
- package/dist/chunk-QIBE7GVN.mjs.map +0 -1
- package/dist/chunk-QIOC54LQ.mjs +0 -130
- package/dist/chunk-QIOC54LQ.mjs.map +0 -1
- package/dist/chunk-TQN37HIN.js.map +0 -1
- package/dist/chunk-WZDOPUJW.js.map +0 -1
- package/dist/chunk-XJTZDXSR.mjs +0 -94
- package/dist/chunk-XJTZDXSR.mjs.map +0 -1
- package/dist/chunk-Y364QIQH.js.map +0 -1
- package/dist/chunk-YXM6Q4JS.mjs +0 -94
- package/dist/chunk-YXM6Q4JS.mjs.map +0 -1
- package/dist/chunk-ZDMFMUDR.js.map +0 -1
- package/dist/chunk-ZVJ6NQUM.mjs +0 -82
- package/dist/chunk-ZVJ6NQUM.mjs.map +0 -1
- package/dist/color.js.map +0 -1
- package/dist/color.mjs +0 -4
- package/dist/color.mjs.map +0 -1
- package/dist/crypto.js.map +0 -1
- package/dist/crypto.mjs +0 -4
- package/dist/crypto.mjs.map +0 -1
- package/dist/data-structure.js.map +0 -1
- package/dist/data-structure.mjs +0 -4
- package/dist/data-structure.mjs.map +0 -1
- package/dist/date.js.map +0 -1
- package/dist/date.mjs +0 -4
- package/dist/date.mjs.map +0 -1
- package/dist/dom.js.map +0 -1
- package/dist/dom.mjs +0 -4
- package/dist/dom.mjs.map +0 -1
- package/dist/file.js.map +0 -1
- package/dist/file.mjs +0 -4
- package/dist/file.mjs.map +0 -1
- package/dist/i18n.js.map +0 -1
- package/dist/i18n.mjs +0 -4
- package/dist/i18n.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -17155
- package/dist/index.mjs.map +0 -1
- package/dist/network.js.map +0 -1
- package/dist/network.mjs +0 -4
- package/dist/network.mjs.map +0 -1
- package/dist/number.js.map +0 -1
- package/dist/number.mjs +0 -4
- package/dist/number.mjs.map +0 -1
- package/dist/object.js.map +0 -1
- package/dist/object.mjs +0 -4
- package/dist/object.mjs.map +0 -1
- package/dist/performance.js.map +0 -1
- package/dist/performance.mjs +0 -4
- package/dist/performance.mjs.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/storage.mjs +0 -5
- package/dist/storage.mjs.map +0 -1
- package/dist/string.js.map +0 -1
- package/dist/string.mjs +0 -4
- package/dist/string.mjs.map +0 -1
- package/dist/tracking.js.map +0 -1
- package/dist/tracking.mjs +0 -4
- package/dist/tracking.mjs.map +0 -1
- package/dist/transform.js.map +0 -1
- package/dist/transform.mjs +0 -4
- package/dist/transform.mjs.map +0 -1
- package/dist/upload.js.map +0 -1
- package/dist/upload.mjs +0 -5
- package/dist/upload.mjs.map +0 -1
- package/dist/url.js.map +0 -1
- package/dist/url.mjs +0 -4
- package/dist/url.mjs.map +0 -1
- package/dist/validation.js.map +0 -1
- package/dist/validation.mjs +0 -4
- package/dist/validation.mjs.map +0 -1
package/dist/upload.js
CHANGED
|
@@ -1,22 +1,404 @@
|
|
|
1
|
-
|
|
1
|
+
// src/browser/file.ts
|
|
2
|
+
async function calculateBlobMD5(blob) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
if (typeof FileReader === "undefined") {
|
|
5
|
+
reject(new Error("FileReader is not supported in this environment"));
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const reader = new FileReader();
|
|
9
|
+
reader.onload = async (e) => {
|
|
10
|
+
try {
|
|
11
|
+
const arrayBuffer = e.target?.result;
|
|
12
|
+
if (!arrayBuffer) {
|
|
13
|
+
reject(new Error("Failed to read blob"));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", arrayBuffer);
|
|
17
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
18
|
+
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
19
|
+
resolve(hashHex);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
reject(error);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
reader.onerror = reject;
|
|
25
|
+
reader.readAsArrayBuffer(blob);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function splitFileIntoChunks(file, chunkSize) {
|
|
29
|
+
const chunks = [];
|
|
30
|
+
let start = 0;
|
|
31
|
+
while (start < file.size) {
|
|
32
|
+
const end = Math.min(start + chunkSize, file.size);
|
|
33
|
+
chunks.push(file.slice(start, end));
|
|
34
|
+
start = end;
|
|
35
|
+
}
|
|
36
|
+
return chunks;
|
|
37
|
+
}
|
|
2
38
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
39
|
+
// src/browser/upload.ts
|
|
40
|
+
var ChunkUploader = class {
|
|
41
|
+
constructor(file, options = {}) {
|
|
42
|
+
this.taskId = null;
|
|
43
|
+
this.chunks = [];
|
|
44
|
+
this.uploadedChunks = /* @__PURE__ */ new Set();
|
|
45
|
+
this.status = "pending" /* PENDING */;
|
|
46
|
+
this.abortController = null;
|
|
47
|
+
this.file = file;
|
|
48
|
+
this.options = {
|
|
49
|
+
chunkSize: options.chunkSize || 2 * 1024 * 1024,
|
|
50
|
+
// 默认2MB
|
|
51
|
+
concurrency: options.concurrency || 3,
|
|
52
|
+
retryCount: options.retryCount || 3,
|
|
53
|
+
retryDelay: options.retryDelay || 1e3,
|
|
54
|
+
baseURL: options.baseURL || "",
|
|
55
|
+
headers: options.headers || {},
|
|
56
|
+
onProgress: options.onProgress || (() => {
|
|
57
|
+
}),
|
|
58
|
+
onComplete: options.onComplete || (() => {
|
|
59
|
+
}),
|
|
60
|
+
onError: options.onError || (() => {
|
|
61
|
+
})
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 初始化上传
|
|
66
|
+
*/
|
|
67
|
+
async initUpload() {
|
|
68
|
+
const fileMd5 = await this.calculateFileMD5();
|
|
69
|
+
const request = {
|
|
70
|
+
fileName: this.file.name,
|
|
71
|
+
fileSize: this.file.size,
|
|
72
|
+
fileMd5,
|
|
73
|
+
chunkSize: this.options.chunkSize
|
|
74
|
+
};
|
|
75
|
+
const response = await this.request("/api/files/common/init", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: {
|
|
78
|
+
"Content-Type": "application/json",
|
|
79
|
+
...this.options.headers
|
|
80
|
+
},
|
|
81
|
+
body: JSON.stringify(request)
|
|
82
|
+
});
|
|
83
|
+
if (response.code !== 200) {
|
|
84
|
+
throw new Error(response.message || "\u521D\u59CB\u5316\u4E0A\u4F20\u5931\u8D25");
|
|
85
|
+
}
|
|
86
|
+
return response.data;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 计算文件MD5
|
|
90
|
+
*/
|
|
91
|
+
async calculateFileMD5() {
|
|
92
|
+
const chunks = splitFileIntoChunks(this.file, this.options.chunkSize);
|
|
93
|
+
const md5Promises = chunks.map(
|
|
94
|
+
(chunk, index) => calculateBlobMD5(chunk).then((md5) => ({ index, md5 }))
|
|
95
|
+
);
|
|
96
|
+
const md5Results = await Promise.all(md5Promises);
|
|
97
|
+
return md5Results.map((r) => r.md5).join("");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 准备分片
|
|
101
|
+
*/
|
|
102
|
+
prepareChunks() {
|
|
103
|
+
const blobChunks = splitFileIntoChunks(this.file, this.options.chunkSize);
|
|
104
|
+
this.chunks = blobChunks.map((blob, index) => ({
|
|
105
|
+
index,
|
|
106
|
+
start: index * this.options.chunkSize,
|
|
107
|
+
end: Math.min((index + 1) * this.options.chunkSize, this.file.size),
|
|
108
|
+
blob
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 获取已上传的分片列表(用于断点续传)
|
|
113
|
+
*/
|
|
114
|
+
async getUploadedChunks() {
|
|
115
|
+
if (!this.taskId) return [];
|
|
116
|
+
try {
|
|
117
|
+
const response = await this.request(
|
|
118
|
+
`/api/files/common/chunks/${this.taskId}`,
|
|
119
|
+
{
|
|
120
|
+
method: "GET",
|
|
121
|
+
headers: this.options.headers
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
if (response.code === 200) {
|
|
125
|
+
return response.data || [];
|
|
126
|
+
}
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.warn("\u83B7\u53D6\u5DF2\u4E0A\u4F20\u5206\u7247\u5931\u8D25:", error);
|
|
129
|
+
}
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 上传单个分片
|
|
134
|
+
*/
|
|
135
|
+
async uploadChunk(chunkInfo, retryCount = 0) {
|
|
136
|
+
if (!this.taskId) {
|
|
137
|
+
throw new Error("\u4EFB\u52A1ID\u4E0D\u5B58\u5728");
|
|
138
|
+
}
|
|
139
|
+
if (this.uploadedChunks.has(chunkInfo.index)) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const chunkMd5 = await calculateBlobMD5(chunkInfo.blob);
|
|
144
|
+
const formData = new FormData();
|
|
145
|
+
formData.append("file", chunkInfo.blob, this.file.name);
|
|
146
|
+
const url = `/api/files/common/chunk?taskId=${this.taskId}&chunkIndex=${chunkInfo.index}&chunkMd5=${chunkMd5}`;
|
|
147
|
+
const response = await this.request(url, {
|
|
148
|
+
method: "POST",
|
|
149
|
+
headers: this.options.headers,
|
|
150
|
+
body: formData
|
|
151
|
+
});
|
|
152
|
+
if (response.code === 200 && response.data.success) {
|
|
153
|
+
this.uploadedChunks.add(chunkInfo.index);
|
|
154
|
+
await this.updateProgress();
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error(response.message || "\u5206\u7247\u4E0A\u4F20\u5931\u8D25");
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
if (retryCount < this.options.retryCount) {
|
|
160
|
+
await this.delay(this.options.retryDelay);
|
|
161
|
+
return this.uploadChunk(chunkInfo, retryCount + 1);
|
|
162
|
+
}
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 并发上传分片
|
|
168
|
+
*/
|
|
169
|
+
async uploadChunksConcurrently() {
|
|
170
|
+
const chunksToUpload = this.chunks.filter((chunk) => !this.uploadedChunks.has(chunk.index));
|
|
171
|
+
if (chunksToUpload.length === 0) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
let currentIndex = 0;
|
|
175
|
+
const uploadNext = async () => {
|
|
176
|
+
while (this.status === "uploading" /* UPLOADING */) {
|
|
177
|
+
const chunkIndex = currentIndex++;
|
|
178
|
+
if (chunkIndex >= chunksToUpload.length) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
const chunk = chunksToUpload[chunkIndex];
|
|
182
|
+
await this.uploadChunk(chunk);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const tasks = Array(this.options.concurrency).fill(null).map(() => uploadNext());
|
|
186
|
+
await Promise.all(tasks);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 更新上传进度(仅用于回调前端显示)
|
|
190
|
+
*/
|
|
191
|
+
async updateProgress() {
|
|
192
|
+
if (!this.taskId) return;
|
|
193
|
+
try {
|
|
194
|
+
const response = await this.request(
|
|
195
|
+
`/api/files/common/progress/${this.taskId}`,
|
|
196
|
+
{
|
|
197
|
+
method: "GET",
|
|
198
|
+
headers: this.options.headers
|
|
199
|
+
}
|
|
200
|
+
);
|
|
201
|
+
if (response.code === 200 && response.data) {
|
|
202
|
+
this.options.onProgress(response.data);
|
|
203
|
+
}
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.warn("\u83B7\u53D6\u4E0A\u4F20\u8FDB\u5EA6\u5931\u8D25:", error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* 获取上传进度
|
|
210
|
+
*/
|
|
211
|
+
async getUploadProgress() {
|
|
212
|
+
if (!this.taskId) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const response = await this.request(
|
|
217
|
+
`/api/files/common/progress/${this.taskId}`,
|
|
218
|
+
{
|
|
219
|
+
method: "GET",
|
|
220
|
+
headers: this.options.headers
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
if (response.code === 200 && response.data) {
|
|
224
|
+
console.log("[\u83B7\u53D6\u8FDB\u5EA6]", response.data);
|
|
225
|
+
return response.data;
|
|
226
|
+
}
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.warn("\u83B7\u53D6\u4E0A\u4F20\u8FDB\u5EA6\u5931\u8D25:", error);
|
|
229
|
+
}
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* 完成上传(调用后端合并分片接口)
|
|
234
|
+
*/
|
|
235
|
+
async completeUpload() {
|
|
236
|
+
if (!this.taskId) {
|
|
237
|
+
throw new Error("\u4EFB\u52A1ID\u4E0D\u5B58\u5728");
|
|
238
|
+
}
|
|
239
|
+
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u8C03\u7528\u5B8C\u6210\u63A5\u53E3:", `/api/files/common/complete/${this.taskId}`);
|
|
240
|
+
const response = await this.request(
|
|
241
|
+
`/api/files/common/complete/${this.taskId}`,
|
|
242
|
+
{
|
|
243
|
+
method: "POST",
|
|
244
|
+
headers: this.options.headers
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
console.log("[\u5B8C\u6210\u4E0A\u4F20] \u63A5\u53E3\u54CD\u5E94:", response);
|
|
248
|
+
if (response.code !== 200) {
|
|
249
|
+
throw new Error(response.message || "\u5B8C\u6210\u4E0A\u4F20\u5931\u8D25");
|
|
250
|
+
}
|
|
251
|
+
return response.data;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* 开始上传
|
|
255
|
+
*/
|
|
256
|
+
async upload() {
|
|
257
|
+
try {
|
|
258
|
+
this.status = "uploading" /* UPLOADING */;
|
|
259
|
+
this.abortController = new AbortController();
|
|
260
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 1. \u521D\u59CB\u5316\u4E0A\u4F20");
|
|
261
|
+
const initResponse = await this.initUpload();
|
|
262
|
+
this.taskId = initResponse.taskId;
|
|
263
|
+
if (initResponse.instantUpload && initResponse.fileUrl) {
|
|
264
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] \u79D2\u4F20\u6210\u529F");
|
|
265
|
+
this.status = "completed" /* COMPLETED */;
|
|
266
|
+
const result = {
|
|
267
|
+
taskId: this.taskId,
|
|
268
|
+
fileUrl: initResponse.fileUrl,
|
|
269
|
+
fileName: this.file.name,
|
|
270
|
+
fileSize: this.file.size,
|
|
271
|
+
fileMd5: "",
|
|
272
|
+
success: true,
|
|
273
|
+
message: "\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u79D2\u4F20\u6210\u529F"
|
|
274
|
+
};
|
|
275
|
+
this.options.onComplete(result);
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 2. \u51C6\u5907\u5206\u7247");
|
|
279
|
+
this.prepareChunks();
|
|
280
|
+
const totalChunks = this.chunks.length;
|
|
281
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] \u5171 ${totalChunks} \u4E2A\u5206\u7247`);
|
|
282
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 3. \u68C0\u67E5\u5DF2\u4E0A\u4F20\u5206\u7247");
|
|
283
|
+
const existingChunks = await this.getUploadedChunks();
|
|
284
|
+
existingChunks.forEach((index) => this.uploadedChunks.add(index));
|
|
285
|
+
console.log(
|
|
286
|
+
`[\u4E0A\u4F20\u6D41\u7A0B] \u5DF2\u4E0A\u4F20 ${existingChunks.length} \u4E2A\u5206\u7247\uFF0C\u8FD8\u9700\u4E0A\u4F20 ${totalChunks - existingChunks.length} \u4E2A`
|
|
287
|
+
);
|
|
288
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 4. \u5F00\u59CB\u4E0A\u4F20\u5206\u7247");
|
|
289
|
+
await this.uploadChunksConcurrently();
|
|
290
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 5. \u6240\u6709\u5206\u7247\u4E0A\u4F20\u5B8C\u6210");
|
|
291
|
+
const uploadedCount = this.uploadedChunks.size;
|
|
292
|
+
if (uploadedCount < totalChunks) {
|
|
293
|
+
throw new Error(`\u4E0A\u4F20\u9A8C\u8BC1\u5931\u8D25\uFF1A\u5DF2\u4E0A\u4F20 ${uploadedCount}/${totalChunks} \u4E2A\u5206\u7247`);
|
|
294
|
+
}
|
|
295
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] 6. \u9A8C\u8BC1\u901A\u8FC7\uFF1A${uploadedCount}/${totalChunks} \u4E2A\u5206\u7247\u5DF2\u4E0A\u4F20`);
|
|
296
|
+
const localPercentage = Math.round(uploadedCount / totalChunks * 100);
|
|
297
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] 7. \u672C\u5730\u8FDB\u5EA6\uFF1A${localPercentage}%`);
|
|
298
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 8. \u83B7\u53D6\u670D\u52A1\u7AEF\u8FDB\u5EA6");
|
|
299
|
+
const serverProgress = await this.getUploadProgress();
|
|
300
|
+
const serverPercentage = serverProgress?.percentage ?? 0;
|
|
301
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] \u670D\u52A1\u7AEF\u8FDB\u5EA6\uFF1A${serverPercentage}%`);
|
|
302
|
+
const finalPercentage = serverProgress?.percentage ?? localPercentage;
|
|
303
|
+
console.log(`[\u4E0A\u4F20\u6D41\u7A0B] 9. \u6700\u7EC8\u8FDB\u5EA6\uFF1A${finalPercentage}%`);
|
|
304
|
+
if (finalPercentage >= 100) {
|
|
305
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] 10. \u2705 \u8FDB\u5EA6\u8FBE\u5230100%\uFF0C\u8C03\u7528\u5B8C\u6210\u63A5\u53E3");
|
|
306
|
+
const result = await this.completeUpload();
|
|
307
|
+
this.status = "completed" /* COMPLETED */;
|
|
308
|
+
this.options.onComplete(result);
|
|
309
|
+
console.log("[\u4E0A\u4F20\u6D41\u7A0B] \u2705 \u4E0A\u4F20\u5B8C\u6210");
|
|
310
|
+
return result;
|
|
311
|
+
} else {
|
|
312
|
+
console.error(`[\u4E0A\u4F20\u6D41\u7A0B] \u274C \u8FDB\u5EA6\u4E0D\u8DB3100%\uFF1A${finalPercentage}%`);
|
|
313
|
+
throw new Error(`\u4E0A\u4F20\u672A\u5B8C\u6210\uFF1A\u5F53\u524D\u8FDB\u5EA6 ${finalPercentage.toFixed(2)}%`);
|
|
314
|
+
}
|
|
315
|
+
} catch (error) {
|
|
316
|
+
this.status = "failed" /* FAILED */;
|
|
317
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
318
|
+
this.options.onError(err);
|
|
319
|
+
console.error("[\u4E0A\u4F20\u6D41\u7A0B] \u274C \u4E0A\u4F20\u5931\u8D25:", err);
|
|
320
|
+
throw err;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* 暂停上传
|
|
325
|
+
*/
|
|
326
|
+
pause() {
|
|
327
|
+
if (this.status === "uploading" /* UPLOADING */) {
|
|
328
|
+
this.status = "paused" /* PAUSED */;
|
|
329
|
+
if (this.abortController) {
|
|
330
|
+
this.abortController.abort();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* 恢复上传
|
|
336
|
+
*/
|
|
337
|
+
async resume() {
|
|
338
|
+
if (this.status === "paused" /* PAUSED */) {
|
|
339
|
+
return this.upload();
|
|
340
|
+
}
|
|
341
|
+
throw new Error("\u5F53\u524D\u72B6\u6001\u65E0\u6CD5\u6062\u590D\u4E0A\u4F20");
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* 取消上传
|
|
345
|
+
*/
|
|
346
|
+
async cancel() {
|
|
347
|
+
if (this.taskId && this.status === "uploading" /* UPLOADING */) {
|
|
348
|
+
try {
|
|
349
|
+
await this.request(`/api/files/common/cancel/${this.taskId}`, {
|
|
350
|
+
method: "POST",
|
|
351
|
+
headers: this.options.headers
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
console.warn("\u53D6\u6D88\u4E0A\u4F20\u5931\u8D25:", error);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
this.status = "cancelled" /* CANCELLED */;
|
|
358
|
+
if (this.abortController) {
|
|
359
|
+
this.abortController.abort();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* 获取当前状态
|
|
364
|
+
*/
|
|
365
|
+
getStatus() {
|
|
366
|
+
return this.status;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* 获取任务ID
|
|
370
|
+
*/
|
|
371
|
+
getTaskId() {
|
|
372
|
+
return this.taskId;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* HTTP请求封装
|
|
376
|
+
*/
|
|
377
|
+
async request(url, options = {}) {
|
|
378
|
+
const fullUrl = `${this.options.baseURL}${url}`;
|
|
379
|
+
const signal = this.abortController?.signal;
|
|
380
|
+
const response = await fetch(fullUrl, {
|
|
381
|
+
...options,
|
|
382
|
+
signal
|
|
383
|
+
});
|
|
384
|
+
if (!response.ok) {
|
|
385
|
+
throw new Error(`HTTP\u9519\u8BEF: ${response.status} ${response.statusText}`);
|
|
386
|
+
}
|
|
387
|
+
return response.json();
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* 延迟函数
|
|
391
|
+
*/
|
|
392
|
+
delay(ms) {
|
|
393
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
function createUploader(file, options) {
|
|
397
|
+
return new ChunkUploader(file, options);
|
|
398
|
+
}
|
|
399
|
+
async function uploadFile(file, options) {
|
|
400
|
+
const uploader = createUploader(file, options);
|
|
401
|
+
return uploader.upload();
|
|
402
|
+
}
|
|
6
403
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Object.defineProperty(exports, "ChunkUploader", {
|
|
10
|
-
enumerable: true,
|
|
11
|
-
get: function () { return chunkFEBKPX5A_js.ChunkUploader; }
|
|
12
|
-
});
|
|
13
|
-
Object.defineProperty(exports, "createUploader", {
|
|
14
|
-
enumerable: true,
|
|
15
|
-
get: function () { return chunkFEBKPX5A_js.createUploader; }
|
|
16
|
-
});
|
|
17
|
-
Object.defineProperty(exports, "uploadFile", {
|
|
18
|
-
enumerable: true,
|
|
19
|
-
get: function () { return chunkFEBKPX5A_js.uploadFile; }
|
|
20
|
-
});
|
|
21
|
-
//# sourceMappingURL=upload.js.map
|
|
22
|
-
//# sourceMappingURL=upload.js.map
|
|
404
|
+
export { ChunkUploader, createUploader, uploadFile };
|
|
@@ -100,5 +100,3 @@ exports.parseUrl = parseUrl;
|
|
|
100
100
|
exports.removeQueryParams = removeQueryParams;
|
|
101
101
|
exports.setQueryParams = setQueryParams;
|
|
102
102
|
exports.updateQueryParams = updateQueryParams;
|
|
103
|
-
//# sourceMappingURL=chunk-KGFTD255.js.map
|
|
104
|
-
//# sourceMappingURL=chunk-KGFTD255.js.map
|
package/dist/url.js
CHANGED
|
@@ -1,45 +1,92 @@
|
|
|
1
|
-
|
|
1
|
+
// src/format/url.ts
|
|
2
|
+
function parseUrl(url) {
|
|
3
|
+
try {
|
|
4
|
+
const urlObj = new URL(url);
|
|
5
|
+
return {
|
|
6
|
+
protocol: urlObj.protocol,
|
|
7
|
+
host: urlObj.host,
|
|
8
|
+
hostname: urlObj.hostname,
|
|
9
|
+
port: urlObj.port,
|
|
10
|
+
pathname: urlObj.pathname,
|
|
11
|
+
search: urlObj.search,
|
|
12
|
+
hash: urlObj.hash,
|
|
13
|
+
origin: urlObj.origin
|
|
14
|
+
};
|
|
15
|
+
} catch {
|
|
16
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function buildUrl(parts) {
|
|
20
|
+
const { protocol = "https:", host = "", pathname = "/", search = "", hash = "" } = parts;
|
|
21
|
+
return `${protocol}//${host}${pathname}${search}${hash}`;
|
|
22
|
+
}
|
|
23
|
+
function getQueryParams(url) {
|
|
24
|
+
const searchParams = url ? new URL(url).searchParams : new URLSearchParams(window.location.search);
|
|
25
|
+
const params = {};
|
|
26
|
+
searchParams.forEach((value, key) => {
|
|
27
|
+
params[key] = value;
|
|
28
|
+
});
|
|
29
|
+
return params;
|
|
30
|
+
}
|
|
31
|
+
function setQueryParams(url, params) {
|
|
32
|
+
try {
|
|
33
|
+
const urlObj = new URL(url);
|
|
34
|
+
Object.keys(params).forEach((key) => {
|
|
35
|
+
urlObj.searchParams.set(key, String(params[key]));
|
|
36
|
+
});
|
|
37
|
+
return urlObj.toString();
|
|
38
|
+
} catch {
|
|
39
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function removeQueryParams(url, keys) {
|
|
43
|
+
try {
|
|
44
|
+
const urlObj = new URL(url);
|
|
45
|
+
keys.forEach((key) => {
|
|
46
|
+
urlObj.searchParams.delete(key);
|
|
47
|
+
});
|
|
48
|
+
return urlObj.toString();
|
|
49
|
+
} catch {
|
|
50
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function updateQueryParams(url, params) {
|
|
54
|
+
try {
|
|
55
|
+
const urlObj = new URL(url);
|
|
56
|
+
Object.keys(params).forEach((key) => {
|
|
57
|
+
const value = params[key];
|
|
58
|
+
if (value === null) {
|
|
59
|
+
urlObj.searchParams.delete(key);
|
|
60
|
+
} else {
|
|
61
|
+
urlObj.searchParams.set(key, String(value));
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return urlObj.toString();
|
|
65
|
+
} catch {
|
|
66
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function isAbsoluteUrl(url) {
|
|
70
|
+
try {
|
|
71
|
+
new URL(url);
|
|
72
|
+
return true;
|
|
73
|
+
} catch {
|
|
74
|
+
return /^https?:\/\//i.test(url);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function joinUrl(baseUrl, ...paths) {
|
|
78
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
79
|
+
const joinedPaths = paths.map((path) => path.replace(/^\/+|\/+$/g, "")).filter((path) => path.length > 0).join("/");
|
|
80
|
+
return `${base}/${joinedPaths}`;
|
|
81
|
+
}
|
|
82
|
+
function normalizeUrl(url) {
|
|
83
|
+
try {
|
|
84
|
+
const urlObj = new URL(url);
|
|
85
|
+
urlObj.pathname = urlObj.pathname.replace(/\/+/g, "/");
|
|
86
|
+
return urlObj.toString();
|
|
87
|
+
} catch {
|
|
88
|
+
return url;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
2
91
|
|
|
3
|
-
|
|
4
|
-
require('./chunk-PR4QN5HX.js');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Object.defineProperty(exports, "buildUrl", {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
get: function () { return chunkKGFTD255_js.buildUrl; }
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(exports, "getQueryParams", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () { return chunkKGFTD255_js.getQueryParams; }
|
|
15
|
-
});
|
|
16
|
-
Object.defineProperty(exports, "isAbsoluteUrl", {
|
|
17
|
-
enumerable: true,
|
|
18
|
-
get: function () { return chunkKGFTD255_js.isAbsoluteUrl; }
|
|
19
|
-
});
|
|
20
|
-
Object.defineProperty(exports, "joinUrl", {
|
|
21
|
-
enumerable: true,
|
|
22
|
-
get: function () { return chunkKGFTD255_js.joinUrl; }
|
|
23
|
-
});
|
|
24
|
-
Object.defineProperty(exports, "normalizeUrl", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () { return chunkKGFTD255_js.normalizeUrl; }
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(exports, "parseUrl", {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
get: function () { return chunkKGFTD255_js.parseUrl; }
|
|
31
|
-
});
|
|
32
|
-
Object.defineProperty(exports, "removeQueryParams", {
|
|
33
|
-
enumerable: true,
|
|
34
|
-
get: function () { return chunkKGFTD255_js.removeQueryParams; }
|
|
35
|
-
});
|
|
36
|
-
Object.defineProperty(exports, "setQueryParams", {
|
|
37
|
-
enumerable: true,
|
|
38
|
-
get: function () { return chunkKGFTD255_js.setQueryParams; }
|
|
39
|
-
});
|
|
40
|
-
Object.defineProperty(exports, "updateQueryParams", {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
get: function () { return chunkKGFTD255_js.updateQueryParams; }
|
|
43
|
-
});
|
|
44
|
-
//# sourceMappingURL=url.js.map
|
|
45
|
-
//# sourceMappingURL=url.js.map
|
|
92
|
+
export { buildUrl, getQueryParams, isAbsoluteUrl, joinUrl, normalizeUrl, parseUrl, removeQueryParams, setQueryParams, updateQueryParams };
|