RAGflow/management/web/src/common/apis/files/upload.ts

109 lines
3.0 KiB
TypeScript

import { uploadRequest } from "@/http/upload-axios"
/**
* 文件上传配置接口
*/
interface UploadConfig {
onProgress?: (progress: number) => void
timeout?: number
chunkSize?: number
}
/**
* 优化的文件上传API
* 支持进度回调、自定义超时、错误重试
*/
export function uploadFileApiV2(
formData: FormData,
config: UploadConfig = {}
) {
const { onProgress, timeout = 300000 } = config
return uploadRequest<{
code: number
data: Array<{
name: string
size: number
type: string
status: string
}>
message: string
}>({
url: "/api/v1/files/upload",
method: "post",
data: formData,
timeout,
onUploadProgress: (progressEvent) => {
if (onProgress && progressEvent.total) {
const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
onProgress(progress)
}
}
})
}
/**
* 分块上传大文件
* 将大文件分割成小块进行上传,提高成功率
*/
export async function uploadLargeFile(
file: File,
config: UploadConfig & { parentId?: string } = {}
) {
const { chunkSize = 5 * 1024 * 1024, onProgress, parentId } = config // 默认5MB分块
// 小文件直接上传
if (file.size <= chunkSize) {
const formData = new FormData()
formData.append("file", file)
if (parentId) formData.append("parent_id", parentId)
return uploadFileApiV2(formData, { onProgress })
}
// 大文件分块上传
const totalChunks = Math.ceil(file.size / chunkSize)
const uploadId = `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
const start = chunkIndex * chunkSize
const end = Math.min(start + chunkSize, file.size)
const chunk = file.slice(start, end)
const formData = new FormData()
formData.append("chunk", chunk)
formData.append("chunkIndex", chunkIndex.toString())
formData.append("totalChunks", totalChunks.toString())
formData.append("uploadId", uploadId)
formData.append("fileName", file.name)
if (parentId) formData.append("parent_id", parentId)
try {
await uploadRequest({
url: "/api/v1/files/upload/chunk",
method: "post",
data: formData,
timeout: 60000, // 单个分块1分钟超时
onUploadProgress: (progressEvent) => {
if (onProgress && progressEvent.total) {
const chunkProgress = (progressEvent.loaded / progressEvent.total) * 100
const totalProgress = ((chunkIndex + chunkProgress / 100) / totalChunks) * 100
onProgress(Math.round(totalProgress))
}
}
})
} catch (error) {
// 分块上传失败,尝试重试
console.error(`分块 ${chunkIndex + 1}/${totalChunks} 上传失败:`, error)
throw new Error(`文件上传失败:分块 ${chunkIndex + 1} 上传出错`)
}
}
// 合并分块
return uploadRequest({
url: "/api/v1/files/upload/merge",
method: "post",
data: { uploadId, fileName: file.name, totalChunks, parentId }
})
}