docs: 更新项目文档,完善需求和技术细节
This commit is contained in:
181
backend/routes/upload.js
Normal file
181
backend/routes/upload.js
Normal file
@@ -0,0 +1,181 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user