Files
Agent-n8n/web_frontend/web_result/app.js
Yep_Q 68da1fc605 fix: 修复展示页面多个关键问题
修复内容:
1. 修复Agent头像显示问题 - 使用真实图片替代emoji
2. 移除ResultPageV2自动跳转行为
3. 删除不符合需求的ResultPageV2组件
4. 修复undefined变量错误(currentTerminalData)
5. 添加缺失的getSimulationData导入
6. 优化ResultModal支持动态内容展示

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 21:32:28 +08:00

301 lines
11 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('/css', express.static('css'));
app.use('/js', express.static('js'));
app.use('/data', express.static('data'));
app.use('/order-classes', express.static('order-classes'));
// 为每个订单班提供独立的静态文件服务
app.use('/order-class/wenlu/css', express.static('order-classes/wenlu/css'));
app.use('/order-class/wenlu/js', express.static('order-classes/wenlu/js'));
app.use('/order-class/wenlu/data', express.static('order-classes/wenlu/data'));
// 由于HTML中使用相对路径还需要从父路径提供静态文件
app.use('/order-class/css', express.static('order-classes/wenlu/css'));
app.use('/order-class/js', express.static('order-classes/wenlu/js'));
app.use('/order-class/data', express.static('order-classes/wenlu/data'));
app.use('/order-class/food/css', express.static('order-classes/food/css'));
app.use('/order-class/food/js', express.static('order-classes/food/js'));
app.use('/order-class/food/data', express.static('order-classes/food/data'));
// 日志中间件
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/*.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': '🍽️',
'caijing': '💰',
'jiankang': '🏥',
'huagong': '⚗️',
'huanbao': '🌱',
'jiaotong': '🚚',
'nengyuan': '⚡',
'shijue': '🎨',
'tumu': '🏗️',
'zhineng-dev': '💻',
'zhineng-mfg': '🏭'
};
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);
});