const express = require('express'); const router = express.Router(); const multer = require('multer'); const path = require('path'); const fs = require('fs'); const { getServices, getServiceVersionsByClassName, saveServiceVersion, createService } = require('../utils/service-utils'); const { serviceCodeGen, serviceCodeZip, serviceCodeUnzip, serviceCodeCompile } = require('../utils/xnCoreService'); // 获取所有服务列表 router.get('/services', (req, res) => { try { const services = getServices(); res.json(services); } catch (error) { console.error('获取服务列表失败:', error); res.status(500).json({ error: '获取服务列表失败', details: error.message }); } }); // 获取指定ClassName的服务版本 router.get('/service-versions/:className', (req, res) => { try { const className = req.params.className; if (!className) { return res.status(400).json({ error: '服务类名不能为空' }); } const versions = getServiceVersionsByClassName(className); // 确保版本列表每项都有Name属性,如果没有则使用列名一致性处理 const processedVersions = versions.map(version => { // 如果没有Name属性(可能是表结构原因),则使用与前端组件兼容的方式 if (version.Name === undefined && version.ServiceName) { version.Name = version.ServiceName; } return version; }); res.json(processedVersions); } catch (error) { console.error(`获取服务版本失败: ${error.message}`); res.status(500).json({ error: '获取服务版本失败', details: error.message }); } }); // 保存服务版本信息 router.post('/service-versions', (req, res) => { try { const versionData = req.body; if (!versionData || !versionData.ClassName) { return res.status(400).json({ error: '缺少必要的服务版本数据' }); } // 确保数据字段一致性 if (versionData.ServiceName === undefined && versionData.Name) { versionData.ServiceName = versionData.Name; } // 验证 CmdList 和 OtherParam 是否为有效的 JSON 字符串 if (versionData.CmdList !== undefined) { try { JSON.parse(versionData.CmdList); } catch (e) { return res.status(400).json({ error: 'CmdList 必须是有效的 JSON 字符串' }); } } if (versionData.OtherParam !== undefined) { try { JSON.parse(versionData.OtherParam); } catch (e) { return res.status(400).json({ error: 'OtherParam 必须是有效的 JSON 字符串' }); } } const result = saveServiceVersion(versionData); res.json(result); } catch (error) { console.error(`保存服务版本失败: ${error.message}`); res.status(500).json({ error: '保存服务版本失败', details: error.message }); } }); // 创建新服务 router.post('/services', (req, res) => { try { const serviceData = req.body; if (!serviceData || !serviceData.ClassName || !serviceData.ServiceName || !serviceData.ServiceName_CN) { return res.status(400).json({ error: '缺少必要的服务数据' }); } // 验证类名是否以XN开头 if (!serviceData.ClassName.startsWith('XN')) { return res.status(400).json({ error: '服务类名必须以XN开头' }); } const result = createService(serviceData); res.json(result); } catch (error) { console.error(`创建服务失败: ${error.message}`); res.status(500).json({ error: '创建服务失败', details: error.message }); } }); // 生成服务代码 router.post('/generate-code', (req, res) => { try { const { className, version } = req.body; if (!className || !version) { return res.status(400).json({ error: '缺少必要的参数:className 和 version' }); } const result = serviceCodeGen(className, version); if (result.includes('成功')) { res.json({ success: true, message: result }); } else { res.status(500).json({ success: false, error: result }); } } catch (error) { console.error(`生成服务代码失败: ${error.message}`); res.status(500).json({ error: '生成服务代码失败', details: error.message }); } }); // 压缩服务代码 router.post('/zip-code', (req, res) => { try { const { className, version } = req.body; if (!className || !version) { return res.status(400).json({ error: '缺少必要的参数:className 和 version' }); } const result = serviceCodeZip(className, version); if (result.success) { res.json({ success: true, message: result.message, dstPath: result.dstPath }); } else { res.status(500).json({ success: false, error: result.message }); } } catch (error) { console.error(`压缩服务代码失败: ${error.message}`); res.status(500).json({ error: '压缩服务代码失败', details: error.message }); } }); // 解压服务代码 router.post('/unzip-code', (req, res) => { try { const { className, version, srcPath } = req.body; if (!className || !version || !srcPath) { return res.status(400).json({ error: '缺少必要的参数:className、version 和 srcPath' }); } const result = serviceCodeUnzip(className, version, srcPath); if (result.includes('成功')) { res.json({ success: true, message: result }); } else { res.status(500).json({ success: false, error: result }); } } catch (error) { console.error(`解压服务代码失败: ${error.message}`); res.status(500).json({ error: '解压服务代码失败', details: error.message }); } }); // 编译服务代码 router.post('/compile-code', (req, res) => { try { const { className, version } = req.body; if (!className || !version) { return res.status(400).json({ error: '缺少必要的参数:className 和 version' }); } const result = serviceCodeCompile(className, version); if (result.includes('成功')) { res.json({ success: true, message: result }); } else { res.status(500).json({ success: false, error: result }); } } catch (error) { console.error(`编译服务代码失败: ${error.message}`); res.status(500).json({ error: '编译服务代码失败', details: error.message }); } }); // 下载ZIP文件 router.post('/download-zip', (req, res) => { try { const { filePath } = req.body; if (!filePath) { return res.status(400).json({ error: '缺少文件路径参数' }); } // 检查文件是否存在 if (!fs.existsSync(filePath)) { return res.status(404).json({ error: '文件不存在' }); } // 检查文件是否为ZIP格式 if (!filePath.toLowerCase().endsWith('.zip')) { return res.status(400).json({ error: '只能下载ZIP格式的文件' }); } // 获取文件名 const fileName = path.basename(filePath); // 设置响应头 res.setHeader('Content-Type', 'application/zip'); res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); // 发送文件 res.sendFile(filePath); } catch (error) { console.error(`下载ZIP文件失败: ${error.message}`); res.status(500).json({ error: '下载ZIP文件失败', details: error.message }); } }); // 配置multer用于文件上传 const storage = multer.diskStorage({ destination: function (req, file, cb) { // 获取XNCore环境变量 const xnCorePath = process.env.XNCore || ''; if (!xnCorePath) { return cb(new Error('XNCore环境变量未设置')); } // 创建ServiceProjects目录 const serviceProjectsDir = path.join(xnCorePath, 'ServiceProjects'); if (!fs.existsSync(serviceProjectsDir)) { fs.mkdirSync(serviceProjectsDir, { recursive: true }); } cb(null, serviceProjectsDir); }, filename: function (req, file, cb) { cb(null, file.originalname); } }); const upload = multer({ storage: storage, fileFilter: function (req, file, cb) { // 只允许ZIP文件 if (file.mimetype === 'application/zip' || file.originalname.toLowerCase().endsWith('.zip')) { cb(null, true); } else { cb(new Error('只允许上传ZIP格式的文件'), false); } }, limits: { fileSize: 100 * 1024 * 1024 // 限制100MB } }); // 上传ZIP文件 router.post('/upload-zip', upload.single('file'), (req, res) => { try { // 检查XNCore环境变量 const xnCorePath = process.env.XNCore || ''; if (!xnCorePath) { return res.status(500).json({ error: 'XNCore环境变量未设置' }); } if (!req.file) { return res.status(400).json({ error: '没有选择文件' }); } const filePath = req.file.path; const fileName = req.file.filename; // 验证文件是否成功保存到ServiceProjects目录 if (!fs.existsSync(filePath)) { return res.status(500).json({ error: '文件上传失败,文件未保存到目标目录' }); } res.json({ success: true, message: '文件上传成功', filePath: filePath, fileName: fileName, originalName: req.file.originalname, uploadDir: path.dirname(filePath) }); } catch (error) { console.error(`上传ZIP文件失败: ${error.message}`); res.status(500).json({ error: '上传ZIP文件失败', details: error.message }); } }); // 处理multer错误 router.use('/upload-zip', (error, req, res, next) => { if (error instanceof multer.MulterError) { if (error.code === 'LIMIT_FILE_SIZE') { return res.status(400).json({ error: '文件大小超过限制(最大100MB)' }); } return res.status(400).json({ error: `文件上传错误: ${error.message}` }); } if (error.message === 'XNCore环境变量未设置') { return res.status(500).json({ error: 'XNCore环境变量未设置,无法上传文件' }); } if (error.message.includes('只允许上传ZIP格式的文件')) { return res.status(400).json({ error: '只允许上传ZIP格式的文件' }); } console.error('文件上传错误:', error); res.status(500).json({ error: '文件上传失败', details: error.message }); }); module.exports = router;