335 lines
10 KiB
JavaScript
335 lines
10 KiB
JavaScript
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;
|