import { ArrowRightLeft, RefreshCw, Trash2, Download, Info, Lock, Ban, Diamond, Gem, Circle, Clock, ToggleLeft, ToggleRight, Fingerprint } from 'lucide-react';
import { Account } from '../../types/account';
import { getQuotaColor, formatTimeRemaining, getTimeRemainingColor } from '../../utils/format';
import { cn } from '../../utils/cn';
import { useTranslation } from 'react-i18next';
interface AccountRowProps {
account: Account;
selected: boolean;
onSelect: () => void;
isCurrent: boolean;
isRefreshing: boolean;
isSwitching?: boolean;
onSwitch: () => void;
onRefresh: () => void;
onViewDevice: () => void;
onViewDetails: () => void;
onExport: () => void;
onDelete: () => void;
onToggleProxy: () => void;
}
function AccountRow({ account, selected, onSelect, isCurrent, isRefreshing, isSwitching = false, onSwitch, onRefresh, onViewDetails, onExport, onDelete, onToggleProxy, onViewDevice }: AccountRowProps) {
const { t } = useTranslation();
// [重构] 按组聚合查找逻辑,优先显示组内配额最低的型号以与锁定状态(🔒)对齐
const geminiProModel = account.quota?.models
.filter(m =>
m.name.toLowerCase() === 'gemini-3-pro-high'
|| m.name.toLowerCase() === 'gemini-3-pro-low'
|| m.name.toLowerCase() === 'gemini-3.1-pro-high'
|| m.name.toLowerCase() === 'gemini-3.1-pro-low'
)
.sort((a, b) => (a.percentage || 0) - (b.percentage || 0))[0];
const geminiFlashModel = account.quota?.models.find(m => m.name.toLowerCase() === 'gemini-3-flash');
const geminiImageModel = account.quota?.models.find(m => m.name.toLowerCase() === 'gemini-3-pro-image');
const claudeGroupNames = [
'claude-opus-4-6-thinking',
'claude'
];
const claudeModel = account.quota?.models
.filter(m => claudeGroupNames.includes(m.name.toLowerCase()))
.sort((a, b) => (a.percentage || 0) - (b.percentage || 0))[0];
const isDisabled = Boolean(account.disabled);
// 颜色映射,避免动态类名被 Tailwind purge
const getColorClass = (percentage: number) => {
const color = getQuotaColor(percentage);
switch (color) {
case 'success': return 'bg-emerald-500';
case 'warning': return 'bg-amber-500';
case 'error': return 'bg-rose-500';
default: return 'bg-gray-500';
}
};
const getTimeColorClass = (resetTime: string | undefined) => {
const color = getTimeRemainingColor(resetTime);
switch (color) {
case 'success': return 'text-emerald-500 dark:text-emerald-400';
case 'warning': return 'text-amber-500 dark:text-amber-400';
default: return 'text-blue-600 dark:text-blue-400';
}
};
return (
{/* 序号 */}
|
onSelect()}
onClick={(e) => e.stopPropagation()}
/>
|
{/* 邮箱 */}
{account.email}
{isCurrent && (
{t('accounts.current').toUpperCase()}
)}
{isDisabled && (
{t('accounts.disabled')}
)}
{account.proxy_disabled && (
{t('accounts.proxy_disabled')}
)}
{account.quota?.is_forbidden && (
{t('accounts.forbidden')}
)}
{/* 订阅类型徽章 */}
{account.quota?.subscription_tier && (() => {
const tier = account.quota.subscription_tier.toLowerCase();
if (tier.includes('ultra')) {
return (
ULTRA
);
} else if (tier.includes('pro')) {
return (
PRO
);
} else {
return (
FREE
);
}
})()}
|
{/* 模型配额 */}
{account.quota?.is_forbidden ? (
{t('accounts.forbidden_msg')}
) : (
{/* Gemini Pro */}
{geminiProModel && (
)}
{(account.protected_models?.includes('gemini-3-pro-high') || account.protected_models?.includes('gemini-3.1-pro-high')) && }
G3.1 Pro
{geminiProModel?.reset_time ? (
{formatTimeRemaining(geminiProModel.reset_time)}
) : (
N/A
)}
{geminiProModel ? `${geminiProModel.percentage}%` : '-'}
{/* Gemini Flash */}
{geminiFlashModel && (
)}
{account.protected_models?.includes('gemini-3-flash') && }
G3 Flash
{geminiFlashModel?.reset_time ? (
{formatTimeRemaining(geminiFlashModel.reset_time)}
) : (
N/A
)}
{geminiFlashModel ? `${geminiFlashModel.percentage}%` : '-'}
{/* Gemini Image */}
{geminiImageModel && (
)}
{account.protected_models?.includes('gemini-3-pro-image') && }
G3 Image
{geminiImageModel?.reset_time ? (
{formatTimeRemaining(geminiImageModel.reset_time)}
) : (
N/A
)}
{geminiImageModel ? `${geminiImageModel.percentage}%` : '-'}
{/* Claude */}
{claudeModel && (
)}
{account.protected_models?.includes('claude') && }
Claude
{claudeModel?.reset_time ? (
{formatTimeRemaining(claudeModel.reset_time)}
) : (
N/A
)}
{claudeModel ? `${claudeModel.percentage}%` : '-'}
)}
|
{/* 最后使用 */}
{new Date(account.last_used * 1000).toLocaleDateString()}
{new Date(account.last_used * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
|
{/* 操作 */}
{ e.stopPropagation(); onSwitch(); }}
title={isDisabled ? t('accounts.disabled_tooltip') : (isSwitching ? t('common.loading') : t('accounts.switch_to'))}
disabled={isSwitching || isDisabled}
>
{ e.stopPropagation(); onRefresh(); }}
title={isDisabled ? t('accounts.disabled_tooltip') : (isRefreshing ? t('common.refreshing') : t('common.refresh'))}
disabled={isRefreshing || isDisabled}
>
{ e.stopPropagation(); onExport(); }}
title={t('common.export')}
>
{ e.stopPropagation(); onToggleProxy(); }}
title={account.proxy_disabled ? t('accounts.enable_proxy') : t('accounts.disable_proxy')}
>
{account.proxy_disabled ? (
) : (
)}
{ e.stopPropagation(); onDelete(); }}
title={t('common.delete')}
>
|
);
}
export default AccountRow;