177 lines
5.1 KiB
TypeScript
177 lines
5.1 KiB
TypeScript
import axios from 'axios'
|
||
import { message } from 'ant-design-vue'
|
||
|
||
const API_BASE = (import.meta as any).env?.VITE_API_BASE_URL || '/api'
|
||
|
||
export interface FileUpload {
|
||
id: number
|
||
originalName: string
|
||
storedName: string
|
||
filePath: string
|
||
fileUrl: string
|
||
fileSize: number
|
||
fileType: string
|
||
uploaderId: number
|
||
uploaderName: string
|
||
relatedType?: string
|
||
relatedId?: number
|
||
createTime: string
|
||
}
|
||
|
||
/**
|
||
* 上传文件到S3
|
||
* @param files 文件列表
|
||
* @param relatedType 关联类型(可选,如 'task')
|
||
* @param relatedId 关联ID(可选)
|
||
* @param onProgress 上传进度回调
|
||
*/
|
||
export const uploadFilesToS3 = async (
|
||
files: File[],
|
||
relatedType?: string,
|
||
relatedId?: number,
|
||
onProgress?: (progress: number) => void
|
||
): Promise<string[]> => {
|
||
console.log('[uploadFilesToS3] 开始上传,文件数量:', files.length, 'relatedType:', relatedType, 'relatedId:', relatedId)
|
||
|
||
const formData = new FormData()
|
||
files.forEach((file, index) => {
|
||
console.log(`[uploadFilesToS3] 添加文件 ${index + 1}:`, file.name, file.size, file.type)
|
||
formData.append('files', file)
|
||
})
|
||
if (relatedType) {
|
||
formData.append('relatedType', relatedType)
|
||
}
|
||
if (relatedId) {
|
||
formData.append('relatedId', relatedId.toString())
|
||
}
|
||
|
||
const token = localStorage.getItem('token')
|
||
console.log('[uploadFilesToS3] Token存在:', !!token)
|
||
console.log('[uploadFilesToS3] 请求URL:', `${API_BASE}/file/upload`)
|
||
|
||
return new Promise((resolve, reject) => {
|
||
console.log('[uploadFilesToS3] 发送POST请求到:', `${API_BASE}/file/upload`)
|
||
axios.post<{ code: number; message: string; data: string[] }>(
|
||
`${API_BASE}/file/upload`,
|
||
formData,
|
||
{
|
||
headers: {
|
||
'Content-Type': 'multipart/form-data',
|
||
'Authorization': token ? `Bearer ${token}` : ''
|
||
},
|
||
onUploadProgress: (progressEvent) => {
|
||
if (onProgress && progressEvent.total) {
|
||
const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
|
||
onProgress(percent)
|
||
}
|
||
}
|
||
}
|
||
)
|
||
.then(response => {
|
||
console.log('[uploadFilesToS3] 上传响应:', response.data)
|
||
if (response.data.code === 200 && response.data.data) {
|
||
console.log('[uploadFilesToS3] 上传成功,文件URLs:', response.data.data)
|
||
resolve(response.data.data)
|
||
} else {
|
||
console.error('[uploadFilesToS3] 上传失败,响应:', response.data)
|
||
message.error(response.data.message || '上传失败')
|
||
reject(new Error(response.data.message || '上传失败'))
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('[uploadFilesToS3] 上传异常:', error)
|
||
console.error('[uploadFilesToS3] 错误详情:', {
|
||
message: error.message,
|
||
response: error.response?.data,
|
||
status: error.response?.status
|
||
})
|
||
const errorMsg = error.response?.data?.message || error.message || '上传失败'
|
||
message.error(errorMsg)
|
||
reject(new Error(errorMsg))
|
||
})
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 下载文件(需要登录)
|
||
* @param fileId 文件ID
|
||
*/
|
||
export const downloadFile = (fileId: number) => {
|
||
const token = localStorage.getItem('token')
|
||
const url = `${API_BASE}/file/download/${fileId}`
|
||
|
||
// 创建隐藏的a标签进行下载
|
||
const link = document.createElement('a')
|
||
link.href = url
|
||
link.style.display = 'none'
|
||
|
||
// 添加Authorization header(通过fetch实现)
|
||
fetch(url, {
|
||
headers: {
|
||
'Authorization': token ? `Bearer ${token}` : ''
|
||
}
|
||
})
|
||
.then(response => {
|
||
if (response.ok) {
|
||
return response.blob()
|
||
} else {
|
||
throw new Error('下载失败')
|
||
}
|
||
})
|
||
.then(blob => {
|
||
const downloadUrl = window.URL.createObjectURL(blob)
|
||
link.href = downloadUrl
|
||
link.download = ''
|
||
document.body.appendChild(link)
|
||
link.click()
|
||
document.body.removeChild(link)
|
||
window.URL.revokeObjectURL(downloadUrl)
|
||
})
|
||
.catch(error => {
|
||
message.error('文件下载失败: ' + error.message)
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 获取文件信息
|
||
*/
|
||
export const getFileInfo = (fileId: number): Promise<FileUpload> => {
|
||
return axios.get(`${API_BASE}/file/${fileId}`, {
|
||
headers: {
|
||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||
}
|
||
}).then(response => {
|
||
if (response.data.code === 200) {
|
||
return response.data.data
|
||
} else {
|
||
throw new Error(response.data.message || '获取文件信息失败')
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 根据关联信息获取文件列表
|
||
*/
|
||
export const getFilesByRelated = (relatedType: string, relatedId: number): Promise<FileUpload[]> => {
|
||
return axios.get(`${API_BASE}/file/list`, {
|
||
params: { relatedType, relatedId },
|
||
headers: {
|
||
'Authorization': `Bearer ${localStorage.getItem('token')}`
|
||
}
|
||
}).then(response => {
|
||
if (response.data.code === 200) {
|
||
return response.data.data
|
||
} else {
|
||
throw new Error(response.data.message || '获取文件列表失败')
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 直接打开文件URL(用于S3公开URL)
|
||
* @param fileUrl 文件URL
|
||
*/
|
||
export const openFileUrl = (fileUrl: string) => {
|
||
window.open(fileUrl, '_blank')
|
||
}
|