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