Files
Agent-n8n/web_frontend/exhibition-demo/src/components/RequirementModal.tsx
Yep_Q a884afc494 refactor: 优化RequirementModal UI设计和代码清理
主要更新:
- 🎨 UI改进:
  - 将头部背景改为苹果风格设计
  - 添加背景图片 /image/bg.png
  - 将图标替换为动态视频logo
  - 统一配色为蓝色系,移除紫色元素
  - 优化标题和副标题布局

- 🧹 代码清理:
  - 删除5个临时测试文件 (test-*.html)
  - 删除4个旧版本页面组件 (WorkflowPage V1-V3, ResultPage V1)
  - 保留当前使用的 WorkflowPageV4 和 ResultPageV2

- 🔧 细节调整:
  - 视频logo尺寸调整为 80x80px
  - 移除视频容器的圆角和阴影效果
  - 按钮颜色从紫色渐变改为蓝色渐变

项目结构更加清晰,界面设计更加现代化
2025-09-29 16:07:19 +08:00

313 lines
14 KiB
TypeScript
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.

import React, { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { X, Sparkles, FileText, Zap } from 'lucide-react';
import orderClassesData from '../data/orderClasses.json';
import { OrderClassIconMap } from './OrderClassIcons';
interface RequirementModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (requirement: string, orderClass: string) => void;
}
const RequirementModal: React.FC<RequirementModalProps> = ({ isOpen, onClose, onSubmit }) => {
const [requirement, setRequirement] = useState('');
const [selectedTemplate, setSelectedTemplate] = useState<string | null>(null);
const [selectedOrderClass, setSelectedOrderClass] = useState<string>('');
const handleTemplateSelect = (orderClass: any) => {
// 使用配置文件中的模板内容
const content = orderClass.template?.description || '';
setRequirement(content);
setSelectedTemplate(orderClass.id);
setSelectedOrderClass(orderClass.id);
};
const generateTemplateContent = (orderClass: any) => {
// 直接返回配置中的描述
return orderClass.template?.description || '';
// 保留原有的模板作为备用
const templates: { [key: string]: string } = {
tourism: `展会名称2024长三角国际新能源汽车与智能交通产业博览会
地点:上海国家会展中心
时间2024年10月18日-20日
规模50,000平方米预计350家展商50,000人次观众
主题:双碳目标下的新能源汽车产业创新与发展
特色:整车展示、核心零部件、充电设施、智能交通解决方案`,
food: `展会名称2024国际健康食品与轻食产业博览会
地点:北京国家会议中心
时间2024年11月15日-17日
规模30,000平方米预计200家展商30,000人次观众
主题:健康饮食新风尚,轻食产业新机遇
特色:健康食品展示、轻食品牌推广、营养科技创新、餐饮连锁加盟`,
finance: `展会名称2024国际美妆产业与电商创新博览会
地点:广州琶洲会展中心
时间2024年12月8日-10日
规模40,000平方米预计300家展商40,000人次观众
主题:美妆新零售,电商新生态
特色:美妆品牌展示、电商平台对接、直播带货、供应链展示`,
dev: `展会名称2024国际教育科技与智慧学习博览会
地点:深圳会展中心
时间2024年10月25日-27日
规模35,000平方米预计250家展商35,000人次观众
主题AI赋能教育科技引领未来
特色:智慧教育解决方案、在线学习平台、教育硬件、课程内容`,
manufacturing: `展会名称2024国际智能制造与工业自动化博览会
地点:苏州国际博览中心
时间2024年11月20日-22日
规模45,000平方米预计300家展商40,000人次观众
主题:智能制造,智慧工厂
特色工业机器人、PLC控制、智能物流、数字化工厂`,
design: `展会名称2024国际文创设计与视觉艺术博览会
地点:杭州国际博览中心
时间2024年11月5日-7日
规模25,000平方米预计150家展商25,000人次观众
主题:创意设计,美好生活
特色:文创产品、视觉设计、影视制作、数字艺术`,
logistics: `展会名称2024国际智慧物流与供应链博览会
地点:上海新国际博览中心
时间2024年12月15日-17日
规模50,000平方米预计400家展商50,000人次观众
主题:智慧物流,高效供应链
特色AGV系统、智能仓储、冷链物流、供应链管理`,
civil: `展会名称2024国际建筑科技与绿色建造博览会
地点:武汉国际博览中心
时间2024年11月28日-30日
规模35,000平方米预计200家展商30,000人次观众
主题:绿色建筑,智慧建造
特色BIM技术、装配式建筑、生态材料、智慧工地`,
health: `展会名称2024国际大健康产业与医疗创新博览会
地点:成都世纪城新国际会展中心
时间2024年12月22日-24日
规模40,000平方米预计300家展商35,000人次观众
主题:科技赋能健康,创新引领医疗
特色:智慧医疗、心理健康、康复设备、健康管理`,
energy: `展会名称2024国际新能源与光伏产业博览会
地点:西安国际会展中心
时间2024年11月12日-14日
规模38,000平方米预计280家展商35,000人次观众
主题:清洁能源,绿色发展
特色:光伏技术、储能系统、智能电网、新能源装备`,
chemical: `展会名称2024国际新材料与精细化工博览会
地点:南京国际博览中心
时间2024年12月5日-7日
规模30,000平方米预计200家展商25,000人次观众
主题:新材料,新未来
特色:半导体材料、精细化工、功能材料、检测设备`,
environment: `展会名称2024国际环保科技与生态治理博览会
地点:青岛国际会展中心
时间2024年11月25日-27日
规模32,000平方米预计220家展商28,000人次观众
主题:生态文明,绿色发展
特色:环境监测、污水处理、大气治理、生态修复`
};
return templates[orderClass.id] || orderClass.scenario;
};
const handleSubmit = () => {
if (requirement.trim() && selectedOrderClass) {
onSubmit(requirement, selectedOrderClass);
setRequirement('');
setSelectedTemplate(null);
setSelectedOrderClass('');
}
};
return (
<AnimatePresence>
{isOpen && (
<>
{/* 背景遮罩 */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50"
onClick={onClose}
/>
{/* 弹窗内容 */}
<motion.div
initial={{ opacity: 0, scale: 0.9, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.9, y: 20 }}
transition={{ type: 'spring', damping: 25, stiffness: 300 }}
className="fixed inset-0 flex items-center justify-center z-50 p-4"
onClick={(e) => e.stopPropagation()}
>
<div className="bg-white rounded-2xl shadow-2xl max-w-5xl w-full max-h-[90vh] overflow-hidden">
{/* 头部 - 苹果风格设计 */}
<div className="relative">
{/* 渐变背景 */}
<div
className="absolute inset-0 bg-gradient-to-br from-slate-50 via-white to-gray-50"
style={{
backgroundImage: 'url(/image/bg.png)',
backgroundSize: '100% 100%',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat'
}}
/>
{/* 内容区 */}
<div className="relative px-8 py-6">
<div className="flex items-center justify-between">
<div>
<div className="flex items-center gap-4">
<div className="w-20 h-20 overflow-hidden flex-shrink-0">
<video
src="https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/cloude.mp4"
className="w-full h-full object-cover"
autoPlay
loop
muted
playsInline
controls={false}
/>
</div>
<div>
<h2 className="text-2xl font-bold bg-gradient-to-r from-gray-900 to-gray-600 bg-clip-text text-transparent">
AI
</h2>
<p className="text-gray-500 text-sm mt-1">AI为您定制专属解决方案</p>
</div>
</div>
</div>
<button
onClick={onClose}
className="w-10 h-10 bg-white hover:bg-gray-50 rounded-full shadow-sm hover:shadow-md transition-all duration-200 flex items-center justify-center group"
>
<X className="w-5 h-5 text-gray-400 group-hover:text-gray-600 transition-colors" />
</button>
</div>
</div>
{/* 底部分割线 */}
<div className="h-px bg-gradient-to-r from-transparent via-gray-200 to-transparent" />
</div>
<div className="p-6 max-h-[calc(90vh-120px)] overflow-y-auto">
{/* 订单班选择 */}
<div className="mb-6">
<h3 className="text-sm font-semibold text-gray-700 mb-3 flex items-center gap-2">
<FileText className="w-4 h-4" />
</h3>
<div className="grid grid-cols-3 gap-3">
{orderClassesData.orderClasses.map((orderClass) => (
<button
key={orderClass.id}
onClick={() => handleTemplateSelect(orderClass)}
className={`p-4 rounded-xl border-2 transition-all hover:shadow-lg ${
selectedTemplate === orderClass.id
? 'border-blue-500 bg-blue-50'
: 'border-gray-200 hover:border-gray-300'
}`}
>
<div className="flex items-center gap-3 mb-2">
<div className={`p-2 rounded-lg transition-all ${
selectedTemplate === orderClass.id
? 'bg-gradient-to-br from-blue-500 to-blue-600 text-white shadow-md scale-110'
: 'text-white hover:scale-105'
}`}
style={{
backgroundColor: selectedTemplate === orderClass.id ? undefined : orderClass.color,
boxShadow: selectedTemplate === orderClass.id ? '0 4px 12px rgba(59, 130, 246, 0.4)' : undefined
}}>
{(() => {
const IconComponent = OrderClassIconMap[orderClass.id];
return IconComponent ? <IconComponent size={20} /> : <FileText className="w-5 h-5" />;
})()}
</div>
<div className="text-left flex-1">
<div className="font-medium text-gray-900">{orderClass.name}</div>
<div className="text-xs text-gray-500 truncate">{orderClass.template?.title || orderClass.description}</div>
</div>
</div>
</button>
))}
</div>
</div>
{/* 输入区域 */}
<div className="mb-6">
<label className="block text-sm font-semibold text-gray-700 mb-2">
</label>
<textarea
value={requirement}
onChange={(e) => setRequirement(e.target.value)}
placeholder="请输入项目的具体需求、规模、时间、预算等信息..."
className="w-full h-48 px-4 py-3 border border-gray-300 rounded-xl text-gray-900 placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none transition-all"
style={{ fontFamily: 'system-ui, -apple-system, sans-serif' }}
/>
<div className="mt-2 flex justify-between items-center">
<span className="text-xs text-gray-500">{requirement.length} </span>
{selectedTemplate && (
<span className="text-xs bg-blue-100 text-blue-700 px-2 py-1 rounded-full">
{orderClassesData.orderClasses.find(o => o.id === selectedTemplate)?.name}
</span>
)}
</div>
</div>
{/* 底部按钮 */}
<div className="flex items-center justify-between">
<div className="text-sm text-gray-500">
<span className="inline-flex items-center gap-1">
<Sparkles className="w-4 h-4 text-yellow-500" />
{selectedTemplate ? (
<>
AI将基于您的需求生成专业的
<strong className="font-semibold text-gray-700">
{orderClassesData.orderClasses.find(o => o.id === selectedTemplate)?.template?.title || '解决方案'}
</strong>
</>
) : (
'AI将基于您的需求生成专业的解决方案'
)}
</span>
</div>
<div className="flex gap-3">
<button
onClick={onClose}
className="px-6 py-2.5 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors font-medium"
>
</button>
<button
onClick={handleSubmit}
disabled={!requirement.trim() || !selectedOrderClass}
className={`px-6 py-2.5 rounded-lg font-medium transition-all flex items-center gap-2 ${
requirement.trim() && selectedOrderClass
? 'bg-gradient-to-r from-blue-500 to-blue-600 text-white hover:shadow-lg transform hover:scale-105'
: 'bg-gray-300 text-gray-500 cursor-not-allowed'
}`}
>
<Zap className="w-4 h-4" />
</button>
</div>
</div>
</div>
</div>
</motion.div>
</>
)}
</AnimatePresence>
);
};
export default RequirementModal;