mixvideo-v2/apps/desktop/src/components/BatchMatchingSummaryCard.tsx

208 lines
7.7 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 from 'react';
import {
CheckCircle,
XCircle,
Target,
Clock,
Film,
Users,
TrendingUp,
TrendingDown,
BarChart3,
} from 'lucide-react';
import {
BatchMatchingResult,
formatDuration,
calculateSuccessRate,
} from '../types/batchMatching';
interface BatchMatchingSummaryCardProps {
result: BatchMatchingResult;
className?: string;
}
export const BatchMatchingSummaryCard: React.FC<BatchMatchingSummaryCardProps> = ({
result,
className = '',
}) => {
const successRate = calculateSuccessRate(result.successful_matches, result.total_bindings);
const getOverallStatusColor = () => {
if (result.failed_matches === 0 && result.successful_matches > 0) {
return 'border-green-200 bg-green-50';
} else if (result.successful_matches > 0 && result.failed_matches > 0) {
return 'border-yellow-200 bg-yellow-50';
} else {
return 'border-red-200 bg-red-50';
}
};
const getOverallStatusIcon = () => {
if (result.failed_matches === 0 && result.successful_matches > 0) {
return <CheckCircle className="w-6 h-6 text-green-600" />;
} else if (result.successful_matches > 0 && result.failed_matches > 0) {
return <Target className="w-6 h-6 text-yellow-600" />;
} else {
return <XCircle className="w-6 h-6 text-red-600" />;
}
};
const getOverallStatusText = () => {
if (result.failed_matches === 0 && result.successful_matches > 0) {
return '全部成功';
} else if (result.successful_matches > 0 && result.failed_matches > 0) {
return '部分成功';
} else {
return '全部失败';
}
};
return (
<div className={`border-2 rounded-lg p-6 ${getOverallStatusColor()} ${className}`}>
{/* 头部状态 */}
<div className="flex items-center justify-between mb-6">
<div className="flex items-center space-x-3">
{getOverallStatusIcon()}
<div>
<h3 className="text-lg font-semibold text-gray-900">
{getOverallStatusText()}
</h3>
<p className="text-sm text-gray-600">
</p>
</div>
</div>
<div className="text-right">
<div className="text-2xl font-bold text-gray-900">{successRate}%</div>
<div className="text-sm text-gray-600"></div>
</div>
</div>
{/* 核心统计 */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<div className="text-center">
<div className="flex items-center justify-center mb-2">
<CheckCircle className="w-5 h-5 text-green-600" />
</div>
<div className="text-xl font-bold text-green-900">{result.successful_matches}</div>
<div className="text-sm text-gray-600"></div>
</div>
<div className="text-center">
<div className="flex items-center justify-center mb-2">
<XCircle className="w-5 h-5 text-red-600" />
</div>
<div className="text-xl font-bold text-red-900">{result.failed_matches}</div>
<div className="text-sm text-gray-600"></div>
</div>
<div className="text-center">
<div className="flex items-center justify-center mb-2">
<BarChart3 className="w-5 h-5 text-blue-600" />
</div>
<div className="text-xl font-bold text-blue-900">{result.total_bindings}</div>
<div className="text-sm text-gray-600"></div>
</div>
<div className="text-center">
<div className="flex items-center justify-center mb-2">
<Clock className="w-5 h-5 text-purple-600" />
</div>
<div className="text-lg font-bold text-purple-900">
{formatDuration(result.total_duration_ms)}
</div>
<div className="text-sm text-gray-600"></div>
</div>
</div>
{/* 详细统计 */}
<div className="border-t border-gray-200 pt-4">
<h4 className="text-sm font-medium text-gray-900 mb-3"></h4>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4 text-sm">
<div className="flex items-center space-x-2">
<Film className="w-4 h-4 text-gray-600" />
<span className="text-gray-600">:</span>
<span className="font-medium">{result.summary.total_segments_matched}</span>
</div>
<div className="flex items-center space-x-2">
<Target className="w-4 h-4 text-gray-600" />
<span className="text-gray-600">使:</span>
<span className="font-medium">{result.summary.total_materials_used}</span>
</div>
<div className="flex items-center space-x-2">
<Users className="w-4 h-4 text-gray-600" />
<span className="text-gray-600">使:</span>
<span className="font-medium">{result.summary.total_models_used}</span>
</div>
<div className="flex items-center space-x-2">
<TrendingUp className="w-4 h-4 text-gray-600" />
<span className="text-gray-600">:</span>
<span className="font-medium">{Math.min(result.summary.average_success_rate * 100, 100).toFixed(1)}%</span>
</div>
{result.summary.best_matching_template && (
<div className="flex items-center space-x-2 col-span-2">
<TrendingUp className="w-4 h-4 text-green-600" />
<span className="text-gray-600">:</span>
<span className="font-medium text-green-800 truncate">
{result.summary.best_matching_template}
</span>
</div>
)}
{result.summary.worst_matching_template && (
<div className="flex items-center space-x-2 col-span-2">
<TrendingDown className="w-4 h-4 text-red-600" />
<span className="text-gray-600">:</span>
<span className="font-medium text-red-800 truncate">
{result.summary.worst_matching_template}
</span>
</div>
)}
</div>
</div>
{/* 建议和提示 */}
{result.failed_matches > 0 && (
<div className="border-t border-gray-200 pt-4 mt-4">
<div className="bg-yellow-50 border border-yellow-200 rounded-md p-3">
<div className="flex items-start space-x-2">
<Target className="w-4 h-4 text-yellow-600 mt-0.5" />
<div className="text-sm">
<p className="font-medium text-yellow-800"></p>
<p className="text-yellow-700 mt-1">
{result.failed_matches}
</p>
</div>
</div>
</div>
</div>
)}
{result.successful_matches === result.total_bindings && result.total_bindings > 0 && (
<div className="border-t border-gray-200 pt-4 mt-4">
<div className="bg-green-50 border border-green-200 rounded-md p-3">
<div className="flex items-start space-x-2">
<CheckCircle className="w-4 h-4 text-green-600 mt-0.5" />
<div className="text-sm">
<p className="font-medium text-green-800"></p>
<p className="text-green-700 mt-1">
</p>
</div>
</div>
</div>
</div>
)}
</div>
);
};