208 lines
7.7 KiB
TypeScript
208 lines
7.7 KiB
TypeScript
/**
|
||
* 一键匹配汇总卡片组件
|
||
* 遵循前端开发规范的组件设计原则
|
||
*/
|
||
|
||
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>
|
||
);
|
||
};
|