feat: Initial commit of PDF Tools project
This commit is contained in:
200
server/routes/conversion.js
Normal file
200
server/routes/conversion.js
Normal file
@@ -0,0 +1,200 @@
|
||||
const express = require('express');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const { optionalAuth } = require('../middleware/auth');
|
||||
const conversionService = require('../services/conversionService');
|
||||
const ConversionTask = require('../models/ConversionTask');
|
||||
const File = require('../models/File');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
* @route POST /api/convert/start
|
||||
* @desc 开始一个新的文件转换任务
|
||||
* @access Private (optional)
|
||||
*/
|
||||
router.post('/start', optionalAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { fileId, outputFormat, options = {} } = req.body;
|
||||
|
||||
if (!fileId || !outputFormat) {
|
||||
return res.status(400).json({ success: false, message: '缺少必要参数:fileId和outputFormat' });
|
||||
}
|
||||
|
||||
// 验证文件是否存在
|
||||
const file = await File.findOne({ fileId });
|
||||
if (!file) {
|
||||
return res.status(404).json({ success: false, message: '文件未找到' });
|
||||
}
|
||||
|
||||
// 创建转换任务
|
||||
const task = await ConversionTask.create({
|
||||
taskId: uuidv4(),
|
||||
fileId,
|
||||
outputFormat,
|
||||
options,
|
||||
userId: req.user?.userId || null,
|
||||
sourceFile: {
|
||||
name: file.fileName,
|
||||
size: file.size,
|
||||
type: file.mimeType
|
||||
}
|
||||
});
|
||||
|
||||
// 异步开始转换,不阻塞响应
|
||||
conversionService.startConversion(task.taskId);
|
||||
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
message: '转换任务已创建',
|
||||
data: {
|
||||
taskId: task.taskId,
|
||||
status: task.status,
|
||||
progress: task.progress
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route GET /api/convert/status/:taskId
|
||||
* @desc 查询转换任务的状态
|
||||
* @access Public
|
||||
*/
|
||||
router.get('/status/:taskId', async (req, res, next) => {
|
||||
try {
|
||||
const { taskId } = req.params;
|
||||
const task = await ConversionTask.findOne({ taskId }).lean();
|
||||
|
||||
if (!task) {
|
||||
return res.status(404).json({ success: false, message: '转换任务未找到' });
|
||||
}
|
||||
|
||||
res.json({ success: true, data: task });
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route GET /api/convert/result/:taskId
|
||||
* @desc 获取转换任务的结果
|
||||
* @access Public
|
||||
*/
|
||||
router.get('/result/:taskId', async (req, res, next) => {
|
||||
try {
|
||||
const { taskId } = req.params;
|
||||
const task = await ConversionTask.findOne({ taskId }).lean();
|
||||
|
||||
if (!task) {
|
||||
return res.status(404).json({ success: false, message: '转换任务未找到' });
|
||||
}
|
||||
|
||||
if (task.status !== 'completed') {
|
||||
return res.status(400).json({ success: false, message: '转换尚未完成' });
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
taskId: task.taskId,
|
||||
resultUrl: task.resultFile.downloadUrl,
|
||||
fileName: task.resultFile.fileName,
|
||||
fileSize: task.resultFile.fileSize
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route POST /api/convert/batch
|
||||
* @desc 开始批量转换任务
|
||||
* @access Private (optional)
|
||||
*/
|
||||
router.post('/batch', optionalAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { fileIds, outputFormat, options = {} } = req.body;
|
||||
|
||||
if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {
|
||||
return res.status(400).json({ success: false, message: '请提供要转换的文件ID列表' });
|
||||
}
|
||||
|
||||
if (fileIds.length > 10) {
|
||||
return res.status(400).json({ success: false, message: '批量转换最多支持10个文件' });
|
||||
}
|
||||
|
||||
const batchId = uuidv4();
|
||||
const createdTasks = [];
|
||||
|
||||
for (const fileId of fileIds) {
|
||||
const file = await File.findOne({ fileId });
|
||||
if (file) {
|
||||
const task = await ConversionTask.create({
|
||||
taskId: uuidv4(),
|
||||
batchId,
|
||||
fileId,
|
||||
outputFormat,
|
||||
options,
|
||||
userId: req.user?.userId || null,
|
||||
sourceFile: {
|
||||
name: file.fileName,
|
||||
size: file.size,
|
||||
type: file.mimeType
|
||||
}
|
||||
});
|
||||
createdTasks.push(task);
|
||||
// 异步开始转换
|
||||
conversionService.startConversion(task.taskId);
|
||||
}
|
||||
}
|
||||
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
message: '批量转换任务已创建',
|
||||
data: {
|
||||
batchId,
|
||||
taskCount: createdTasks.length,
|
||||
tasks: createdTasks.map(t => ({ taskId: t.taskId, status: t.status }))
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route POST /api/convert/cancel/:taskId
|
||||
* @desc 取消一个正在进行的转换任务
|
||||
* @access Private (optional)
|
||||
*/
|
||||
router.post('/cancel/:taskId', optionalAuth, async (req, res, next) => {
|
||||
try {
|
||||
const { taskId } = req.params;
|
||||
const task = await ConversionTask.findOne({ taskId });
|
||||
|
||||
if (!task) {
|
||||
return res.status(404).json({ success: false, message: '转换任务未找到' });
|
||||
}
|
||||
|
||||
// 权限检查:确保用户只能取消自己的任务
|
||||
if (task.userId && (!req.user || task.userId !== req.user.userId)) {
|
||||
return res.status(403).json({ success: false, message: '无权操作此任务' });
|
||||
}
|
||||
|
||||
await task.cancel();
|
||||
|
||||
res.json({ success: true, message: '转换任务已取消' });
|
||||
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user