import { useState, useEffect } from 'react' import { Plus, Trash2, CheckCircle2, Play, X, Server, ShieldCheck, Copy, Check, ChevronLeft, ChevronRight, ChevronDown } from 'lucide-react' import clsx from 'clsx' import { useI18n } from '../i18n' export default function AccountManager({ config, onRefresh, onMessage, authFetch }) { const { t } = useI18n() const [showAddKey, setShowAddKey] = useState(false) const [showAddAccount, setShowAddAccount] = useState(false) const [newKey, setNewKey] = useState('') const [copiedKey, setCopiedKey] = useState(null) const [newAccount, setNewAccount] = useState({ email: '', mobile: '', password: '' }) const [loading, setLoading] = useState(false) const [testing, setTesting] = useState({}) const [testingAll, setTestingAll] = useState(false) const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0, results: [] }) const [queueStatus, setQueueStatus] = useState(null) const [keysExpanded, setKeysExpanded] = useState(false) // 分页状态 const [accounts, setAccounts] = useState([]) const [page, setPage] = useState(1) const [pageSize] = useState(10) const [totalPages, setTotalPages] = useState(1) const [totalAccounts, setTotalAccounts] = useState(0) const [loadingAccounts, setLoadingAccounts] = useState(false) const apiFetch = authFetch || fetch const fetchAccounts = async (targetPage = page) => { setLoadingAccounts(true) try { const res = await apiFetch(`/admin/accounts?page=${targetPage}&page_size=${pageSize}`) if (res.ok) { const data = await res.json() setAccounts(data.items || []) setTotalPages(data.total_pages || 1) setTotalAccounts(data.total || 0) setPage(data.page || 1) } } catch (e) { console.error('Failed to fetch accounts:', e) } finally { setLoadingAccounts(false) } } const fetchQueueStatus = async () => { try { const res = await apiFetch('/admin/queue/status') if (res.ok) { const data = await res.json() setQueueStatus(data) } } catch (e) { console.error('Failed to fetch queue status:', e) } } useEffect(() => { fetchAccounts() fetchQueueStatus() const interval = setInterval(fetchQueueStatus, 5000) return () => clearInterval(interval) }, []) const addKey = async () => { if (!newKey.trim()) return setLoading(true) try { const res = await apiFetch('/admin/keys', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key: newKey.trim() }), }) if (res.ok) { onMessage('success', t('accountManager.addKeySuccess')) setNewKey('') setShowAddKey(false) onRefresh() } else { const data = await res.json() onMessage('error', data.detail || t('messages.failedToAdd')) } } catch (e) { onMessage('error', t('messages.networkError')) } finally { setLoading(false) } } const deleteKey = async (key) => { if (!confirm(t('accountManager.deleteKeyConfirm'))) return try { const res = await apiFetch(`/admin/keys/${encodeURIComponent(key)}`, { method: 'DELETE' }) if (res.ok) { onMessage('success', t('messages.deleted')) onRefresh() } else { onMessage('error', t('messages.deleteFailed')) } } catch (e) { onMessage('error', t('messages.networkError')) } } const addAccount = async () => { if (!newAccount.password || (!newAccount.email && !newAccount.mobile)) { onMessage('error', t('accountManager.requiredFields')) return } setLoading(true) try { const res = await apiFetch('/admin/accounts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newAccount), }) if (res.ok) { onMessage('success', t('accountManager.addAccountSuccess')) setNewAccount({ email: '', mobile: '', password: '' }) setShowAddAccount(false) fetchAccounts(1) // 添加后回到第一页 onRefresh() } else { const data = await res.json() onMessage('error', data.detail || t('messages.failedToAdd')) } } catch (e) { onMessage('error', t('messages.networkError')) } finally { setLoading(false) } } const deleteAccount = async (id) => { if (!confirm(t('accountManager.deleteAccountConfirm'))) return try { const res = await apiFetch(`/admin/accounts/${encodeURIComponent(id)}`, { method: 'DELETE' }) if (res.ok) { onMessage('success', t('messages.deleted')) fetchAccounts() // 刷新当前页 onRefresh() } else { onMessage('error', t('messages.deleteFailed')) } } catch (e) { onMessage('error', t('messages.networkError')) } } const testAccount = async (identifier) => { setTesting(prev => ({ ...prev, [identifier]: true })) try { const res = await apiFetch('/admin/accounts/test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ identifier }), }) const data = await res.json() const statusMessage = data.success ? t('apiTester.testSuccess', { account: identifier, time: data.response_time }) : `${identifier}: ${data.message}` onMessage(data.success ? 'success' : 'error', statusMessage) fetchAccounts() // 刷新当前页 onRefresh() } catch (e) { onMessage('error', t('accountManager.testFailed', { error: e.message })) } finally { setTesting(prev => ({ ...prev, [identifier]: false })) } } const testAllAccounts = async () => { if (!confirm(t('accountManager.testAllConfirm'))) return const allAccounts = config.accounts || [] if (allAccounts.length === 0) return setTestingAll(true) setBatchProgress({ current: 0, total: allAccounts.length, results: [] }) let successCount = 0 const results = [] for (let i = 0; i < allAccounts.length; i++) { const acc = allAccounts[i] const id = acc.email || acc.mobile try { const res = await apiFetch('/admin/accounts/test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ identifier: id }), }) const data = await res.json() results.push({ id, success: data.success, message: data.message, time: data.response_time }) if (data.success) successCount++ } catch (e) { results.push({ id, success: false, message: e.message }) } setBatchProgress({ current: i + 1, total: allAccounts.length, results: [...results] }) } onMessage('success', t('accountManager.testAllCompleted', { success: successCount, total: allAccounts.length })) fetchAccounts() // 刷新当前页 onRefresh() setTestingAll(false) } return (
{/* Queue Status - Flat & Clean */} { queueStatus && (

{t('accountManager.available')}

{queueStatus.available} {t('accountManager.accountsUnit')}

{t('accountManager.inUse')}

{queueStatus.in_use} {t('accountManager.threadsUnit')}

{t('accountManager.totalPool')}

{queueStatus.total} {t('accountManager.accountsUnit')}
) } {/* API Keys Section */}
setKeysExpanded(!keysExpanded)} >

