blob: 6435787cd90db340ffb92c9f91a837ddd7aefaca [file] [log] [blame]
86133aaa3f5d2025-04-20 21:33:29 +08001
2import React, { useState, useRef, useEffect } from 'react';
3import { useIntl, FormattedMessage, useAccess } from '@umijs/max';
4import { Card, Col, Dropdown, FormInstance, Row, Space, Switch } from 'antd';
5import { Button, message, Modal } from 'antd';
6import { ActionType, FooterToolbar, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
7import { PlusOutlined, DeleteOutlined, ExclamationCircleOutlined, DownOutlined, EditOutlined } from '@ant-design/icons';
8import { getUserList, removeUser, addUser, updateUser, exportUser, getUser, changeUserStatus, updateAuthRole, resetUserPwd } from '@/services/system/user';
9import UpdateForm from './edit';
10import { getDictValueEnum } from '@/services/system/dict';
11import { DataNode } from 'antd/es/tree';
12import { getDeptTree } from '@/services/system/user';
13import DeptTree from './components/DeptTree';
14import ResetPwd from './components/ResetPwd';
15import { getPostList } from '@/services/system/post';
16import { getRoleList } from '@/services/system/role';
17import AuthRoleForm from './components/AuthRole';
18
19const { confirm } = Modal;
20
21/* *
22 *
23 * @author whiteshader@163.com
24 * @datetime 2023/02/06
25 *
26 * */
27
28/**
29 * 添加节点
30 *
31 * @param fields
32 */
33const handleAdd = async (fields: API.System.User) => {
34 const hide = message.loading('正在添加');
35 try {
36 await addUser({ ...fields });
37 hide();
38 message.success('添加成功');
39 return true;
40 } catch (error) {
41 hide();
42 message.error('添加失败请重试!');
43 return false;
44 }
45};
46
47/**
48 * 更新节点
49 *
50 * @param fields
51 */
52const handleUpdate = async (fields: API.System.User) => {
53 const hide = message.loading('正在配置');
54 try {
55 await updateUser(fields);
56 hide();
57 message.success('配置成功');
58 return true;
59 } catch (error) {
60 hide();
61 message.error('配置失败请重试!');
62 return false;
63 }
64};
65
66/**
67 * 删除节点
68 *
69 * @param selectedRows
70 */
71const handleRemove = async (selectedRows: API.System.User[]) => {
72 const hide = message.loading('正在删除');
73 if (!selectedRows) return true;
74 try {
75 await removeUser(selectedRows.map((row) => row.userId).join(','));
76 hide();
77 message.success('删除成功,即将刷新');
78 return true;
79 } catch (error) {
80 hide();
81 message.error('删除失败,请重试');
82 return false;
83 }
84};
85
86const handleRemoveOne = async (selectedRow: API.System.User) => {
87 const hide = message.loading('正在删除');
88 if (!selectedRow) return true;
89 try {
90 const params = [selectedRow.userId];
91 await removeUser(params.join(','));
92 hide();
93 message.success('删除成功,即将刷新');
94 return true;
95 } catch (error) {
96 hide();
97 message.error('删除失败,请重试');
98 return false;
99 }
100};
101
102/**
103 * 导出数据
104 *
105 *
106 */
107const handleExport = async () => {
108 const hide = message.loading('正在导出');
109 try {
110 await exportUser();
111 hide();
112 message.success('导出成功');
113 return true;
114 } catch (error) {
115 hide();
116 message.error('导出失败,请重试');
117 return false;
118 }
119};
120
121const UserTableList: React.FC = () => {
122 const [messageApi, contextHolder] = message.useMessage();
123
124 const formTableRef = useRef<FormInstance>();
125
126 const [modalVisible, setModalVisible] = useState<boolean>(false);
127 const [resetPwdModalVisible, setResetPwdModalVisible] = useState<boolean>(false);
128 const [authRoleModalVisible, setAuthRoleModalVisible] = useState<boolean>(false);
129
130 const actionRef = useRef<ActionType>();
131 const [currentRow, setCurrentRow] = useState<API.System.User>();
132 const [selectedRows, setSelectedRows] = useState<API.System.User[]>([]);
133
134 const [selectDept, setSelectDept] = useState<any>({ id: 0 });
135 const [sexOptions, setSexOptions] = useState<any>([]);
136 const [statusOptions, setStatusOptions] = useState<any>([]);
137
138 const [postIds, setPostIds] = useState<number[]>();
139 const [postList, setPostList] = useState<any[]>();
140 const [roleIds, setRoleIds] = useState<number[]>();
141 const [roleList, setRoleList] = useState<any[]>();
142 const [deptTree, setDeptTree] = useState<DataNode[]>();
143
144 const access = useAccess();
145
146 /** 国际化配置 */
147 const intl = useIntl();
148
149 useEffect(() => {
150 getDictValueEnum('sys_user_sex').then((data) => {
151 setSexOptions(data);
152 });
153 getDictValueEnum('sys_normal_disable').then((data) => {
154 setStatusOptions(data);
155 });
156 }, []);
157
158 const showChangeStatusConfirm = (record: API.System.User) => {
159 let text = record.status === "1" ? "启用" : "停用";
160 const newStatus = record.status === '0' ? '1' : '0';
161 confirm({
162 title: `确认要${text}${record.userName}用户吗?`,
163 onOk() {
164 changeUserStatus(record.userId, newStatus).then(resp => {
165 if (resp.code === 200) {
166 messageApi.open({
167 type: 'success',
168 content: '更新成功!',
169 });
170 actionRef.current?.reload();
171 } else {
172 messageApi.open({
173 type: 'error',
174 content: '更新失败!',
175 });
176 }
177 });
178 },
179 });
180 };
181
182 const fetchUserInfo = async (userId: number) => {
183 const res = await getUser(userId);
184 setPostIds(res.postIds);
185 setPostList(
186 res.posts.map((item: any) => {
187 return {
188 value: item.postId,
189 label: item.postName,
190 };
191 }),
192 );
193 setRoleIds(res.roleIds);
194 setRoleList(
195 res.roles.map((item: any) => {
196 return {
197 value: item.roleId,
198 label: item.roleName,
199 };
200 }),
201 );
202 };
203
204 const columns: ProColumns<API.System.User>[] = [
205 {
206 title: <FormattedMessage id="system.user.user_id" defaultMessage="用户编号" />,
207 dataIndex: 'deptId',
208 valueType: 'text',
209 },
210 {
211 title: <FormattedMessage id="system.user.user_name" defaultMessage="用户账号" />,
212 dataIndex: 'userName',
213 valueType: 'text',
214 },
215 {
216 title: <FormattedMessage id="system.user.nick_name" defaultMessage="用户昵称" />,
217 dataIndex: 'nickName',
218 valueType: 'text',
219 },
220 {
221 title: <FormattedMessage id="system.user.dept_name" defaultMessage="部门" />,
222 dataIndex: ['dept', 'deptName'],
223 valueType: 'text',
224 hideInSearch: true
225 },
226 {
227 title: <FormattedMessage id="system.user.phonenumber" defaultMessage="手机号码" />,
228 dataIndex: 'phonenumber',
229 valueType: 'text',
230 },
231 {
232 title: <FormattedMessage id="system.user.status" defaultMessage="帐号状态" />,
233 dataIndex: 'status',
234 valueType: 'select',
235 valueEnum: statusOptions,
236 render: (_, record) => {
237 return (
238 <Switch
239 checked={record.status === '0'}
240 checkedChildren="正常"
241 unCheckedChildren="停用"
242 defaultChecked
243 onClick={() => showChangeStatusConfirm(record)}
244 />)
245 },
246 },
247 {
248 title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
249 dataIndex: 'option',
250 width: '220px',
251 valueType: 'option',
252 render: (_, record) => [
253 <Button
254 type="link"
255 size="small"
256 key="edit"
257 icon=<EditOutlined />
258 hidden={!access.hasPerms('system:user:edit')}
259 onClick={async () => {
260 fetchUserInfo(record.userId);
261 const treeData = await getDeptTree({});
262 setDeptTree(treeData);
263 setModalVisible(true);
264 setCurrentRow(record);
265 }}
266 >
267 编辑
268 </Button>,
269 <Button
270 type="link"
271 size="small"
272 danger
273 icon=<DeleteOutlined />
274 key="batchRemove"
275 hidden={!access.hasPerms('system:user:remove')}
276 onClick={async () => {
277 Modal.confirm({
278 title: '删除',
279 content: '确定删除该项吗?',
280 okText: '确认',
281 cancelText: '取消',
282 onOk: async () => {
283 const success = await handleRemoveOne(record);
284 if (success) {
285 if (actionRef.current) {
286 actionRef.current.reload();
287 }
288 }
289 },
290 });
291 }}
292 >
293 删除
294 </Button>,
295 <Dropdown
296 key="more"
297 menu={{
298 items: [
299 {
300 label: <FormattedMessage id="system.user.reset.password" defaultMessage="密码重置" />,
301 key: 'reset',
302 disabled: !access.hasPerms('system:user:edit'),
303 },
304 {
305 label: '分配角色',
306 key: 'authRole',
307 disabled: !access.hasPerms('system:user:edit'),
308 },
309 ],
310 onClick: ({ key }) => {
311 if (key === 'reset') {
312 setResetPwdModalVisible(true);
313 setCurrentRow(record);
314 }
315 else if (key === 'authRole') {
316 fetchUserInfo(record.userId);
317 setAuthRoleModalVisible(true);
318 setCurrentRow(record);
319 }
320 }
321 }}
322 >
323 <a onClick={(e) => e.preventDefault()}>
324 <Space>
325 <DownOutlined />
326 更多
327 </Space>
328 </a>
329 </Dropdown>,
330 ],
331 },
332 ];
333
334 return (
335 <PageContainer>
336 {contextHolder}
337 <Row gutter={[16, 24]}>
338 <Col lg={6} md={24}>
339 <Card>
340 <DeptTree
341 onSelect={async (value: any) => {
342 setSelectDept(value);
343 if (actionRef.current) {
344 formTableRef?.current?.submit();
345 }
346 }}
347 />
348 </Card>
349 </Col>
350 <Col lg={18} md={24}>
351 <ProTable<API.System.User>
352 headerTitle={intl.formatMessage({
353 id: 'pages.searchTable.title',
354 defaultMessage: '信息',
355 })}
356 actionRef={actionRef}
357 formRef={formTableRef}
358 rowKey="userId"
359 key="userList"
360 search={{
361 labelWidth: 120,
362 }}
363 toolBarRender={() => [
364 <Button
365 type="primary"
366 key="add"
367 hidden={!access.hasPerms('system:user:add')}
368 onClick={async () => {
369 const treeData = await getDeptTree({});
370 setDeptTree(treeData);
371
372 const postResp = await getPostList()
373 if (postResp.code === 200) {
374 setPostList(
375 postResp.rows.map((item: any) => {
376 return {
377 value: item.postId,
378 label: item.postName,
379 };
380 }),
381 );
382 }
383
384 const roleResp = await getRoleList()
385 if (roleResp.code === 200) {
386 setRoleList(
387 roleResp.rows.map((item: any) => {
388 return {
389 value: item.roleId,
390 label: item.roleName,
391 };
392 }),
393 );
394 }
395 setCurrentRow(undefined);
396 setModalVisible(true);
397 }}
398 >
399 <PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="新建" />
400 </Button>,
401 <Button
402 type="primary"
403 key="remove"
404 danger
405 hidden={selectedRows?.length === 0 || !access.hasPerms('system:user:remove')}
406 onClick={async () => {
407 Modal.confirm({
408 title: '是否确认删除所选数据项?',
409 icon: <ExclamationCircleOutlined />,
410 content: '请谨慎操作',
411 async onOk() {
412 const success = await handleRemove(selectedRows);
413 if (success) {
414 setSelectedRows([]);
415 actionRef.current?.reloadAndRest?.();
416 }
417 },
418 onCancel() { },
419 });
420 }}
421 >
422 <DeleteOutlined />
423 <FormattedMessage id="pages.searchTable.delete" defaultMessage="删除" />
424 </Button>,
425 <Button
426 type="primary"
427 key="export"
428 hidden={!access.hasPerms('system:user:export')}
429 onClick={async () => {
430 handleExport();
431 }}
432 >
433 <PlusOutlined />
434 <FormattedMessage id="pages.searchTable.export" defaultMessage="导出" />
435 </Button>,
436 ]}
437 request={(params) =>
438 getUserList({ ...params, deptId: selectDept.id } as API.System.UserListParams).then((res) => {
439 const result = {
440 data: res.rows,
441 total: res.total,
442 success: true,
443 };
444 return result;
445 })
446 }
447 columns={columns}
448 rowSelection={{
449 onChange: (_, selectedRows) => {
450 setSelectedRows(selectedRows);
451 },
452 }}
453 />
454 </Col>
455 </Row>
456 {selectedRows?.length > 0 && (
457 <FooterToolbar
458 extra={
459 <div>
460 <FormattedMessage id="pages.searchTable.chosen" defaultMessage="已选择" />
461 <a style={{ fontWeight: 600 }}>{selectedRows.length}</a>
462 <FormattedMessage id="pages.searchTable.item" defaultMessage="项" />
463 </div>
464 }
465 >
466 <Button
467 key="remove"
468 danger
469 hidden={!access.hasPerms('system:user:del')}
470 onClick={async () => {
471 Modal.confirm({
472 title: '删除',
473 content: '确定删除该项吗?',
474 okText: '确认',
475 cancelText: '取消',
476 onOk: async () => {
477 const success = await handleRemove(selectedRows);
478 if (success) {
479 setSelectedRows([]);
480 actionRef.current?.reloadAndRest?.();
481 }
482 },
483 });
484 }}
485 >
486 <FormattedMessage id="pages.searchTable.batchDeletion" defaultMessage="批量删除" />
487 </Button>
488 </FooterToolbar>
489 )}
490 <UpdateForm
491 onSubmit={async (values) => {
492 let success = false;
493 if (values.userId) {
494 success = await handleUpdate({ ...values } as API.System.User);
495 } else {
496 success = await handleAdd({ ...values } as API.System.User);
497 }
498 if (success) {
499 setModalVisible(false);
500 setCurrentRow(undefined);
501 if (actionRef.current) {
502 actionRef.current.reload();
503 }
504 }
505 }}
506 onCancel={() => {
507 setModalVisible(false);
508 setCurrentRow(undefined);
509 }}
510 open={modalVisible}
511 values={currentRow || {}}
512 sexOptions={sexOptions}
513 statusOptions={statusOptions}
514 posts={postList || []}
515 postIds={postIds || []}
516 roles={roleList || []}
517 roleIds={roleIds || []}
518 depts={deptTree || []}
519 />
520 <ResetPwd
521 onSubmit={async (values: any) => {
522 const success = await resetUserPwd(values.userId, values.password);
523 if (success) {
524 setResetPwdModalVisible(false);
525 setSelectedRows([]);
526 setCurrentRow(undefined);
527 message.success('密码重置成功。');
528 }
529 }}
530 onCancel={() => {
531 setResetPwdModalVisible(false);
532 setSelectedRows([]);
533 setCurrentRow(undefined);
534 }}
535 open={resetPwdModalVisible}
536 values={currentRow || {}}
537 />
538 <AuthRoleForm
539 onSubmit={async (values: any) => {
540 const success = await updateAuthRole(values);
541 if (success) {
542 setAuthRoleModalVisible(false);
543 setSelectedRows([]);
544 setCurrentRow(undefined);
545 message.success('配置成功。');
546 }
547 }}
548 onCancel={() => {
549 setAuthRoleModalVisible(false);
550 setSelectedRows([]);
551 setCurrentRow(undefined);
552 }}
553 open={authRoleModalVisible}
554 roles={roleList || []}
555 roleIds={roleIds || []}
556 />
557 </PageContainer>
558 );
559};
560
561export default UserTableList;