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。