Files
Agent-n8n/web_frontend/web_result/app.js
Yep_Q 125a134902 fix: 修复ResultModal数据提取时的agent调用错误
详细说明:
- 修复getProjectInfo函数中seq.agent()的类型错误
- 添加兼容性处理,支持函数和对象两种数据格式
- 解决选择订单班后点击按钮导致页面崩溃的问题
- 修改文件: WorkflowPageV4.tsx (第934行)
- 影响模块: ResultModal数据显示系统

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-10 14:25:07 +08:00

310 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const path = require('path');
const fs = require('fs');
const yaml = require('js-yaml');
// 加载路由配置
function loadRoutes() {
try {
const fileContents = fs.readFileSync('routes.yaml', 'utf8');
return yaml.load(fileContents);
} catch (e) {
console.error('加载路由配置失败:', e);
process.exit(1);
}
}
const config = loadRoutes();
const app = express();
const PORT = config.server.port || 4155;
// 静态文件服务
app.use('/order-classes', express.static('order-classes'));
// 为所有订单班提供独立的静态文件服务
const orderClassDirs = ['wenlu', 'food', 'finance', 'health', 'chemical', 'environmental',
'transportation', 'energy', 'visual-design', 'civil', 'developer', 'manufacturing'];
orderClassDirs.forEach(dir => {
// 每个订单班的资源路径
app.use(`/order-class/${dir}/css`, express.static(`order-classes/${dir}/css`));
app.use(`/order-class/${dir}/js`, express.static(`order-classes/${dir}/js`));
app.use(`/order-class/${dir}/data`, express.static(`order-classes/${dir}/data`));
app.use(`/order-class/${dir}/images`, express.static(`order-classes/${dir}/images`));
app.use(`/order-class/${dir}/agent-avatars`, express.static(`order-classes/${dir}/agent-avatars`));
});
// 日志中间件
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
});
// 主路由 - 显示订单班选择页面
app.get('/', (req, res) => {
const orderClass = req.query.class;
if (orderClass) {
// 如果指定了订单班,重定向到对应路由
res.redirect(`/order-class/${orderClass}`);
} else {
// 显示选择页面
res.send(generateIndexPage());
}
});
// 处理 /order-class/wenlu/*.html 形式的请求
app.get('/order-class/wenlu/:page', (req, res) => {
const page = req.params.page;
const filePath = path.join(__dirname, 'order-classes', 'wenlu', page);
if (fs.existsSync(filePath)) {
let html = fs.readFileSync(filePath, 'utf8');
res.send(html);
} else {
res.status(404).send(generate404Page(`wenlu/${page}`));
}
});
// 处理 /order-class/*.html 形式的请求wenlu 子页面)- 兼容旧路径
app.get('/order-class/:page', (req, res, next) => {
const page = req.params.page;
// 只处理 .html 文件
if (!page.endsWith('.html')) {
// 如果不是 .html 文件,继续下一个路由
next();
return;
}
const filePath = path.join(__dirname, 'order-classes', 'wenlu', page);
if (fs.existsSync(filePath)) {
let html = fs.readFileSync(filePath, 'utf8');
res.send(html);
} else {
res.status(404).send(generate404Page(page));
}
});
// 订单班路由
app.get('/order-class/:className', (req, res) => {
const className = req.params.className;
const classConfig = config.order_classes[className];
if (!classConfig) {
res.status(404).send(generate404Page(className));
return;
}
// 如果订单班已完成,返回其页面
if (classConfig.status === 'completed') {
const filePath = path.join(__dirname, classConfig.path, classConfig.entry);
if (fs.existsSync(filePath)) {
// 读取文件并修改相对路径
let html = fs.readFileSync(filePath, 'utf8');
// 保持相对路径,让浏览器自己解析
// 不需要修改路径,因为我们已经设置了静态文件服务
res.send(html);
} else {
res.send(generateComingSoonPage(classConfig));
}
} else {
res.send(generateComingSoonPage(classConfig));
}
});
// 处理订单班内部页面如文旅的overview.html等
app.get('/order-classes/:className/:page', (req, res) => {
const { className, page } = req.params;
const filePath = path.join(__dirname, 'order-classes', className, page);
if (fs.existsSync(filePath)) {
let html = fs.readFileSync(filePath, 'utf8');
// 保持相对路径不变
res.send(html);
} else {
res.status(404).send(generate404Page(`${className}/${page}`));
}
});
// 已删除 /order-class/pages/:page 路由,因为导航链接已修复为相对路径
// 生成首页(选择页面)
function generateIndexPage() {
const orderClasses = Object.entries(config.order_classes);
const completedClasses = orderClasses.filter(([_, c]) => c.status === 'completed');
const pendingClasses = orderClasses.filter(([_, c]) => c.status === 'pending');
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>订单班AI生成方案展示系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
body { font-family: 'Inter', 'Noto Sans SC', sans-serif; }
.order-card {
transition: all 0.3s ease;
cursor: pointer;
}
.order-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
</style>
</head>
<body class="bg-gray-50">
<div class="gradient-bg text-white py-12">
<div class="container mx-auto px-4 text-center">
<h1 class="text-4xl font-bold mb-4">订单班AI生成方案展示系统</h1>
<p class="text-xl opacity-90">基于多Agent协作的智能方案生成平台</p>
</div>
</div>
<div class="container mx-auto px-4 py-12">
<h2 class="text-2xl font-bold mb-6">已完成的订单班方案</h2>
<div class="grid md:grid-cols-3 lg:grid-cols-4 gap-6 mb-12">
${completedClasses.map(([key, config]) => `
<div class="order-card bg-white rounded-lg p-6 shadow-md" onclick="location.href='/order-class/${key}/'">
<div class="text-3xl mb-3">${getClassIcon(key)}</div>
<h3 class="font-bold text-lg mb-2">${config.name}</h3>
<p class="text-sm text-gray-600 mb-3">${config.description}</p>
<div class="text-sm text-gray-500">
<i class="fas fa-users"></i> ${config.agents.length || 0} 位AI专家
</div>
<div class="mt-4 text-blue-600 font-semibold">
查看方案 <i class="fas fa-arrow-right"></i>
</div>
</div>
`).join('')}
</div>
<h2 class="text-2xl font-bold mb-6 text-gray-500">即将推出</h2>
<div class="grid md:grid-cols-3 lg:grid-cols-4 gap-6">
${pendingClasses.map(([key, config]) => `
<div class="bg-gray-100 rounded-lg p-6 opacity-60">
<div class="text-3xl mb-3 text-gray-400">${getClassIcon(key)}</div>
<h3 class="font-bold text-lg mb-2 text-gray-500">${config.name}</h3>
<p class="text-sm text-gray-400">${config.description}</p>
<div class="mt-4 text-gray-400">
开发中...
</div>
</div>
`).join('')}
</div>
</div>
<script>
// 可以添加一些交互效果
</script>
</body>
</html>`;
}
// 生成404页面
function generate404Page(resource) {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>页面未找到</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="text-center">
<h1 class="text-6xl font-bold text-gray-300 mb-4">404</h1>
<p class="text-xl text-gray-600 mb-2">页面未找到</p>
<p class="text-gray-500 mb-6">资源 "${resource}" 不存在</p>
<a href="/" class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700">
返回首页
</a>
</div>
</body>
</html>`;
}
// 生成即将推出页面
function generateComingSoonPage(classConfig) {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${classConfig.name} - 即将推出</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gradient-to-br from-purple-600 to-blue-600 text-white min-h-screen flex items-center justify-center">
<div class="text-center">
<div class="text-6xl mb-6">${getClassIcon(classConfig.name)}</div>
<h1 class="text-4xl font-bold mb-4">${classConfig.name}</h1>
<p class="text-xl mb-2">${classConfig.title}</p>
<p class="opacity-80 mb-8">${classConfig.description}</p>
<div class="bg-white/20 backdrop-blur rounded-lg p-6 max-w-md mx-auto">
<p class="text-lg font-semibold mb-2">🚀 正在开发中</p>
<p>我们的AI专家团队正在为您准备专业的解决方案</p>
</div>
<a href="/" class="mt-8 inline-block bg-white text-purple-600 px-6 py-3 rounded-lg hover:bg-gray-100">
返回首页
</a>
</div>
</body>
</html>`;
}
// 获取订单班图标
function getClassIcon(key) {
const icons = {
'wenlu': '🚗',
'food': '🍽️',
'finance': '💰',
'health': '🏥',
'chemical': '⚗️',
'environmental': '🌱',
'transportation': '🚚',
'energy': '⚡',
'visual-design': '🎨',
'civil': '🏗️',
'developer': '💻',
'manufacturing': '🏭'
};
return icons[key] || '📦';
}
// 启动服务器
app.listen(PORT, () => {
console.log(`
╔═══════════════════════════════════════════════════════╗
║ 订单班AI生成方案展示系统 - 服务器已启动 ║
╠═══════════════════════════════════════════════════════╣
║ ║
║ 访问地址: ║
║ • http://localhost:${PORT}
║ ║
║ 路由示例: ║
║ • 首页: http://localhost:${PORT}/ ║
║ • 文旅: http://localhost:${PORT}/order-class/wenlu ║
║ • 食品: http://localhost:${PORT}/order-class/food ║
║ ║
║ 快捷访问: ║
║ • http://localhost:${PORT}/?class=wenlu ║
║ • http://localhost:${PORT}/?class=food ║
║ ║
╚═══════════════════════════════════════════════════════╝
`);
});
// 优雅关闭
process.on('SIGINT', () => {
console.log('\n正在关闭服务器...');
process.exit(0);
});