fix: 修复TypeScript配置错误并更新项目文档
详细说明: - 修复了@n8n/config包的TypeScript配置错误 - 移除了不存在的jest-expect-message类型引用 - 清理了所有TypeScript构建缓存 - 更新了可行性分析文档,添加了技术实施方案 - 更新了Agent prompt文档 - 添加了会展策划工作流文档 - 包含了n8n-chinese-translation子项目 - 添加了exhibition-demo展示系统框架
This commit is contained in:
104
web_frontend/exhibition-demo/src/components/ContentGenerator.tsx
Normal file
104
web_frontend/exhibition-demo/src/components/ContentGenerator.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { FileText, Image, Loader2 } from 'lucide-react';
|
||||
|
||||
interface ContentGeneratorProps {
|
||||
content?: string;
|
||||
images?: string[];
|
||||
speed?: number;
|
||||
}
|
||||
|
||||
const ContentGenerator: React.FC<ContentGeneratorProps> = ({
|
||||
content = "正在生成会展策划方案内容...",
|
||||
images = [],
|
||||
speed = 35
|
||||
}) => {
|
||||
const [displayedContent, setDisplayedContent] = useState('');
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const [loadingImages, setLoadingImages] = useState<Set<number>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
if (currentIndex < content.length) {
|
||||
const timeout = setTimeout(() => {
|
||||
setDisplayedContent(prev => prev + content[currentIndex]);
|
||||
setCurrentIndex(prev => prev + 1);
|
||||
}, speed);
|
||||
return () => clearTimeout(timeout);
|
||||
}
|
||||
}, [currentIndex, content, speed]);
|
||||
|
||||
const handleImageLoad = (index: number) => {
|
||||
setLoadingImages(prev => {
|
||||
const newSet = new Set(prev);
|
||||
newSet.delete(index);
|
||||
return newSet;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Text Content */}
|
||||
<div className="p-4 bg-neutral-50 dark:bg-neutral-900 rounded-lg">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<FileText className="w-4 h-4 text-blue-500" />
|
||||
<span className="text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
||||
生成中...
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="font-mono text-sm text-neutral-700 dark:text-neutral-300 whitespace-pre-wrap">
|
||||
{displayedContent}
|
||||
{currentIndex < content.length && (
|
||||
<span className="inline-block w-2 h-4 bg-blue-500 animate-pulse ml-1" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Images */}
|
||||
{images.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Image className="w-4 h-4 text-purple-500" />
|
||||
<span className="text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
||||
相关图片
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
{images.map((src, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
transition={{ delay: index * 0.2 }}
|
||||
className="relative aspect-video rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-800"
|
||||
>
|
||||
{loadingImages.has(index) && (
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<Loader2 className="w-6 h-6 animate-spin text-neutral-400" />
|
||||
</div>
|
||||
)}
|
||||
<img
|
||||
src={src}
|
||||
alt={`Generated content ${index + 1}`}
|
||||
className="w-full h-full object-cover"
|
||||
onLoad={() => handleImageLoad(index)}
|
||||
onLoadStart={() => setLoadingImages(prev => new Set(prev).add(index))}
|
||||
/>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Stats */}
|
||||
<div className="flex items-center gap-6 text-xs text-neutral-500 dark:text-neutral-400">
|
||||
<span>字符: {displayedContent.length}</span>
|
||||
<span>速度: {speed}字/秒</span>
|
||||
<span>进度: {Math.round((currentIndex / content.length) * 100)}%</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentGenerator;
|
||||
Reference in New Issue
Block a user