@alibarbar/common 1.0.0 → 1.0.1

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/array.ts"],"names":["shuffled"],"mappings":"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","file":"chunk-LCXGZISK.js","sourcesContent":["/**\n * 数组工具函数\n */\n\n/**\n * 数组去重\n * @param arr - 输入数组\n * @returns 去重后的数组\n */\nexport function unique<T>(arr: T[]): T[] {\n return Array.from(new Set(arr));\n}\n\n/**\n * 数组分组\n * @param arr - 输入数组\n * @param keyFn - 分组键函数或属性名\n * @returns 分组后的对象\n */\nexport function groupBy<T, K extends string | number>(\n arr: T[],\n keyFn: ((item: T) => K) | string\n): Record<K, T[]> {\n const getKey = typeof keyFn === 'string' \n ? (item: T) => (item as Record<string, K>)[keyFn] as K\n : keyFn;\n \n return arr.reduce(\n (acc, item) => {\n const key = getKey(item);\n if (!acc[key]) {\n acc[key] = [];\n }\n acc[key].push(item);\n return acc;\n },\n {} as Record<K, T[]>\n );\n}\n\n/**\n * 数组分块\n * @param arr - 输入数组\n * @param size - 每块大小\n * @returns 分块后的二维数组\n */\nexport function chunk<T>(arr: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size));\n }\n return chunks;\n}\n\n/**\n * 数组扁平化\n * @param arr - 输入数组\n * @param depth - 扁平化深度,默认为 1\n * @returns 扁平化后的数组\n */\nexport function flatten<T>(arr: (T | T[])[], depth = 1): T[] {\n return depth > 0\n ? arr.reduce<T[]>(\n (acc, val) => acc.concat(Array.isArray(val) ? flatten(val, depth - 1) : val),\n []\n )\n : (arr as T[]);\n}\n\n/**\n * 数组随机打乱(Fisher-Yates算法)\n * @param arr - 输入数组\n * @returns 打乱后的新数组\n */\nexport function shuffle<T>(arr: T[]): T[] {\n const result = [...arr];\n for (let i = result.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [result[i], result[j]] = [result[j], result[i]];\n }\n return result;\n}\n\n/**\n * 随机取样\n * @param arr - 输入数组\n * @param count - 取样数量,默认为 1。当 count=1 时返回单个元素,否则返回数组\n * @returns 随机取样的数组或单个元素\n */\nexport function sample<T>(arr: T[]): T;\nexport function sample<T>(arr: T[], count: number): T | T[];\nexport function sample<T>(arr: T[], count = 1): T | T[] {\n if (arr.length === 0) {\n throw new Error('Cannot sample from empty array');\n }\n \n if (count === 1) {\n const shuffled = shuffle(arr);\n return shuffled[0];\n }\n \n if (count >= arr.length) return [...arr];\n const shuffled = shuffle(arr);\n return shuffled.slice(0, count);\n}\n\n/**\n * 数组差集(在arr1中但不在arr2中的元素)\n * @param arr1 - 第一个数组\n * @param arr2 - 第二个数组\n * @returns 差集数组\n */\nexport function difference<T>(arr1: T[], arr2: T[]): T[] {\n const set2 = new Set(arr2);\n return arr1.filter(item => !set2.has(item));\n}\n\n/**\n * 数组交集\n * @param arr1 - 第一个数组\n * @param arr2 - 第二个数组\n * @returns 交集数组\n */\nexport function intersection<T>(arr1: T[], arr2: T[]): T[] {\n const set2 = new Set(arr2);\n return arr1.filter(item => set2.has(item));\n}\n\n/**\n * 数组并集\n * @param arr1 - 第一个数组\n * @param arr2 - 第二个数组\n * @returns 并集数组\n */\nexport function union<T>(arr1: T[], arr2: T[]): T[] {\n return unique([...arr1, ...arr2]);\n}\n\n/**\n * 按属性排序\n * @param arr - 输入数组\n * @param keyFn - 获取排序键的函数或属性名\n * @param order - 排序顺序,'asc' 或 'desc',默认为 'asc'\n * @returns 排序后的新数组\n */\nexport function sortBy<T, K extends string | number>(\n arr: T[],\n keyFn: ((item: T) => K) | string,\n order: 'asc' | 'desc' = 'asc'\n): T[] {\n const getKey = typeof keyFn === 'string'\n ? (item: T) => (item as Record<string, K>)[keyFn] as K\n : keyFn;\n \n const result = [...arr];\n result.sort((a, b) => {\n const keyA = getKey(a);\n const keyB = getKey(b);\n if (keyA < keyB) return order === 'asc' ? -1 : 1;\n if (keyA > keyB) return order === 'asc' ? 1 : -1;\n return 0;\n });\n return result;\n}\n\n/**\n * 按条件查找索引\n * @param arr - 输入数组\n * @param predicate - 条件函数\n * @returns 找到的索引,未找到返回 -1\n */\nexport function findIndexBy<T>(arr: T[], predicate: (item: T) => boolean): number {\n return arr.findIndex(predicate);\n}\n\n/**\n * 数组分割(满足条件/不满足条件)\n * @param arr - 输入数组\n * @param predicate - 条件函数\n * @returns 包含两个数组的元组:[满足条件的数组, 不满足条件的数组]\n */\nexport function partition<T>(arr: T[], predicate: (item: T) => boolean): [T[], T[]] {\n const truthy: T[] = [];\n const falsy: T[] = [];\n arr.forEach(item => {\n if (predicate(item)) {\n truthy.push(item);\n } else {\n falsy.push(item);\n }\n });\n return [truthy, falsy];\n}\n\n/**\n * 数组压缩(将多个数组合并成元组数组)\n * @param arrays - 要压缩的数组\n * @returns 压缩后的元组数组\n */\nexport function zip<T extends readonly unknown[]>(\n ...arrays: T\n): Array<{ [K in keyof T]: T[K] extends readonly (infer U)[] ? U : never }> {\n const maxLength = Math.max(...arrays.map(arr => (arr as unknown[]).length));\n const result: Array<{ [K in keyof T]: T[K] extends readonly (infer U)[] ? U : never }> = [];\n for (let i = 0; i < maxLength; i++) {\n result.push(\n arrays.map(arr => (arr as unknown[])[i]) as {\n [K in keyof T]: T[K] extends readonly (infer U)[] ? U : never;\n }\n );\n }\n return result;\n}\n\n/**\n * 数组解压(将元组数组拆分成多个数组)\n * @param array - 要解压的数组\n * @returns 解压后的数组元组\n */\nexport function unzip<T extends readonly unknown[]>(\n array: Array<{ [K in keyof T]: T[number] extends readonly (infer U)[] ? U : never }>\n): T {\n if (array.length === 0) return [] as unknown as T;\n const length = (array[0] as unknown[]).length;\n const result = Array.from({ length }, () => []) as unknown as unknown[][];\n array.forEach(item => {\n (item as unknown[]).forEach((val, index) => {\n result[index].push(val);\n });\n });\n return result as unknown as T;\n}\n\n/**\n * 移除假值(null, undefined, false, 0, '')\n * @param arr - 输入数组\n * @returns 移除假值后的数组\n */\nexport function compact<T>(arr: (T | null | undefined | false | 0 | '')[]): T[] {\n return arr.filter((item): item is T => Boolean(item));\n}\n\n/**\n * 取前N个元素\n * @param arr - 输入数组\n * @param n - 要取的元素数量\n * @returns 前N个元素的数组\n */\nexport function take<T>(arr: T[], n: number): T[] {\n return arr.slice(0, n);\n}\n\n/**\n * 跳过前N个元素\n * @param arr - 输入数组\n * @param n - 要跳过的元素数量\n * @returns 跳过后的数组\n */\nexport function drop<T>(arr: T[], n: number): T[] {\n return arr.slice(n);\n}\n\n/**\n * 条件取元素(直到条件不满足)\n * @param arr - 输入数组\n * @param predicate - 条件函数\n * @returns 满足条件的连续元素数组\n */\nexport function takeWhile<T>(arr: T[], predicate: (item: T) => boolean): T[] {\n const result: T[] = [];\n for (const item of arr) {\n if (!predicate(item)) break;\n result.push(item);\n }\n return result;\n}\n\n/**\n * 条件跳过元素(直到条件不满足)\n * @param arr - 输入数组\n * @param predicate - 条件函数\n * @returns 跳过后的数组\n */\nexport function dropWhile<T>(arr: T[], predicate: (item: T) => boolean): T[] {\n let index = 0;\n while (index < arr.length && predicate(arr[index])) {\n index++;\n }\n return arr.slice(index);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/format/number.ts"],"names":["dec"],"mappings":"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","file":"chunk-MMR6XQNX.js","sourcesContent":["/**\n * 数字工具函数\n */\n\n/**\n * 数字格式化(千分位)\n * @param num - 数字\n * @param options - 格式化选项\n * @returns 格式化后的字符串\n */\nexport function formatNumber(\n num: number,\n options: {\n decimals?: number;\n separator?: string;\n decimalPoint?: string;\n minimumFractionDigits?: number;\n } = {}\n): string {\n const {\n decimals,\n separator = ',',\n decimalPoint = '.',\n minimumFractionDigits,\n } = options;\n \n // 如果没有指定 decimals,自动检测小数位\n let numStr: string;\n if (decimals !== undefined) {\n numStr = num.toFixed(decimals);\n } else if (minimumFractionDigits !== undefined) {\n numStr = num.toFixed(minimumFractionDigits);\n } else {\n // 自动检测小数位\n const str = num.toString();\n if (str.includes('.')) {\n numStr = str;\n } else {\n numStr = num.toFixed(0);\n }\n }\n \n const parts = numStr.split('.');\n parts[0] = parts[0].replace(/\\B(?=(\\d{3})+(?!\\d))/g, separator);\n return parts.join(decimalPoint);\n}\n\n/**\n * 生成随机数\n * @param min - 最小值\n * @param max - 最大值\n * @param integer - 是否为整数,默认为 false\n * @returns 随机数\n */\nexport function random(min: number, max: number, integer = false): number {\n const value = Math.random() * (max - min) + min;\n return integer ? Math.floor(value) : value;\n}\n\n/**\n * 限制数值范围\n * @param num - 数字\n * @param min - 最小值\n * @param max - 最大值\n * @returns 限制后的数字\n */\nexport function clamp(num: number, min: number, max: number): number {\n return Math.min(Math.max(num, min), max);\n}\n\n/**\n * 增强版四舍五入\n * @param num - 数字\n * @param decimals - 小数位数,默认为 0\n * @returns 四舍五入后的数字\n */\nexport function round(num: number, decimals = 0): number {\n const factor = Math.pow(10, decimals);\n return Math.round(num * factor) / factor;\n}\n\n/**\n * 增强版向下取整\n * @param num - 数字\n * @param decimals - 小数位数,默认为 0\n * @returns 向下取整后的数字\n */\nexport function floor(num: number, decimals = 0): number {\n const factor = Math.pow(10, decimals);\n return Math.floor(num * factor) / factor;\n}\n\n/**\n * 增强版向上取整\n * @param num - 数字\n * @param decimals - 小数位数,默认为 0\n * @returns 向上取整后的数字\n */\nexport function ceil(num: number, decimals = 0): number {\n const factor = Math.pow(10, decimals);\n return Math.ceil(num * factor) / factor;\n}\n\n/**\n * 保留小数位(增强版)\n * @param num - 数字\n * @param decimals - 小数位数\n * @returns 格式化后的字符串\n */\nexport function toFixed(num: number, decimals: number): string {\n return num.toFixed(decimals);\n}\n\n/**\n * 解析数字字符串\n * @param str - 数字字符串\n * @param defaultValue - 默认值,解析失败时返回\n * @returns 解析后的数字\n */\nexport function parseNumber(str: string, defaultValue = 0): number {\n const num = Number(str);\n return isNaN(num) ? defaultValue : num;\n}\n\n/**\n * 判断是否在范围内\n * @param num - 数字\n * @param min - 最小值\n * @param max - 最大值\n * @param inclusive - 是否包含边界,默认为 true\n * @returns 是否在范围内\n */\nexport function isBetween(num: number, min: number, max: number, inclusive = true): boolean {\n if (inclusive) {\n return num >= min && num <= max;\n }\n return num > min && num < max;\n}\n\n/**\n * 百分比计算\n * @param value - 当前值(0-1之间的小数)或当前值(当提供total时)\n * @param decimals - 小数位数,默认为 0(当value是0-1之间的小数时)或总值(当value是实际值时)\n * @returns 百分比数字(当value是0-1之间的小数时)或百分比字符串(当提供total时)\n */\nexport function percent(value: number, decimals?: number): number;\nexport function percent(value: number, total: number, decimals: number): string;\nexport function percent(\n value: number,\n decimalsOrTotal?: number,\n decimals?: number\n): number | string {\n // 如果 value 是 0-1 之间的小数,且只传了一个参数或第二个参数是小数位数\n if (value >= 0 && value <= 1 && (decimalsOrTotal === undefined || decimalsOrTotal < 10)) {\n const dec = decimalsOrTotal ?? 0;\n return Number((value * 100).toFixed(dec));\n }\n \n // 如果提供了 total(第二个参数大于等于10,认为是total)\n if (decimalsOrTotal !== undefined && decimalsOrTotal >= 10) {\n const total = decimalsOrTotal;\n const dec = decimals ?? 2;\n if (total === 0) return '0%';\n return `${((value / total) * 100).toFixed(dec)}%`;\n }\n \n // 默认情况:value 是 0-1 之间的小数\n const dec = decimalsOrTotal ?? 0;\n return Number((value * 100).toFixed(dec));\n}\n\n/**\n * 货币格式化\n * @param num - 数字\n * @param currency - 货币符号,默认为 '¥'\n * @param decimals - 小数位数,默认为 2\n * @returns 格式化后的货币字符串\n */\nexport function formatCurrency(num: number, currency = '¥', decimals = 2): string {\n return `${currency}${formatNumber(num, { decimals, separator: ',' })}`;\n}\n\n/**\n * 字节格式化\n * @param bytes - 字节数\n * @param decimals - 小数位数,默认为 2\n * @returns 格式化后的字节字符串\n */\nexport function formatBytes(bytes: number, decimals = 2): string {\n if (bytes === 0) return '0 Bytes';\n const k = 1024;\n const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/types/upload.ts","../src/browser/upload.ts"],"names":["UploadStatus","result"],"mappings":"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","file":"chunk-QV6MIQ7H.mjs","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\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(简化版,实际应该使用spark-md5等库)\n */\n private async calculateFileMD5(): Promise<string> {\n // 这里使用简化的方法,实际项目中应该使用spark-md5库\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 // 简单拼接,实际应该使用正确的MD5算法\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 // 计算分片MD5\n const chunkMd5 = await calculateBlobMD5(chunkInfo.blob);\n\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 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 const uploadPromises: Promise<void>[] = [];\n let currentIndex = 0;\n\n const uploadNext = async (): Promise<void> => {\n while (currentIndex < chunksToUpload.length && this.status === UploadStatus.UPLOADING) {\n const chunk = chunksToUpload[currentIndex++];\n const promise = this.uploadChunk(chunk).then(() => {\n if (currentIndex < chunksToUpload.length) {\n return uploadNext();\n }\n });\n uploadPromises.push(promise);\n\n if (uploadPromises.length >= this.options.concurrency) {\n await Promise.race(uploadPromises);\n uploadPromises.splice(\n uploadPromises.findIndex(p => p === promise),\n 1\n );\n }\n }\n };\n\n // 启动并发上传\n const concurrencyPromises: Promise<void>[] = [];\n for (let i = 0; i < this.options.concurrency; i++) {\n concurrencyPromises.push(uploadNext());\n }\n\n await Promise.all(concurrencyPromises);\n }\n\n /**\n * 完成上传\n */\n private async completeUpload(): Promise<CompleteUploadResponse> {\n if (!this.taskId) {\n throw new Error('任务ID不存在');\n }\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 if (response.code !== 200) {\n throw new Error(response.message || '完成上传失败');\n }\n\n return response.data;\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 && this.options.onProgress) {\n this.options.onProgress(response.data);\n }\n } catch (error) {\n console.warn('获取上传进度失败:', error);\n }\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 const initResponse = await this.initUpload();\n this.taskId = initResponse.taskId;\n\n // 如果已经完成上传(秒传)\n if (initResponse.instantUpload && initResponse.fileUrl) {\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 // 2. 准备分片\n this.prepareChunks();\n\n // 3. 获取已上传的分片(断点续传)\n const existingChunks = await this.getUploadedChunks();\n existingChunks.forEach(index => this.uploadedChunks.add(index));\n\n // 4. 上传分片\n await this.uploadChunksConcurrently();\n\n // 5. 完成上传\n const result = await this.completeUpload();\n this.status = UploadStatus.COMPLETED;\n this.options.onComplete(result);\n\n return result;\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 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"]}