Files
deerflow-code/web-code/pages/LightAppCenter.tsx
T
2026-05-27 19:43:15 +08:00

486 lines
17 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 { useTheme } from '../contexts/ThemeContext';
import {
BarChart,
FileText,
Table,
Search,
Send,
Sparkles,
Clock,
ChevronRight,
Bot,
Loader2,
Copy,
CheckCheck,
Download,
RefreshCw,
FileBarChart,
Database,
Brain,
PieChart,
LineChart,
FileSpreadsheet,
FileSearch,
BookOpen,
} from 'lucide-react';
interface LightAppCenterProps {
onNavigate: (page: string) => void;
initialApp?: 'analysis' | 'report' | 'data' | 'research';
}
type AppType = 'analysis' | 'report' | 'data' | 'research';
interface AppCard {
id: AppType;
title: string;
description: string;
icon: React.ElementType;
color: string;
}
const apps: AppCard[] = [
{
id: 'analysis',
title: '快速分析',
description: '对文本、数据进行快速分析处理,提取关键信息和洞察',
icon: BarChart,
color: 'blue',
},
{
id: 'report',
title: '报告生成',
description: '基于输入内容生成结构化分析报告,支持多种格式',
icon: FileText,
color: 'green',
},
{
id: 'data',
title: '数据处理',
description: '数据清洗、转换、统计和可视化处理',
icon: Table,
color: 'purple',
},
{
id: 'research',
title: '研究助手',
description: '辅助学术研究和资料整理,支持文献分析和摘要',
icon: Search,
color: 'orange',
},
];
const LightAppCenter: React.FC<LightAppCenterProps> = ({ onNavigate, initialApp }) => {
const { theme } = useTheme();
const isDark = theme === 'dark';
const [selectedApp, setSelectedApp] = useState<AppType | null>(initialApp || null);
const [input, setInput] = useState('');
const [isProcessing, setIsProcessing] = useState(false);
const [result, setResult] = useState('');
const [copied, setCopied] = useState(false);
const [activeTab, setActiveTab] = useState<'input' | 'history'>('input');
const handleAppSelect = (app: AppCard) => {
setSelectedApp(app.id);
setInput('');
setResult('');
};
const handleSubmit = async () => {
if (!input.trim() || !selectedApp) return;
setIsProcessing(true);
setResult('');
// 模拟处理过程
await new Promise(resolve => setTimeout(resolve, 1500));
// 根据不同应用生成模拟结果
let mockResult = '';
switch (selectedApp) {
case 'analysis':
mockResult = `【分析结果】
1. 关键主题
• 主题A:核心概念和定义
• 主题B:应用场景和实践
• 主题C:发展趋势和展望
2. 情感分析
• 整体倾向:中性偏正面
• 关键情感词:创新、发展、应用
3. 关键实体
• 机构:示例机构
• 人物:相关专家
• 地点:主要应用区域
4. 重要数据
• 增长率:15-20%
• 覆盖范围:多个领域
• 时间周期:持续进行`;
break;
case 'report':
mockResult = `# 分析报告
## 概述
基于提供的内容,生成以下分析报告。
## 主要发现
### 1. 核心内容
详细描述主要发现和观察结果...
### 2. 深入分析
对关键点进行深入分析和解读...
### 3. 结论建议
基于分析结果提出建议和行动方案...
## 附录
- 数据来源
- 分析方法
- 局限性说明`;
break;
case 'data':
mockResult = `【数据处理结果】
| 指标 | 数值 | 变化 |
|------|------|------|
| 样本量 | 1,234 | +12% |
| 准确率 | 95.6% | +3.2% |
| 覆盖率 | 89.3% | +8.7% |
统计摘要:
• 总计处理 1,234 条记录
• 有效数据 1,156 条(93.7%)
• 异常数据 78 条(6.3%)
图表数据已准备好可视化`;
break;
case 'research':
mockResult = `【研究摘要】
## 文献概览
找到相关研究文献 12 篇,主要涉及以下方向:
### 核心观点
1. 研究方向A - 理论基础
2. 研究方向B - 方法论
3. 研究方向C - 实证应用
### 关键结论
• 结论1:...
• 结论2:...
• 结论3:...
### 研究空白
当前研究存在以下空白点,可作为进一步探索的方向...
### 建议阅读
1. 《核心文献一》- 理论基础
2. 《核心文献二》- 方法创新
3. 《核心文献三》- 实践应用`;
break;
}
setResult(mockResult);
setIsProcessing(false);
};
const handleCopy = () => {
navigator.clipboard.writeText(result);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const getColorClasses = (color: string) => {
const colors: Record<string, { bg: string; text: string; border: string; light: string }> = {
blue: {
bg: isDark ? 'bg-blue-500/20' : 'bg-blue-50',
text: isDark ? 'text-blue-400' : 'text-blue-600',
border: isDark ? 'border-blue-500/30' : 'border-blue-200',
light: isDark ? 'hover:bg-blue-500/30' : 'hover:bg-blue-100',
},
green: {
bg: isDark ? 'bg-green-500/20' : 'bg-green-50',
text: isDark ? 'text-green-400' : 'text-green-600',
border: isDark ? 'border-green-500/30' : 'border-green-200',
light: isDark ? 'hover:bg-green-500/30' : 'hover:bg-green-100',
},
purple: {
bg: isDark ? 'bg-purple-500/20' : 'bg-purple-50',
text: isDark ? 'text-purple-400' : 'text-purple-600',
border: isDark ? 'border-purple-500/30' : 'border-purple-200',
light: isDark ? 'hover:bg-purple-500/30' : 'hover:bg-purple-100',
},
orange: {
bg: isDark ? 'bg-orange-500/20' : 'bg-orange-50',
text: isDark ? 'text-orange-400' : 'text-orange-600',
border: isDark ? 'border-orange-500/30' : 'border-orange-200',
light: isDark ? 'hover:bg-orange-500/30' : 'hover:bg-orange-100',
},
};
return colors[color];
};
const selectedAppData = apps.find(a => a.id === selectedApp);
return (
<div className="space-y-6">
{/* 页面标题 */}
<div className="flex items-center justify-between">
<div>
<h1 className={`text-2xl font-bold theme-text ${isDark ? 'text-white' : 'text-gray-900'}`}>
轻应用中心
</h1>
<p className={`mt-1 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
快速调用工具完成临时分析需求
</p>
</div>
{selectedApp && (
<button
onClick={() => setSelectedApp(null)}
className={`px-4 py-2 rounded-lg text-sm font-medium transition-all duration-200 ${
isDark
? 'bg-slate-700 text-slate-300 hover:bg-slate-600'
: 'bg-gray-100 text-gray-600 hover:bg-gray-200'
}`}
>
返回应用列表
</button>
)}
</div>
{/* 应用选择卡片 */}
{!selectedApp && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{apps.map((app) => {
const Icon = app.icon;
const colors = getColorClasses(app.color);
return (
<button
key={app.id}
onClick={() => handleAppSelect(app)}
className={`p-6 rounded-xl border transition-all duration-200 text-left group ${
isDark
? `bg-slate-800/50 ${colors.border} hover:${colors.bg}`
: `bg-white ${colors.border} hover:${colors.bg}`
}`}
>
<div className="flex items-start gap-4">
<div className={`p-3 rounded-lg ${colors.bg}`}>
<Icon className={`w-6 h-6 ${colors.text}`} />
</div>
<div className="flex-1">
<h3 className={`font-semibold group-hover:${colors.text} ${isDark ? 'text-white' : 'text-gray-900'}`}>
{app.title}
</h3>
<p className={`mt-1 text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
{app.description}
</p>
</div>
<ChevronRight className={`w-5 h-5 ${isDark ? 'text-slate-500' : 'text-gray-400'} group-hover:${colors.text}`} />
</div>
</button>
);
})}
</div>
)}
{/* 应用工作区 */}
{selectedApp && selectedAppData && (
<div className={`rounded-xl border overflow-hidden ${
isDark ? 'bg-slate-800/50 border-slate-700' : 'bg-white border-gray-200'
}`}>
{/* 应用标题栏 */}
<div className={`px-6 py-4 border-b flex items-center gap-3 ${
isDark ? 'border-slate-700 bg-slate-800' : 'border-gray-200 bg-gray-50'
}`}>
<div className={`p-2 rounded-lg ${getColorClasses(selectedAppData.color).bg}`}>
{React.createElement(selectedAppData.icon, {
className: `w-5 h-5 ${getColorClasses(selectedAppData.color).text}`
})}
</div>
<div>
<h2 className={`font-semibold ${isDark ? 'text-white' : 'text-gray-900'}`}>
{selectedAppData.title}
</h2>
<p className={`text-xs ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
{selectedAppData.description}
</p>
</div>
</div>
{/* 标签页 */}
<div className={`px-6 border-b ${isDark ? 'border-slate-700' : 'border-gray-200'}`}>
<div className="flex gap-4">
<button
onClick={() => setActiveTab('input')}
className={`py-3 px-1 text-sm font-medium border-b-2 transition-colors ${
activeTab === 'input'
? isDark
? 'border-blue-500 text-blue-400'
: 'border-red-500 text-red-600'
: isDark
? 'border-transparent text-slate-400 hover:text-slate-300'
: 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
输入分析
</button>
<button
onClick={() => setActiveTab('history')}
className={`py-3 px-1 text-sm font-medium border-b-2 transition-colors ${
activeTab === 'history'
? isDark
? 'border-blue-500 text-blue-400'
: 'border-red-500 text-red-600'
: isDark
? 'border-transparent text-slate-400 hover:text-slate-300'
: 'border-transparent text-gray-500 hover:text-gray-700'
}`}
>
历史记录
</button>
</div>
</div>
<div className="p-6">
{activeTab === 'input' ? (
<div className="space-y-4">
{/* 输入区域 */}
<div>
<label className={`block text-sm font-medium mb-2 ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
输入内容
</label>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder={`请输入需要${selectedAppData.title}的内容...`}
rows={6}
className={`w-full px-4 py-3 rounded-lg border transition-colors focus:outline-none focus:ring-2 resize-none ${
isDark
? 'bg-slate-900 border-slate-600 text-slate-200 placeholder-slate-500 focus:border-blue-500 focus:ring-blue-500/20'
: 'bg-gray-50 border-gray-300 text-gray-900 placeholder-gray-400 focus:border-red-500 focus:ring-red-500/20'
}`}
/>
</div>
{/* 操作按钮 */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<button className={`p-2 rounded-lg ${isDark ? 'hover:bg-slate-700 text-slate-400' : 'hover:bg-gray-100 text-gray-500'}`}>
<RefreshCw className="w-4 h-4" />
</button>
<button className={`p-2 rounded-lg ${isDark ? 'hover:bg-slate-700 text-slate-400' : 'hover:bg-gray-100 text-gray-500'}`}>
<FileBarChart className="w-4 h-4" />
</button>
<button className={`p-2 rounded-lg ${isDark ? 'hover:bg-slate-700 text-slate-400' : 'hover:bg-gray-100 text-gray-500'}`}>
<Database className="w-4 h-4" />
</button>
</div>
<button
onClick={handleSubmit}
disabled={!input.trim() || isProcessing}
className={`px-6 py-2.5 rounded-lg font-medium flex items-center gap-2 transition-all duration-200 ${
!input.trim() || isProcessing
? isDark
? 'bg-slate-700 text-slate-500 cursor-not-allowed'
: 'bg-gray-200 text-gray-400 cursor-not-allowed'
: isDark
? 'bg-blue-600 text-white hover:bg-blue-500'
: 'bg-red-500 text-white hover:bg-red-600'
}`}
>
{isProcessing ? (
<>
<Loader2 className="w-4 h-4 animate-spin" />
处理中...
</>
) : (
<>
<Send className="w-4 h-4" />
开始处理
</>
)}
</button>
</div>
{/* 结果区域 */}
{result && (
<div className={`mt-6 p-4 rounded-lg border ${
isDark ? 'bg-slate-900 border-slate-700' : 'bg-gray-50 border-gray-200'
}`}>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Sparkles className={`w-4 h-4 ${isDark ? 'text-blue-400' : 'text-red-500'}`} />
<span className={`text-sm font-medium ${isDark ? 'text-slate-300' : 'text-gray-700'}`}>
处理结果
</span>
</div>
<div className="flex items-center gap-2">
<button
onClick={handleCopy}
className={`p-1.5 rounded-lg transition-colors ${
isDark ? 'hover:bg-slate-700 text-slate-400' : 'hover:bg-gray-200 text-gray-500'
}`}
>
{copied ? (
<CheckCheck className="w-4 h-4 text-green-500" />
) : (
<Copy className="w-4 h-4" />
)}
</button>
<button className={`p-1.5 rounded-lg transition-colors ${
isDark ? 'hover:bg-slate-700 text-slate-400' : 'hover:bg-gray-200 text-gray-500'
}`}>
<Download className="w-4 h-4" />
</button>
</div>
</div>
<pre className={`whitespace-pre-wrap text-sm font-mono leading-relaxed ${
isDark ? 'text-slate-300' : 'text-gray-600'
}`}>
{result}
</pre>
</div>
)}
</div>
) : (
<div className="text-center py-12">
<Clock className={`w-12 h-12 mx-auto mb-4 ${isDark ? 'text-slate-600' : 'text-gray-300'}`} />
<p className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>
暂无历史记录
</p>
</div>
)}
</div>
</div>
)}
{/* 提示信息 */}
{!selectedApp && (
<div className={`p-4 rounded-lg border ${
isDark ? 'bg-blue-500/10 border-blue-500/30' : 'bg-blue-50 border-blue-200'
}`}>
<div className="flex items-start gap-3">
<Sparkles className={`w-5 h-5 mt-0.5 ${isDark ? 'text-blue-400' : 'text-blue-500'}`} />
<div>
<p className={`text-sm font-medium ${isDark ? 'text-blue-300' : 'text-blue-800'}`}>
关于轻应用中心
</p>
<p className={`mt-1 text-sm ${isDark ? 'text-blue-400/80' : 'text-blue-700'}`}>
轻应用中心提供了一系列快速分析工具,适合处理临时性的分析需求。相比完整的任务级应用,轻应用更加轻量便捷,可以快速调用多种工具完成分析工作。
</p>
</div>
</div>
</div>
)}
</div>
);
};
export default LightAppCenter;