603 lines
25 KiB
TypeScript
603 lines
25 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Plus, Search, Eye, Play, Pause, Trash2, Target, Clock, User, ChevronRight, Filter, Bot, Workflow, Users, MoreHorizontal, Edit, Copy, FileText } from 'lucide-react';
|
|
import { useTheme } from '@/contexts/ThemeContext';
|
|
import { PageType } from '@/components/Sidebar';
|
|
|
|
interface TaskListProps {
|
|
onViewWorkspace: (id: string) => void;
|
|
onNavigate: (page: PageType) => void;
|
|
}
|
|
|
|
interface Task {
|
|
id: string;
|
|
name: string;
|
|
type: 'single' | 'scene' | 'consultation';
|
|
agent?: string;
|
|
scene?: string;
|
|
participants?: string[];
|
|
status: 'draft' | 'pending' | 'running' | 'paused' | 'blocked' | 'completed';
|
|
currentPhase: string;
|
|
summary?: string;
|
|
creator: string;
|
|
createTime: string;
|
|
updateTime: string;
|
|
column: 'unanalyzed' | 'analyzing' | 'completed';
|
|
}
|
|
|
|
const TaskList: React.FC<TaskListProps> = ({ onViewWorkspace, onNavigate }) => {
|
|
const { theme } = useTheme();
|
|
const isDark = theme === 'dark';
|
|
|
|
const [tasks] = useState<Task[]>([
|
|
// 未分析列
|
|
{
|
|
id: '8',
|
|
name: '端午节品牌传播方案',
|
|
type: 'scene',
|
|
scene: '宣传策略生成',
|
|
status: 'draft',
|
|
currentPhase: '待配置',
|
|
summary: '针对端午节品牌活动制定完整传播策略方案',
|
|
creator: '李策划',
|
|
createTime: '2026-03-19 16:00',
|
|
updateTime: '2026-03-19 16:00',
|
|
column: 'unanalyzed',
|
|
},
|
|
{
|
|
id: '9',
|
|
name: '新品上市用户调研',
|
|
type: 'single',
|
|
agent: 'AudienceAgent',
|
|
status: 'pending',
|
|
currentPhase: '待启动',
|
|
summary: '对新品目标用户进行画像分析',
|
|
creator: '王运营',
|
|
createTime: '2026-03-19 14:30',
|
|
updateTime: '2026-03-19 15:00',
|
|
column: 'unanalyzed',
|
|
},
|
|
// 分析中列
|
|
{
|
|
id: '1',
|
|
name: '五四青年节宣传活动策略',
|
|
type: 'scene',
|
|
scene: '宣传策略生成',
|
|
status: 'running',
|
|
currentPhase: '行为分析',
|
|
summary: '正在按场景模板执行目标、受众、行为、叙事等分析...',
|
|
creator: '张策略',
|
|
createTime: '2026-03-19 10:30',
|
|
updateTime: '2026-03-19 15:45',
|
|
column: 'analyzing',
|
|
},
|
|
{
|
|
id: '7',
|
|
name: '品牌升级叙事方向研讨',
|
|
type: 'consultation',
|
|
participants: ['GoalAgent', 'NarrativeAgent', 'RiskAgent'],
|
|
status: 'running',
|
|
currentPhase: '第2轮讨论中',
|
|
summary: '围绕宣传方向、叙事方式和受众切入点开展多视角会商...',
|
|
creator: '王策划',
|
|
createTime: '2026-03-19 15:00',
|
|
updateTime: '2026-03-19 16:30',
|
|
column: 'analyzing',
|
|
},
|
|
{
|
|
id: '3',
|
|
name: '年度品牌升级方案推演',
|
|
type: 'scene',
|
|
scene: '宣传方案推演',
|
|
status: 'paused',
|
|
currentPhase: '叙事分析',
|
|
summary: '任务已暂停,等待人工介入确认叙事方向',
|
|
creator: '王策划',
|
|
createTime: '2026-03-17 14:00',
|
|
updateTime: '2026-03-19 11:30',
|
|
column: 'analyzing',
|
|
},
|
|
// 已完成列
|
|
{
|
|
id: '2',
|
|
name: '新产品发布会舆情应对预案',
|
|
type: 'scene',
|
|
scene: '舆情应对策略',
|
|
status: 'completed',
|
|
currentPhase: '已完成',
|
|
summary: '已完成舆情应对策略方案生成',
|
|
creator: '李分析师',
|
|
createTime: '2026-03-18 09:00',
|
|
updateTime: '2026-03-18 16:20',
|
|
column: 'completed',
|
|
},
|
|
{
|
|
id: '4',
|
|
name: '五四青年节受众快速分析',
|
|
type: 'single',
|
|
agent: 'AudienceAgent',
|
|
status: 'completed',
|
|
currentPhase: '已完成',
|
|
summary: '已完成目标受众识别、关切提炼和阻力分析',
|
|
creator: '赵运营',
|
|
createTime: '2026-03-19 09:00',
|
|
updateTime: '2026-03-19 09:15',
|
|
column: 'completed',
|
|
},
|
|
{
|
|
id: '6',
|
|
name: '五四青年节宣传策略会商',
|
|
type: 'consultation',
|
|
participants: ['GoalAgent', 'AudienceAgent', 'NarrativeAgent', 'RiskAgent'],
|
|
status: 'completed',
|
|
currentPhase: '已完成',
|
|
summary: '已完成多智能体会商,形成结论与分歧报告',
|
|
creator: '赵运营',
|
|
createTime: '2026-03-19 14:30',
|
|
updateTime: '2026-03-19 16:00',
|
|
column: 'completed',
|
|
},
|
|
]);
|
|
|
|
const [activeTab, setActiveTab] = useState<'all' | 'unanalyzed' | 'analyzing' | 'completed'>('all');
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const [modeFilter, setModeFilter] = useState<'all' | 'single' | 'scene' | 'consultation'>('all');
|
|
|
|
const getTypeConfig = (type: string) => {
|
|
if (isDark) {
|
|
switch (type) {
|
|
case 'single':
|
|
return { label: '单智能体', color: 'bg-cyan-500/20 text-cyan-400', icon: Bot };
|
|
case 'scene':
|
|
return { label: '场景执行', color: 'bg-purple-500/20 text-purple-400', icon: Workflow };
|
|
case 'consultation':
|
|
return { label: '多智能体会商', color: 'bg-orange-500/20 text-orange-400', icon: Users };
|
|
default:
|
|
return { label: '未知', color: 'bg-slate-500/20 text-slate-400', icon: Bot };
|
|
}
|
|
} else {
|
|
switch (type) {
|
|
case 'single':
|
|
return { label: '单智能体', color: 'bg-red-100 text-red-600', icon: Bot };
|
|
case 'scene':
|
|
return { label: '场景执行', color: 'bg-red-100 text-red-600', icon: Workflow };
|
|
case 'consultation':
|
|
return { label: '多智能体会商', color: 'bg-red-100 text-red-600', icon: Users };
|
|
default:
|
|
return { label: '未知', color: 'bg-gray-100 text-gray-600', icon: Bot };
|
|
}
|
|
}
|
|
};
|
|
|
|
const getStatusConfig = (status: string) => {
|
|
if (isDark) {
|
|
switch (status) {
|
|
case 'draft':
|
|
return { label: '草稿', color: 'bg-slate-500/20 text-slate-400' };
|
|
case 'pending':
|
|
return { label: '待启动', color: 'bg-slate-500/20 text-slate-400' };
|
|
case 'running':
|
|
return { label: '运行中', color: 'bg-blue-500/20 text-blue-400' };
|
|
case 'paused':
|
|
return { label: '已暂停', color: 'bg-yellow-500/20 text-yellow-400' };
|
|
case 'blocked':
|
|
return { label: '阻塞中', color: 'bg-red-500/20 text-red-400' };
|
|
case 'completed':
|
|
return { label: '已完成', color: 'bg-green-500/20 text-green-400' };
|
|
default:
|
|
return { label: '未知', color: 'bg-slate-500/20 text-slate-400' };
|
|
}
|
|
} else {
|
|
switch (status) {
|
|
case 'draft':
|
|
return { label: '草稿', color: 'bg-gray-100 text-gray-600' };
|
|
case 'pending':
|
|
return { label: '待启动', color: 'bg-gray-100 text-gray-600' };
|
|
case 'running':
|
|
return { label: '运行中', color: 'bg-red-100 text-red-600' };
|
|
case 'paused':
|
|
return { label: '已暂停', color: 'bg-yellow-100 text-yellow-600' };
|
|
case 'blocked':
|
|
return { label: '阻塞中', color: 'bg-red-100 text-red-600' };
|
|
case 'completed':
|
|
return { label: '已完成', color: 'bg-green-100 text-green-600' };
|
|
default:
|
|
return { label: '未知', color: 'bg-gray-100 text-gray-600' };
|
|
}
|
|
}
|
|
};
|
|
|
|
const filteredTasks = tasks.filter(task => {
|
|
const matchesTab = activeTab === 'all' || task.column === activeTab;
|
|
const matchesSearch = task.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
task.id.toLowerCase().includes(searchQuery.toLowerCase());
|
|
const matchesMode = modeFilter === 'all' || task.type === modeFilter;
|
|
return matchesTab && matchesSearch && matchesMode;
|
|
});
|
|
|
|
const unanalyzedTasks = filteredTasks.filter(t => t.column === 'unanalyzed');
|
|
const analyzingTasks = filteredTasks.filter(t => t.column === 'analyzing');
|
|
const completedTasks = filteredTasks.filter(t => t.column === 'completed');
|
|
|
|
const totalCount = tasks.length;
|
|
const unanalyzedCount = tasks.filter(t => t.column === 'unanalyzed').length;
|
|
const analyzingCount = tasks.filter(t => t.column === 'analyzing').length;
|
|
const completedCount = tasks.filter(t => t.column === 'completed').length;
|
|
|
|
const handleTaskClick = (task: Task) => {
|
|
if (task.column === 'completed') {
|
|
if (task.type === 'consultation') {
|
|
onNavigate('task-consult-result');
|
|
} else {
|
|
onNavigate('strategy-result');
|
|
}
|
|
} else if (task.column === 'analyzing') {
|
|
if (task.type === 'scene') {
|
|
onNavigate('task-scene');
|
|
} else if (task.type === 'consultation') {
|
|
onNavigate('task-consult');
|
|
} else {
|
|
onNavigate('task-single');
|
|
}
|
|
} else {
|
|
// 未分析 - 进入创建/配置
|
|
onNavigate('task-create');
|
|
}
|
|
};
|
|
|
|
const TaskCard = ({ task }: { task: Task }) => {
|
|
const typeConfig = getTypeConfig(task.type);
|
|
const statusConfig = getStatusConfig(task.status);
|
|
const TypeIcon = typeConfig.icon;
|
|
|
|
return (
|
|
<div
|
|
className={`rounded-xl p-4 hover:border-red-400 transition-all duration-200 group cursor-pointer theme-card border ${
|
|
isDark
|
|
? 'bg-slate-800/40 backdrop-blur-xl border-blue-800/30 hover:border-blue-500/50'
|
|
: 'bg-white border-red-100 hover:shadow-md shadow-red-100'
|
|
}`}
|
|
onClick={() => handleTaskClick(task)}
|
|
>
|
|
{/* 卡片头部:模式标签 + 状态标签 */}
|
|
<div className="flex items-center justify-between mb-3">
|
|
<span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded text-xs font-medium ${typeConfig.color}`}>
|
|
<TypeIcon className="w-3 h-3" />
|
|
{typeConfig.label}
|
|
</span>
|
|
<span className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${statusConfig.color}`}>
|
|
{statusConfig.label}
|
|
</span>
|
|
</div>
|
|
|
|
{/* 任务名称 */}
|
|
<h3 className={`font-semibold text-sm mb-1 line-clamp-2 group-hover:text-red-500 transition-colors ${
|
|
isDark ? 'text-white' : 'text-gray-900'
|
|
}`}>
|
|
{task.name}
|
|
</h3>
|
|
|
|
{/* 任务编号 */}
|
|
<p className={`text-xs mb-2 ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>TASK-{task.id.padStart(4, '0')}</p>
|
|
|
|
{/* 任务摘要 */}
|
|
<p className={`text-xs mb-3 line-clamp-2 ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>{task.summary}</p>
|
|
|
|
{/* 补充信息 */}
|
|
<div className="space-y-1.5 mb-3">
|
|
{task.type === 'single' && (
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Bot className={`w-3 h-3 ${isDark ? 'text-cyan-400' : 'text-red-500'}`} />
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-500'}>执行智能体:</span>
|
|
<span className={isDark ? 'text-cyan-400' : 'text-red-600'}>{task.agent}</span>
|
|
</div>
|
|
)}
|
|
{task.type === 'scene' && (
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Workflow className={`w-3 h-3 ${isDark ? 'text-purple-400' : 'text-red-500'}`} />
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-500'}>关联场景:</span>
|
|
<span className={isDark ? 'text-purple-400' : 'text-red-600'}>{task.scene}</span>
|
|
</div>
|
|
)}
|
|
{task.type === 'consultation' && (
|
|
<>
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Users className={`w-3 h-3 ${isDark ? 'text-orange-400' : 'text-red-500'}`} />
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-500'}>参与智能体:</span>
|
|
<span className={isDark ? 'text-orange-400' : 'text-red-600'}>{task.participants?.length || 0}个</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Clock className={`w-3 h-3 ${isDark ? 'text-slate-500' : 'text-gray-400'}`} />
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-500'}>当前轮次:</span>
|
|
<span className={isDark ? 'text-slate-300' : 'text-gray-700'}>{task.currentPhase}</span>
|
|
</div>
|
|
</>
|
|
)}
|
|
{task.column !== 'unanalyzed' && task.column !== 'completed' && (
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Target className={`w-3 h-3 ${isDark ? 'text-slate-500' : 'text-gray-400'}`} />
|
|
<span className={isDark ? 'text-slate-400' : 'text-gray-500'}>当前阶段:</span>
|
|
<span className={isDark ? 'text-slate-300' : 'text-gray-700'}>{task.currentPhase}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 时间信息 */}
|
|
<div className={`flex items-center justify-between text-xs pt-3 border-t ${
|
|
isDark
|
|
? 'text-slate-500 border-blue-800/30'
|
|
: 'text-gray-400 border-red-100'
|
|
}`}>
|
|
<div className="flex items-center gap-1.5">
|
|
<User className="w-3 h-3" />
|
|
<span>{task.creator}</span>
|
|
</div>
|
|
<span>{task.column === 'completed' ? `完成于 ${task.updateTime}` : `更新于 ${task.updateTime}`}</span>
|
|
</div>
|
|
|
|
{/* 操作按钮区 */}
|
|
<div className={`flex items-center gap-2 mt-3 pt-3 border-t ${
|
|
isDark ? 'border-blue-800/30' : 'border-red-100'
|
|
}`}>
|
|
{task.column === 'unanalyzed' && (
|
|
<>
|
|
<button className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-white rounded-lg text-xs font-medium transition-colors ${
|
|
isDark
|
|
? 'bg-blue-600 hover:bg-blue-500'
|
|
: 'bg-red-600 hover:bg-red-500 shadow-md'
|
|
}`}>
|
|
<Play className="w-3 h-3" />
|
|
开始分析
|
|
</button>
|
|
<button className={`p-1.5 rounded-lg transition-colors ${
|
|
isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
|
}`} title="编辑">
|
|
<Edit className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-red-400'}`} />
|
|
</button>
|
|
</>
|
|
)}
|
|
{(task.column === 'analyzing') && (
|
|
<>
|
|
<button className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-white rounded-lg text-xs font-medium transition-colors ${
|
|
isDark
|
|
? 'bg-blue-600 hover:bg-blue-500'
|
|
: 'bg-red-600 hover:bg-red-500 shadow-md'
|
|
}`}>
|
|
<Play className="w-3 h-3" />
|
|
继续处理
|
|
</button>
|
|
<button className={`px-2 py-1.5 rounded-lg text-xs transition-colors ${
|
|
isDark
|
|
? 'hover:bg-slate-700/50 border border-blue-800/30 text-slate-300'
|
|
: 'hover:bg-red-50 border border-red-200 text-red-600'
|
|
}`}>
|
|
查看进展
|
|
</button>
|
|
</>
|
|
)}
|
|
{task.column === 'completed' && (
|
|
<>
|
|
<button className={`flex-1 flex items-center justify-center gap-1.5 px-3 py-1.5 text-white rounded-lg text-xs font-medium transition-colors ${
|
|
isDark
|
|
? 'bg-green-600 hover:bg-green-500'
|
|
: 'bg-green-600 hover:bg-green-500 shadow-md'
|
|
}`}>
|
|
<Eye className="w-3 h-3" />
|
|
查看结果
|
|
</button>
|
|
<button className={`px-2 py-1.5 rounded-lg text-xs transition-colors ${
|
|
isDark
|
|
? 'hover:bg-slate-700/50 border border-blue-800/30 text-slate-300'
|
|
: 'hover:bg-red-50 border border-red-200 text-red-600'
|
|
}`}>
|
|
导出
|
|
</button>
|
|
</>
|
|
)}
|
|
<button className={`p-1.5 rounded-lg transition-colors ${
|
|
isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
|
}`} title="更多">
|
|
<MoreHorizontal className={`w-4 h-4 ${isDark ? 'text-slate-400' : 'text-red-400'}`} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const ColumnHeader = ({ title, count, color }: { title: string; count: number; color: string }) => (
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-2">
|
|
<div className={`w-2 h-2 rounded-full ${color}`} />
|
|
<h2 className={`font-semibold text-sm ${isDark ? 'text-white' : 'text-gray-900'}`}>{title}</h2>
|
|
<span className={`px-2 py-0.5 rounded-full text-xs ${
|
|
isDark ? 'bg-slate-700/50 text-slate-400' : 'bg-red-50 text-red-500'
|
|
}`}>{count}</span>
|
|
</div>
|
|
<button className={`p-1 rounded transition-colors ${
|
|
isDark ? 'hover:bg-slate-700/50' : 'hover:bg-red-50'
|
|
}`}>
|
|
<ChevronRight className={`w-4 h-4 ${isDark ? 'text-slate-500' : 'text-red-400'}`} />
|
|
</button>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="h-full flex flex-col">
|
|
{/* 顶部工具栏 */}
|
|
<div className={`rounded-xl p-4 flex-shrink-0 mb-4 theme-card border ${
|
|
isDark
|
|
? 'bg-slate-800/30 backdrop-blur-xl border-blue-800/30'
|
|
: 'bg-white border-red-100 shadow-sm'
|
|
}`}>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h1 className={`text-xl font-bold ${isDark ? 'text-white' : 'text-gray-900'}`}>任务中心</h1>
|
|
<button
|
|
onClick={() => onNavigate('task-create')}
|
|
className={`flex items-center gap-2 px-4 py-2 text-white rounded-lg text-sm font-medium transition-colors ${
|
|
isDark
|
|
? 'bg-blue-600 hover:bg-blue-500'
|
|
: 'bg-red-600 hover:bg-red-500 shadow-md'
|
|
}`}
|
|
>
|
|
<Plus className="w-4 h-4" />
|
|
新建任务
|
|
</button>
|
|
</div>
|
|
|
|
{/* 搜索和筛选 */}
|
|
<div className="flex items-center gap-4">
|
|
<div className="relative flex-1 max-w-md">
|
|
<Search className={`absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 ${isDark ? 'text-slate-500' : 'text-red-400'}`} />
|
|
<input
|
|
type="text"
|
|
placeholder="搜索任务名称 / 任务编号 / 关键词"
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
className={`w-full pl-10 pr-4 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 transition-colors theme-transition ${
|
|
isDark
|
|
? 'bg-slate-900/50 border-blue-800/30 text-white placeholder-slate-500'
|
|
: 'bg-white border-red-200 text-gray-900 placeholder-red-300'
|
|
}`}
|
|
/>
|
|
</div>
|
|
<select
|
|
value={modeFilter}
|
|
onChange={(e) => setModeFilter(e.target.value as any)}
|
|
className={`px-4 py-2 border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-red-500/20 cursor-pointer theme-transition ${
|
|
isDark
|
|
? 'bg-slate-900/50 border-blue-800/30 text-slate-300'
|
|
: 'bg-white border-red-200 text-gray-700'
|
|
}`}
|
|
>
|
|
<option value="all">全部模式</option>
|
|
<option value="single">单智能体</option>
|
|
<option value="scene">场景执行</option>
|
|
<option value="consultation">多智能体会商</option>
|
|
</select>
|
|
<button className={`flex items-center gap-2 px-4 py-2 border rounded-lg text-sm transition-colors theme-transition ${
|
|
isDark
|
|
? 'bg-slate-800/50 border-blue-800/30 text-slate-300 hover:bg-slate-700/50'
|
|
: 'bg-white border-red-200 text-gray-700 hover:bg-red-50'
|
|
}`}>
|
|
<Clock className="w-4 h-4" />
|
|
时间范围
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 统计概览栏 */}
|
|
<div className="grid grid-cols-4 gap-4 mb-4 flex-shrink-0">
|
|
<button
|
|
onClick={() => setActiveTab('all')}
|
|
className={`p-4 rounded-xl border transition-all duration-200 ${
|
|
activeTab === 'all'
|
|
? isDark
|
|
? 'bg-blue-600/20 border-blue-500/50'
|
|
: 'bg-red-50 border-red-300'
|
|
: isDark
|
|
? 'bg-slate-800/30 border-blue-800/30 hover:border-blue-500/30'
|
|
: 'bg-white border-red-100 hover:border-red-300'
|
|
}`}
|
|
>
|
|
<p className={`text-2xl font-bold ${isDark ? 'text-white' : 'text-gray-900'}`}>{totalCount}</p>
|
|
<p className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>全部任务</p>
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('unanalyzed')}
|
|
className={`p-4 rounded-xl border transition-all duration-200 ${
|
|
activeTab === 'unanalyzed'
|
|
? isDark
|
|
? 'bg-yellow-500/20 border-yellow-500/50'
|
|
: 'bg-yellow-50 border-yellow-300'
|
|
: isDark
|
|
? 'bg-slate-800/30 border-blue-800/30 hover:border-blue-500/30'
|
|
: 'bg-white border-red-100 hover:border-red-300'
|
|
}`}
|
|
>
|
|
<p className={`text-2xl font-bold ${isDark ? 'text-white' : 'text-gray-900'}`}>{unanalyzedCount}</p>
|
|
<p className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>未分析</p>
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('analyzing')}
|
|
className={`p-4 rounded-xl border transition-all duration-200 ${
|
|
activeTab === 'analyzing'
|
|
? isDark
|
|
? 'bg-blue-500/20 border-blue-500/50'
|
|
: 'bg-red-50 border-red-300'
|
|
: isDark
|
|
? 'bg-slate-800/30 border-blue-800/30 hover:border-blue-500/30'
|
|
: 'bg-white border-red-100 hover:border-red-300'
|
|
}`}
|
|
>
|
|
<p className={`text-2xl font-bold ${isDark ? 'text-white' : 'text-gray-900'}`}>{analyzingCount}</p>
|
|
<p className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>分析中</p>
|
|
</button>
|
|
<button
|
|
onClick={() => setActiveTab('completed')}
|
|
className={`p-4 rounded-xl border transition-all duration-200 ${
|
|
activeTab === 'completed'
|
|
? isDark
|
|
? 'bg-green-500/20 border-green-500/50'
|
|
: 'bg-green-50 border-green-300'
|
|
: isDark
|
|
? 'bg-slate-800/30 border-blue-800/30 hover:border-blue-500/30'
|
|
: 'bg-white border-red-100 hover:border-red-300'
|
|
}`}
|
|
>
|
|
<p className={`text-2xl font-bold ${isDark ? 'text-white' : 'text-gray-900'}`}>{completedCount}</p>
|
|
<p className={`text-sm ${isDark ? 'text-slate-400' : 'text-gray-500'}`}>已完成</p>
|
|
</button>
|
|
</div>
|
|
|
|
{/* 看板区 */}
|
|
<div className="flex-1 grid grid-cols-3 gap-4 min-h-0 overflow-hidden">
|
|
{/* 未分析列 */}
|
|
<div className="flex flex-col min-h-0">
|
|
<ColumnHeader title="未分析" count={unanalyzedTasks.length} color={isDark ? 'bg-yellow-400' : 'bg-yellow-400'} />
|
|
<div className="flex-1 overflow-y-auto space-y-3 pr-1 scrollbar-thin">
|
|
{unanalyzedTasks.length === 0 ? (
|
|
<div className={`flex flex-col items-center justify-center py-8 ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<FileText className="w-8 h-8 mb-2 opacity-50" />
|
|
<p className="text-sm">暂无待分析任务</p>
|
|
</div>
|
|
) : (
|
|
unanalyzedTasks.map(task => <TaskCard key={task.id} task={task} />)
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 分析中列 */}
|
|
<div className="flex flex-col min-h-0">
|
|
<ColumnHeader title="分析中" count={analyzingTasks.length} color={isDark ? 'bg-blue-400' : 'bg-red-400'} />
|
|
<div className="flex-1 overflow-y-auto space-y-3 pr-1 scrollbar-thin">
|
|
{analyzingTasks.length === 0 ? (
|
|
<div className={`flex flex-col items-center justify-center py-8 ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<Clock className="w-8 h-8 mb-2 opacity-50" />
|
|
<p className="text-sm">暂无分析中任务</p>
|
|
</div>
|
|
) : (
|
|
analyzingTasks.map(task => <TaskCard key={task.id} task={task} />)
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 已完成列 */}
|
|
<div className="flex flex-col min-h-0">
|
|
<ColumnHeader title="已完成" count={completedTasks.length} color={isDark ? 'bg-green-400' : 'bg-green-400'} />
|
|
<div className="flex-1 overflow-y-auto space-y-3 pr-1 scrollbar-thin">
|
|
{completedTasks.length === 0 ? (
|
|
<div className={`flex flex-col items-center justify-center py-8 ${isDark ? 'text-slate-500' : 'text-gray-400'}`}>
|
|
<Target className="w-8 h-8 mb-2 opacity-50" />
|
|
<p className="text-sm">暂无已完成任务</p>
|
|
</div>
|
|
) : (
|
|
completedTasks.map(task => <TaskCard key={task.id} task={task} />)
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TaskList;
|