Files
Agent-n8n/web_frontend/exhibition-demo/src/components/RequirementModal.tsx

279 lines
13 KiB
TypeScript
Raw Normal View History

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长三角国际新能源汽车与智能交通产业博览会
20241018-20
50,00035050,000
`,
food: `展会名称2024国际健康食品与轻食产业博览会
20241115-17
30,00020030,000
广`,
finance: `展会名称2024国际美妆产业与电商创新博览会
广
2024128-10
40,00030040,000
`,
dev: `展会名称2024国际教育科技与智慧学习博览会
20241025-27
35,00025035,000
AI赋能教育
线`,
manufacturing: `展会名称2024国际智能制造与工业自动化博览会
20241120-22
45,00030040,000
PLC控制`,
design: `展会名称2024国际文创设计与视觉艺术博览会
2024115-7
25,00015025,000
`,
logistics: `展会名称2024国际智慧物流与供应链博览会
20241215-17
50,00040050,000
AGV系统`,
civil: `展会名称2024国际建筑科技与绿色建造博览会
20241128-30
35,00020030,000
绿
BIM技术`,
health: `展会名称2024国际大健康产业与医疗创新博览会
20241222-24
40,00030035,000
`,
energy: `展会名称2024国际新能源与光伏产业博览会
西
20241112-14
38,00028035,000
绿
`,
chemical: `展会名称2024国际新材料与精细化工博览会
2024125-7
30,00020025,000
`,
environment: `展会名称2024国际环保科技与生态治理博览会
20241125-27
32,00022028,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="bg-gradient-to-r from-blue-600 to-purple-600 p-6 text-white">
<div className="flex items-center justify-between">
<div>
<h2 className="text-2xl font-bold mb-2"></h2>
<p className="text-blue-100"></p>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-white/20 rounded-lg transition-colors"
>
<X className="w-6 h-6" />
</button>
</div>
</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-600 to-purple-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;