{t('accountManager.apiKeysTitle')}

{t('accountManager.apiKeysDesc')} ({config.keys?.length || 0})

{keysExpanded && (
{config.keys?.length > 0 ? ( config.keys.map((key, i) => (
{key.slice(0, 16)}****
{copiedKey === key && ( {t('accountManager.copied')} )}
)) ) : (
{t('accountManager.noApiKeys')}
)}
)}
{/* Accounts Section */}

{t('accountManager.accountsTitle')}

{t('accountManager.accountsDesc')}

{/* Batch Progress */} {testingAll && batchProgress.total > 0 && (
{t('accountManager.testingAllAccounts')} {batchProgress.current} / {batchProgress.total}
{batchProgress.results.length > 0 && (
{batchProgress.results.map((r, i) => (
{r.success ? '✓' : '✗'} {r.id}
))}
)}
)}
{loadingAccounts ? (
{t('actions.loading')}
) : accounts.length > 0 ? ( accounts.map((acc, i) => { const id = acc.email || acc.mobile return (
{id}
{acc.has_token ? t('accountManager.sessionActive') : t('accountManager.reauthRequired')} {acc.token_preview && ( {acc.token_preview} )}
) }) ) : (
{t('accountManager.noAccounts')}
)}
{/* 分页控件 */} {totalPages > 1 && (
{t('accountManager.pageInfo', { current: page, total: totalPages, count: totalAccounts })}
{page} / {totalPages}
)}
{/* Modals */} { showAddKey && (

{t('accountManager.modalAddKeyTitle')}

setNewKey(e.target.value)} autoFocus />

{t('accountManager.generateHint')}

) } { showAddAccount && (

{t('accountManager.modalAddAccountTitle')}

setNewAccount({ ...newAccount, email: e.target.value })} />
setNewAccount({ ...newAccount, mobile: e.target.value })} />
setNewAccount({ ...newAccount, password: e.target.value })} />
) }
) }