'use client'; import { useState, useEffect } from 'react'; import { Plus, Search, RefreshCw, X, Lock } from 'lucide-react'; import api from '@/lib/api'; import { toast } from 'react-hot-toast'; // 引入拆分后的组件 import AccountTable, { Account } from '@/components/admin/accounts/AccountTable'; import Pagination from '@/components/common/Pagination'; export default function AdminAccountsPage() { // === 1. 状态定义 === const [loading, setLoading] = useState(true); const [data, setData] = useState([]); // 分页与搜索 const [page, setPage] = useState(1); // 1-based UI const [pageSize] = useState(10); const [total, setTotal] = useState(0); const [keyword, setKeyword] = useState(''); // 模态框状态 const [showAddModal, setShowAddModal] = useState(false); const [showLockModal, setShowLockModal] = useState(false); const [selectedAccount, setSelectedAccount] = useState(null); // 表单状态 const [addForm, setAddForm] = useState({ pool_name: '', username: '', password: '', extra_data_str: '{}' }); const [lockDuration, setLockDuration] = useState(3600); // === 2. 数据获取 === const fetchAccounts = async (targetPage: number = page) => { setLoading(true); try { // API 使用 0-based,前端使用 1-based // const apiPage = targetPage - 1; const res = await api.get('/api/account/list_all', { params: { page: targetPage, size: pageSize, keyword: keyword } }); const resData = res.data?.data || {}; if (resData && Array.isArray(resData.items)) { setData(resData.items); setTotal(resData.total || 0); } else { setData([]); setTotal(0); } setPage(targetPage); // 翻页滚动优化 if (targetPage > 1) { window.scrollTo({ top: 0, behavior: 'smooth' }); } } catch (error) { console.error("Fetch accounts failed", error); toast.error('获取列表失败'); setData([]); } finally { setLoading(false); } }; useEffect(() => { fetchAccounts(1); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const handleSearch = () => fetchAccounts(1); const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') handleSearch(); }; // === 3. 业务逻辑 === const handleAddAccount = async () => { try { let extraDataJson = {}; try { extraDataJson = JSON.parse(addForm.extra_data_str); } catch (e) { toast.error('Extra Data 必须是 JSON 格式'); return; } await api.post('/api/account/add', { pool_name: addForm.pool_name, username: addForm.username, password: addForm.password, extra_data: extraDataJson }); toast.success('添加成功'); setShowAddModal(false); setAddForm({ pool_name: '', username: '', password: '', extra_data_str: '{}' }); fetchAccounts(1); } catch (error) { toast.error('添加失败'); } }; const handleLockConfirm = async () => { if (!selectedAccount) return; try { await api.post('/api/account/lock', { pool_name: selectedAccount.pool_name, username: selectedAccount.username, duration: Number(lockDuration) }); toast.success('锁定成功'); setShowLockModal(false); fetchAccounts(page); // 刷新当前页 } catch (error) { toast.error('锁定失败'); } }; const handleDisable = async (account: Account) => { if (!confirm(`确定要禁用账号 ${account.username} 吗?`)) return; try { await api.post('/api/account/disable', { pool_name: account.pool_name, username: account.username }); toast.success('禁用成功'); fetchAccounts(page); } catch (error) { toast.error('禁用失败'); } }; return (
{/* === 头部区域 === */}

账号池管理

管理爬虫账号、查看锁定状态及禁用异常账号

{/* 搜索框 */}
setKeyword(e.target.value)} onKeyDown={handleKeyDown} />
{/* 刷新 */} {/* 新增 */}
{/* === 表格组件 === */} { setSelectedAccount(acc); setShowLockModal(true); }} onDisable={handleDisable} /> {/* === 分页组件 === */}
{/* === Modals === */} {/* 新增 Modal */} {showAddModal && (

新增账号

setAddForm({...addForm, pool_name: e.target.value})} />
setAddForm({...addForm, username: e.target.value})} />
setAddForm({...addForm, password: e.target.value})} />