300 lines
12 KiB
TypeScript
300 lines
12 KiB
TypeScript
import { useTheme } from '@/contexts/ThemeContext';
|
|
import { TaskListItem } from '@/pages/TaskManagement';
|
|
import { Bot, ChevronRight, Download, Edit, Eye, FileText, Layers, MoreHorizontal, Play, User, Users, Workflow } from 'lucide-react';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { PageType } from '../Sidebar';
|
|
import { format } from 'date-fns';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { useChatContext } from '@/contexts/ChatContext';
|
|
|
|
interface KanbanColumnProps {
|
|
TaskType?: string;
|
|
task: TaskListItem;
|
|
onNavigate: (page: PageType) => void;
|
|
handleStartAnalysis: (task: TaskListItem) => void
|
|
}
|
|
|
|
export const TaskCard: React.FC<KanbanColumnProps> = ({ task, TaskType = 'task', onNavigate, handleStartAnalysis }) => {
|
|
const { theme } = useTheme();
|
|
const { setStartConfig } = useChatContext();
|
|
const isDark = theme === 'dark';
|
|
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
|
|
const textMuted = isDark ? 'text-slate-500' : 'text-gray-400';
|
|
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
|
|
const navigate = useNavigate();
|
|
|
|
const handleStartChange = (task: TaskListItem) => {
|
|
// if (TaskType === 'task') {
|
|
// handleStartAnalysis(task);
|
|
// } else {
|
|
// sceneDataChange(task);
|
|
// }
|
|
handleStartAnalysis(task);
|
|
}
|
|
|
|
const sceneDataChange = (task: TaskListItem) => {
|
|
const sceneItem = JSON.parse(task.scene);
|
|
if (sceneItem.taskJson) {
|
|
sceneItem.taskJson = JSON.parse(sceneItem.taskJson);
|
|
setStartConfig({
|
|
...sceneItem.taskJson,
|
|
llm_preset_id: 'BAILING',
|
|
consistency_mode: 'soft',
|
|
phase_config: { diverge_rounds: 3 },
|
|
task_context: task.overview
|
|
});
|
|
navigate('/qa-center/mope-chat')
|
|
}
|
|
console.log('sceneItem', sceneItem);
|
|
}
|
|
// 处理卡片点击
|
|
const handleTaskClick = (task: TaskListItem) => {
|
|
if (TaskType === 'sentiment') {
|
|
console.log('点击了', task)
|
|
sceneDataChange(task);
|
|
// window.open(`http://ch1.b.uat.4.cn/taskcop/#/situation-overview/action/sentiment?taskId=${task.id}`)
|
|
} else {
|
|
if (task.column === 'completed') {
|
|
// if (task.type === 'consultation') {
|
|
// onNavigate('task-consult-result');
|
|
// } else {
|
|
// onNavigate('strategy-result');
|
|
// }
|
|
navigate('/strategy-result')
|
|
} else if (task.column === 'running') {
|
|
// navigate('/task-management/task-consult')
|
|
sceneDataChange(task);
|
|
// window.open(`http://ch1.b.uat.4.cn/mopeweb/#/mope?taskOverview=${task.overview}`)
|
|
// if (task.type === 'scene') {
|
|
// onNavigate('task-scene');
|
|
// } else if (task.type === 'consultation') {
|
|
// onNavigate('task-consult');
|
|
// } else {
|
|
// onNavigate('task-single');
|
|
// }
|
|
}
|
|
}
|
|
};
|
|
|
|
// 获取任务类型配置
|
|
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 };
|
|
case 'multi-agent':
|
|
return { label: '多智能体协同', color: 'bg-green-500/20 text-green-400', icon: Layers };
|
|
}
|
|
} else {
|
|
switch (type) {
|
|
case 'single':
|
|
return { label: '单智能体', color: 'bg-blue-100 text-blue-600', icon: Bot };
|
|
case 'scene':
|
|
return { label: '场景执行', color: 'bg-purple-100 text-purple-600', icon: Workflow };
|
|
case 'consultation':
|
|
return { label: '多智能体会商', color: 'bg-orange-100 text-orange-600', icon: Users };
|
|
case 'multi-agent':
|
|
return { label: '多智能体协同', color: 'bg-green-100 text-green-600', icon: Layers };
|
|
}
|
|
}
|
|
};
|
|
const typeConfig = getTypeConfig('single');
|
|
// 获取任务等级
|
|
const getLevel = (type: number) => {
|
|
if (isDark) {
|
|
switch (type) {
|
|
case 1:
|
|
return { label: '一般', color: 'bg-cyan-500/20 text-cyan-400', icon: Bot };
|
|
case 2:
|
|
return { label: '紧急', color: 'bg-purple-500/20 text-purple-400', icon: Workflow };
|
|
case 3:
|
|
return { label: '加急', color: 'bg-orange-500/20 text-orange-400', icon: Users };
|
|
}
|
|
} else {
|
|
switch (type) {
|
|
case 1:
|
|
return { label: '一般', color: 'bg-blue-100 text-blue-600', icon: Bot };
|
|
case 2:
|
|
return { label: '紧急', color: 'bg-purple-100 text-purple-600', icon: Workflow };
|
|
case 3:
|
|
return { label: '加急', color: 'bg-orange-100 text-orange-600', icon: Users };
|
|
}
|
|
}
|
|
};
|
|
|
|
const levelConfig = getLevel(task.taskLevel);
|
|
const LevelIcon = levelConfig?.icon || Bot;
|
|
// 获取状态配置
|
|
const getStatusConfig = (column: string) => {
|
|
if (column === 'unanalyzed') {
|
|
return { label: '待分析', color: isDark ? 'bg-yellow-500/20 text-yellow-400' : 'bg-yellow-100 text-yellow-600' };
|
|
} else if (column === 'running') {
|
|
return { label: '运行中', color: isDark ? 'bg-blue-500/20 text-blue-400' : 'bg-red-100 text-red-600' };
|
|
} else {
|
|
return { label: '已完成', color: isDark ? 'bg-green-500/20 text-green-400' : 'bg-green-100 text-green-600' };
|
|
}
|
|
};
|
|
const statusConfig = getStatusConfig(task.column);
|
|
return (
|
|
<div
|
|
className={`rounded-xl p-4 hover:shadow-md transition-all duration-200 cursor-pointer group 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-2">
|
|
<span className={`inline-flex items-center gap-1.5 px-2 py-0.5 rounded text-xs font-medium ${levelConfig.color}`}>
|
|
{LevelIcon && <LevelIcon className="w-3 h-3" />}
|
|
{levelConfig.label}
|
|
</span>
|
|
<span></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 ${textPrimary}`}>
|
|
{task.taskName}
|
|
</h3>
|
|
|
|
{/* 任务编号 */}
|
|
<p className={`text-xs mb-2 ${textMuted}`}>TASK-{task.id}</p>
|
|
|
|
{/* 任务摘要 */}
|
|
<p className={`text-xs mb-3 line-clamp-2 ${textSecondary}`}>{task.overview}</p>
|
|
|
|
{/* 补充信息区 */}
|
|
{/* <div className="space-y-1 mb-3">
|
|
{task.type === 'single' && task.agent && (
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Bot className={`w-3 h-3 ${isDark ? 'text-cyan-400' : 'text-red-500'}`} />
|
|
<span className={textSecondary}>执行智能体:</span>
|
|
<span className={isDark ? 'text-cyan-400' : 'text-red-600'}>{task.agent}</span>
|
|
</div>
|
|
)}
|
|
{task.type === 'scene' && task.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={textSecondary}>关联场景:</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={textSecondary}>参与智能体:</span>
|
|
<span className={isDark ? 'text-orange-400' : 'text-red-600'}>{task.participants?.length || 0}个</span>
|
|
</div>
|
|
{task.currentRound && (
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Clock className={`w-3 h-3 ${textMuted}`} />
|
|
<span className={textSecondary}>当前轮次:</span>
|
|
<span className={textPrimary}>第{task.currentRound}轮</span>
|
|
</div>
|
|
)}
|
|
</>
|
|
)}
|
|
{task.column === 'analyzing' && task.currentPhase && (
|
|
<div className="flex items-center gap-2 text-xs">
|
|
<Target className={`w-3 h-3 ${textMuted}`} />
|
|
<span className={textSecondary}>当前阶段:</span>
|
|
<span className={textPrimary}>{task.currentPhase}</span>
|
|
</div>
|
|
)}
|
|
</div> */}
|
|
|
|
{/* 时间信息 */}
|
|
<div className={`flex items-center justify-between text-xs pt-3 border-t ${isDark ? 'border-blue-800/30 text-slate-500' : 'border-red-100 text-gray-400'
|
|
}`}>
|
|
<div className="flex items-center gap-1.5">
|
|
<User className="w-3 h-3" />
|
|
<span>{task.taskDirection}</span>
|
|
</div>
|
|
<span>{format(new Date(task.updateTime), 'yyyy-MM-dd HH:mm:ss')}</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
|
|
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
|
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
|
|
onClick={(e) => { e.stopPropagation(); onNavigate('task-create'); }}
|
|
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 === 'running' && (
|
|
<>
|
|
<button
|
|
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
|
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
|
|
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
|
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
|
|
onClick={(e) => { e.stopPropagation(); handleStartChange(task); }}
|
|
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'
|
|
}`}>
|
|
<Download className="w-4 h-4" />
|
|
</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>
|
|
);
|
|
}
|