返回 AiToEarn
UserManageModal.tsx
1 import {
2 ForwardedRef,
3 forwardRef,
4 memo,
5 useImperativeHandle,
6 useMemo,
7 useRef,
8 useState,
9 } from 'react';
10 import {
11 Avatar,
12 Drawer,
13 message,
14 Modal,
15 Select,
16 Table,
17 TableProps,
18 Tooltip,
19 } from 'antd';
20 import styles from './AccountSidebar.module.scss';
21 import { useAccountStore } from '@/store/account';
22 import { useShallow } from 'zustand/react/shallow';
23 import { AccountModel } from '../../../../../electron/db/models/account';
24 import { AccountPlatInfoMap } from '../../comment';
25 import { AccountStatus } from '../../../../../commont/AccountEnum';
26 import {
27 CheckCircleOutlined,
28 DeleteOutlined,
29 WarningOutlined,
30 } from '@ant-design/icons';
31 import { AvatarPlat } from '@/views/publish/components/PubProgressModule/PubProgressModule';
32 import {
33 icpAccountEditGroup,
34 icpDeleteAccounts,
35 icpEditDeleteAccountGroup,
36 } from '@/icp/account';
37 import UserManageSidebar from './UserManageSidebar';
38
39 export interface IUserManageModalRef {
40 setActiveGroup: (groupId: number) => void;
41 }
42
43 export interface IUserManageModalProps {
44 open: boolean;
45 onCancel: () => void;
46 }
47
48 const UserGroupSelect = ({
49 account,
50 onChange,
51 }: {
52 account: AccountModel;
53 onChange: (groupId: number) => void;
54 }) => {
55 const { accountGroupList } = useAccountStore(
56 useShallow((state) => ({
57 accountGroupList: state.accountGroupList,
58 })),
59 );
60
61 return (
62 <Select
63 value={account.groupId}
64 style={{ width: '160px' }}
65 fieldNames={{
66 value: 'id',
67 label: 'name',
68 }}
69 options={accountGroupList}
70 onChange={onChange}
71 />
72 );
73 };
74
75 const UserManageModal = memo(
76 forwardRef(
77 (
78 { open, onCancel }: IUserManageModalProps,
79 ref: ForwardedRef<IUserManageModalRef>,
80 ) => {
81 const { accountList, getAccountList, accountGroupList, accountMap } =
82 useAccountStore(
83 useShallow((state) => ({
84 accountList: state.accountList,
85 getAccountList: state.getAccountList,
86 accountGroupList: state.accountGroupList,
87 accountMap: state.accountMap,
88 })),
89 );
90 const [deleteHitOpen, setDeleteHitOpen] = useState(false);
91 const [selectedRows, setSelectedRows] = useState<AccountModel[]>([]);
92 // 全部账号
93 const allUser = useRef(-1);
94 // -1=全部账号,不然为对应分组 ID
95 const [activeGroup, setActiveGroup] = useState(allUser.current);
96 // 是否改变了顺序
97 const isUpdateRank = useRef(false);
98
99 const columns = useMemo(() => {
100 const columns: TableProps<AccountModel>['columns'] = [
101 {
102 title: '账号',
103 render: (text, am) => {
104 return (
105 <div
106 className={`userManage-content-user ${am.status === AccountStatus.DISABLE ? 'userManage-content-user--disable' : ''}`}
107 >
108 <Avatar src={am.avatar} />
109 <span
110 className="userManage-content-user-name"
111 title={am.nickname}
112 >
113 {am.nickname}
114 </span>
115 </div>
116 );
117 },
118 width: 200,
119 key: 'nickname',
120 },
121 {
122 title: '平台',
123 render: (text, am) => {
124 const platInfo = AccountPlatInfoMap.get(am.type)!;
125 return (
126 <div className="userManage-content-plat">
127 <Tooltip title={platInfo.name}>
128 <img src={platInfo.icon} />
129 </Tooltip>
130 </div>
131 );
132 },
133 width: 80,
134 key: 'nickname',
135 },
136 {
137 title: '账号状态',
138 render: (text, am) => {
139 return (
140 <>
141 {am.status === AccountStatus.USABLE ? (
142 <>
143 <CheckCircleOutlined
144 style={{
145 color: 'var(--successColor)',
146 marginRight: '3px',
147 }}
148 />
149 在线
150 </>
151 ) : (
152 <>
153 <WarningOutlined
154 style={{
155 color: 'var(--warningColor)',
156 marginRight: '3px',
157 }}
158 />
159 离线
160 </>
161 )}
162 </>
163 );
164 },
165 width: 100,
166 key: 'nickname',
167 },
168 {
169 title: '所属列表',
170 render: (text, am) => {
171 return (
172 <UserGroupSelect
173 account={am}
174 onChange={async (groupId) => {
175 await updateAccountGroupRank();
176 await icpAccountEditGroup(am.id, groupId);
177 await getAccountList();
178 }}
179 />
180 );
181 },
182 width: 200,
183 key: 'groupId',
184 },
185 ];
186 return columns;
187 }, []);
188
189 const rowSelection: TableProps<AccountModel>['rowSelection'] = {
190 onChange: (
191 selectedRowKeys: React.Key[],
192 selectedRows: AccountModel[],
193 ) => {
194 setSelectedRows(selectedRows);
195 },
196 getCheckboxProps: (record: AccountModel) => ({
197 name: record.nickname,
198 }),
199 selectedRowKeys: selectedRows.map((v) => v.id),
200 };
201
202 const close = () => {
203 onCancel();
204 setSelectedRows([]);
205 updateAccountGroupRank();
206 };
207
208 // 更新账户组顺序
209 const updateAccountGroupRank = async () => {
210 if (isUpdateRank.current) {
211 const accountGroupList = useAccountStore.getState().accountGroupList;
212 for (let i = 0; i < accountGroupList.length; i++) {
213 const v = accountGroupList[i];
214 // 这里不需要更新数据,因为在排序完成后已经更新了全局的sotre,引用sotre的所有位置都会发生更改
215 await icpEditDeleteAccountGroup({
216 id: v.id,
217 rank: i,
218 });
219 }
220 isUpdateRank.current = false;
221 }
222 };
223
224 const accountListLast = useMemo(() => {
225 if (activeGroup === allUser.current) {
226 return accountList;
227 }
228 return accountGroupList.find((v) => v.id === activeGroup)?.children;
229 }, [accountMap, activeGroup, accountGroupList]);
230
231 const imperativeHandle: IUserManageModalRef = {
232 setActiveGroup,
233 };
234 useImperativeHandle(ref, () => imperativeHandle);
235
236 return (
237 <>
238 <Modal
239 centered
240 open={deleteHitOpen}
241 title="删除提示"
242 width={500}
243 zIndex={1002}
244 onCancel={() => setDeleteHitOpen(false)}
245 rootClassName={styles.userManageDeleteHitModal}
246 onOk={async () => {
247 await icpDeleteAccounts(selectedRows.map((v) => v.id));
248 await getAccountList();
249 setDeleteHitOpen(false);
250 setSelectedRows([]);
251 message.success('删除成功');
252 }}
253 >
254 <p>
255 是否删除以下
256 <span style={{ color: 'var(--errerColor)' }}>
257 {selectedRows.length}
258 </span>
259 个账号?
260 </p>
261 <div className={styles['userManageDeleteHitModal-users']}>
262 {selectedRows.map((v) => {
263 return (
264 <li key={v.id}>
265 <AvatarPlat account={v} size="large" />
266 <span>{v.nickname}</span>
267 </li>
268 );
269 })}
270 </div>
271 </Modal>
272
273 <Modal
274 open={open}
275 title="账号管理器"
276 zIndex={1001}
277 footer={null}
278 width={1000}
279 onCancel={close}
280 rootClassName={styles.userManageModal}
281 >
282 <div className={styles.userManage}>
283 <UserManageSidebar
284 allUser={allUser.current}
285 activeGroup={activeGroup}
286 onChange={setActiveGroup}
287 onSortEnd={() => {
288 isUpdateRank.current = true;
289 }}
290 />
291
292 <div className="userManage-content">
293 {/*<div className="userManage-content-head">*/}
294 {/* <div></div>*/}
295 {/*</div>*/}
296 <Table<AccountModel>
297 columns={columns}
298 dataSource={accountListLast}
299 rowKey="id"
300 scroll={{ y: '100%' }}
301 rowSelection={{ type: 'checkbox', ...rowSelection }}
302 />
303
304 <Drawer
305 title={
306 <>
307 已选择
308 <span style={{ color: 'var(--successColor)' }}>
309 {selectedRows.length}
310 </span>
311 个账号
312 </>
313 }
314 placement="bottom"
315 mask={false}
316 height={150}
317 closable={true}
318 onClose={() => {
319 setSelectedRows([]);
320 }}
321 open={selectedRows.length !== 0}
322 getContainer={false}
323 >
324 <div className="userManage-content-multiple">
325 <div
326 className="userManage-content-multiple-item"
327 onClick={() => {
328 setDeleteHitOpen(true);
329 }}
330 >
331 <div className="userManage-content-multiple-item-icon">
332 <DeleteOutlined />
333 </div>
334 <span>删除账号</span>
335 </div>
336 </div>
337 </Drawer>
338 </div>
339 </div>
340 </Modal>
341 </>
342 );
343 },
344 ),
345 );
346 UserManageModal.displayName = 'UserManageModal';
347
348 export default UserManageModal;
349
349 lines Plain Text