From 9fba12aad0d68efd366ba37e8f34a1e7876cec5e Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 22 Jun 2026 15:45:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/schemas.cpython-312.pyc | Bin 5704 -> 5751 bytes .../routers/__pycache__/login.cpython-312.pyc | Bin 7450 -> 7497 bytes web/backend/routers/login.py | 1 + web/backend/schemas.py | 1 + .../__pycache__/login_service.cpython-312.pyc | Bin 8476 -> 11579 bytes web/backend/services/login_service.py | 177 ++++++++++++------ web/frontend/src/api/modules.ts | 4 +- web/frontend/src/pages/LoginTasksPage.tsx | 76 +++++++- 8 files changed, 199 insertions(+), 60 deletions(-) diff --git a/web/backend/__pycache__/schemas.cpython-312.pyc b/web/backend/__pycache__/schemas.cpython-312.pyc index 6a6c628f7cd7fd040f1b655c86af34fb3dbd854a..9851552e56c01c1816a8eb0fd23f89290ce442e9 100644 GIT binary patch delta 407 zcmX@1^IeDcG%qg~0}ymRu*j;}$h(A((Q2}zi16g2d{ROwEK%&KEUBz1tTsRum28^q zlOOXLiN0h8@@{b_=jSDt78RxDC0F`sa!i)sS7G#>Tqr0!*_)qFM-ix`mEne<=!E2n zl9ySeZpbTKU=g1oe3?bzhPXt7_XOc9ED}Y6KvhMalkam&Zl1#5$jBNAmiEDxgeh?80 zBKSZ=9EgYq5eXn75kw?`oXiysVuFaQ$-%;*jM0-<3Ma^=fCNEA2@n^v0*Mxe8!Q|U zSEqn%a}cp(44qsrqQ#aDQmY9zD-Fa15tWnAh{!XhO@1SiA^>(P*cPyq`vS>78NrF00q}wNB{r; delta 384 zcmeyab3%vrG%qg~0}yPwYmw!@k#`9nqt4__e7Y=^ESjv7Kk^wd`)RUIw%}KpoX9WB zC_cHKU!3a-i$akgP)m{L!2S z2N4M%0?pt^kQj)_oZKWF${0EMhH!#h5=an46oW7;kZ57J!NLJ?PZG%Pd=Wdw;K}Pm zw3JgpYQZi*GdTq$0U|0U{}z#FOqnb#nj!%92iQ)q9VwIhMP(T?Ca)Fk=3!z~oWc2p N0Z4t}n(QKG3;?+4O_~4z diff --git a/web/backend/routers/__pycache__/login.cpython-312.pyc b/web/backend/routers/__pycache__/login.cpython-312.pyc index d66f9860e30dc62f085f3f8cf126d0622952892e..3f5eaf1691553f8f6c35de357fe98e27dffc9e06 100644 GIT binary patch delta 793 zcmY+CTWb?R6vuaRnQV61Y;~)-LMxSG+NQB4YHW)yN~%~)qHn#BwwtAPyJo}8#tTHP zXdjEzc@V@G5m8YDiTw;J`T@$~LqCB;TYPrTrhRZ=e*EX0|C}>BJI}|zjVs?3MH2Yf z+9{ZOpOoH!B=glHK6jVe!+{OoU`sHMgX914A@n}njog!3k~zq};=bgG15Zny|mYOLlT>F7yh8pNb2LE9-V$ZxUkE^}B3AyoeI)wYY)P zyb8&%T-e4#UHLX_N>f}O<&)a&l%%4b?cV6K(q?H-lOlMn*om>cJmb$4vusmNp-lUu z91Gxlcl!@@Hh&VN3OE8d&EW=2d!Bpx)o@EbvvSAKhrscTEAs2XgA~CiSu513dTuhu1J}V; zMuM;=bRvSHKDpG^4*f-Fh)LQp>>VJ>#)UV`X6 zLD(DZGMaDy)+&Cr$^&Vi8?=mDhDFM(5{=_!FwL+=G&XVt(z1&eb=_zc%cce?u+Pz~Tmy%9o+b7x8jE`$rrf4g%U)io11X{0bHCjeEBbH&>=SG? z(cmxSXJUN<{&BZM0B*y(hwiDp%CPmFK<2^al@=#&+O?)-oF|Xji{$#~IW!-*Vxf}oh delta 758 zcmYL`O-~a+7{_;Zx7&S5TcFr?V-;dj-LzIwuo4djYZL_WrX`lLtkPxa)|o9{KuH=d zCL|_v!-EG;MlWW+fHyT9@MO#;8WX=jBi_6?&lch&^V|PC&;NPmWj|MTE0MiOMCI6c zxj$j;zmE)yDlEHf9?W=W#T|a&UHGjG4vyPYH&kns{*X?TPxm7nx1mik=@yRG)|n&q z|I4a$S`3e%5`7_NB*co`GR5K7NTvySk#^-Nl%}8L9i-Em;z-a8>-39asZ}NuY?2jk zN{u1q&!7^OwyM1ZHMIM}sp=^GpyiP6eb-W=bfI7OH&z=ffs6r;0mc}7(Q=wC9EJ5X zAh4eYbrGP`=L7j?WssKuLkzy$Atr7$)=YdGVzYobzzE1(H&fqJ=Y%SL<;|c{aV-RF#*;!Cs-enKn8{we0p4__h5VM7Vu$?cmfn=nSQAIJ^L^ zptU@?<}7z?^D6Grz3g^z0?nXrN~R}(_$kMFArL)@iw^w`gFFy8KH1}g=sJCx`zS)Q Ee}=QJ<^TWy diff --git a/web/backend/routers/login.py b/web/backend/routers/login.py index 3087a4e..b01700a 100644 --- a/web/backend/routers/login.py +++ b/web/backend/routers/login.py @@ -61,6 +61,7 @@ async def create_batch( proxy_config=proxy, log_queue=log_queue, loop=loop, + concurrency=req.concurrency, ) batch_id = runner.batch_id diff --git a/web/backend/schemas.py b/web/backend/schemas.py index 7494c13..17f6dfd 100644 --- a/web/backend/schemas.py +++ b/web/backend/schemas.py @@ -83,6 +83,7 @@ class AccountOut(BaseModel): class LoginBatchRequest(BaseModel): account_ids: list[int] max_geetest_retries: int = 5 + concurrency: int = 3 # 并发数,1-10 class LoginTaskOut(BaseModel): diff --git a/web/backend/services/__pycache__/login_service.cpython-312.pyc b/web/backend/services/__pycache__/login_service.cpython-312.pyc index 0833bb013a282249da46c2b8b10b701244cb422b..f7b5690c4baea98169f88d500062aaecc1a78693 100644 GIT binary patch literal 11579 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%0DBR1ansZ3OcV@vPwfe`v^kn?%a?;FlD)L zRatMrQk18(>M~7+OjE!3YSO{Ec`jU6ri^tgsNUW+XqDHO8QBHZ$)`TI#-*y?OaozCRGgvvq+S#3OVurV4ZO3GzO;_4QK&dU_j?5il}l1@ zK^aQtOR;s4ZrsTuR;{ zll;`ePNuAm>h^SbzBpc~z6{rdenaN0Ilh}*a=ST8))McA;PFoiH4oWmiSL1v>$osH zAL=L6E)9nOUm+#BQ@T=^zx;i7ChfNtqo4IED654e;ZAtrLO(o``1%T z+UUgr=UU9)N*w!=#3@CtT|dE$DKv*5g79M48qRAMW3G~W1fSqsqzzgFNPeblRU^Vr z4Ot&fVtHSgo3)m2*?;-$`~SC1-mH~gA>E<|2Whb#vi{IIcBMEDFazjC?Ljoa1pVaJ zvSyva#!`Lhmjf$Xpe^v-x&G_VfB(z*@oOh+38=u|JsuMW!jVKm(GNs$iWVnwDA3dh z5mQW&Xf&Nk$>Erw=p;EJXCzz!3{J#2jme!r6R|Z`HFsyA*xk8tWB$jN=CA#3{?w~? zfAgB6$F$Z$v16XS2hSwwbk$Vhc8bM5rD+$`DTa(B;#4Fll7p_b9>p#uBe6s{mW=d= z`_otsY7|Z_4VWi4T^ot3YWZ*mng`$fZ^!PAOei{94l)TjxB`Q^YE4nJ2{EOXUA3Aj z+_8*^2Ng?a(URS1K};yRzF0yQv7(`NaeXl?$rxU43@wOaj!07MNJVtQ&i#9;Nfn-sUGPUVxnSv z;>D=gFUQg;+6c%vXj99p>KlcVX{RMA+6XmSOT((LKu}D@(ksNGRHq_N>#o9t6(*+W zOW{}a>R~kId)#myBTCTnsD*g}&`#m&Ca?1#Wk@%u;V02;zWU7O$;~4MvZ1-jmCQAy zW)10r4ps0YT%NC<;{&tgN6oJXD#mw>?mF9eQG3>X%hFT`AZKHt85ynP`ceJ3ZPYev zs3Eg02Zr6gN&N&n5y^X-CfJ{u^ZwP-k4~@1HEf|X%SV9~zuJ0f>&?L03HFx5SI{Gm zzhFStit+8E+sC^{yJsz)yruGvw`Gc(^R|t4k93Z{M0bnk?fm$O(Gzoa-;CWiYhRXk zIM3K7ZD$8_ts7?@n-quZc3ohkYi#Fm-r`uY*=;(b+n)W-#h#1DrYbH;7saWLD|@G1 zmqSy#avOHM!@uYGo97){F0g;ra-hI^t^1gd>iqe7--YMSJy#y;>MsP(1@nRCxxl)a zz`A^MaISgdO!LO~n>(-Ld}GU8o#IzE z}OEJBZUw{!oe2PS3Gjo-$z>OKJrFw!`{xR$QzGO zt((?NuerAA>Za+ox9zz-J?}`l<$LEGy)%y9uM2uA%lu1%PW;`8A=p_EuwpB1wSm+lOZ7e0@!*q_JrBNJvpf`Lxo$8AnQ7B zn)Ufr9r?8zzT}-;%WVr^;OIzmwW{uHVDex=4>JRD)f9|?nb6Max`G){3-bC4R={ki zx*^x_$V^px!47i=a(d2gzp(q9 - api.post('/login/batch', { account_ids, max_geetest_retries }), + createBatch: (account_ids: number[], max_geetest_retries?: number, concurrency?: number) => + api.post('/login/batch', { account_ids, max_geetest_retries, concurrency }), listTasks: (batch_id?: string) => api.get('/login/tasks', { params: batch_id ? { batch_id } : {} }), stop: (batch_id: string) => api.post(`/login/stop/${batch_id}`), diff --git a/web/frontend/src/pages/LoginTasksPage.tsx b/web/frontend/src/pages/LoginTasksPage.tsx index 0a2fde7..3c067ea 100644 --- a/web/frontend/src/pages/LoginTasksPage.tsx +++ b/web/frontend/src/pages/LoginTasksPage.tsx @@ -1,8 +1,8 @@ import { useEffect, useState, useRef, useMemo, useCallback } from 'react'; import { - Table, Button, Select, message, Tag, Space, Card, Row, Col, Statistic, Spin, + Table, Button, Select, message, Tag, Space, Card, Row, Col, Statistic, Spin, InputNumber, Tooltip, } from 'antd'; -import { PlayCircleOutlined, StopOutlined, FilterOutlined } from '@ant-design/icons'; +import { PlayCircleOutlined, StopOutlined, FilterOutlined, ThunderboltOutlined, ReloadOutlined } from '@ant-design/icons'; import { accountApi, loginApi } from '../api/modules'; import { getUser, hasPerm } from '../store/auth'; @@ -31,6 +31,7 @@ export default function LoginTasksPage() { const [logs, setLogs] = useState<{ level: string; message: string }[]>([]); const [wsConnected, setWsConnected] = useState(false); const [selectedTags, setSelectedTags] = useState([]); + const [concurrency, setConcurrency] = useState(3); const wsRef = useRef(null); const user = getUser(); @@ -111,15 +112,16 @@ export default function LoginTasksPage() { return () => clearInterval(timer); }, [batchId]); - const handleBatchLogin = async () => { - if (selectedIds.length === 0) { + // 共享的批量登录启动逻辑 + const startBatch = async (accountIds: number[]) => { + if (accountIds.length === 0) { message.warning('请选择账号'); return; } setLoading(true); setLogs([]); try { - const result = await loginApi.createBatch(selectedIds); + const result = await loginApi.createBatch(accountIds, 5, concurrency); setBatchId(result.batch_id); message.success(`已创建登录任务,共 ${result.count} 个账号`); @@ -148,6 +150,27 @@ export default function LoginTasksPage() { } }; + const handleBatchLogin = () => startBatch(selectedIds); + + // 重试当前批次所有失败的任务 + const handleRetryFailed = () => { + const failedIds = tasks + .filter((t) => ['failed', 'error'].includes(t.status)) + .map((t) => t.account_id); + if (failedIds.length === 0) { + message.info('没有失败的任务'); + return; + } + startBatch(failedIds); + }; + + // 重试单个失败任务 + const handleRetryOne = (taskId: number) => { + const task = tasks.find((t) => t.id === taskId); + if (!task) return; + startBatch([task.account_id]); + }; + const handleStop = async () => { if (batchId) { try { @@ -172,6 +195,25 @@ export default function LoginTasksPage() { }, { title: '消息', dataIndex: 'message', ellipsis: true }, { title: '时间', dataIndex: 'created_at', width: 180 }, + { + title: '操作', + width: 80, + render: (_: any, record: any) => { + if (['failed', 'error'].includes(record.status) && !wsConnected) { + return ( + + ); + } + return null; + }, + }, ]; return ( @@ -252,6 +294,17 @@ export default function LoginTasksPage() { )} /> + + + + setConcurrency(v || 1)} + style={{ width: 60 }} + size="small" + /> + ) + } style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }} bodyStyle={{ flex: 1, overflow: 'auto', padding: 0 }} >