import { Shield, Check } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { QuotaProtectionConfig } from '../../types/config'; import { MODEL_CONFIG } from '../../config/modelConfig'; interface QuotaProtectionProps { config: QuotaProtectionConfig; onChange: (config: QuotaProtectionConfig) => void; } const QuotaProtection = ({ config, onChange }: QuotaProtectionProps) => { const { t } = useTranslation(); const handleEnabledChange = (enabled: boolean) => { let newConfig = { ...config, enabled }; // 如果开启保护且勾选列表为空,则默认勾选 claude if (enabled && (!config.monitored_models || config.monitored_models.length === 0)) { newConfig.monitored_models = ['claude']; } onChange(newConfig); }; const handlePercentageChange = (value: string) => { const percentage = parseInt(value) || 10; const clampedPercentage = Math.max(1, Math.min(99, percentage)); onChange({ ...config, threshold_percentage: clampedPercentage }); }; const toggleModel = (model: string) => { const currentModels = config.monitored_models || []; let newModels: string[]; if (currentModels.includes(model)) { // 必须勾选其中一个,不能全取消 if (currentModels.length <= 1) return; newModels = currentModels.filter(m => m !== model); } else { newModels = [...currentModels, model]; } onChange({ ...config, monitored_models: newModels }); }; const uniqueLabels = new Set(); const monitoredModelsOptions = Object.entries(MODEL_CONFIG) .filter(([id, config]) => { if (id.includes('thinking')) return false; const label = config.shortLabel || config.label; if (uniqueLabels.has(label)) return false; uniqueLabels.add(label); return true; }) .map(([id, config]) => ({ id, label: config.shortLabel || config.label })); // 计算示例值 const exampleTotal = 150; const exampleThreshold = Math.floor(exampleTotal * config.threshold_percentage / 100); return (
{/* 图标部分 - 使用红色/玫瑰色调表示保护/警示 */}
{t('settings.quota_protection.title')}

{t('settings.quota_protection.enable_desc')}

{/* 开关部分 */}
{/* 展开的详情设置部分 */} {config.enabled && (
{/* 百分比设置 */}
handlePercentageChange(e.target.value)} /> %
{/* 监控模型勾选 */}

{t('settings.quota_protection.monitored_models_desc')}

{monitoredModelsOptions.map((model) => { const isSelected = config.monitored_models?.includes(model.id); return (
toggleModel(model.id)} className={` flex items-center justify-between p-2 rounded-lg border cursor-pointer transition-all duration-200 ${isSelected ? 'bg-rose-50 dark:bg-rose-900/10 border-rose-200 dark:border-rose-800/50 text-rose-700 dark:text-rose-400' : 'bg-gray-50/50 dark:bg-base-200/50 border-gray-100 dark:border-base-300/50 text-gray-500 hover:border-gray-200 dark:hover:border-base-300'} `} > {model.label}
); })}
{/* 示例提示卡片 */}
💡

{t('settings.quota_protection.example', { percentage: config.threshold_percentage, total: exampleTotal, threshold: exampleThreshold })}

✓ {t('settings.quota_protection.auto_restore_info')}
)}
); }; export default QuotaProtection;