You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

70 lines
1.8 KiB

import multer from 'multer';
import fs from 'node:fs';
import path from 'node:path';
import { callNodeListener } from 'h3';
import {
RELATIVE_ASSETS_DIR,
POST_MEDIA_PUBLIC_PREFIX,
ALLOWED_MIME_TYPES,
MAX_FILE_SIZE,
MAX_FILE_COUNT,
} from '#server/constants/upload';
import { getContextUser } from '#server/utils/context';
interface IFile {
name: string;
url: string;
mimeType: string;
size: number;
}
export default defineWrappedResponseHandler({ auth: 'required' }, async (event) => {
const user = getContextUser(event)!;
const uploadDir = path.resolve(RELATIVE_ASSETS_DIR);
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
const storage = multer.diskStorage({
destination: uploadDir,
filename: (_req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
const ext = path.extname(file.originalname).toLowerCase();
const baseName = path.basename(file.originalname, ext).replace(/[^a-z0-9]/gi, '-');
cb(null, `${uniqueSuffix}-${baseName}${ext}`);
},
});
const upload = multer({
storage,
limits: { fileSize: MAX_FILE_SIZE },
fileFilter: (_req, file, cb) => {
if ((ALLOWED_MIME_TYPES as readonly string[]).includes(file.mimetype)) {
cb(null, true);
} else {
cb(new Error('只支持 PNG/JPG/WebP 格式图片'));
}
},
});
await callNodeListener(
// @ts-expect-error Nuxt 类型兼容
upload.array('file', MAX_FILE_COUNT),
event.node.req,
event.node.res,
);
// @ts-expect-error
const uploadedFiles = event.node.req.files || [];
const result: IFile[] = uploadedFiles.map((file: any) => ({
name: file.originalname,
url: `${POST_MEDIA_PUBLIC_PREFIX}${file.filename}`,
mimeType: file.mimetype,
size: file.size,
}));
return result;
});