Files
aijianhua/backend/routes/upload.js

181 lines
4.3 KiB
JavaScript

const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const dbConnector = require('../utils/dbConnector');
const { asyncHandler } = require('../middlewares/errorHandler');
const router = express.Router();
// 配置multer用于文件上传
const storage = multer.diskStorage({
destination: (req, file, cb) => {
const uploadType = req.body.type || 'common';
const uploadDir = path.join(__dirname, `../uploads/${uploadType}`);
// 确保上传目录存在
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
cb(null, uploadDir);
},
filename: (req, file, cb) => {
const uploadType = req.body.type || 'common';
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
const ext = path.extname(file.originalname);
const filename = `${uploadType}_${uniqueSuffix}${ext}`;
cb(null, filename);
}
});
const upload = multer({
storage: storage,
limits: {
fileSize: 10 * 1024 * 1024, // 10MB限制
},
fileFilter: (req, file, cb) => {
// 允许所有文件类型
cb(null, true);
}
});
/**
* 文件上传接口
* POST /api/v1/upload
*/
router.post('/', upload.single('file'), asyncHandler(async (req, res) => {
if (!req.file) {
return res.status(400).json({
code: 400,
message: '请选择要上传的文件'
});
}
const uploadType = req.body.type || 'common';
const userId = req.user?.id;
// 构建文件访问URL
const fileUrl = `/uploads/${uploadType}/${req.file.filename}`;
// 保存文件记录到数据库(可选)
if (userId) {
try {
await dbConnector.query(
`INSERT INTO uploads
(user_id, filename, original_name, file_type, file_size, file_url, upload_type, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`,
[
userId,
req.file.filename,
req.file.originalname,
req.file.mimetype,
req.file.size,
fileUrl,
uploadType
]
);
} catch (error) {
console.warn('保存文件记录失败:', error);
// 不中断上传流程,仅记录警告
}
}
res.json({
code: 200,
message: '上传成功',
data: {
url: fileUrl,
filename: req.file.filename,
original_name: req.file.originalname,
size: req.file.size,
mime_type: req.file.mimetype,
upload_type: uploadType
}
});
}));
/**
* 获取上传文件列表
* GET /api/v1/upload
*/
router.get('/', asyncHandler(async (req, res) => {
const userId = req.user.id;
const { page = 1, limit = 10, type } = req.query;
const offset = (page - 1) * limit;
let query = 'SELECT * FROM uploads WHERE user_id = ?';
let queryParams = [userId];
if (type) {
query += ' AND upload_type = ?';
queryParams.push(type);
}
query += ' ORDER BY created_at DESC LIMIT ? OFFSET ?';
queryParams.push(parseInt(limit), parseInt(offset));
const files = await dbConnector.query(query, queryParams);
const countResult = await dbConnector.query(
'SELECT COUNT(*) as count FROM uploads WHERE user_id = ?' + (type ? ' AND upload_type = ?' : ''),
type ? [userId, type] : [userId]
);
const total = countResult[0].count;
res.json({
code: 200,
message: '获取成功',
data: {
files: files,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total: total,
pages: Math.ceil(total / limit)
}
}
});
}));
/**
* 删除上传文件
* DELETE /api/v1/upload/:id
*/
router.delete('/:id', asyncHandler(async (req, res) => {
const { id } = req.params;
const userId = req.user.id;
// 查询文件信息
const file = await dbConnector.query(
'SELECT * FROM uploads WHERE id = ? AND user_id = ?',
[id, userId]
);
if (file.length === 0) {
return res.status(404).json({
code: 404,
message: '文件不存在'
});
}
// 删除物理文件
const filePath = path.join(__dirname, `../${file[0].file_url}`);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
}
// 删除数据库记录
await dbConnector.query(
'DELETE FROM uploads WHERE id = ? AND user_id = ?',
[id, userId]
);
res.json({
code: 200,
message: '删除成功'
});
}));
module.exports = router;