Răsfoiți Sursa

✨ feat(file): add direct file upload functionality

- 添加saveFile方法,支持直接上传文件内容到MinIO并保存文件记录
- 添加saveFileWithCustomPath方法,支持自定义存储路径的文件上传
- 实现文件元数据记录与MinIO存储的完整流程
- 添加详细的日志记录,便于追踪上传过程和问题排查
- 支持文件MIME类型自动识别与手动指定
yourname 4 luni în urmă
părinte
comite
f44dd71242
1 a modificat fișierele cu 140 adăugiri și 0 ștergeri
  1. 140 0
      src/server/modules/files/file.service.ts

+ 140 - 0
src/server/modules/files/file.service.ts

@@ -216,4 +216,144 @@ export class FileService extends GenericCrudService<File> {
       throw new Error('完成分片上传失败');
     }
   }
+
+  /**
+   * 保存文件记录并将文件内容直接上传到MinIO
+   * @param fileData - 文件基础信息
+   * @param fileContent - 文件内容(Buffer)
+   * @param contentType - 文件MIME类型
+   * @returns 保存的文件记录和文件访问URL
+   */
+  async saveFile(
+    fileData: {
+      name: string;
+      size: number;
+      mimeType: string;
+      uploadUserId: number;
+      [key: string]: any;
+    },
+    fileContent: Buffer,
+    contentType?: string
+  ) {
+    try {
+      logger.db('Starting saveFile process:', {
+        filename: fileData.name,
+        size: fileData.size,
+        mimeType: fileData.mimeType,
+        uploadUserId: fileData.uploadUserId
+      });
+
+      // 生成唯一文件存储路径
+      const fileKey = `${fileData.uploadUserId}/${uuidv4()}-${fileData.name}`;
+
+      // 确保存储桶存在
+      await this.minioService.ensureBucketExists();
+
+      // 直接上传文件内容到MinIO
+      const fileUrl = await this.minioService.createObject(
+        this.minioService.bucketName,
+        fileKey,
+        fileContent,
+        contentType || fileData.mimeType
+      );
+
+      // 准备文件记录数据
+      const completeFileData = {
+        ...fileData,
+        path: fileKey,
+        uploadTime: new Date(),
+      };
+
+      // 保存文件记录到数据库
+      const savedFile = await this.create(completeFileData as any);
+
+      logger.db('File saved successfully:', {
+        fileId: savedFile.id,
+        filename: savedFile.name,
+        size: savedFile.size,
+        url: fileUrl
+      });
+
+      return {
+        file: savedFile,
+        url: fileUrl
+      };
+    } catch (error) {
+      logger.error('Failed to save file:', error);
+      throw new Error(`文件保存失败: ${error instanceof Error ? error.message : '未知错误'}`);
+    }
+  }
+
+  /**
+   * 保存文件记录并将文件内容直接上传到MinIO(支持自定义存储路径)
+   * @param fileData - 文件基础信息
+   * @param fileContent - 文件内容(Buffer)
+   * @param customPath - 自定义存储路径(可选)
+   * @param contentType - 文件MIME类型
+   * @returns 保存的文件记录和文件访问URL
+   */
+  async saveFileWithCustomPath(
+    fileData: {
+      name: string;
+      size: number;
+      mimeType: string;
+      uploadUserId: number;
+      [key: string]: any;
+    },
+    fileContent: Buffer,
+    customPath?: string,
+    contentType?: string
+  ) {
+    try {
+      logger.db('Starting saveFileWithCustomPath process:', {
+        filename: fileData.name,
+        size: fileData.size,
+        mimeType: fileData.mimeType,
+        uploadUserId: fileData.uploadUserId,
+        customPath: customPath || 'auto-generated'
+      });
+
+      // 使用自定义路径或生成唯一文件存储路径
+      const fileKey = customPath || `${fileData.uploadUserId}/${uuidv4()}-${fileData.name}`;
+
+      // 确保存储桶存在
+      await this.minioService.ensureBucketExists();
+
+      // 直接上传文件内容到MinIO
+      const fileUrl = await this.minioService.createObject(
+        this.minioService.bucketName,
+        fileKey,
+        fileContent,
+        contentType || fileData.mimeType
+      );
+
+      // 准备文件记录数据
+      const completeFileData = {
+        ...fileData,
+        path: fileKey,
+        uploadTime: new Date(),
+        // createdAt: new Date(),
+        // updatedAt: new Date()
+      };
+
+      // 保存文件记录到数据库
+      const savedFile = await this.create(completeFileData as any);
+
+      logger.db('File saved with custom path successfully:', {
+        fileId: savedFile.id,
+        filename: savedFile.name,
+        size: savedFile.size,
+        path: fileKey,
+        url: fileUrl
+      });
+
+      return {
+        file: savedFile,
+        url: fileUrl
+      };
+    } catch (error) {
+      logger.error('Failed to save file with custom path:', error);
+      throw new Error(`文件保存失败: ${error instanceof Error ? error.message : '未知错误'}`);
+    }
+  }
 }