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 => { 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 => { 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 => { 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') }