返回 AiToEarn
AccountSidebar.tsx
1 import {
2 ForwardedRef,
3 forwardRef,
4 memo,
5 useMemo,
6 useRef,
7 useState,
8 } from 'react';
9 import styles from './AccountSidebar.module.scss';
10 import { AccountInfo, AccountPlatInfoMap } from '../../comment';
11 import { Avatar, Button, Collapse, message, Popover, Tooltip } from 'antd';
12 import { accountLogin, acpAccountLoginCheck } from '@/icp/account';
13 import AddAccountModal from '../AddAccountModal';
14 import {
15 AccountStatus,
16 PlatType,
17 defaultAccountGroupId,
18 XhsAccountAbnormal,
19 } from '@@/AccountEnum';
20 import Icon, {
21 CheckCircleOutlined,
22 PlusOutlined,
23 UserOutlined,
24 WarningOutlined,
25 } from '@ant-design/icons';
26 import PubAccountDetModule, {
27 IPubAccountDetModuleRef,
28 } from '../../../publish/components/PubAccountDetModule/PubAccountDetModule';
29 import { useShallow } from 'zustand/react/shallow';
30 import { useAccountStore } from '@/store/account';
31 import UserManageModal, { IUserManageModalRef } from './UserManageModal';
32 import ProxyManage from '@/views/account/components/AccountSidebar/ProxyManage';
33 import ProxyIcon from '@/assets/svgs/proxy.svg?react';
34 import { AccountModel } from '../../../../../electron/db/models/account';
35
36 export interface IAccountSidebarRef {}
37
38 export interface IAccountSidebarProps {
39 // 选择的账户id
40 activeAccountId: number;
41 // 切换选择的账户
42 onAccountChange: (info: AccountInfo) => void;
43 // 排除的平台类型
44 excludePlatforms?: PlatType[];
45 }
46
47 const AccountStatusView = ({ account }: { account: AccountModel }) => {
48 if (
49 account.type === PlatType.Xhs &&
50 account.abnormalStatus &&
51 account.abnormalStatus[PlatType.Xhs] === XhsAccountAbnormal.Abnormal
52 ) {
53 return (
54 <Tooltip title="账号状态异常,无法发布作品,请检查后重试!">
55 <WarningOutlined style={{ color: 'var(--warningColor)' }} />
56 异常
57 </Tooltip>
58 );
59 }
60
61 if (account.status === AccountStatus.USABLE) {
62 return (
63 <>
64 <CheckCircleOutlined style={{ color: 'var(--successColor)' }} />
65 在线
66 </>
67 );
68 }
69
70 return (
71 <>
72 <WarningOutlined style={{ color: 'var(--warningColor)' }} />
73 离线
74 </>
75 );
76 };
77
78 const AccountPopoverInfo = ({ accountInfo }: { accountInfo: AccountInfo }) => {
79 const platInfo = AccountPlatInfoMap.get(accountInfo.type)!;
80 const [detLoading, setDetLoading] = useState(false);
81
82 return (
83 <div
84 className={styles.accountPopoverInfo}
85 onClick={(e) => e.stopPropagation()}
86 >
87 <div className="accountPopoverInfo_top">
88 <Avatar src={accountInfo.avatar} size="large" />
89 <div className="accountPopoverInfo_top-right">
90 <div className="accountPopoverInfo-item">
91 <p>昵称:</p>
92 <p>{accountInfo.nickname}</p>
93 </div>
94 <div className="accountPopoverInfo-item">
95 <p>平台:</p>
96 <p>
97 <img src={platInfo.icon} />
98 {platInfo.name}
99 </p>
100 </div>
101 </div>
102 </div>
103
104 <div className="accountPopoverInfo-item">
105 <p>登录状态:</p>
106 <p>
107 <AccountStatusView account={accountInfo} />
108 <Button
109 type="link"
110 style={{ padding: '0 0 0 5px' }}
111 loading={detLoading}
112 onClick={async () => {
113 setDetLoading(true);
114 const res = await acpAccountLoginCheck(
115 accountInfo!.type,
116 accountInfo!.uid,
117 );
118 message.success(
119 `登录状态检测完成:${res.status === AccountStatus.USABLE ? '在线' : '离线,请重新登录'}`,
120 );
121 setTimeout(async () => {
122 setDetLoading(false);
123 if (res.status === AccountStatus.DISABLE) {
124 const res = await accountLogin(accountInfo.type);
125 if (!res) return;
126 message.success('账号更新成功!');
127 }
128 }, 500);
129 }}
130 >
131 登录状态检测
132 </Button>
133 </p>
134 </div>
135 </div>
136 );
137 };
138
139 const AccountSidebar = memo(
140 forwardRef(
141 (
142 {
143 activeAccountId,
144 onAccountChange,
145 excludePlatforms = [],
146 }: IAccountSidebarProps,
147 ref: ForwardedRef<IAccountSidebarRef>,
148 ) => {
149 const [isAccountModalOpen, setIsAccountModalOpen] = useState(false);
150 const pubAccountDetModuleRef = useRef<IPubAccountDetModuleRef>(null);
151 const {
152 accountList: fullAccountList,
153 getAccountList,
154 accountGroupList,
155 } = useAccountStore(
156 useShallow((state) => ({
157 accountList: state.accountList,
158 getAccountList: state.getAccountList,
159 accountGroupList: state.accountGroupList,
160 })),
161 );
162 const [userManageModalOpen, setUserManageModalOpen] = useState(false);
163 const [proxyManageOpen, setProxyManageOpen] = useState(false);
164 const userManageModalRef = useRef<IUserManageModalRef>(null);
165
166 // 在组件内部过滤账号列表,而不是在 useAccountStore 中过滤
167 const accountList = useMemo(() => {
168 return fullAccountList.filter(
169 (account) => !excludePlatforms.includes(account.type),
170 );
171 }, [fullAccountList, excludePlatforms]);
172
173 return (
174 <>
175 <ProxyManage
176 open={proxyManageOpen}
177 onCancel={() => setProxyManageOpen(false)}
178 onExamineAccountClick={(groupId) => {
179 userManageModalRef.current?.setActiveGroup(groupId);
180 setUserManageModalOpen(true);
181 }}
182 />
183 <UserManageModal
184 ref={userManageModalRef}
185 open={userManageModalOpen}
186 onCancel={() => setUserManageModalOpen(false)}
187 />
188 <PubAccountDetModule
189 title="账号检测"
190 tips="所有平台在线"
191 ref={pubAccountDetModuleRef}
192 accounts={accountList}
193 isFooter={false}
194 />
195 <AddAccountModal
196 open={isAccountModalOpen}
197 onClose={() => setIsAccountModalOpen(false)}
198 onAddSuccess={getAccountList}
199 />
200 <div className={styles.accountSidebar}>
201 <div className="accountSidebar-top">
202 <div className="accountSidebar-top-box">
203 <Button
204 onClick={() => {
205 setUserManageModalOpen(true);
206 }}
207 >
208 <UserOutlined />
209 账号管理器
210 </Button>
211 <Tooltip title="添加账号">
212 <Button
213 type="primary"
214 className="accountSidebar-top-addUser"
215 icon={<PlusOutlined />}
216 onClick={() => {
217 setIsAccountModalOpen(true);
218 }}
219 ></Button>
220 </Tooltip>
221 </div>
222 <div className="accountSidebar-top-box">
223 <Button
224 icon={<Icon component={ProxyIcon} />}
225 onClick={() => {
226 setProxyManageOpen(true);
227 }}
228 >
229 代理管理器
230 </Button>
231 </div>
232 </div>
233
234 <Collapse
235 defaultActiveKey={[defaultAccountGroupId]}
236 items={accountGroupList.map((v) => {
237 return {
238 key: v.id,
239 label: (
240 <>
241 {v.name}
242 <span className="accountSidebar-userCount">
243 {v.children?.length}/
244 {
245 v.children?.map(
246 (v) => v.status === AccountStatus.USABLE,
247 ).length
248 }
249 </span>
250 </>
251 ),
252 children: (
253 <ul key={v.id} className="accountList">
254 {v.children?.map((account) => {
255 if (excludePlatforms.includes(account.type)) return '';
256 const platInfo = AccountPlatInfoMap.get(account.type)!;
257 return (
258 <li
259 className={[
260 'accountList-item',
261 `${activeAccountId === account.id ? 'accountList-item--active' : ''}`,
262 // 失效状态
263 account.status === AccountStatus.DISABLE &&
264 'accountList-item--disable',
265 // 异常状态
266 account.abnormalStatus &&
267 account.abnormalStatus[PlatType.Xhs] ===
268 XhsAccountAbnormal.Abnormal &&
269 'accountList-item--abnormal',
270 ].join(' ')}
271 key={account.id}
272 onClick={async () => {
273 if (account.status === AccountStatus.DISABLE) {
274 const res = await accountLogin(account.type);
275 if (!res) return;
276 message.success('账号登录成功!');
277 return;
278 }
279 onAccountChange(account);
280 }}
281 >
282 <Avatar src={account.avatar} size="large" />
283 <div className="accountList-item-right">
284 <div
285 className="accountList-item-right-name"
286 title={account.nickname}
287 >
288 <Tooltip
289 title={
290 account.abnormalStatus &&
291 account.abnormalStatus[PlatType.Xhs] ===
292 XhsAccountAbnormal.Abnormal
293 ? '账号状态异常,无法发布作品,请检查后重试'
294 : undefined
295 }
296 >
297 {account.nickname}
298 </Tooltip>
299 </div>
300 <div className="accountList-item-right-footer">
301 <p className="accountList-item-right-plat">
302 <img src={platInfo.icon} />
303 <span>{platInfo.name}</span>
304 </p>
305 <Popover
306 content={
307 <AccountPopoverInfo accountInfo={account} />
308 }
309 // trigger="click"
310 placement="right"
311 >
312 ...
313 </Popover>
314 </div>
315 </div>
316 </li>
317 );
318 })}
319 </ul>
320 ),
321 };
322 })}
323 />
324
325 <div className="accountSidebar-footer">
326 <Button
327 type="link"
328 onClick={() => {
329 pubAccountDetModuleRef.current?.startDet();
330 }}
331 >
332 一键检测登录状态
333 </Button>
334 </div>
335 </div>
336 </>
337 );
338 },
339 ),
340 );
341 AccountSidebar.displayName = 'AccountSidebar';
342
343 export default AccountSidebar;
344
344 lines Plain Text