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.

144 lines
3.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 文件上传中间件
*
* 功能:处理图片上传(如菜品图片、用户头像)
* 使用multer库实现文件上传
*/
const multer = require('multer');
const path = require('path');
const fs = require('fs');
// 确保上传目录存在
const uploadDir = 'uploads/images';
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
/**
* 配置文件存储
* destination: 文件保存位置
* filename: 文件名生成规则
*/
const storage = multer.diskStorage({
// 设置上传文件的存储目录
destination: function (req, file, cb) {
cb(null, uploadDir); // null表示没有错误
},
// 设置上传文件的文件名
filename: function (req, file, cb) {
// 生成唯一文件名:时间戳-随机数.原扩展名
// 例如1704873600000-123456.jpg
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const ext = path.extname(file.originalname); // 获取文件扩展名
cb(null, uniqueSuffix + ext);
}
});
/**
* 文件过滤器
* 只允许上传图片文件
*/
const fileFilter = (req, file, cb) => {
// 允许的图片MIME类型
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
if (allowedTypes.includes(file.mimetype)) {
cb(null, true); // 接受文件
} else {
cb(new Error('只能上传图片文件jpg, jpeg, png, gif, webp'), false);
}
};
/**
* 创建multer上传实例
*/
const upload = multer({
storage: storage,
fileFilter: fileFilter,
limits: {
fileSize: 5 * 1024 * 1024 // 限制文件大小为5MB
}
});
/**
* 单个图片上传中间件
*
* 使用示例:
* router.post('/dishes', uploadSingle, createDish);
*
* 前端上传示例FormData
* const formData = new FormData();
* formData.append('image', file);
* axios.post('/dishes', formData);
*/
const uploadSingle = upload.single('image'); // 'image'是表单字段名
/**
* 多个图片上传中间件
*
* 使用示例:
* router.post('/gallery', uploadMultiple, uploadGallery);
*
* 前端上传示例:
* const formData = new FormData();
* files.forEach(file => {
* formData.append('images', file);
* });
*/
const uploadMultiple = upload.array('images', 10); // 最多10张图片
/**
* 删除上传的文件
* @param {string} filename - 文件名
*
* 说明:当删除数据库记录时,也要删除对应的图片文件
*/
const deleteUploadedFile = (filename) => {
try {
if (!filename) return;
const filePath = path.join(uploadDir, filename);
// 检查文件是否存在
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath); // 同步删除文件
console.log(`✅ 已删除文件: ${filename}`);
}
} catch (error) {
console.error('❌ 删除文件失败:', error.message);
}
};
/**
* 获取文件的访问URL
* @param {string} filename - 文件名
* @returns {string} 文件URL
*
* 例如:/uploads/images/1704873600000-123456.jpg
*/
const getFileUrl = (filename) => {
if (!filename) return null;
return `/uploads/images/${filename}`;
};
/**
* 从URL中提取文件名
* @param {string} url - 文件URL
* @returns {string} 文件名
*/
const getFilenameFromUrl = (url) => {
if (!url) return null;
return path.basename(url);
};
// 导出所有函数
module.exports = {
uploadSingle,
uploadMultiple,
deleteUploadedFile,
getFileUrl,
getFilenameFromUrl
};