@file-ud.js/core 0.1.0

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/README.md ADDED
@@ -0,0 +1,382 @@
1
+ # @file-ud.js/core
2
+
3
+ 强大的文件传输库,支持分片上传、断点续传、秒传等功能。
4
+
5
+ ## ✨ 核心特性
6
+
7
+ - 🚀 **分片上传**:大文件自动分片,支持并发上传
8
+ - 🔄 **断点续传**:网络中断后可继续上传,无需重新开始
9
+ - ⚡ **秒传功能**:相同文件自动检测,跳过重复上传
10
+ - 📊 **实时进度**:精确的上传进度、速度、剩余时间
11
+ - 🎯 **智能重试**:可配置的重试策略(通过插件)
12
+ - 🔌 **插件系统**:丰富的插件生态,轻松扩展功能
13
+ - 📱 **响应式更新**:基于 Vue 3 响应式系统,UI 自动更新
14
+ - 🛡️ **类型安全**:完整的 TypeScript 类型定义
15
+
16
+ ---
17
+
18
+ ## 🚀 快速开始
19
+
20
+ ### 1. 安装
21
+
22
+ ```bash
23
+ npm install @file-ud.js/core
24
+ ```
25
+
26
+ ### 2. 基本使用
27
+
28
+ ```typescript
29
+ import { FileUD } from '@file-ud.js/core';
30
+
31
+ // 创建上传器
32
+ const uploader = FileUD.createUploader("myUploader", {
33
+ action: '/api/upload',
34
+ multiple: true,
35
+ autoUpload: true
36
+ });
37
+
38
+ // 监听上传成功
39
+ uploader.onSuccess = (response, file) => {
40
+ console.log('上传成功:', response);
41
+ };
42
+
43
+ // 打开文件选择器
44
+ uploader.open();
45
+ ```
46
+
47
+ ### 3. 分片上传
48
+
49
+ ```typescript
50
+ const uploader = FileUD.createUploader("chunkUploader", {
51
+ action: '/api/upload-chunk',
52
+ chunkOptions: {
53
+ chunkSize: 2 * 1024 * 1024, // 2MB 分片
54
+ maxConcurrent: 3, // 最多3个并发
55
+ retries: 3 // 失败重试3次
56
+ }
57
+ });
58
+
59
+ // 初始化分片上传回调
60
+ uploader.onInitChunk = async (uploadFile) => {
61
+ const { data } = await checkFile({
62
+ fileHash: uploadFile.chunkManager?.fileHash
63
+ });
64
+
65
+ return {
66
+ chunks: data.chunks || [],
67
+ fileHash: data.fileHash
68
+ };
69
+ };
70
+
71
+ // 合并分片回调
72
+ uploader.onMergeChunk = async (chunkManager) => {
73
+ const { data } = await mergeChunks({
74
+ fileHash: chunkManager.fileHash,
75
+ fileName: chunkManager.uploadFile.fileName,
76
+ totalChunks: chunkManager.totalChunks
77
+ });
78
+
79
+ return data;
80
+ };
81
+ ```
82
+
83
+ ---
84
+
85
+ ## 📚 详细文档
86
+
87
+ - **[Uploader 上传器文档](./README_UPLOADER.md)** — 完整上传 API、配置、事件、分片上传、插件系统
88
+ - **[Downloader 下载器文档](./README_DOWNLOADER.md)** — 完整下载 API、配置、事件、分片下载、File System Access
89
+ - **[高级指南与排障文档](https://github.com/ChYuanJinlin/file-ud.js/tree/main/packages/docs/advanced)** — setFiles/addFile、分片回显、IndexedDB 缓存、取消与重试等内部流程说明
90
+
91
+ ---
92
+
93
+ ## 📖 API 文档
94
+
95
+ ### 配置选项
96
+
97
+ ```typescript
98
+ interface UploaderConfig {
99
+ /** 是否支持多选 */
100
+ multiple?: boolean;
101
+
102
+ /** 接受的文件类型 */
103
+ accept?: string[];
104
+
105
+ /** 是否自动上传 */
106
+ autoUpload?: boolean;
107
+
108
+ /** 上传地址 */
109
+ action: string | ((formData: FormData, uploadFile: UploadFile) => Promise<any>);
110
+
111
+ /** 文件大小限制(字节) */
112
+ maxSize?: number;
113
+
114
+ /** 文件数量限制 */
115
+ limit?: number;
116
+
117
+ /** 分片上传配置 */
118
+ chunkOptions?: ChunkOptions | null;
119
+ }
120
+ ```
121
+
122
+ ### 回调函数
123
+
124
+ ```typescript
125
+ // 上传成功
126
+ uploader.onSuccess = (response, file) => {
127
+ console.log('URL:', response.url);
128
+ };
129
+
130
+ // 上传进度
131
+ uploader.onUpdate = (files) => {
132
+ files.forEach(file => {
133
+ console.log(`${file.fileName}: ${file.percent}%`);
134
+ });
135
+ };
136
+
137
+ // 错误处理
138
+ uploader.onError = (error) => {
139
+ console.error('上传失败:', error.message);
140
+ };
141
+ ```
142
+
143
+ ### 文件操作
144
+
145
+ ```typescript
146
+ // 暂停上传
147
+ file.pause();
148
+
149
+ // 恢复上传
150
+ file.resume();
151
+
152
+ // 取消上传
153
+ file.cancel();
154
+
155
+ // 重试上传
156
+ file.retry();
157
+
158
+ // 移除文件
159
+ file.remove();
160
+ ```
161
+
162
+ ### 批量操作
163
+
164
+ ```typescript
165
+ // 全部暂停
166
+ uploader.pauseAll();
167
+
168
+ // 全部恢复
169
+ uploader.resumeAll();
170
+
171
+ // 全部取消
172
+ uploader.cancelAll();
173
+
174
+ // 全部重试
175
+ uploader.retryAll();
176
+
177
+ // 清空列表
178
+ uploader.clearFiles();
179
+ ```
180
+
181
+ ---
182
+
183
+ ## 🔌 插件系统
184
+
185
+ file-ud.js 提供强大的插件系统,可以轻松扩展功能:
186
+
187
+ ### 安装插件包
188
+
189
+ ```bash
190
+ npm install @file-ud.js/plugins
191
+ ```
192
+
193
+ ### 使用插件
194
+
195
+ ```typescript
196
+ import {
197
+ FileValidatorPlugin,
198
+ CompressImagePlugin,
199
+ WatermarkPlugin
200
+ } from '@file-ud.js/plugins/uploader';
201
+ import { SmartRetryPlugin } from '@file-ud.js/plugins/retry';
202
+
203
+ // 文件验证
204
+ uploader.use(new FileValidatorPlugin({
205
+ maxSize: 10 * 1024 * 1024, // 10MB
206
+ accept: ['image/*']
207
+ }));
208
+
209
+ // 图片压缩
210
+ uploader.use(new CompressImagePlugin({
211
+ quality: 0.8,
212
+ format: 'webp'
213
+ }));
214
+
215
+ // 添加水印
216
+ uploader.use(new WatermarkPlugin({
217
+ text: '© MyCompany',
218
+ position: 'bottom-right'
219
+ }));
220
+
221
+ // 智能重试
222
+ uploader.use(new SmartRetryPlugin({
223
+ maxRetries: 3,
224
+ strategy: 'exponential'
225
+ }));
226
+ ```
227
+
228
+ 📚 **详细插件文档**:[查看插件文档](../plugins/README.md)
229
+
230
+ ---
231
+
232
+ ## 💡 示例项目
233
+
234
+ 查看完整的示例应用:
235
+
236
+ ```bash
237
+ cd packages/example
238
+ npm run dev
239
+ ```
240
+
241
+ 示例包含:
242
+ - ✅ 基础上传
243
+ - ✅ 分片上传
244
+ - ✅ 断点续传
245
+ - ✅ 秒传功能
246
+ - ✅ 插件使用
247
+ - ✅ 进度展示
248
+ - ✅ 错误处理
249
+
250
+ ---
251
+
252
+ ## 🎯 高级用法
253
+
254
+ ### 自定义上传逻辑
255
+
256
+ ```typescript
257
+ const uploader = FileUD.createUploader("customUploader", {
258
+ // 使用自定义上传函数
259
+ action: async (formData, uploadFile) => {
260
+ const response = await fetch('/api/upload', {
261
+ method: 'POST',
262
+ body: formData,
263
+ headers: {
264
+ 'Authorization': 'Bearer token'
265
+ }
266
+ });
267
+
268
+ return await response.json();
269
+ }
270
+ });
271
+ ```
272
+
273
+ ### 监听事件
274
+
275
+ ```typescript
276
+ // 文件选择
277
+ uploader.on('change', (file) => {
278
+ console.log('文件已选择:', file.fileName);
279
+ });
280
+
281
+ // 上传开始
282
+ uploader.on('files-start', (files) => {
283
+ console.log('开始上传', files.length, '个文件');
284
+ });
285
+
286
+ // 上传完成
287
+ uploader.on('files-complete', (files) => {
288
+ console.log('所有文件传输完成');
289
+ });
290
+
291
+ // 分片上传事件
292
+ uploader.on('chunk-success', (data) => {
293
+ console.log(`分片 ${data.chunkIndex} 上传成功`);
294
+ });
295
+ ```
296
+
297
+ ### 响应式数据
298
+
299
+ ```typescript
300
+ import { ref } from 'vue';
301
+
302
+ const files = ref([]);
303
+
304
+ uploader.onUpdate = (updatedFiles) => {
305
+ files.value = updatedFiles;
306
+ };
307
+ ```
308
+
309
+ 在模板中使用:
310
+
311
+ ```vue
312
+ <template>
313
+ <div v-for="file in files" :key="file.fileId">
314
+ <div>{{ file.fileName }}</div>
315
+ <div>进度: {{ file.percent }}%</div>
316
+ <div>大小: {{ file.formatSize }}</div>
317
+ <div>已上传: {{ file.uploadedSize }}</div>
318
+ <div>速度: {{ file.speed?.currentSpeedFormatted }}</div>
319
+ </div>
320
+ </template>
321
+ ```
322
+
323
+ ---
324
+
325
+ ## 🛠️ 开发指南
326
+
327
+ ### 项目结构
328
+
329
+ ```
330
+ packages/core/
331
+ ├── src/
332
+ │ ├── uploader/ # 上传核心逻辑
333
+ │ │ ├── index.ts # Uploader 类
334
+ │ │ ├── UploadFile.ts # 文件实例类
335
+ │ │ └── uploadChunkManager.ts # 分片管理器
336
+ │ ├── types/ # TypeScript 类型定义
337
+ │ ├── utils/ # 工具函数
338
+ │ └── fileUD/ # FileUD 入口
339
+ └── package.json
340
+ ```
341
+
342
+ ### 本地开发
343
+
344
+ ```bash
345
+ # 安装依赖
346
+ pnpm install
347
+
348
+ # 构建 core 包
349
+ pnpm --filter @file-ud.js/core build
350
+
351
+ # 运行示例
352
+ pnpm --filter example dev
353
+ ```
354
+
355
+ ---
356
+
357
+ ## 📝 更新日志
358
+
359
+ ### v1.0.0 (2024-01-XX)
360
+ - ✨ 首次发布
361
+ - ✅ 分片上传
362
+ - ✅ 断点续传
363
+ - ✅ 秒传功能
364
+ - ✅ 插件系统
365
+ - ✅ 实时进度
366
+ - ✅ TypeScript 支持
367
+
368
+ ---
369
+
370
+ ## 🤝 贡献指南
371
+
372
+ 欢迎提交 Issue 和 Pull Request!
373
+
374
+ **报告 Bug**:[GitHub Issues](https://github.com/ChYuanJinlin/file-ud.js/issues)
375
+
376
+ **提出建议**:[Feature Requests](https://github.com/ChYuanJinlin/file-ud.js/discussions)
377
+
378
+ ---
379
+
380
+ ## 📄 许可证
381
+
382
+ MIT License
@@ -0,0 +1,334 @@
1
+ # Downloader 使用指南
2
+
3
+ ## 简介
4
+
5
+ `Downloader` 是 `file-UD` 库中的文件下载模块,支持普通下载、分片并发下载、断点续传、秒下(instant download)、速率统计、流式写入磁盘等功能。
6
+
7
+ ## 快速开始
8
+
9
+ ### 1. 基础用法
10
+
11
+ ```typescript
12
+ import { FileUD } from "@file-ud.js/core";
13
+
14
+ // 创建下载器实例
15
+ const downloader = FileUD.createDownloader("myDownloader", {
16
+ action: "https://example.com/file.pdf",
17
+ headers: { Authorization: "Bearer token" },
18
+ timeout: 30000,
19
+ });
20
+
21
+ // 设置更新回调(所有文件列表变化时触发)
22
+ downloader.onUpdate = (files) => {
23
+ files.forEach((file) => {
24
+ console.log(`${file.fileName}: ${file.percent}%`);
25
+ });
26
+ };
27
+
28
+ // 设置成功回调
29
+ downloader.onSuccess = (response, file) => {
30
+ console.log(`下载完成: ${file.fileName}`);
31
+ };
32
+
33
+ // 添加下载任务(立即开始下载)
34
+ downloader.downloadFile({
35
+ url: "https://example.com/file.pdf",
36
+ fileName: "document.pdf",
37
+ });
38
+ ```
39
+
40
+ ### 2. 分片下载(断点续传 + 秒下)
41
+
42
+ ```typescript
43
+ const downloader = FileUD.createDownloader("chunkDownloader", {
44
+ action: "https://example.com/file",
45
+ chunkOptions: {
46
+ chunkSize: 2 * 1024 * 1024, // 2MB 分片
47
+ maxConcurrent: 3, // 最多 3 个并发
48
+ retries: 3, // 失败重试 3 次
49
+ timeout: 10000, // 单分片超时
50
+ enableFileCache: true, // 启用 IndexedDB 缓存(支持断点续传)
51
+ },
52
+ });
53
+
54
+ // 分片初始化回调(查询服务端已存在的分片,实现断点续传 / 秒下)
55
+ downloader.onInitChunk = async (downloadFile, totalChunks, fileHash) => {
56
+ const { data } = await checkFile({ fileHash });
57
+ return {
58
+ fileHash: data.fileHash,
59
+ chunks: data.chunks || [], // 已存在的分片索引
60
+ isInstantDownload: data.isInstant, // 秒下标记
61
+ };
62
+ };
63
+
64
+ // 分片合并回调
65
+ downloader.onMergeChunk = async (chunkManager) => {
66
+ // 流式模式自动落盘,内存模式需要手动保存(触发浏览器下载对话框)
67
+ };
68
+
69
+ // 添加分片下载任务
70
+ downloader.downloadFile({
71
+ url: "https://example.com/large-file.zip",
72
+ fileName: "large-file.zip",
73
+ size: 1024 * 1024 * 500, // 500MB,用于端侧校验
74
+ });
75
+ ```
76
+
77
+ ### 3. File System Access API(流式写入磁盘)
78
+
79
+ 分片下载时,浏览器会自动弹出"另存为"对话框,使用 File System Access API 将每个分片直接写入磁盘,**避免内存中累积完整文件**,适合大文件下载。
80
+
81
+ ```typescript
82
+ // 方式 1:自动弹出保存对话框(分片模式下默认行为)
83
+ downloader.downloadFile({
84
+ url: "https://example.com/big-file.zip",
85
+ fileName: "big-file.zip",
86
+ });
87
+
88
+ // 方式 2:预先获取 FileHandle(手动控制保存位置)
89
+ const fileHandle = await Downloader.pickSaveFile("big-file.zip");
90
+ if (fileHandle) {
91
+ downloader.downloadFile(
92
+ { url: "https://example.com/big-file.zip", fileName: "big-file.zip" },
93
+ fileHandle,
94
+ );
95
+ }
96
+ ```
97
+
98
+ ### 4. 手动控制下载
99
+
100
+ ```typescript
101
+ // 文件级别控制
102
+ const file = downloader.downloadFile({ url: "...", fileName: "..." });
103
+
104
+ file.pause(); // 暂停下载(仅分片模式)
105
+ file.resume(); // 恢复下载(仅分片模式)
106
+ file.cancel(); // 取消下载
107
+ file.retry(); // 重试下载
108
+ file.remove(); // 从列表移除
109
+ ```
110
+
111
+ ### 5. 批量操作
112
+
113
+ ```typescript
114
+ downloader.pauseAll(); // 暂停所有
115
+ downloader.resumeAll(); // 恢复所有
116
+ downloader.cancelAll(); // 取消所有
117
+ downloader.retryAll(); // 重试所有失败/取消的任务
118
+ downloader.removeAll(); // 清空所有任务
119
+ downloader.submit(); // 提交所有 pending 任务
120
+ ```
121
+
122
+ ### 6. 全局统计信息
123
+
124
+ ```typescript
125
+ downloader.onUpdate = (files) => {
126
+ // 全局进度
127
+ console.log(`总进度: ${downloader.totalPercent}%`);
128
+ console.log(`已下载: ${downloader.transferredFormatSize}`);
129
+ console.log(`总大小: ${downloader.totalFormatSize}`);
130
+ // 全局速度
131
+ console.log(`瞬时速度: ${downloader.speed.currentSpeedFormatted}`);
132
+ console.log(`平均速度: ${downloader.speed.averageSpeedFormatted}`);
133
+ console.log(`预计剩余: ${downloader.speed.estimatedTimeFormatted}`);
134
+ };
135
+ ```
136
+
137
+ ---
138
+
139
+ ## API 参考
140
+
141
+ ### DownloaderConfig 配置
142
+
143
+ ```typescript
144
+ interface DownloaderConfig {
145
+ /** 下载地址:字符串 URL 或函数 */
146
+ action: string | ((transferFile: DownloadFile) => string | Promise<any>);
147
+ /** 自定义请求头 */
148
+ headers?: Record<string, any>;
149
+ /** 超时时间(毫秒),默认 30000 */
150
+ timeout?: number;
151
+ /** 分片下载配置 */
152
+ chunkOptions?: ChunkOptions | null;
153
+ /** 文件数量限制 */
154
+ limit?: number;
155
+ /** 单文件大小限制(字节) */
156
+ maxSize?: number;
157
+ /** 最大同时传输文件数 */
158
+ maxFileConcurrent?: number;
159
+ /** 自定义 axios 实例 */
160
+ axiosInstance?: AxiosInstance;
161
+ /** axios 请求配置(method、responseType 等) */
162
+ axiosOptions?: AxiosRequestConfig;
163
+ /** 下载最大速率限制(bytes/秒) */
164
+ maxDownloadSpeed?: number;
165
+ }
166
+ ```
167
+
168
+ ### ChunkOptions 分片配置
169
+
170
+ ```typescript
171
+ interface ChunkOptions {
172
+ /** 分片大小(字节),如 2 * 1024 * 1024 */
173
+ chunkSize?: number;
174
+ /** 分片最大并发数 */
175
+ maxConcurrent?: number;
176
+ /** 失败重试次数 */
177
+ retries?: number | null;
178
+ /** 重试延迟(毫秒) */
179
+ retryDelay?: number;
180
+ /** 单分片超时(毫秒) */
181
+ timeout?: number;
182
+ /** 是否启用 IndexedDB 文件缓存(断点续传用) */
183
+ enableFileCache?: boolean;
184
+ /** 缓存保留天数,默认 7 天 */
185
+ cacheRetentionDays?: number;
186
+ }
187
+ ```
188
+
189
+ ### Downloader 方法
190
+
191
+ | 方法 | 说明 | 返回值 |
192
+ |------|------|--------|
193
+ | `downloadFile(file, fileHandle?)` | 添加下载任务并立即开始 | `DownloadFile` |
194
+ | `use(plugin)` | 注册插件 | `this` |
195
+ | `unuse(name)` | 移除插件 | `this` |
196
+ | `getPlugin(name?)` | 获取插件 | `IUDPlugin \| IUDPlugin[]` |
197
+ | `updateConfig(config)` | 动态更新配置 | `void` |
198
+ | `pauseAll()` | 暂停所有进行中的下载 | `void` |
199
+ | `resumeAll()` | 恢复所有暂停的下载 | `Promise<void>` |
200
+ | `cancelAll()` | 取消所有下载 | `void` |
201
+ | `retryAll()` | 重试所有失败/取消的任务 | `Promise<void>` |
202
+ | `removeAll()` | 清空所有任务 | `void` |
203
+ | `submit()` | 提交所有 pending 任务 | `void` |
204
+
205
+ ### Downloader 静态方法
206
+
207
+ | 方法 | 说明 |
208
+ |------|------|
209
+ | `Downloader.setDefaultPlugins(plugins)` | 设置全局默认插件 |
210
+ | `Downloader.pickSaveFile(name?)` | 弹出系统保存对话框,返回 FileHandle |
211
+ | `Downloader.saveBlob(fileName, data)` | 保存 Blob 到本地(触发浏览器下载) |
212
+ | `Downloader.saveFile(fileName, url)` | 通过 URL 下载并保存文件 |
213
+
214
+ ### Downloader 回调设置器
215
+
216
+ | 设置器 | 回调签名 | 说明 |
217
+ |--------|----------|------|
218
+ | `onSuccess = fn` | `(response, file) => void` | 单文件下载成功 |
219
+ | `onUpdate = fn` | `(files: DownloadFile[]) => void` | 文件列表更新(进度/状态变化) |
220
+ | `onInitChunk = fn` | `(file, totalChunks, fileHash) => Promise` | 分片初始化(查已下载分片) |
221
+ | `onMergeChunk = fn` | `(chunkManager) => Promise` | 分片合并 |
222
+ | `onbeforeTransfer = fn` | `(file) => boolean \| Promise` | 下载前拦截 |
223
+
224
+ ### DownloadFile 属性
225
+
226
+ | 属性 | 类型 | 说明 |
227
+ |------|------|------|
228
+ | `fileId` | `string` | 文件唯一标识 |
229
+ | `fileName` | `string` | 文件名 |
230
+ | `url` | `string` | 下载地址 |
231
+ | `size` | `number` | 文件大小(字节) |
232
+ | `percent` | `number` | 下载进度 (0-100) |
233
+ | `status` | `string` | 状态:pending / UDLoading / paused / success / fail / error / cancelled |
234
+ | `speed` | `speedInfo` | 速率信息(瞬时/平均速度、预计剩余时间) |
235
+ | `formatSize` | `string` | 格式化文件大小 |
236
+ | `transferFormatSize` | `string` | 已下载大小格式化字符串 |
237
+ | `fileHandle` | `FileSystemFileHandle \| null` | 流式写入的文件句柄 |
238
+
239
+ ### DownloadFile 方法
240
+
241
+ | 方法 | 说明 |
242
+ |------|------|
243
+ | `start(chunkManager)` | 开始下载 |
244
+ | `pause()` | 暂停下载(仅分片模式) |
245
+ | `resume()` | 恢复下载(仅分片模式) |
246
+ | `cancel()` | 取消下载 |
247
+ | `retry()` | 重试下载 |
248
+ | `remove()` | 从列表移除 |
249
+
250
+ ### 事件
251
+
252
+ 通过 `downloader.on(eventName, callback)` 监听:
253
+
254
+ | 事件名 | 回调参数 | 说明 |
255
+ |--------|----------|------|
256
+ | `progress` | `(percent: number)` | 全局进度 |
257
+ | `change` | `(file: DownloadFile)` | 文件新增 |
258
+ | `pause` | `(file: DownloadFile)` | 文件暂停 |
259
+ | `resume` | `(file: DownloadFile)` | 文件恢复 |
260
+ | `cancel` | `(file: DownloadFile)` | 文件取消 |
261
+ | `retry` | `(file: DownloadFile)` | 文件重试 |
262
+ | `remove` | `(file: DownloadFile)` | 文件移除 |
263
+ | `files-start` | `(files: DownloadFile[])` | 批量开始 |
264
+ | `files-complete` | `(files: DownloadFile[])` | 批量完成 |
265
+ | `chunk-success` | `(data: ChunkSuccessData)` | 分片下载成功 |
266
+ | `chunk-error` | `(data: ChunkErrorData)` | 分片下载失败 |
267
+ | `chunk-download-start` | `(data: ChunkStartData)` | 分片下载开始 |
268
+ | `merging` | `(data)` | 分片合并中 |
269
+ | `merge-success` | `(data)` | 分片合并完成 |
270
+ | `merge-error` | `(data)` | 分片合并失败 |
271
+
272
+ ---
273
+
274
+ ## 插件系统
275
+
276
+ ```typescript
277
+ const myPlugin = {
278
+ name: "my-download-plugin",
279
+ version: "1.0.0",
280
+
281
+ onFileSelect: async (file, context) => {
282
+ console.log(`准备下载: ${file.fileName}`);
283
+ return file; // 返回 false 可拒绝下载
284
+ },
285
+
286
+ beforeTransfer: async (file, context) => {
287
+ return true; // 返回 false 阻止下载
288
+ },
289
+
290
+ onProgress: (percent, file, context) => {
291
+ console.log(`${file.fileName}: ${percent}%`);
292
+ },
293
+
294
+ onSuccess: (response, file, context) => {
295
+ console.log(`✅ ${file.fileName} 下载成功`);
296
+ },
297
+
298
+ onError: (error, file, context) => {
299
+ console.error(`❌ ${file.fileName} 下载失败:`, error);
300
+ },
301
+ };
302
+
303
+ downloader.use(myPlugin);
304
+ ```
305
+
306
+ ---
307
+
308
+ ## 下载流程说明
309
+
310
+ ### 普通下载流程
311
+ ```
312
+ downloadFile() → onFileSelect 钩子 → beforeTransfer 钩子
313
+ → axios GET → 进度回调 → 成功 → saveBlob / 流式写入 → onSuccess
314
+ ```
315
+
316
+ ### 分片下载流程
317
+ ```
318
+ downloadFile()
319
+ → onInitChunk 回调(查服务端已存在分片)
320
+ → IndexedDB 恢复(如启用 enableFileCache)
321
+ → 磁盘断点续传检测(File System Access API)
322
+ → 秒下检查(全部已完成 → 跳过下载)
323
+ → 并发下载缺失分片(Range 请求)
324
+ → 流式写入磁盘 / 内存累积
325
+ → 分片合并
326
+ → onSuccess
327
+ ```
328
+
329
+ ### 文件状态流转
330
+ ```
331
+ pending → UDLoading → success
332
+ → paused → UDLoading(恢复)
333
+ → cancelled / fail / error → retry → UDLoading
334
+ ```