library-picturebook-activity/backend/src/upload/upload.service.ts

76 lines
2.0 KiB
TypeScript
Raw Normal View History

2026-01-09 18:14:35 +08:00
import { Injectable, BadRequestException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as fs from 'fs';
import * as path from 'path';
import { randomBytes } from 'crypto';
@Injectable()
export class UploadService {
private readonly uploadDir: string;
constructor(private configService: ConfigService) {
// 上传文件存储目录
this.uploadDir = path.join(process.cwd(), 'uploads');
// 确保上传目录存在
if (!fs.existsSync(this.uploadDir)) {
fs.mkdirSync(this.uploadDir, { recursive: true });
}
}
async uploadFile(
file: Express.Multer.File,
tenantId?: number,
userId?: number,
): Promise<{ url: string; fileName: string; size: number }> {
if (!file) {
throw new BadRequestException('文件不存在');
}
// 生成唯一文件名
const fileExt = path.extname(file.originalname);
const uniqueId = randomBytes(16).toString('hex');
const fileName = `${uniqueId}${fileExt}`;
// 根据租户ID和用户ID创建目录结构uploads/tenantId/userId/
let targetDir = this.uploadDir;
if (tenantId) {
targetDir = path.join(targetDir, `tenant_${tenantId}`);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
if (userId) {
targetDir = path.join(targetDir, `user_${userId}`);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
}
}
// 文件保存路径
const filePath = path.join(targetDir, fileName);
// 保存文件
fs.writeFileSync(filePath, file.buffer);
// 生成访问URL
// 格式:/api/uploads/tenantId/userId/fileName 或 /api/uploads/fileName
let urlPath = '/api/uploads';
if (tenantId) {
urlPath += `/tenant_${tenantId}`;
if (userId) {
urlPath += `/user_${userId}`;
}
}
urlPath += `/${fileName}`;
return {
url: urlPath,
fileName: file.originalname,
size: file.size,
};
}
}