Files
Agent-n8n/web_frontend/web_result/app.js
Yep_Q c579dae90a feat: 完成化工订单班图片处理和项目记忆重组
详细说明:
- 化工订单班图片已标准化处理(8个图片,文件名与alt text完全一致)
- 完成环保、财经商贸订单班的图片重命名工作
- 重组项目记忆文件,按照功能模块编号(00-09)
- 删除旧的分散记忆文件,统一到新的编号体系
- 添加终端模拟文件:chemical.ts, environmental.ts, finance.ts
- 清理web_result冗余文件(food react-app等)
- 新增playwright截图记录和记忆文档
- 影响模块:订单班文档资料、项目记忆系统、终端模拟系统
2025-10-04 00:34:44 +08:00

303 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('/order-class/food/images', express.static('order-classes/food/images'));
app.use('/order-class/food/agent-avatars', express.static('order-classes/food/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/*.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);
});