486 lines
17 KiB
TypeScript
486 lines
17 KiB
TypeScript
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;
|