From 4681136484e7b6ef0c1337509bcb2f77f5fa0c66 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Thu, 25 Jun 2026 08:54:54 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=99=BB=E5=BD=95=E5=BC=B9?= =?UTF-8?q?=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/backend/schemas.py | 4 +- web/frontend/src/pages/LoginTasksPage.tsx | 101 +++++++++++++++++++--- 2 files changed, 89 insertions(+), 16 deletions(-) diff --git a/web/backend/schemas.py b/web/backend/schemas.py index 51f1418..80e3cbf 100644 --- a/web/backend/schemas.py +++ b/web/backend/schemas.py @@ -124,8 +124,8 @@ class AccountOut(BaseModel): # ---- 登录任务 ---- class LoginBatchRequest(BaseModel): account_ids: list[int] - max_login_retries: int = 0 # 登录整体重试次数,0=无限重试直到成功 - max_total_time: float = 0 # 单账号登录总时长上限,0=不限制 + max_login_retries: int = 0 # 登录整体重试次数,0=无限重试直到成功(后端兜底 20 次) + max_total_time: float = 300 # 单账号登录总时长上限(秒),0=不限制 concurrency: int = 3 # 并发数,1-10 diff --git a/web/frontend/src/pages/LoginTasksPage.tsx b/web/frontend/src/pages/LoginTasksPage.tsx index 9489889..d606eb7 100644 --- a/web/frontend/src/pages/LoginTasksPage.tsx +++ b/web/frontend/src/pages/LoginTasksPage.tsx @@ -1,8 +1,8 @@ import { useEffect, useState, useMemo, useCallback } from 'react'; import { - Table, Button, Select, message, Tag, Space, InputNumber, Tooltip, Popconfirm, theme, + Table, Button, Select, message, Tag, Space, InputNumber, Tooltip, Popconfirm, theme, Modal, Form, } from 'antd'; -import { PlayCircleOutlined, StopOutlined, FilterOutlined, ThunderboltOutlined, ReloadOutlined, DeleteOutlined } from '@ant-design/icons'; +import { PlayCircleOutlined, StopOutlined, FilterOutlined, ReloadOutlined, DeleteOutlined, SettingOutlined } from '@ant-design/icons'; import { accountApi, loginApi, type AccountItem, type LoginTaskItem } from '../api/modules'; import RealtimeLogPanel from '../components/RealtimeLogPanel'; import { usePermissions } from '../hooks/usePermissions'; @@ -43,9 +43,20 @@ export default function LoginTasksPage() { const v = localStorage.getItem('login_concurrency'); return v ? Math.max(1, Math.min(10, Number(v) || 3)) : 3; }); + const [maxTotalTime, setMaxTotalTime] = useState(() => { + const v = localStorage.getItem('login_max_total_time'); + return v !== null ? Math.max(0, Number(v) || 0) : 300; + }); + const [maxLoginRetries, setMaxLoginRetries] = useState(() => { + const v = localStorage.getItem('login_max_login_retries'); + return v !== null ? Math.max(0, Number(v) || 0) : 0; + }); + const [settingsOpen, setSettingsOpen] = useState(false); // 值变化时自动持久化 useEffect(() => { localStorage.setItem('login_concurrency', String(concurrency)); }, [concurrency]); + useEffect(() => { localStorage.setItem('login_max_total_time', String(maxTotalTime)); }, [maxTotalTime]); + useEffect(() => { localStorage.setItem('login_max_login_retries', String(maxLoginRetries)); }, [maxLoginRetries]); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const { logs, connected: wsConnected, connect: connectLogs } = useWebSocketLogs(); const { can } = usePermissions(); @@ -143,6 +154,8 @@ export default function LoginTasksPage() { const result = await loginApi.createBatch({ account_ids: accountIds, concurrency, + max_login_retries: maxLoginRetries, + max_total_time: maxTotalTime, }); setBatchId(result.batch_id); message.success(`已创建登录任务,共 ${result.count} 个账号`); @@ -329,18 +342,12 @@ export default function LoginTasksPage() { 标签选中 {accounts.filter((a) => selectedTags.includes((a.tag || '').trim())).length} 个 )} - - - - setConcurrency(v || 1)} - style={{ width: 50 }} - size="small" - /> - + + , + , + ]} + > +
+ + setConcurrency(v || 1)} + style={{ width: 120 }} + addonAfter="个" + /> + + + setMaxTotalTime(v ?? 0)} + style={{ width: 120 }} + addonAfter="秒" + placeholder="0=不限" + /> + + + setMaxLoginRetries(v ?? 0)} + style={{ width: 120 }} + addonAfter="次" + placeholder="0=无限" + /> + +
+ ); }