| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- import * as React from 'react';
- import { Modal, Table, Input, Select, Space, message, Tree, Divider, Button } from 'antd';
- import type { TableColumnsType } from 'antd';
- import type { DataNode } from 'antd/es/tree';
- import { Tree as TreeIcon, Group, Search } from 'iconoir-react';
- import './VipSelector.scss';
- interface VipUser {
- userId: string;
- userName: string;
- nickName: string;
- deptName: string;
- deptId: string;
- userTypeName: string;
- }
- interface Department {
- deptId: string;
- deptName: string;
- children?: Department[];
- }
- interface VipSelectorProps {
- open: boolean;
- onClose: () => void;
- onConfirm: (users: VipUser[]) => void;
- existingUsers?: VipUser[];
- }
- // Mock 数据 - 部门树
- const mockDepartments: Department[] = [
- {
- deptId: 'dept_001',
- deptName: '政务服务中心',
- children: [
- { deptId: 'dept_001_01', deptName: '窗口服务科' },
- { deptId: 'dept_001_02', deptName: '在线咨询科' },
- ],
- },
- {
- deptId: 'dept_002',
- deptName: '市场监管局',
- children: [
- { deptId: 'dept_002_01', deptName: '企业注册科' },
- { deptId: 'dept_002_02', deptName: '质量监管科' },
- ],
- },
- {
- deptId: 'dept_003',
- deptName: '大数据局',
- children: [
- { deptId: 'dept_003_01', deptName: '数据共享科' },
- { deptId: 'dept_003_02', deptName: '智慧城市科' },
- ],
- },
- {
- deptId: 'dept_004',
- deptName: '财政局',
- children: [
- { deptId: 'dept_004_01', deptName: '预算科' },
- { deptId: 'dept_004_02', deptName: '国库科' },
- ],
- },
- {
- deptId: 'dept_005',
- deptName: '人社局',
- children: [
- { deptId: 'dept_005_01', deptName: '社保科' },
- { deptId: 'dept_005_02', deptName: '就业科' },
- ],
- },
- ];
- // Mock 数据 - 用户列表(带部门关联)
- const mockUserList: VipUser[] = [
- { userId: 'user_001', userName: 'zhangsan', nickName: '张三', deptName: '政务服务中心', deptId: 'dept_001', userTypeName: '普通用户' },
- { userId: 'user_002', userName: 'lisi', nickName: '李四', deptName: '市场监管局', deptId: 'dept_002', userTypeName: 'VIP 用户' },
- { userId: 'user_003', userName: 'wangwu', nickName: '王五', deptName: '大数据局', deptId: 'dept_003', userTypeName: '管理员' },
- { userId: 'user_004', userName: 'zhaoliu', nickName: '赵六', deptName: '财政局', deptId: 'dept_004', userTypeName: '普通用户' },
- { userId: 'user_005', userName: 'qianqi', nickName: '钱七', deptName: '人社局', deptId: 'dept_005', userTypeName: 'VIP 用户' },
- { userId: 'user_006', userName: 'sunba', nickName: '孙八', deptName: '政务服务中心', deptId: 'dept_001', userTypeName: '普通用户' },
- { userId: 'user_007', userName: 'zhoujiu', nickName: '周九', deptName: '市场监管局', deptId: 'dept_002', userTypeName: '管理员' },
- { userId: 'user_008', userName: 'zhengshi', nickName: '郑十', deptName: '大数据局', deptId: 'dept_003', userTypeName: 'VIP 用户' },
- { userId: 'user_009', userName: 'wushi', nickName: '吴十', deptName: '财政局', deptId: 'dept_004', userTypeName: '普通用户' },
- { userId: 'user_010', userName: 'zhengyi', nickName: '郑十一', deptName: '人社局', deptId: 'dept_005', userTypeName: '管理员' },
- ];
- // 将部门树转换为 Tree 组件需要的格式
- const convertToTreeData = (departments: Department[]): DataNode[] => {
- return departments.map(dept => ({
- title: dept.deptName,
- key: dept.deptId,
- children: dept.children?.map(child => ({
- title: child.deptName,
- key: child.deptId,
- isLeaf: true,
- })),
- }));
- };
- const VipSelector: React.FC<VipSelectorProps> = ({ open, onClose, onConfirm, existingUsers = [] }) => {
- const [selectedRowKeys, setSelectedRowKeys] = React.useState<React.Key[]>([]);
- const [selectedDeptId, setSelectedDeptId] = React.useState<string>('');
- const [searchUserName, setSearchUserName] = React.useState('');
- const [searchNickName, setSearchNickName] = React.useState('');
- const [searchUserType, setSearchUserType] = React.useState<string | undefined>();
- // 初始化选中项为已选的 VIP 用户
- React.useEffect(() => {
- if (open) {
- setSelectedRowKeys(existingUsers.map(item => item.userId));
- }
- }, [open, existingUsers]);
- // 部门树选择处理
- const onDeptSelect: TreeProps['onSelect'] = (selectedKeys) => {
- if (selectedKeys.length > 0) {
- setSelectedDeptId(selectedKeys[0] as string);
- } else {
- setSelectedDeptId('');
- }
- };
- // 根据部门和筛选条件过滤用户
- const filteredUsers = mockUserList.filter(user => {
- const matchDept = !selectedDeptId || user.deptId === selectedDeptId ||
- mockDepartments.some(d => d.deptId === selectedDeptId && user.deptId === d.deptId);
- const matchUserName = !searchUserName || user.userName.toLowerCase().includes(searchUserName.toLowerCase());
- const matchNickName = !searchNickName || user.nickName.includes(searchNickName);
- const matchUserType = !searchUserType || user.userTypeName === searchUserType;
- return matchDept && matchUserName && matchNickName && matchUserType;
- });
- const columns: TableColumnsType<VipUser> = [
- {
- title: '昵称',
- dataIndex: 'nickName',
- key: 'nickName',
- width: 100,
- },
- {
- title: '用户名称',
- dataIndex: 'userName',
- key: 'userName',
- width: 120,
- },
- {
- title: '部门',
- dataIndex: 'deptName',
- key: 'deptName',
- width: 140,
- },
- {
- title: '用户类型',
- dataIndex: 'userTypeName',
- key: 'userTypeName',
- width: 100,
- },
- ];
- const rowSelection = {
- selectedRowKeys,
- onChange: (newSelectedRowKeys: React.Key[]) => {
- setSelectedRowKeys(newSelectedRowKeys);
- },
- };
- const handleConfirm = () => {
- const selectedUsers = filteredUsers.filter(user =>
- selectedRowKeys.includes(user.userId)
- );
- onConfirm(selectedUsers);
- message.success(`已选择 ${selectedUsers.length} 个用户`);
- };
- const handleSelectAll = () => {
- setSelectedRowKeys(filteredUsers.map(user => user.userId));
- };
- const handleClearAll = () => {
- setSelectedRowKeys([]);
- };
- return (
- <Modal
- title="请选择指定用户"
- open={open}
- onOk={handleConfirm}
- onCancel={onClose}
- width={900}
- className='vip-selector-modal'
- okText="确定"
- cancelText="取消"
- >
- <div className='vip-selector-container'>
- {/* 左侧:部门树 */}
- <div className='vip-selector-left'>
- <div className='section-title'>
- <TreeIcon width="18" height="18" />
- 选择部门
- </div>
- <Tree
- treeData={convertToTreeData(mockDepartments)}
- onSelect={onDeptSelect}
- selectedKeys={[selectedDeptId]}
- showLine
- blockNode
- />
- <Divider className='dept-divider' />
- <div className='selected-count'>
- 已选:{selectedRowKeys.length} 人
- </div>
- </div>
- {/* 右侧:用户列表 */}
- <div className='vip-selector-right'>
- <div className='section-title'>
- <Group width="18" height="18" />
- 用户列表
- {selectedDeptId && (
- <span className='dept-filter-tag'>
- {mockDepartments.find(d => d.deptId === selectedDeptId)?.deptName || '已筛选'}
- </span>
- )}
- </div>
- {/* 筛选条件 */}
- <Space className='filter-bar' wrap>
- <Input
- placeholder="搜索用户名称"
- value={searchUserName}
- onChange={(e) => setSearchUserName(e.target.value)}
- style={{ width: 140 }}
- allowClear
- prefix={<Search width="14" height="14" />}
- />
- <Input
- placeholder="搜索昵称"
- value={searchNickName}
- onChange={(e) => setSearchNickName(e.target.value)}
- style={{ width: 120 }}
- allowClear
- />
- <Select
- placeholder="用户类型"
- value={searchUserType}
- onChange={setSearchUserType}
- style={{ width: 120 }}
- allowClear
- >
- <Select.Option value="普通用户">普通用户</Select.Option>
- <Select.Option value="VIP 用户">VIP 用户</Select.Option>
- <Select.Option value="管理员">管理员</Select.Option>
- </Select>
- <Button size="small" onClick={handleSelectAll}>全选</Button>
- <Button size="small" onClick={handleClearAll}>清空</Button>
- </Space>
- {/* 用户表格 */}
- <Table
- rowKey="userId"
- rowSelection={rowSelection}
- columns={columns}
- dataSource={filteredUsers}
- pagination={{
- showTotal: (total) => `共 ${total} 条`,
- showSizeChanger: false,
- showQuickJumper: true,
- current: 1,
- pageSize: 10,
- total: filteredUsers.length,
- }}
- scroll={{ y: 360 }}
- size="small"
- />
- </div>
- </div>
- </Modal>
- );
- };
- export default VipSelector;
|