vdi/web-fe/src/pages/userList/index.tsx

559 lines
15 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-use-before-define */
import {
ERROR_CODE,
GENDER_MAP,
PRIORITY_MAP,
USER_TYPE_MAP,
} from '@/constants/constants';
import CustomTree from '@/pages/components/customTree';
import {
deleteUser,
deleteUserGroup,
getGroupTree,
getUserList,
} from '@/services/userList';
import {
DeleteOutlined,
PlusOutlined,
RedoOutlined,
TeamOutlined,
} from '@ant-design/icons';
import { Button, Input, message, Popconfirm, Spin, Table, Tooltip } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import React, { useEffect, useState } from 'react';
import styles from './index.less';
import UserEditModal from './mod/eidtUser';
import CreatGroup from './mod/group';
import PasswordResetModal from './mod/passwordEdit';
const UserListPage: React.FC = () => {
const [orgTreeData, setOrgTreeData] = useState<User.OrganizationNode[]>([]);
const [selectedOrg, setSelectedOrg] = useState<any>();
// 用户列表
const [dataSource, setDataSource] = useState<User.UserItem[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [spinning, setSpinning] = useState<boolean>(false);
const [searchText, setSearchText] = useState<string>('');
const [selectedRowKeys, setSelectedRowKeys] = useState<[]>([]);
const [orgSearchText, setOrgSearchText] = useState<string>('');
// 分页参数
const [currentPage, setCurrentPage] = useState<number>(1);
const [pageSize, setPageSize] = useState<number>(10);
const [total, setTotal] = useState<number>(0);
// 编辑用户
const [currentUserInfo, setCurrentUserInfo] = useState<any>({
visible: false,
});
// 重置密码
const [eidtPassword, setEidtPassword] = useState<any>({
visible: false,
});
// 添加分组
const [visible, setVisible] = useState<boolean>(false);
// 获取用户分组组织树
useEffect(() => {
getUserGroupList();
}, []);
// 获取用户列表数据
useEffect(() => {
getDataSource();
}, [searchText, selectedOrg, currentPage, pageSize]);
const getUserGroupList = async () => {
setSpinning(true);
const params = {
type: 1,
};
try {
const result = await getGroupTree(params);
console.log('result=====', result);
const { code, data = [] } = result || {};
setSpinning(false);
if (code === ERROR_CODE) {
if (data.length > 0) {
const { children = [] } = data[0] || {};
setOrgTreeData(children);
// if (children.length > 0) {
// setSelectedOrg(children[0].id);
// }
}
} else {
message.error(result.message || '获取用户分组失败');
}
} catch (err) {
message.error('获取用户分组失败');
setSpinning(false);
}
};
const filterTreeData = (
data: User.OrganizationNode[],
searchTerm: string,
): User.OrganizationNode[] => {
if (!searchTerm) return data;
return data.reduce((acc: User.OrganizationNode[], node) => {
const isMatch = node.name
?.toLowerCase()
.includes(searchTerm.toLowerCase());
if (isMatch) {
// If current node matches, include it
acc.push({ ...node });
} else if (node.children && node.children.length > 0) {
// If current node doesn't match, check children
const filteredChildren = filterTreeData(node.children, searchTerm);
if (filteredChildren.length > 0) {
// If any children match, include current node with filtered children
acc.push({
...node,
children: filteredChildren,
});
}
}
return acc;
}, []);
};
const filteredOrgTreeData = filterTreeData(orgTreeData, orgSearchText);
const getDataSource = async () => {
const params: any = {
page_size: pageSize,
page_num: currentPage,
};
if (selectedOrg) {
params.user_group_id = selectedOrg;
}
if (searchText) {
params.user_name = searchText;
}
setLoading(true);
try {
const result = await getUserList(params);
console.log('res======', result);
const { code, data = {} } = result || {};
const { data: list, total = 0 } = data || {};
if (code === ERROR_CODE) {
setDataSource(list || []);
setTotal(total);
setLoading(false);
} else {
message.error(result.message || '获取用户列表失败');
setLoading(false);
}
} catch (err) {
message.error('获取用户列表失败');
setLoading(false);
}
};
const onDelete = (user?: User.UserItem) => {
const { id } = user || {};
const payload = {
id: id ? id : selectedRowKeys,
};
deleteUser(payload as any).then((res) => {
console.log('res=====', res);
const { code } = res || {};
if (code === ERROR_CODE) {
message.success('删除成功');
setSelectedRowKeys([]);
getDataSource();
}
});
};
const handlePassword = (user: User.UserItem) => {
setEidtPassword({
recordData: { ...user },
visible: true,
});
};
const handleCreatUserInfo = () => {
setCurrentUserInfo({
visible: true,
});
};
const handleEditUserInfo = (user: User.UserItem) => {
setCurrentUserInfo({
recordData: { ...user },
visible: true,
});
};
const columns: ColumnsType<User.UserItem> = [
{
title: '序号',
dataIndex: 'order',
key: 'order',
width: 80,
align: 'center',
render: (_: any, record: any, index: number) => <span>{index + 1}</span>,
},
{
title: '用户名',
dataIndex: 'user_name',
key: 'user_name',
width: 150,
align: 'center',
render: (text) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '用户分组',
dataIndex: 'user_group_name',
key: 'user_group_name',
width: 150,
align: 'center',
render: (text) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 150,
align: 'center',
render: (text) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '用户类别',
dataIndex: 'user_type',
key: 'user_type',
width: 150,
align: 'center',
render: (text: number) => {
const key = text as keyof typeof USER_TYPE_MAP;
return <Tooltip>{USER_TYPE_MAP[key] || '--'}</Tooltip>;
},
},
{
title: '优先级',
dataIndex: 'priority',
key: 'priority',
width: 150,
align: 'center',
render: (text: number) => {
const key = text as keyof typeof PRIORITY_MAP;
return <Tooltip>{PRIORITY_MAP[key] || '--'}</Tooltip>;
},
},
{
title: '性别',
dataIndex: 'gender',
key: 'gender',
width: 150,
align: 'center',
render: (text: number) => {
const key = text as keyof typeof GENDER_MAP;
return <Tooltip>{GENDER_MAP[key] || '--'}</Tooltip>;
},
},
{
title: '电话',
dataIndex: 'cell_phone',
key: 'cell_phone',
width: 150,
align: 'center',
render: (text: any) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '出生日期',
dataIndex: 'birthday',
key: 'birthday',
width: 150,
align: 'center',
render: (text: any) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '身份证号',
dataIndex: 'identity_no',
key: 'identity_no',
width: 150,
align: 'center',
render: (text: any) => {
return <Tooltip>{text || '--'}</Tooltip>;
},
},
{
title: '操作',
key: 'actions',
align: 'center',
width: 150,
fixed: 'right',
render: (_, record) => (
<div style={{ display: 'flex' }}>
{/* <Button type="link" onClick={() => handlePassword(record)}>
重置密码
</Button> */}
<Button type="link" onClick={() => handleEditUserInfo(record)}>
</Button>
<Popconfirm
title=""
description="删除操作不可逆,请确认是否删除?"
onConfirm={() => onDelete(record)}
// onCancel={cancel}
okText="删除"
cancelText="取消"
>
<Button type="link"></Button>
</Popconfirm>
</div>
),
},
];
const onOrgSelect = (selectedKeys: React.Key[]) => {
if (selectedKeys.length > 0) {
setSelectedOrg(selectedKeys[0]);
setCurrentPage(1);
}
};
const handlePageChange = (page: number, size: number) => {
setCurrentPage(page);
setPageSize(size);
};
const handlePageSizeChange = (current: number, size: number) => {
setCurrentPage(1);
setPageSize(size);
};
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
console.log('selectedRowKeys changed: ', newSelectedRowKeys);
setSelectedRowKeys(newSelectedRowKeys as any);
};
const onSaveGroup = () => {
getUserGroupList();
};
const onSaveUserCallback = () => {
setCurrentUserInfo({
recordData: {},
visible: false,
});
getDataSource();
};
const onDeleteGroup = async () => {
if (selectedOrg) {
try {
const params = {
id: selectedOrg,
};
const res = await deleteUserGroup(params);
const { code } = res || {};
if (code === ERROR_CODE) {
message.success('分组删除成功');
setSelectedOrg(null);
getUserGroupList();
}
} catch (error) {
message.error('分组删除失败');
}
}
};
return (
<div className={styles.user_content}>
<div className={styles.left_content}>
<div className={styles.search}>
<div style={{ paddingBottom: '5px' }}>
<Button
type="text"
style={{ marginRight: '8px', fontSize: '16px' }}
icon={<RedoOutlined />}
onClick={() => getUserGroupList()}
title="刷新"
/>
<Button
type="text"
style={{ marginRight: '8px', fontSize: '16px' }}
icon={<PlusOutlined />}
onClick={() => setVisible(true)}
title="新增"
/>
<Popconfirm
title=""
description="删除操作不可逆,请确认是否删除?"
onConfirm={() => onDeleteGroup()}
// onCancel={cancel}
okText="删除"
cancelText="取消"
disabled={!selectedOrg}
>
<Button
type="text"
style={{ fontSize: '16px' }}
icon={<DeleteOutlined />}
title="删除"
disabled={!selectedOrg}
/>
</Popconfirm>
</div>
<Input.Search
placeholder="请输入名称"
style={{ marginBottom: 6 }}
onSearch={(value) => setOrgSearchText(value)}
onChange={(e) => setOrgSearchText(e.target.value)}
/>
</div>
<div className={styles.tree_box}>
<Spin spinning={spinning} delay={100}>
<CustomTree
treeData={filteredOrgTreeData}
titleField="name"
keyField="id"
childrenField="children"
defaultExpandAll
onSelect={onOrgSelect}
selectedKeys={selectedOrg ? [selectedOrg] : []}
icon={<TeamOutlined style={{ fontSize: '15px' }} />}
/>
</Spin>
</div>
</div>
<div className={styles.right_content}>
<div className={styles.teble_content}>
<div
style={{
marginBottom: 16,
display: 'flex',
justifyContent: 'space-between',
}}
>
<div>
<Button
style={{ marginRight: '8px' }}
onClick={() => handleCreatUserInfo()}
>
</Button>
{/* <Popconfirm
title=""
description="删除操作不可逆,请确认是否删除?"
onConfirm={() => onDelete()}
// onCancel={cancel}
okText="删除"
cancelText="取消"
disabled={selectedRowKeys.length === 0}
>
<Button
disabled={selectedRowKeys.length === 0}
style={{ marginRight: '8px' }}
icon={<DeleteOutlined />}
>
删除
</Button>
</Popconfirm> */}
<Button style={{ marginRight: '8px' }} onClick={getDataSource}>
</Button>
</div>
<div>
<div>
<Input.Search
placeholder="用户名"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
style={{ width: 300 }}
onSearch={(value) => {
console.log('Search user:', value);
setCurrentPage(1); // Reset to first page when searching
}}
/>
</div>
</div>
</div>
<div className={styles.teble_box}>
<Table
columns={columns}
dataSource={dataSource}
loading={loading}
rowKey="id"
pagination={{
current: currentPage,
pageSize: pageSize,
total: total,
onChange: handlePageChange,
onShowSizeChange: handlePageSizeChange,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ['10', '20', '50', '100'],
showTotal: (total) => {
return `${total}条数据`;
},
}}
// rowSelection={{
// selectedRowKeys,
// onChange: onSelectChange,
// }}
scroll={{ x: 'max-content', y: 55 * 12 }}
/>
</div>
</div>
</div>
{visible && (
<CreatGroup
visible={visible}
type={1}
title="新增用户分组"
selectedOrg={selectedOrg}
onCancel={() => {
setVisible(false);
}}
onOk={onSaveGroup}
orgTreeData={orgTreeData}
/>
)}
{currentUserInfo.visible && (
<UserEditModal
selectedOrg={selectedOrg}
orgTreeData={orgTreeData}
currentUserInfo={currentUserInfo}
onCancel={() => {
setCurrentUserInfo({
recordData: {},
visible: false,
});
}}
onOk={() => {
onSaveUserCallback();
}}
/>
)}
<PasswordResetModal
visible={eidtPassword.visible}
onCancel={() => {
setEidtPassword({
recordData: {},
visible: false,
});
}}
onOk={() => {}}
/>
</div>
);
};
export default UserListPage;