'use client'; import { Box, Card, CardContent, Typography, Chip, IconButton, Menu, MenuItem, LinearProgress, Avatar, Grid, Tooltip, Divider } from '@mui/material'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import DeleteIcon from '@mui/icons-material/Delete'; import StopIcon from '@mui/icons-material/Stop'; import VisibilityIcon from '@mui/icons-material/Visibility'; import AccessTimeIcon from '@mui/icons-material/AccessTime'; import EmojiEventsIcon from '@mui/icons-material/EmojiEvents'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { alpha, useTheme } from '@mui/material/styles'; const STATUS_MAP = { 0: { label: 'blindTest.statusProcessing', color: 'primary', bgColor: 'primary.main' }, 1: { label: 'blindTest.statusCompleted', color: 'success', bgColor: 'success.main' }, 2: { label: 'blindTest.statusFailed', color: 'error', bgColor: 'error.main' }, 3: { label: 'blindTest.statusInterrupted', color: 'warning', bgColor: 'warning.main' } }; export default function BlindTestTaskCard({ task, onView, onDelete, onInterrupt, onContinue }) { const { t } = useTranslation(); const theme = useTheme(); const [anchorEl, setAnchorEl] = useState(null); const handleMenuOpen = e => { e.stopPropagation(); setAnchorEl(e.currentTarget); }; const handleMenuClose = () => { setAnchorEl(null); }; const handleView = e => { e?.stopPropagation?.(); handleMenuClose(); onView?.(task); }; const handleDelete = e => { e?.stopPropagation?.(); handleMenuClose(); onDelete?.(task); }; const handleInterrupt = e => { e?.stopPropagation?.(); handleMenuClose(); onInterrupt?.(task); }; const handleContinue = e => { e?.stopPropagation?.(); handleMenuClose(); onContinue?.(task); }; const statusConfig = STATUS_MAP[task.status] || STATUS_MAP[0]; const progress = task.totalCount > 0 ? (task.completedCount / task.totalCount) * 100 : 0; const isProcessing = task.status === 0; const isCompleted = task.status === 1; // 计算模型得分 const results = task.detail?.results || []; const modelAScore = results.reduce((sum, r) => sum + (r.modelAScore || 0), 0); const modelBScore = results.reduce((sum, r) => sum + (r.modelBScore || 0), 0); const totalScore = modelAScore + modelBScore; // Calculate win percentages for visual bar const modelAPercent = totalScore > 0 ? (modelAScore / totalScore) * 100 : 50; const modelBPercent = totalScore > 0 ? (modelBScore / totalScore) * 100 : 50; const winner = isCompleted ? (modelAScore > modelBScore ? 'A' : modelBScore > modelAScore ? 'B' : 'Tie') : null; return ( handleView(e)} > {/* Status & Time */} {new Date(task.createAt).toLocaleDateString()} {/* Model Comparison Area */} {/* Model A */} A {task.modelInfo?.modelA?.modelName || 'Model A'} {task.modelInfo?.modelA?.providerName} {isCompleted && winner === 'A' && } {/* Center Status/Score */} {isCompleted ? ( {modelAScore.toFixed(1)} : {modelBScore.toFixed(1)} ) : ( VS {Math.round(progress)}% )} {/* Model B */} B {task.modelInfo?.modelB?.modelName || 'Model B'} {task.modelInfo?.modelB?.providerName} {isCompleted && winner === 'B' && } {/* Menu */} {/* 菜单 */} {t('blindTest.viewDetails', '查看详情')} {isProcessing && ( {t('blindTest.continue', '继续盲测')} )} {isProcessing && ( {t('blindTest.interrupt', '中断任务')} )} {t('common.delete', '删除')} ); }