返回 AiToEarn
PubAccountDetModule.tsx
1 import {
2 ForwardedRef,
3 forwardRef,
4 memo,
5 useEffect,
6 useImperativeHandle,
7 useState,
8 } from 'react';
9 import styles from './pubAccountDetModule.module.scss';
10 import { Alert, Button, Checkbox, message, Modal, Tooltip } from 'antd';
11 import { CheckCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
12 import { AccountInfo } from '../../../account/comment';
13 import { LoadingOutlined } from '@ant-design/icons';
14 import {
15 accountLogin,
16 acpAccountLoginCheck,
17 icpProxyCheck,
18 } from '../../../../icp/account';
19 import { AccountStatus } from '../../../../../commont/AccountEnum';
20 import { AvatarPlat } from '../PubProgressModule/PubProgressModule';
21 import { AccountGroupItem, useAccountStore } from '@/store/account';
22 import { useShallow } from 'zustand/react/shallow';
23 import { AccountModel } from '../../../../../electron/db/models/account';
24
25 export interface IPubAccountDetModuleRef {
26 // 打开弹框并且开始检测
27 startDet: () => void;
28 }
29
30 export interface IPubAccountDetModuleProps {
31 // 待检测的账户
32 accounts: AccountInfo[];
33 // 弹框关闭
34 onClose?: () => void;
35 // 发布
36 onPubClick?: () => void;
37 /**
38 * 检测完成
39 * @param accounts 检测过后的账户数据
40 */
41 onDetFinish?: (accounts: AccountInfo[]) => void;
42 // 重新登录完成事件
43 onRestartLoginFinish?: (accounts: AccountInfo) => void;
44 title?: string;
45 tips?: string;
46 // 是否需要footer操作栏
47 isFooter?: boolean;
48 // 是否需要校验代理地址
49 isCheckProxy?: boolean;
50 }
51
52 // 发布用户检测
53 const PubAccountDetModule = memo(
54 forwardRef(
55 (
56 {
57 onRestartLoginFinish,
58 accounts,
59 onClose,
60 onPubClick,
61 onDetFinish,
62 title = '发布检测',
63 tips = '以下账号将发布至平台',
64 isFooter = true,
65 isCheckProxy = false,
66 }: IPubAccountDetModuleProps,
67 ref: ForwardedRef<IPubAccountDetModuleRef>,
68 ) => {
69 const [open, setOpen] = useState(false);
70 const [detLoading, setDetLoading] = useState(false);
71 // 失效 ids
72 const [disabledIdSet, setDisabledIdSet] = useState<Set<number>>(
73 new Set([]),
74 );
75 const [progress, setProgress] = useState(0);
76 const [isFilterAccountOl, setIsFilterAccountOl] = useState(false);
77 // 代理失效的账户组Map
78 const [proxyInvalidAccountMap, setProxyInvalidAccountMap] = useState<
79 Map<number, AccountGroupItem>
80 >(new Map());
81 const { accountGroupMap, getAccountList } = useAccountStore(
82 useShallow((state) => ({
83 accountGroupMap: state.accountGroupMap,
84 getAccountList: state.getAccountList,
85 })),
86 );
87
88 useEffect(() => {
89 if (open) {
90 setDisabledIdSet(new Set([]));
91 setIsFilterAccountOl(false);
92 }
93 }, [open]);
94
95 useEffect(() => {
96 if (disabledIdSet.size === 0) {
97 setIsFilterAccountOl(false);
98 }
99 }, [disabledIdSet]);
100
101 const close = () => {
102 if (detLoading) return;
103 setOpen(false);
104 if (onClose) onClose();
105 };
106
107 // 检测账户状态
108 const retLoginStatusCore = async (account: AccountInfo) => {
109 const res = await acpAccountLoginCheck(
110 account.type,
111 account.uid,
112 false,
113 );
114 setProgress((prevProgress) => prevProgress + 1);
115 return res;
116 };
117
118 // 检测代理地址有效性
119 const retProxyCheckCore = async (group: AccountGroupItem) => {
120 let status = true;
121 if (group.proxyIp) {
122 status = await icpProxyCheck(group.proxyIp);
123 }
124 return {
125 status,
126 group,
127 };
128 };
129
130 const getIp = (account: AccountModel) => {
131 if (!isCheckProxy) return '';
132 const group = accountGroupMap.get(account.groupId!)!;
133 if (!group.proxyOpen || !group.proxyIp) return '';
134 return '代理' + ` ${group.proxyIp}`;
135 };
136
137 const imperative: IPubAccountDetModuleRef = {
138 async startDet() {
139 setProxyInvalidAccountMap(new Map());
140 setDisabledIdSet(new Set([]));
141 setOpen(true);
142 setDetLoading(true);
143
144 // 账户状态
145 const tasksAccountStatus: Promise<AccountInfo>[] = [];
146 // 代理地址有效性检测
147 const tasksProxyCheck: Promise<{
148 status: boolean;
149 group: AccountGroupItem;
150 }>[] = [];
151 // 代理地址需要检测的账户组
152 const proxyGroupSet = new Set<number>([]);
153 for (let i = 0; i < accounts.length; i++) {
154 const account = accounts[i];
155 tasksAccountStatus.push(retLoginStatusCore(account));
156
157 if (isCheckProxy) {
158 // 代理有效性检测
159 if (!proxyGroupSet.has(account.groupId!)) {
160 const group = accountGroupMap.get(account.groupId!)!;
161 if (group.proxyOpen) {
162 tasksProxyCheck.push(
163 retProxyCheckCore(accountGroupMap.get(account.groupId!)!),
164 );
165 }
166 proxyGroupSet.add(account.groupId!);
167 }
168 }
169 }
170
171 // 等待代理和账号有效性检测...
172 const resGroupProxyStatus = await Promise.all(tasksProxyCheck);
173 const resAccountStatus = await Promise.all(tasksAccountStatus);
174
175 await getAccountList();
176
177 setTimeout(() => {
178 if (onDetFinish) onDetFinish(resAccountStatus);
179 setDetLoading(false);
180
181 const disabledIdSet = new Set<number>([]);
182 resAccountStatus.map((v) =>
183 v.status === AccountStatus.DISABLE ? disabledIdSet.add(v.id) : '',
184 );
185 setDisabledIdSet(disabledIdSet);
186 setProgress(0);
187
188 resGroupProxyStatus.map((v) => {
189 if (!v.status) {
190 setProxyInvalidAccountMap((prevState) => {
191 const newState = new Map<number, AccountGroupItem>(prevState);
192 newState.set(v.group.id, v.group);
193 return newState;
194 });
195 }
196 });
197 }, 50);
198 },
199 };
200 useImperativeHandle(ref, () => imperative);
201
202 return (
203 <Modal
204 width={530}
205 title={title}
206 maskClosable={false}
207 open={open}
208 onCancel={close}
209 footer={null}
210 >
211 <div className={styles.pubAccountDetModule}>
212 <div className="pubAccountDetModule-tips">
213 {!detLoading ? (
214 <>
215 {disabledIdSet.size === 0 ? (
216 proxyInvalidAccountMap.size === 0 && `${tips}`
217 ) : (
218 <Alert
219 style={{ marginBottom: '10px' }}
220 message={
221 <div className={styles.loginStatusDisable}>
222 <span>账号登录状态失效,点击账户重新登录</span>
223 <Checkbox
224 checked={isFilterAccountOl}
225 onChange={(e) =>
226 setIsFilterAccountOl(e.target.checked)
227 }
228 >
229 过滤在线账户
230 </Checkbox>
231 </div>
232 }
233 type="error"
234 showIcon
235 />
236 )}
237
238 {proxyInvalidAccountMap.size !== 0 && (
239 <Alert
240 message={
241 <div>
242 <span>以下代理不可用,请调整后重试:</span>
243 <ul>
244 {Array.from(proxyInvalidAccountMap).map(
245 ([_, v]) => {
246 return (
247 <li key={v.id}>
248 用户组:{v.name},代理地址:{v.proxyIp}{' '}
249 不可用
250 </li>
251 );
252 },
253 )}
254 </ul>
255 </div>
256 }
257 type="error"
258 showIcon
259 />
260 )}
261 </>
262 ) : (
263 <>
264 正在检测账号状态 {progress} / {accounts.length}
265 <LoadingOutlined />
266 </>
267 )}
268 </div>
269 <div className="pubAccountDetModule-accounts">
270 {accounts
271 .filter((v) =>
272 isFilterAccountOl
273 ? disabledIdSet.has(v.id) && !detLoading
274 : true,
275 )
276 .map((v) => {
277 return (
278 <div
279 className={[
280 'pubAccountDetModule-accounts-account',
281 disabledIdSet.has(v.id) ||
282 proxyInvalidAccountMap.get(v.groupId)
283 ? 'pubAccountDetModule-accounts-disable'
284 : !disabledIdSet.has(v.id) &&
285 !detLoading &&
286 'pubAccountDetModule-accounts-ol',
287 ].join(' ')}
288 style={{
289 cursor: disabledIdSet.has(v.id) ? 'pointer' : 'auto',
290 }}
291 key={v.id}
292 onClick={async () => {
293 if (disabledIdSet.has(v.id)) {
294 const res = await accountLogin(v.type);
295 if (!res) return;
296 message.success('登录成功!');
297 if (onRestartLoginFinish) onRestartLoginFinish(res);
298 setDisabledIdSet((prevState) => {
299 const newState = new Set<number>(prevState);
300 newState.delete(res.id);
301 return newState;
302 });
303 }
304 }}
305 >
306 <AvatarPlat account={v} size="default" />
307 <Tooltip title={v.nickname}>
308 <div
309 className={['pubAccountDetModule-accounts-name'].join(
310 ' ',
311 )}
312 >
313 <div className="pubAccountDetModule-accounts-name-wrapper">
314 <CloseCircleOutlined className="pubAccountDetModule-accounts-disable-icon" />
315 <CheckCircleOutlined className="pubAccountDetModule-accounts-ol-icon" />
316 <span>{v.nickname}</span>
317 </div>
318 </div>
319 </Tooltip>
320 <div className="pubAccountDetModule-accounts-proxy">
321 <Tooltip title={getIp(v)}>
322 <span>{getIp(v)}</span>
323 </Tooltip>
324 </div>
325 </div>
326 );
327 })}
328 </div>
329 </div>
330
331 {isFooter && (
332 <div style={{ display: 'flex', justifyContent: 'right' }}>
333 <Button style={{ marginRight: '10px' }} onClick={close}>
334 取消
335 </Button>
336 <Button
337 type="primary"
338 loading={detLoading}
339 disabled={
340 disabledIdSet.size !== 0 || proxyInvalidAccountMap.size !== 0
341 }
342 onClick={() => {
343 setOpen(false);
344 if (onPubClick) onPubClick();
345 }}
346 >
347 发布至平台
348 </Button>
349 </div>
350 )}
351 </Modal>
352 );
353 },
354 ),
355 );
356 PubAccountDetModule.displayName = 'PubAccountDetModule';
357
358 export default PubAccountDetModule;
359
359 lines Plain Text