| import { useState } from 'react' |
|
|
| export function useAccountActions({ apiFetch, t, onMessage, onRefresh, config, fetchAccounts, resolveAccountIdentifier }) { |
| const [showAddKey, setShowAddKey] = useState(false) |
| const [editingKey, setEditingKey] = useState(null) |
| const [showAddAccount, setShowAddAccount] = useState(false) |
| const [showEditAccount, setShowEditAccount] = useState(false) |
| const [editingAccount, setEditingAccount] = useState(null) |
| const [newKey, setNewKey] = useState({ key: '', name: '', remark: '' }) |
| const [copiedKey, setCopiedKey] = useState(null) |
| const [newAccount, setNewAccount] = useState({ name: '', remark: '', email: '', mobile: '', password: '' }) |
| const [editAccount, setEditAccount] = useState({ name: '', remark: '' }) |
| const [loading, setLoading] = useState(false) |
| const [testing, setTesting] = useState({}) |
| const [testingAll, setTestingAll] = useState(false) |
| const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0, results: [] }) |
| const [sessionCounts, setSessionCounts] = useState({}) |
| const [deletingSessions, setDeletingSessions] = useState({}) |
| const [updatingProxy, setUpdatingProxy] = useState({}) |
|
|
| const openAddKey = () => { |
| setEditingKey(null) |
| setNewKey({ key: '', name: '', remark: '' }) |
| setShowAddKey(true) |
| } |
|
|
| const openEditKey = (item) => { |
| if (!item?.key) return |
| setEditingKey(item) |
| setNewKey({ |
| key: item.key || '', |
| name: item.name || '', |
| remark: item.remark || '', |
| }) |
| setShowAddKey(true) |
| } |
|
|
| const closeKeyModal = () => { |
| setShowAddKey(false) |
| setEditingKey(null) |
| setNewKey({ key: '', name: '', remark: '' }) |
| } |
|
|
| const openAddAccount = () => { |
| setShowEditAccount(false) |
| setEditingAccount(null) |
| setEditAccount({ name: '', remark: '' }) |
| setNewAccount({ name: '', remark: '', email: '', mobile: '', password: '' }) |
| setShowAddAccount(true) |
| } |
|
|
| const closeAddAccount = () => { |
| setShowAddAccount(false) |
| setNewAccount({ name: '', remark: '', email: '', mobile: '', password: '' }) |
| } |
|
|
| const openEditAccount = (account) => { |
| const identifier = resolveAccountIdentifier(account) |
| if (!identifier) { |
| onMessage('error', t('accountManager.invalidIdentifier')) |
| return |
| } |
| setShowAddAccount(false) |
| setEditingAccount({ |
| identifier, |
| }) |
| setEditAccount({ |
| name: account?.name || '', |
| remark: account?.remark || '', |
| }) |
| setShowEditAccount(true) |
| } |
|
|
| const closeEditAccount = () => { |
| setShowEditAccount(false) |
| setEditingAccount(null) |
| setEditAccount({ name: '', remark: '' }) |
| } |
|
|
| const addKey = async () => { |
| const isEditing = Boolean(editingKey?.key) |
| if (!isEditing && !newKey.key.trim()) { |
| return |
| } |
| setLoading(true) |
| try { |
| const endpoint = isEditing |
| ? `/admin/keys/${encodeURIComponent(editingKey.key)}` |
| : '/admin/keys' |
| const method = isEditing ? 'PUT' : 'POST' |
| const payload = isEditing |
| ? { name: newKey.name, remark: newKey.remark } |
| : { key: newKey.key.trim(), name: newKey.name, remark: newKey.remark } |
| if (!isEditing && !payload.key) { |
| return |
| } |
| const res = await apiFetch(endpoint, { |
| method, |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(payload), |
| }) |
| if (res.ok) { |
| onMessage('success', isEditing ? t('accountManager.updateKeySuccess') : t('accountManager.addKeySuccess')) |
| closeKeyModal() |
| onRefresh() |
| } else { |
| const data = await res.json() |
| onMessage('error', data.detail || (isEditing ? t('messages.requestFailed') : 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')) |
| closeAddAccount() |
| 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 updateAccount = async () => { |
| const identifier = String(editingAccount?.identifier || '').trim() |
| if (!identifier) { |
| onMessage('error', t('accountManager.invalidIdentifier')) |
| return |
| } |
| setLoading(true) |
| try { |
| const res = await apiFetch(`/admin/accounts/${encodeURIComponent(identifier)}`, { |
| method: 'PUT', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify(editAccount), |
| }) |
| if (res.ok) { |
| onMessage('success', t('accountManager.updateAccountSuccess')) |
| closeEditAccount() |
| fetchAccounts() |
| onRefresh() |
| } else { |
| const data = await res.json() |
| onMessage('error', data.detail || t('messages.requestFailed')) |
| } |
| } catch (e) { |
| onMessage('error', t('messages.networkError')) |
| } finally { |
| setLoading(false) |
| } |
| } |
|
|
| const deleteAccount = async (id) => { |
| const identifier = String(id || '').trim() |
| if (!identifier) { |
| onMessage('error', t('accountManager.invalidIdentifier')) |
| return |
| } |
| if (!confirm(t('accountManager.deleteAccountConfirm'))) return |
| try { |
| const res = await apiFetch(`/admin/accounts/${encodeURIComponent(identifier)}`, { 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) => { |
| const accountID = String(identifier || '').trim() |
| if (!accountID) { |
| onMessage('error', t('accountManager.invalidIdentifier')) |
| return |
| } |
| setTesting(prev => ({ ...prev, [accountID]: true })) |
| try { |
| const res = await apiFetch('/admin/accounts/test', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ identifier: accountID }), |
| }) |
| const data = await res.json() |
| |
| |
| if (data.session_count !== undefined) { |
| setSessionCounts(prev => ({ ...prev, [accountID]: data.session_count })) |
| } |
| |
| const statusMessage = data.success |
| ? t('apiTester.testSuccess', { account: accountID, time: data.response_time }) |
| : `${accountID}: ${data.message}` |
| onMessage(data.success ? 'success' : 'error', statusMessage) |
| fetchAccounts() |
| onRefresh() |
| } catch (e) { |
| onMessage('error', t('accountManager.testFailed', { error: e.message })) |
| } finally { |
| setTesting(prev => ({ ...prev, [accountID]: 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 = resolveAccountIdentifier(acc) |
| if (!id) { |
| results.push({ id: '-', success: false, message: t('accountManager.invalidIdentifier') }) |
| setBatchProgress({ current: i + 1, total: allAccounts.length, results: [...results] }) |
| continue |
| } |
|
|
| 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) |
| } |
|
|
| const deleteAllSessions = async (identifier) => { |
| const accountID = String(identifier || '').trim() |
| if (!accountID) { |
| onMessage('error', t('accountManager.invalidIdentifier')) |
| return |
| } |
| if (!confirm(t('accountManager.deleteAllSessionsConfirm'))) return |
| |
| setDeletingSessions(prev => ({ ...prev, [accountID]: true })) |
| try { |
| const res = await apiFetch('/admin/accounts/sessions/delete-all', { |
| method: 'POST', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ identifier: accountID }), |
| }) |
| const data = await res.json() |
| |
| if (data.success) { |
| onMessage('success', t('accountManager.deleteAllSessionsSuccess')) |
| |
| setSessionCounts(prev => { |
| const newCounts = { ...prev } |
| delete newCounts[accountID] |
| return newCounts |
| }) |
| } else { |
| onMessage('error', data.message || t('messages.requestFailed')) |
| } |
| } catch (e) { |
| onMessage('error', t('messages.networkError')) |
| } finally { |
| setDeletingSessions(prev => ({ ...prev, [accountID]: false })) |
| } |
| } |
|
|
| const updateAccountProxy = async (identifier, proxyID) => { |
| const accountID = String(identifier || '').trim() |
| if (!accountID) { |
| onMessage('error', t('accountManager.invalidIdentifier')) |
| return |
| } |
| setUpdatingProxy(prev => ({ ...prev, [accountID]: true })) |
| try { |
| const res = await apiFetch(`/admin/accounts/${encodeURIComponent(accountID)}/proxy`, { |
| method: 'PUT', |
| headers: { 'Content-Type': 'application/json' }, |
| body: JSON.stringify({ proxy_id: proxyID || '' }), |
| }) |
| const data = await res.json() |
| if (!res.ok) { |
| onMessage('error', data.detail || t('messages.requestFailed')) |
| return |
| } |
| onMessage('success', t('accountManager.proxyUpdateSuccess')) |
| fetchAccounts() |
| onRefresh() |
| } catch (_err) { |
| onMessage('error', t('messages.networkError')) |
| } finally { |
| setUpdatingProxy(prev => ({ ...prev, [accountID]: false })) |
| } |
| } |
|
|
| return { |
| showAddKey, |
| openAddKey, |
| openEditKey, |
| closeKeyModal, |
| editingKey, |
| showAddAccount, |
| openAddAccount, |
| closeAddAccount, |
| showEditAccount, |
| editingAccount, |
| editAccount, |
| setEditAccount, |
| openEditAccount, |
| closeEditAccount, |
| newKey, |
| setNewKey, |
| copiedKey, |
| setCopiedKey, |
| newAccount, |
| setNewAccount, |
| loading, |
| testing, |
| testingAll, |
| batchProgress, |
| sessionCounts, |
| deletingSessions, |
| updatingProxy, |
| addKey, |
| deleteKey, |
| addAccount, |
| updateAccount, |
| deleteAccount, |
| testAccount, |
| testAllAccounts, |
| deleteAllSessions, |
| updateAccountProxy, |
| } |
| } |
|
|