201 lines
5.1 KiB
JavaScript
201 lines
5.1 KiB
JavaScript
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;
|