优化登录弹窗
This commit is contained in:
@@ -124,8 +124,8 @@ class AccountOut(BaseModel):
|
|||||||
# ---- 登录任务 ----
|
# ---- 登录任务 ----
|
||||||
class LoginBatchRequest(BaseModel):
|
class LoginBatchRequest(BaseModel):
|
||||||
account_ids: list[int]
|
account_ids: list[int]
|
||||||
max_login_retries: int = 0 # 登录整体重试次数,0=无限重试直到成功
|
max_login_retries: int = 0 # 登录整体重试次数,0=无限重试直到成功(后端兜底 20 次)
|
||||||
max_total_time: float = 0 # 单账号登录总时长上限,0=不限制
|
max_total_time: float = 300 # 单账号登录总时长上限(秒),0=不限制
|
||||||
concurrency: int = 3 # 并发数,1-10
|
concurrency: int = 3 # 并发数,1-10
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useEffect, useState, useMemo, useCallback } from 'react';
|
import { useEffect, useState, useMemo, useCallback } from 'react';
|
||||||
import {
|
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';
|
} 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 { accountApi, loginApi, type AccountItem, type LoginTaskItem } from '../api/modules';
|
||||||
import RealtimeLogPanel from '../components/RealtimeLogPanel';
|
import RealtimeLogPanel from '../components/RealtimeLogPanel';
|
||||||
import { usePermissions } from '../hooks/usePermissions';
|
import { usePermissions } from '../hooks/usePermissions';
|
||||||
@@ -43,9 +43,20 @@ export default function LoginTasksPage() {
|
|||||||
const v = localStorage.getItem('login_concurrency');
|
const v = localStorage.getItem('login_concurrency');
|
||||||
return v ? Math.max(1, Math.min(10, Number(v) || 3)) : 3;
|
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_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<number[]>([]);
|
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
|
||||||
const { logs, connected: wsConnected, connect: connectLogs } = useWebSocketLogs();
|
const { logs, connected: wsConnected, connect: connectLogs } = useWebSocketLogs();
|
||||||
const { can } = usePermissions();
|
const { can } = usePermissions();
|
||||||
@@ -143,6 +154,8 @@ export default function LoginTasksPage() {
|
|||||||
const result = await loginApi.createBatch({
|
const result = await loginApi.createBatch({
|
||||||
account_ids: accountIds,
|
account_ids: accountIds,
|
||||||
concurrency,
|
concurrency,
|
||||||
|
max_login_retries: maxLoginRetries,
|
||||||
|
max_total_time: maxTotalTime,
|
||||||
});
|
});
|
||||||
setBatchId(result.batch_id);
|
setBatchId(result.batch_id);
|
||||||
message.success(`已创建登录任务,共 ${result.count} 个账号`);
|
message.success(`已创建登录任务,共 ${result.count} 个账号`);
|
||||||
@@ -329,18 +342,12 @@ export default function LoginTasksPage() {
|
|||||||
标签选中 {accounts.filter((a) => selectedTags.includes((a.tag || '').trim())).length} 个
|
标签选中 {accounts.filter((a) => selectedTags.includes((a.tag || '').trim())).length} 个
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<Tooltip title="同时登录的账号数,1为顺序执行">
|
<Tooltip title={`登录设置(并发 ${concurrency},超时 ${maxTotalTime || '∞'}s,重试 ${maxLoginRetries || '∞'})`}>
|
||||||
<Space size={4}>
|
<Button
|
||||||
<ThunderboltOutlined style={{ color: token.colorTextSecondary }} />
|
icon={<SettingOutlined />}
|
||||||
<InputNumber
|
onClick={() => setSettingsOpen(true)}
|
||||||
min={1}
|
size="small"
|
||||||
max={10}
|
/>
|
||||||
value={concurrency}
|
|
||||||
onChange={(v) => setConcurrency(v || 1)}
|
|
||||||
style={{ width: 50 }}
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@@ -416,6 +423,72 @@ export default function LoginTasksPage() {
|
|||||||
spinWhenEmpty
|
spinWhenEmpty
|
||||||
style={{ marginTop: 4 }}
|
style={{ marginTop: 4 }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title="登录设置"
|
||||||
|
open={settingsOpen}
|
||||||
|
onCancel={() => setSettingsOpen(false)}
|
||||||
|
footer={[
|
||||||
|
<Button
|
||||||
|
key="reset"
|
||||||
|
onClick={() => {
|
||||||
|
setConcurrency(3);
|
||||||
|
setMaxTotalTime(300);
|
||||||
|
setMaxLoginRetries(0);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
恢复默认
|
||||||
|
</Button>,
|
||||||
|
<Button key="ok" type="primary" onClick={() => setSettingsOpen(false)}>
|
||||||
|
完成
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Form layout="vertical" style={{ marginTop: 8 }}>
|
||||||
|
<Form.Item
|
||||||
|
label="并发数"
|
||||||
|
tooltip="同时登录的账号数。1 为顺序执行,最多 10。"
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
min={1}
|
||||||
|
max={10}
|
||||||
|
value={concurrency}
|
||||||
|
onChange={(v) => setConcurrency(v || 1)}
|
||||||
|
style={{ width: 120 }}
|
||||||
|
addonAfter="个"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="单账号超时"
|
||||||
|
tooltip="单个账号登录的总时长上限,超时则放弃。0 表示不限。"
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
max={3600}
|
||||||
|
step={30}
|
||||||
|
value={maxTotalTime}
|
||||||
|
onChange={(v) => setMaxTotalTime(v ?? 0)}
|
||||||
|
style={{ width: 120 }}
|
||||||
|
addonAfter="秒"
|
||||||
|
placeholder="0=不限"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="登录整体重试次数"
|
||||||
|
tooltip="单个账号最多重试多少轮(每轮换新代理)。0 表示无限重试直到成功或超时。"
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
max={50}
|
||||||
|
value={maxLoginRetries}
|
||||||
|
onChange={(v) => setMaxLoginRetries(v ?? 0)}
|
||||||
|
style={{ width: 120 }}
|
||||||
|
addonAfter="次"
|
||||||
|
placeholder="0=无限"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user