ossApi.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import { authService } from './authService';
  2. const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
  3. export interface OSSUploadResponse {
  4. url: string;
  5. filename: string;
  6. size: number;
  7. }
  8. export interface ApiResponse<T> {
  9. code: number;
  10. message: string;
  11. data: T;
  12. }
  13. class OSSApiService {
  14. private baseUrl = `${API_BASE_URL}/api/oss`;
  15. async uploadFile(file: File, prefix: string = 'uploads'): Promise<ApiResponse<OSSUploadResponse>> {
  16. const formData = new FormData();
  17. formData.append('file', file);
  18. const authHeader = authService.getAuthHeader();
  19. if (!authHeader) {
  20. throw new Error('未授权:请先登录');
  21. }
  22. const response = await fetch(`${this.baseUrl}/upload?prefix=${encodeURIComponent(prefix)}`, {
  23. method: 'POST',
  24. headers: { 'Authorization': authHeader },
  25. body: formData,
  26. });
  27. if (!response.ok) {
  28. if (response.status === 401) {
  29. authService.logout();
  30. throw new Error('未授权:请先登录');
  31. }
  32. throw new Error(`上传失败: ${response.status}`);
  33. }
  34. return response.json();
  35. }
  36. }
  37. export const ossApi = new OSSApiService();
  38. /**
  39. * 上传文件到 OSS(带进度回调)
  40. * @param file 要上传的文件
  41. * @param prefix OSS 路径前缀
  42. * @param onProgress 进度回调函数 (0-100)
  43. * @returns 文件 URL
  44. */
  45. export async function uploadFile(
  46. file: File,
  47. prefix: string = 'uploads',
  48. onProgress?: (percent: number) => void
  49. ): Promise<string> {
  50. const formData = new FormData();
  51. formData.append('file', file);
  52. const authHeader = authService.getAuthHeader();
  53. if (!authHeader) {
  54. throw new Error('未授权:请先登录');
  55. }
  56. return new Promise((resolve, reject) => {
  57. const xhr = new XMLHttpRequest();
  58. // 监听上传进度
  59. xhr.upload.addEventListener('progress', (e) => {
  60. if (e.lengthComputable && onProgress) {
  61. const percent = Math.round((e.loaded / e.total) * 100);
  62. onProgress(percent);
  63. }
  64. });
  65. // 监听完成
  66. xhr.addEventListener('load', () => {
  67. if (xhr.status === 200) {
  68. try {
  69. const response: ApiResponse<OSSUploadResponse> = JSON.parse(xhr.responseText);
  70. if (response.code === 200 && response.data) {
  71. resolve(response.data.url);
  72. } else {
  73. reject(new Error(response.message || '上传失败'));
  74. }
  75. } catch (error) {
  76. reject(new Error('解析响应失败'));
  77. }
  78. } else if (xhr.status === 401) {
  79. authService.logout();
  80. reject(new Error('未授权:请先登录'));
  81. } else {
  82. reject(new Error(`上传失败: ${xhr.status}`));
  83. }
  84. });
  85. // 监听错误
  86. xhr.addEventListener('error', () => {
  87. reject(new Error('网络错误'));
  88. });
  89. xhr.addEventListener('abort', () => {
  90. reject(new Error('上传已取消'));
  91. });
  92. // 发送请求
  93. xhr.open('POST', `${API_BASE_URL}/api/oss/upload?prefix=${encodeURIComponent(prefix)}`);
  94. xhr.setRequestHeader('Authorization', authHeader);
  95. xhr.send(formData);
  96. });
  97. }