createUploader
上传工具工厂,与旧后端上传接口兼容。返回 { uploadImage, uploadVideo, uploadFile, queryVideo } 四个方法,覆盖图片单次上传、视频并发分片 + 转码轮询、普通文件(PDF / 文档 / zip)分片上传三类场景。
📌 业务侧优先用
useUploadercomposable 或SwUploadImage/SwUploadVideo/SwUploadFile组件 —— framework 插件已用createUploader创建好实例并接好 systemInfo / userId。直接调用createUploader主要出现在自定义注入场景(如非标准 store 来源)。
工作原理
- 工厂以 getter 形式注入系统配置与 userId(
getSystemInfo/getUserId),每次调用实时取值,避免 stale closure。 uploadImage:本地先校验字节数(图片按upload_image_max_length,未配置才回退upload_file_max_length);单次 POST,响应的file_info(形如"1280x720")解析为 width / height。uploadVideo:对每个 File 独立实例化分片上传器,并发互不阻塞;默认分片 2MB、单片重试 3 次。uploadFile:与视频共用同一分片端点,但无转码二段(不调queryVideo)—— 分片完成响应即含可访问 URL,以 Promise 返回。queryVideo:每 3 秒轮询转码结果,直到file_m3u8可用或重试耗尽(默认 20 次 ≈ 60 秒)。
接口 URL(upload_image_url 等)来自 systemInfo、已含公共参数;上传超时统一走 swift.config.json request 块的 uploadTimeout(默认 600s)。
API
const uploader = createUploader({
getSystemInfo: () => useSystemStore().info as SystemInfo,
getUserId: () => useUserStore().id,
})
| 方法 | 签名 | 说明 |
|---|---|---|
uploadImage | (file: File, thumbnail: boolean) => Promise<{ id, value, width, height }> | 单次上传图片;thumbnail 是否压缩为缩略图;value 为文件 URL |
uploadVideo | (files: File[], options?) => void | 并发分片上传视频;结果走 onProcess / onSuccess / onError 回调 |
uploadFile | (file: File, options?) => Promise<{ id, value, file_md5 }> | 分片上传普通文件,无转码;value 为文件访问 URL |
queryVideo | (id: string, retries = 20) => Promise<VideoQueryResult> | 轮询转码结果;返回 { id, file_m3u8, file_duration, file_preview_m3u8, file_status, width, height } |
uploadVideo / uploadFile 的 options:chunkSize(默认 2MB)/ retries(默认 3)/ onProcess(进度 { processed_num, chunk_total })/ onBefore;uploadVideo 另有 onSuccess / onError,uploadFile 另有 concurrency(并发分片数,默认 6)。
使用示例
// 上传图片并写入表单
const { id, value, width, height } = await uploader.uploadImage(file, false)
form.cover = { id, url: value, w: width, h: height }
// 分片上传视频 + 进度反馈 + 转码查询
uploader.uploadVideo([videoFile], {
onProcess: ({ processed_num, chunk_total }) => (progress.value = processed_num / chunk_total),
onSuccess: async ({ id }) => {
form.video = await uploader.queryVideo(id)
},
onError: (e) => console.error('upload failed', e),
})
// 普通文件(Promise 风格,无转码二段)
const { value: fileUrl } = await uploader.uploadFile(pdfFile, {
onProcess: ({ processed_num, chunk_total }) => (progress.value = processed_num / chunk_total),
})
注意事项
queryVideo 默认 ~60 秒超时即抛错(UUP-001,warning)
默认轮询 20 次 × 3 秒间隔,耗尽即抛 Error('查询重试次数已用尽')。后端转码慢 / 故障时业务会卡 60 秒后抛错 —— 必须 try/catch + UI 反馈,或按需加大轮次:
onSuccess: async ({ id }) => {
try {
form.video = await uploader.queryVideo(id)
} catch {
useToast().info('视频处理中,请稍后在草稿里查看') // 或 queryVideo(id, 40)
}
}
其他
- 仅浏览器可用(依赖 File / FormData / Blob),SSR 期不要调用。
uploadImage超出图片体积上限时抛Error('文件超出大小')(上限取upload_image_max_length,未配置回退upload_file_max_length);file_info/file_quality尺寸解析失败也会抛明确错误。uploadVideo每次失败静默重试该分片,直到retries耗尽才走onError。