From c635d78b479510ebe2556a420948effcd30a0731 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期六, 21 十二月 2024 18:40:43 +0800
Subject: [PATCH] 新建德森项目分支

---
 zy-asrs-flow/src/pages/system/user/index.jsx | 1494 +++++++++++++++++++++++++++++-----------------------------
 1 files changed, 747 insertions(+), 747 deletions(-)

diff --git a/zy-asrs-flow/src/pages/system/user/index.jsx b/zy-asrs-flow/src/pages/system/user/index.jsx
index dd0f2f9..7a21e6d 100644
--- a/zy-asrs-flow/src/pages/system/user/index.jsx
+++ b/zy-asrs-flow/src/pages/system/user/index.jsx
@@ -1,747 +1,747 @@
-import React, { useState, useRef, useEffect } from 'react';
-import { Button, message, Modal, Row, Col, Card, Tree, Input, Tag, Skeleton } from 'antd';
-import {
-    FooterToolbar,
-    PageContainer,
-    ProTable,
-    LightFilter,
-    TableDropdown
-} from '@ant-design/pro-components';
-import { FormattedMessage, useIntl } from '@umijs/max';
-import { PlusOutlined, ExportOutlined, DownOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
-import Http from '@/utils/http';
-import Edit from './components/edit'
-import Pwd from './components/pwd'
-import AssignRole from './components/assignRole'
-import { TextFilter, SelectFilter, DatetimeRangeFilter, LinkFilter } from '@/components/TableSearch'
-import { transformTreeData, getTreeAllKeys } from '@/utils/tree-util'
-import { statusMap } from '@/utils/enum-util'
-import { repairBug } from '@/utils/common-util';
-
-const TABLE_KEY = "pro-table-user";
-
-const handleSave = async (val, intl) => {
-    const hide = message.loading(intl.formatMessage({ id: 'page.adding', defaultMessage: '姝e湪娣诲姞' }));
-    try {
-        const resp = await Http.doPost('api/user/save', val);
-        if (resp.code === 200) {
-            message.success(intl.formatMessage({ id: 'page.add.success', defaultMessage: '娣诲姞鎴愬姛' }));
-            return true;
-        } else {
-            message.error(resp.msg);
-            return false;
-        }
-    } catch (error) {
-        message.error(intl.formatMessage({ id: 'page.add.fail', defaultMessage: '娣诲姞澶辫触璇烽噸璇曪紒' }));
-        return false;
-    } finally {
-        hide();
-    }
-};
-
-const handleUpdate = async (val, intl) => {
-    const hide = message.loading(intl.formatMessage({ id: 'page.updating', defaultMessage: '姝e湪鏇存柊' }));
-    try {
-        const resp = await Http.doPost('api/user/update', val);
-        if (resp.code === 200) {
-            message.success(intl.formatMessage({ id: 'page.update.success', defaultMessage: '鏇存柊鎴愬姛' }));
-            return true;
-        } else {
-            message.error(resp.msg);
-            return false;
-        }
-    } catch (error) {
-        message.error(intl.formatMessage({ id: 'page.update.fail', defaultMessage: '鏇存柊澶辫触璇烽噸璇曪紒' }));
-        return false;
-    } finally {
-        hide();
-    }
-};
-
-const handleRemove = async (rows, intl) => {
-    if (!rows) return true;
-    const hide = message.loading(intl.formatMessage({ id: 'page.deleting', defaultMessage: '姝e湪鍒犻櫎' }));
-    try {
-        const resp = await Http.doPost('api/user/remove/' + rows.map((row) => row.id).join(','));
-        if (resp.code === 200) {
-            message.success(intl.formatMessage({ id: 'page.delete.success', defaultMessage: '鍒犻櫎鎴愬姛' }));
-            return true;
-        } else {
-            message.error(resp.msg);
-            return false;
-        }
-    } catch (error) {
-        message.error(intl.formatMessage({ id: 'page.delete.fail', defaultMessage: '鍒犻櫎澶辫触锛岃閲嶈瘯锛�' }));
-        return false;
-    } finally {
-        hide();
-    }
-};
-
-const handleExport = async (intl) => {
-    const hide = message.loading(intl.formatMessage({ id: 'page.exporting', defaultMessage: '姝e湪瀵煎嚭' }));
-    try {
-        const resp = await Http.doPostBlob('api/user/export');
-        const blob = new Blob([resp], { type: 'application/vnd.ms-excel' });
-        window.location.href = window.URL.createObjectURL(blob);
-        message.success(intl.formatMessage({ id: 'page.export.success', defaultMessage: '瀵煎嚭鎴愬姛' }));
-        return true;
-    } catch (error) {
-        message.error(intl.formatMessage({ id: 'page.export.fail', defaultMessage: '瀵煎嚭澶辫触锛岃閲嶈瘯' }));
-        return false;
-    } finally {
-        hide();
-    }
-};
-
-const handlePwd = async (val, intl) => {
-    const hide = message.loading(intl.formatMessage({ id: 'page.resetting', defaultMessage: '姝e湪閲嶇疆' }));
-    try {
-        const resp = await Http.doPost('api/user/reset/pwd', val);
-        if (resp.code === 200) {
-            message.success(intl.formatMessage({ id: 'page.reset.success', defaultMessage: '閲嶇疆鎴愬姛' }));
-            return true;
-        } else {
-            message.error(resp.msg);
-            return false;
-        }
-    } catch (error) {
-        message.error(intl.formatMessage({ id: 'page.reset.fail', defaultMessage: '閲嶇疆澶辫触璇烽噸璇曪紒' }));
-        return false;
-    } finally {
-        hide();
-    }
-};
-
-
-const Main = () => {
-    const intl = useIntl();
-    const formTableRef = useRef();
-    const actionRef = useRef();
-    const [selectedRows, setSelectedRows] = useState([]);
-    const [modalVisible, setModalVisible] = useState(false);
-    const [currentRow, setCurrentRow] = useState();
-    const [searchParam, setSearchParam] = useState({});
-
-    const [boxHeight, setBoxHeight] = useState();
-    const [deptTreeLoading, setDeptTreeLoading] = useState(false);
-    const [deptTreeData, setDeptTreeData] = useState([]);
-    const [deptExpandedKeys, setDeptExpandedKeys] = useState([]);
-
-    const [pwdModalVisible, setPwdModalVisible] = useState(false);
-
-    const [assignModalVisible, setAssignModalVisible] = useState(false);
-
-    const loadDeptTreeData = (param) => {
-        setDeptTreeLoading(true);
-        Http.doPostPromise('/api/dept/tree', param, (res) => {
-            setDeptTreeLoading(false);
-            const rootMenu = { id: 0, name: '鍏ㄩ儴', value: 0, children: [] };
-            rootMenu.children = res.data;
-            // const treeData = transformTreeData([rootMenu]);
-            const treeData = transformTreeData(res.data);
-            setDeptTreeData(treeData);
-            const treeAllKeys = getTreeAllKeys(treeData);
-            setDeptExpandedKeys(treeAllKeys);
-        }).catch((err) => {
-            console.error(err);
-            setDeptTreeLoading(false);
-        })
-    }
-
-    useEffect(() => {
-        const handleResize = () => setBoxHeight(window.innerHeight - 320);
-        window.addEventListener('resize', handleResize);
-        handleResize();
-
-        loadDeptTreeData();
-
-        return () => window.removeEventListener('resize', handleResize);
-    }, []);
-
-    const columns = [
-        {
-            title: intl.formatMessage({
-                id: 'page.table.no',
-                defaultMessage: 'No'
-            }),
-            dataIndex: 'index',
-            valueType: 'indexBorder',
-            width: 48,
-        },
-        {
-            title: '閮ㄩ棬',
-            dataIndex: 'deptId$',
-            valueType: 'text',
-            hidden: false,
-            render: (_, record) => {
-                if (_ && _ !== '-') {
-                    return <Tag color={""}>{_}</Tag>
-                } else {
-                    return '-'
-                }
-            },
-            // filterDropdown: (props) => <LinkFilter
-            //     name='deptId'
-            //     major='dept'
-            //     {...props}
-            //     actionRef={actionRef}
-            //     setSearchParam={setSearchParam}
-            // />,
-        },
-        {
-            title: '鐧诲綍璐﹀彿',
-            dataIndex: 'username',
-            valueType: 'text',
-            hidden: false,
-            copyable: true,
-            filterDropdown: (props) => <TextFilter
-                name='username'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-            render: (_, record) => {
-                return <span style={{ fontWeight: "bold" }}>{_}</span>
-            }
-        },
-        {
-            title: '鍚嶇О',
-            dataIndex: 'nickname',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='nickname'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-            render: (_, record) => {
-                return <span style={{ fontWeight: "bold" }}>{_}</span>
-            }
-        },
-        {
-            title: '瀵嗙爜',
-            dataIndex: 'password',
-            valueType: 'password',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='password'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '澶村儚',
-            dataIndex: 'avatar',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='avatar'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '宸ュ彿',
-            dataIndex: 'code',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='code'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '鎬у埆',
-            dataIndex: 'sex$',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <SelectFilter
-                name='sex'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-                data={[
-                    { label: '鏈煡', value: 0 },
-                    { label: '鐢�', value: 1 },
-                    { label: '濂�', value: 2 },
-                ]}
-            />,
-        },
-        {
-            title: '鎵嬫満鍙�',
-            dataIndex: 'phone',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='phone'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '閭',
-            dataIndex: 'email',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='email'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '閭楠岃瘉',
-            dataIndex: 'emailVerified$',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <SelectFilter
-                name='emailVerified'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-                data={[
-                    { label: '鍚�', value: 0 },
-                    { label: '鏄�', value: 1 },
-                ]}
-            />,
-        },
-        {
-            title: '鐪熷疄濮撳悕',
-            dataIndex: 'realName',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='realName'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '韬唤璇佸彿',
-            dataIndex: 'idCard',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='idCard'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '鍑虹敓鏃ユ湡',
-            dataIndex: 'birthday',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='birthday'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '涓汉绠�浠�',
-            dataIndex: 'introduction',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='introduction'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '鐘舵��',
-            dataIndex: 'status$',
-            valueType: 'text',
-            hidden: false,
-            render: (_, record) => {
-                const status = statusMap[record.status]
-                return <Tag color={status.color}>{status.text}</Tag>
-            },
-            filterDropdown: (props) => <SelectFilter
-                name='status'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-                data={[
-                    { label: '姝e父', value: 1 },
-                    { label: '绂佺敤', value: 0 },
-                ]}
-            />,
-        },
-        {
-            title: '娣诲姞鏃堕棿',
-            dataIndex: 'createTime$',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <DatetimeRangeFilter
-                name='createTime'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '淇敼鏃堕棿',
-            dataIndex: 'updateTime$',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <DatetimeRangeFilter
-                name='updateTime'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '淇敼浜哄憳',
-            dataIndex: 'updateBy$',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <LinkFilter
-                name='updateBy'
-                major='user'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-        {
-            title: '澶囨敞',
-            dataIndex: 'memo',
-            valueType: 'text',
-            hidden: false,
-            filterDropdown: (props) => <TextFilter
-                name='memo'
-                {...props}
-                actionRef={actionRef}
-                setSearchParam={setSearchParam}
-            />,
-        },
-
-        {
-            title: '鎿嶄綔',
-            dataIndex: 'option',
-            valueType: 'option',
-            width: 180,
-            render: (_, record) => [
-                <Button
-                    type="link"
-                    key="edit"
-                    style={{ padding: '2px 3px' }}
-                    onClick={() => {
-                        setModalVisible(true);
-                        setCurrentRow(record);
-                    }}
-                >
-                    <FormattedMessage id='page.edit' defaultMessage='缂栬緫' />
-                </Button>,
-                <Button
-                    type="link"
-                    key="pwd"
-                    style={{ padding: '2px 2px' }}
-                    onClick={() => {
-                        setPwdModalVisible(true);
-                        setCurrentRow(record);
-                    }}
-                >
-                    <FormattedMessage id='page.reset.pwd' defaultMessage='閲嶇疆瀵嗙爜' />
-                </Button>,
-                <Button
-                    type="link"
-                    danger
-                    style={{ padding: '4px' }}
-                    key="remove"
-                    onClick={async () => {
-                        Modal.confirm({
-                            title: intl.formatMessage({ id: 'page.delete', defaultMessage: '鍒犻櫎' }),
-                            content: intl.formatMessage({ id: 'page.delete.confirm', defaultMessage: '纭畾鍒犻櫎璇ラ」鍚楋紵' }),
-                            onOk: async () => {
-                                const success = await handleRemove([record], intl);
-                                if (success) {
-                                    if (actionRef.current) {
-                                        actionRef.current.reload();
-                                    }
-                                }
-                            },
-                        });
-                    }}
-                >
-                    <FormattedMessage id='page.delete' defaultMessage='鍒犻櫎' />
-                </Button>,
-                <TableDropdown
-                    key="actionGroup"
-                    name="dropdown"
-                    onSelect={(key) => {
-                        if (key === 'assign') {
-                            setAssignModalVisible(true);
-                            setCurrentRow(record);
-                        }
-                    }}
-                    menus={[
-                        { key: 'assign', name: intl.formatMessage({ id: 'page.assign.role', defaultMessage: '鍒嗛厤瑙掕壊' }) },
-                    ]}
-                />,
-            ],
-        },
-    ];
-
-    return (
-        <PageContainer
-            header={{
-                breadcrumb: {},
-            }}
-        >
-            <Row gutter={[16, 24]}>
-                <Col lg={6} md={24}>
-                    <Card
-                        title={intl.formatMessage({ id: 'system.dept', defaultMessage: '閮ㄩ棬' })}
-                        style={{ width: '100%', height: 'calc(100vh - 160px)' }}
-                    >
-                        <Input
-                            style={{ marginBottom: 10 }}
-                            placeholder={intl.formatMessage({ id: 'commont.enter', defaultMessage: '璇疯緭鍏�' })}
-                            onChange={(e) => {
-                                const { value } = e.target;
-                                loadDeptTreeData({
-                                    condition: value
-                                })
-                            }}
-                        />
-                        <div style={{ height: 'calc(100vh - 325px)', overflowY: 'auto' }}>
-                            {deptTreeLoading ? (
-                                <Skeleton active />
-                            ) : (
-                                <Tree
-                                    showLine
-                                    blockNode
-                                    defaultExpandAll    // 寮傛鍔犺浇澶辨晥
-                                    expandedKeys={deptExpandedKeys}
-                                    onExpand={setDeptExpandedKeys}
-                                    treeData={deptTreeData}
-                                    switcherIcon={<DownOutlined />}
-                                    onSelect={(selectedKeys, info) => {
-                                        const deptId = selectedKeys[0];
-                                        setSearchParam(prevState => ({
-                                            ...prevState,
-                                            deptId: deptId
-                                        }));
-                                        actionRef.current?.reload();
-                                    }}
-                                />
-                            )}
-                        </div>
-                    </Card>
-                </Col>
-                <Col lg={18} md={24}>
-                    <ProTable
-                        key="user"
-                        rowKey="id"
-                        actionRef={actionRef}
-                        formRef={formTableRef}
-                        columns={columns}
-                        cardBordered
-                        size='small'
-                        // scroll={{ y: boxHeight }}
-                        dateFormatter="string"
-                        pagination={{ pageSize: 12 }}
-                        search={false}
-                        toolbar={{
-                            search: {
-                                onSearch: (value) => {
-                                    setSearchParam(prevState => ({
-                                        ...prevState,
-                                        condition: value
-                                    }));
-                                    actionRef.current?.reload();
-                                },
-                            },
-                            filter: (
-                                <LightFilter
-                                    onValuesChange={(val) => {
-                                    }}
-                                >
-                                </LightFilter>
-                            ),
-                            actions: [
-                                <Button
-                                    type="primary"
-                                    danger
-                                    key="removeBatch"
-                                    hidden={selectedRows?.length === 0}
-                                    onClick={async () => {
-                                        Modal.confirm({
-                                            title: intl.formatMessage({ id: 'page.delete', defaultMessage: '鍒犻櫎' }),
-                                            content: intl.formatMessage({ id: 'page.delete.confirm', defaultMessage: '纭畾鍒犻櫎璇ラ」鍚楋紵' }),
-                                            icon: <ExclamationCircleOutlined />,
-                                            async onOk() {
-                                                const success = await handleRemove(selectedRows, intl);
-                                                if (success) {
-                                                    setSelectedRows([]);
-                                                    actionRef.current.reload();
-                                                }
-                                            },
-                                            onCancel() { },
-                                        });
-                                    }}
-                                >
-                                    <DeleteOutlined />
-                                    <FormattedMessage id='page.delete' defaultMessage='鍒犻櫎' />
-                                </Button>,
-                                <Button
-                                    type="primary"
-                                    key="save"
-                                    onClick={async () => {
-                                        setModalVisible(true)
-                                    }}
-                                >
-                                    <PlusOutlined />
-                                    <FormattedMessage id='page.add' defaultMessage='娣诲姞' />
-                                </Button>,
-                                <Button
-                                    key="export"
-                                    onClick={async () => {
-                                        handleExport(intl);
-                                    }}
-                                >
-                                    <ExportOutlined />
-                                    <FormattedMessage id='page.export' defaultMessage='瀵煎嚭' />
-                                </Button>,
-                            ],
-                        }}
-                        request={(params, sorter, filter) =>
-                            Http.doPostPromise('/api/user/page1', { ...params, ...searchParam }, (res) => {
-                                return {
-                                    data: res.data.records,
-                                    total: res.data.total,
-                                    success: true,
-                                }
-                            })
-                        }
-                        tableAlertRender={false}
-                        rowSelection={{
-                            onChange: (ids, rows) => {
-                                setSelectedRows(rows);
-                            }
-                        }}
-                        columnsState={{
-                            persistenceKey: TABLE_KEY,
-                            persistenceType: 'localStorage',
-                            defaultValue: {
-                                password: { show: repairBug(TABLE_KEY, 'password', false) },
-                                avatar: { show: repairBug(TABLE_KEY, 'avatar', false) },
-                                code: { show: repairBug(TABLE_KEY, 'code', false) },
-                                phone: { show: repairBug(TABLE_KEY, 'phone', false) },
-                                email: { show: repairBug(TABLE_KEY, 'email', false) },
-                                emailVerified$: { show: repairBug(TABLE_KEY, 'emailVerified$', false) },
-                                realName: { show: repairBug(TABLE_KEY, 'realName', false) },
-                                idCard: { show: repairBug(TABLE_KEY, 'idCard', false) },
-                                birthday: { show: repairBug(TABLE_KEY, 'birthday', false) },
-                                introduction: { show: repairBug(TABLE_KEY, 'introduction', false) },
-                                createTime$: { show: repairBug(TABLE_KEY, 'createTime$', false) },
-                                updateTime$: { show: repairBug(TABLE_KEY, 'updateTime$', false) },
-                                updateBy$: { show: repairBug(TABLE_KEY, 'updateBy$', false) },
-                                memo: { show: repairBug(TABLE_KEY, 'memo', false) },
-                                option: { fixed: 'right', disable: true },
-                            },
-                            onChange(value) {
-                            },
-                        }}
-                    />
-                </Col>
-            </Row>
-
-            <Edit
-                open={modalVisible}
-                values={currentRow || {}}
-                treeData={deptTreeData}
-                onCancel={
-                    () => {
-                        setModalVisible(false);
-                        setCurrentRow(undefined);
-                    }
-                }
-                onSubmit={async (values) => {
-                    let ok = false;
-                    if (values.id) {
-                        ok = await handleUpdate({ ...values }, intl)
-                    } else {
-                        ok = await handleSave({ ...values }, intl)
-                    }
-                    if (ok) {
-                        setModalVisible(false);
-                        setCurrentRow(undefined);
-                        if (actionRef.current) {
-                            actionRef.current.reload();
-                        }
-                    }
-                }
-                }
-            />
-
-            <Pwd
-                open={pwdModalVisible}
-                values={currentRow || {}}
-                onCancel={
-                    () => {
-                        setPwdModalVisible(false);
-                        setCurrentRow(undefined);
-                    }
-                }
-                onSubmit={async (values) => {
-                    let ok = false;
-                    if (values.id) {
-                        ok = await handlePwd({ ...values }, intl)
-                    }
-                    if (ok) {
-                        setPwdModalVisible(false);
-                        setCurrentRow(undefined);
-                        if (actionRef.current) {
-                            actionRef.current.reload();
-                        }
-                    }
-                }
-                }
-            />
-
-            <AssignRole
-                open={assignModalVisible}
-                values={currentRow || {}}
-                onCancel={
-                    () => {
-                        setAssignModalVisible(false);
-                        setCurrentRow(undefined);
-                    }
-                }
-                onSubmit={async (values) => {
-                    let ok = false;
-                    if (values.id) {
-                        ok = await handleUpdate({ ...values }, intl)
-                    }
-                    if (ok) {
-                        setAssignModalVisible(false);
-                        setCurrentRow(undefined);
-                        if (actionRef.current) {
-                            actionRef.current.reload();
-                        }
-                    }
-                }}
-            />
-
-        </PageContainer>
-    );
-};
-
-export default Main;
+import React, { useState, useRef, useEffect } from 'react';
+import { Button, message, Modal, Row, Col, Card, Tree, Input, Tag, Skeleton } from 'antd';
+import {
+    FooterToolbar,
+    PageContainer,
+    ProTable,
+    LightFilter,
+    TableDropdown
+} from '@ant-design/pro-components';
+import { FormattedMessage, useIntl } from '@umijs/max';
+import { PlusOutlined, ExportOutlined, DownOutlined, DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
+import Http from '@/utils/http';
+import Edit from './components/edit'
+import Pwd from './components/pwd'
+import AssignRole from './components/assignRole'
+import { TextFilter, SelectFilter, DatetimeRangeFilter, LinkFilter } from '@/components/TableSearch'
+import { transformTreeData, getTreeAllKeys } from '@/utils/tree-util'
+import { statusMap } from '@/utils/enum-util'
+import { repairBug } from '@/utils/common-util';
+
+const TABLE_KEY = "pro-table-user";
+
+const handleSave = async (val, intl) => {
+    const hide = message.loading(intl.formatMessage({ id: 'page.adding', defaultMessage: '姝e湪娣诲姞' }));
+    try {
+        const resp = await Http.doPost('api/user/save', val);
+        if (resp.code === 200) {
+            message.success(intl.formatMessage({ id: 'page.add.success', defaultMessage: '娣诲姞鎴愬姛' }));
+            return true;
+        } else {
+            message.error(resp.msg);
+            return false;
+        }
+    } catch (error) {
+        message.error(intl.formatMessage({ id: 'page.add.fail', defaultMessage: '娣诲姞澶辫触璇烽噸璇曪紒' }));
+        return false;
+    } finally {
+        hide();
+    }
+};
+
+const handleUpdate = async (val, intl) => {
+    const hide = message.loading(intl.formatMessage({ id: 'page.updating', defaultMessage: '姝e湪鏇存柊' }));
+    try {
+        const resp = await Http.doPost('api/user/update', val);
+        if (resp.code === 200) {
+            message.success(intl.formatMessage({ id: 'page.update.success', defaultMessage: '鏇存柊鎴愬姛' }));
+            return true;
+        } else {
+            message.error(resp.msg);
+            return false;
+        }
+    } catch (error) {
+        message.error(intl.formatMessage({ id: 'page.update.fail', defaultMessage: '鏇存柊澶辫触璇烽噸璇曪紒' }));
+        return false;
+    } finally {
+        hide();
+    }
+};
+
+const handleRemove = async (rows, intl) => {
+    if (!rows) return true;
+    const hide = message.loading(intl.formatMessage({ id: 'page.deleting', defaultMessage: '姝e湪鍒犻櫎' }));
+    try {
+        const resp = await Http.doPost('api/user/remove/' + rows.map((row) => row.id).join(','));
+        if (resp.code === 200) {
+            message.success(intl.formatMessage({ id: 'page.delete.success', defaultMessage: '鍒犻櫎鎴愬姛' }));
+            return true;
+        } else {
+            message.error(resp.msg);
+            return false;
+        }
+    } catch (error) {
+        message.error(intl.formatMessage({ id: 'page.delete.fail', defaultMessage: '鍒犻櫎澶辫触锛岃閲嶈瘯锛�' }));
+        return false;
+    } finally {
+        hide();
+    }
+};
+
+const handleExport = async (intl) => {
+    const hide = message.loading(intl.formatMessage({ id: 'page.exporting', defaultMessage: '姝e湪瀵煎嚭' }));
+    try {
+        const resp = await Http.doPostBlob('api/user/export');
+        const blob = new Blob([resp], { type: 'application/vnd.ms-excel' });
+        window.location.href = window.URL.createObjectURL(blob);
+        message.success(intl.formatMessage({ id: 'page.export.success', defaultMessage: '瀵煎嚭鎴愬姛' }));
+        return true;
+    } catch (error) {
+        message.error(intl.formatMessage({ id: 'page.export.fail', defaultMessage: '瀵煎嚭澶辫触锛岃閲嶈瘯' }));
+        return false;
+    } finally {
+        hide();
+    }
+};
+
+const handlePwd = async (val, intl) => {
+    const hide = message.loading(intl.formatMessage({ id: 'page.resetting', defaultMessage: '姝e湪閲嶇疆' }));
+    try {
+        const resp = await Http.doPost('api/user/reset/pwd', val);
+        if (resp.code === 200) {
+            message.success(intl.formatMessage({ id: 'page.reset.success', defaultMessage: '閲嶇疆鎴愬姛' }));
+            return true;
+        } else {
+            message.error(resp.msg);
+            return false;
+        }
+    } catch (error) {
+        message.error(intl.formatMessage({ id: 'page.reset.fail', defaultMessage: '閲嶇疆澶辫触璇烽噸璇曪紒' }));
+        return false;
+    } finally {
+        hide();
+    }
+};
+
+
+const Main = () => {
+    const intl = useIntl();
+    const formTableRef = useRef();
+    const actionRef = useRef();
+    const [selectedRows, setSelectedRows] = useState([]);
+    const [modalVisible, setModalVisible] = useState(false);
+    const [currentRow, setCurrentRow] = useState();
+    const [searchParam, setSearchParam] = useState({});
+
+    const [boxHeight, setBoxHeight] = useState();
+    const [deptTreeLoading, setDeptTreeLoading] = useState(false);
+    const [deptTreeData, setDeptTreeData] = useState([]);
+    const [deptExpandedKeys, setDeptExpandedKeys] = useState([]);
+
+    const [pwdModalVisible, setPwdModalVisible] = useState(false);
+
+    const [assignModalVisible, setAssignModalVisible] = useState(false);
+
+    const loadDeptTreeData = (param) => {
+        setDeptTreeLoading(true);
+        Http.doPostPromise('/api/dept/tree', param, (res) => {
+            setDeptTreeLoading(false);
+            const rootMenu = { id: 0, name: '鍏ㄩ儴', value: 0, children: [] };
+            rootMenu.children = res.data;
+            // const treeData = transformTreeData([rootMenu]);
+            const treeData = transformTreeData(res.data);
+            setDeptTreeData(treeData);
+            const treeAllKeys = getTreeAllKeys(treeData);
+            setDeptExpandedKeys(treeAllKeys);
+        }).catch((err) => {
+            console.error(err);
+            setDeptTreeLoading(false);
+        })
+    }
+
+    useEffect(() => {
+        const handleResize = () => setBoxHeight(window.innerHeight - 320);
+        window.addEventListener('resize', handleResize);
+        handleResize();
+
+        loadDeptTreeData();
+
+        return () => window.removeEventListener('resize', handleResize);
+    }, []);
+
+    const columns = [
+        {
+            title: intl.formatMessage({
+                id: 'page.table.no',
+                defaultMessage: 'No'
+            }),
+            dataIndex: 'index',
+            valueType: 'indexBorder',
+            width: 48,
+        },
+        {
+            title: '閮ㄩ棬',
+            dataIndex: 'deptId$',
+            valueType: 'text',
+            hidden: false,
+            render: (_, record) => {
+                if (_ && _ !== '-') {
+                    return <Tag color={""}>{_}</Tag>
+                } else {
+                    return '-'
+                }
+            },
+            // filterDropdown: (props) => <LinkFilter
+            //     name='deptId'
+            //     major='dept'
+            //     {...props}
+            //     actionRef={actionRef}
+            //     setSearchParam={setSearchParam}
+            // />,
+        },
+        {
+            title: '鐧诲綍璐﹀彿',
+            dataIndex: 'username',
+            valueType: 'text',
+            hidden: false,
+            copyable: true,
+            filterDropdown: (props) => <TextFilter
+                name='username'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+            render: (_, record) => {
+                return <span style={{ fontWeight: "bold" }}>{_}</span>
+            }
+        },
+        {
+            title: '鍚嶇О',
+            dataIndex: 'nickname',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='nickname'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+            render: (_, record) => {
+                return <span style={{ fontWeight: "bold" }}>{_}</span>
+            }
+        },
+        {
+            title: '瀵嗙爜',
+            dataIndex: 'password',
+            valueType: 'password',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='password'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '澶村儚',
+            dataIndex: 'avatar',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='avatar'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '宸ュ彿',
+            dataIndex: 'code',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='code'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '鎬у埆',
+            dataIndex: 'sex$',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <SelectFilter
+                name='sex'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+                data={[
+                    { label: '鏈煡', value: 0 },
+                    { label: '鐢�', value: 1 },
+                    { label: '濂�', value: 2 },
+                ]}
+            />,
+        },
+        {
+            title: '鎵嬫満鍙�',
+            dataIndex: 'phone',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='phone'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '閭',
+            dataIndex: 'email',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='email'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '閭楠岃瘉',
+            dataIndex: 'emailVerified$',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <SelectFilter
+                name='emailVerified'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+                data={[
+                    { label: '鍚�', value: 0 },
+                    { label: '鏄�', value: 1 },
+                ]}
+            />,
+        },
+        {
+            title: '鐪熷疄濮撳悕',
+            dataIndex: 'realName',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='realName'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '韬唤璇佸彿',
+            dataIndex: 'idCard',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='idCard'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '鍑虹敓鏃ユ湡',
+            dataIndex: 'birthday',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='birthday'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '涓汉绠�浠�',
+            dataIndex: 'introduction',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='introduction'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '鐘舵��',
+            dataIndex: 'status$',
+            valueType: 'text',
+            hidden: false,
+            render: (_, record) => {
+                const status = statusMap[record.status]
+                return <Tag color={status.color}>{status.text}</Tag>
+            },
+            filterDropdown: (props) => <SelectFilter
+                name='status'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+                data={[
+                    { label: '姝e父', value: 1 },
+                    { label: '绂佺敤', value: 0 },
+                ]}
+            />,
+        },
+        {
+            title: '娣诲姞鏃堕棿',
+            dataIndex: 'createTime$',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <DatetimeRangeFilter
+                name='createTime'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '淇敼鏃堕棿',
+            dataIndex: 'updateTime$',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <DatetimeRangeFilter
+                name='updateTime'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '淇敼浜哄憳',
+            dataIndex: 'updateBy$',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <LinkFilter
+                name='updateBy'
+                major='user'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+        {
+            title: '澶囨敞',
+            dataIndex: 'memo',
+            valueType: 'text',
+            hidden: false,
+            filterDropdown: (props) => <TextFilter
+                name='memo'
+                {...props}
+                actionRef={actionRef}
+                setSearchParam={setSearchParam}
+            />,
+        },
+
+        {
+            title: '鎿嶄綔',
+            dataIndex: 'option',
+            valueType: 'option',
+            width: 180,
+            render: (_, record) => [
+                <Button
+                    type="link"
+                    key="edit"
+                    style={{ padding: '2px 3px' }}
+                    onClick={() => {
+                        setModalVisible(true);
+                        setCurrentRow(record);
+                    }}
+                >
+                    <FormattedMessage id='page.edit' defaultMessage='缂栬緫' />
+                </Button>,
+                <Button
+                    type="link"
+                    key="pwd"
+                    style={{ padding: '2px 2px' }}
+                    onClick={() => {
+                        setPwdModalVisible(true);
+                        setCurrentRow(record);
+                    }}
+                >
+                    <FormattedMessage id='page.reset.pwd' defaultMessage='閲嶇疆瀵嗙爜' />
+                </Button>,
+                <Button
+                    type="link"
+                    danger
+                    style={{ padding: '4px' }}
+                    key="remove"
+                    onClick={async () => {
+                        Modal.confirm({
+                            title: intl.formatMessage({ id: 'page.delete', defaultMessage: '鍒犻櫎' }),
+                            content: intl.formatMessage({ id: 'page.delete.confirm', defaultMessage: '纭畾鍒犻櫎璇ラ」鍚楋紵' }),
+                            onOk: async () => {
+                                const success = await handleRemove([record], intl);
+                                if (success) {
+                                    if (actionRef.current) {
+                                        actionRef.current.reload();
+                                    }
+                                }
+                            },
+                        });
+                    }}
+                >
+                    <FormattedMessage id='page.delete' defaultMessage='鍒犻櫎' />
+                </Button>,
+                <TableDropdown
+                    key="actionGroup"
+                    name="dropdown"
+                    onSelect={(key) => {
+                        if (key === 'assign') {
+                            setAssignModalVisible(true);
+                            setCurrentRow(record);
+                        }
+                    }}
+                    menus={[
+                        { key: 'assign', name: intl.formatMessage({ id: 'page.assign.role', defaultMessage: '鍒嗛厤瑙掕壊' }) },
+                    ]}
+                />,
+            ],
+        },
+    ];
+
+    return (
+        <PageContainer
+            header={{
+                breadcrumb: {},
+            }}
+        >
+            <Row gutter={[16, 24]}>
+                <Col lg={6} md={24}>
+                    <Card
+                        title={intl.formatMessage({ id: 'system.dept', defaultMessage: '閮ㄩ棬' })}
+                        style={{ width: '100%', height: 'calc(100vh - 160px)' }}
+                    >
+                        <Input
+                            style={{ marginBottom: 10 }}
+                            placeholder={intl.formatMessage({ id: 'commont.enter', defaultMessage: '璇疯緭鍏�' })}
+                            onChange={(e) => {
+                                const { value } = e.target;
+                                loadDeptTreeData({
+                                    condition: value
+                                })
+                            }}
+                        />
+                        <div style={{ height: 'calc(100vh - 325px)', overflowY: 'auto' }}>
+                            {deptTreeLoading ? (
+                                <Skeleton active />
+                            ) : (
+                                <Tree
+                                    showLine
+                                    blockNode
+                                    defaultExpandAll    // 寮傛鍔犺浇澶辨晥
+                                    expandedKeys={deptExpandedKeys}
+                                    onExpand={setDeptExpandedKeys}
+                                    treeData={deptTreeData}
+                                    switcherIcon={<DownOutlined />}
+                                    onSelect={(selectedKeys, info) => {
+                                        const deptId = selectedKeys[0];
+                                        setSearchParam(prevState => ({
+                                            ...prevState,
+                                            deptId: deptId
+                                        }));
+                                        actionRef.current?.reload();
+                                    }}
+                                />
+                            )}
+                        </div>
+                    </Card>
+                </Col>
+                <Col lg={18} md={24}>
+                    <ProTable
+                        key="user"
+                        rowKey="id"
+                        actionRef={actionRef}
+                        formRef={formTableRef}
+                        columns={columns}
+                        cardBordered
+                        size='small'
+                        // scroll={{ y: boxHeight }}
+                        dateFormatter="string"
+                        pagination={{ pageSize: 12 }}
+                        search={false}
+                        toolbar={{
+                            search: {
+                                onSearch: (value) => {
+                                    setSearchParam(prevState => ({
+                                        ...prevState,
+                                        condition: value
+                                    }));
+                                    actionRef.current?.reload();
+                                },
+                            },
+                            filter: (
+                                <LightFilter
+                                    onValuesChange={(val) => {
+                                    }}
+                                >
+                                </LightFilter>
+                            ),
+                            actions: [
+                                <Button
+                                    type="primary"
+                                    danger
+                                    key="removeBatch"
+                                    hidden={selectedRows?.length === 0}
+                                    onClick={async () => {
+                                        Modal.confirm({
+                                            title: intl.formatMessage({ id: 'page.delete', defaultMessage: '鍒犻櫎' }),
+                                            content: intl.formatMessage({ id: 'page.delete.confirm', defaultMessage: '纭畾鍒犻櫎璇ラ」鍚楋紵' }),
+                                            icon: <ExclamationCircleOutlined />,
+                                            async onOk() {
+                                                const success = await handleRemove(selectedRows, intl);
+                                                if (success) {
+                                                    setSelectedRows([]);
+                                                    actionRef.current.reload();
+                                                }
+                                            },
+                                            onCancel() { },
+                                        });
+                                    }}
+                                >
+                                    <DeleteOutlined />
+                                    <FormattedMessage id='page.delete' defaultMessage='鍒犻櫎' />
+                                </Button>,
+                                <Button
+                                    type="primary"
+                                    key="save"
+                                    onClick={async () => {
+                                        setModalVisible(true)
+                                    }}
+                                >
+                                    <PlusOutlined />
+                                    <FormattedMessage id='page.add' defaultMessage='娣诲姞' />
+                                </Button>,
+                                <Button
+                                    key="export"
+                                    onClick={async () => {
+                                        handleExport(intl);
+                                    }}
+                                >
+                                    <ExportOutlined />
+                                    <FormattedMessage id='page.export' defaultMessage='瀵煎嚭' />
+                                </Button>,
+                            ],
+                        }}
+                        request={(params, sorter, filter) =>
+                            Http.doPostPromise('/api/user/page1', { ...params, ...searchParam }, (res) => {
+                                return {
+                                    data: res.data.records,
+                                    total: res.data.total,
+                                    success: true,
+                                }
+                            })
+                        }
+                        tableAlertRender={false}
+                        rowSelection={{
+                            onChange: (ids, rows) => {
+                                setSelectedRows(rows);
+                            }
+                        }}
+                        columnsState={{
+                            persistenceKey: TABLE_KEY,
+                            persistenceType: 'localStorage',
+                            defaultValue: {
+                                password: { show: repairBug(TABLE_KEY, 'password', false) },
+                                avatar: { show: repairBug(TABLE_KEY, 'avatar', false) },
+                                code: { show: repairBug(TABLE_KEY, 'code', false) },
+                                phone: { show: repairBug(TABLE_KEY, 'phone', false) },
+                                email: { show: repairBug(TABLE_KEY, 'email', false) },
+                                emailVerified$: { show: repairBug(TABLE_KEY, 'emailVerified$', false) },
+                                realName: { show: repairBug(TABLE_KEY, 'realName', false) },
+                                idCard: { show: repairBug(TABLE_KEY, 'idCard', false) },
+                                birthday: { show: repairBug(TABLE_KEY, 'birthday', false) },
+                                introduction: { show: repairBug(TABLE_KEY, 'introduction', false) },
+                                createTime$: { show: repairBug(TABLE_KEY, 'createTime$', false) },
+                                updateTime$: { show: repairBug(TABLE_KEY, 'updateTime$', false) },
+                                updateBy$: { show: repairBug(TABLE_KEY, 'updateBy$', false) },
+                                memo: { show: repairBug(TABLE_KEY, 'memo', false) },
+                                option: { fixed: 'right', disable: true },
+                            },
+                            onChange(value) {
+                            },
+                        }}
+                    />
+                </Col>
+            </Row>
+
+            <Edit
+                open={modalVisible}
+                values={currentRow || {}}
+                treeData={deptTreeData}
+                onCancel={
+                    () => {
+                        setModalVisible(false);
+                        setCurrentRow(undefined);
+                    }
+                }
+                onSubmit={async (values) => {
+                    let ok = false;
+                    if (values.id) {
+                        ok = await handleUpdate({ ...values }, intl)
+                    } else {
+                        ok = await handleSave({ ...values }, intl)
+                    }
+                    if (ok) {
+                        setModalVisible(false);
+                        setCurrentRow(undefined);
+                        if (actionRef.current) {
+                            actionRef.current.reload();
+                        }
+                    }
+                }
+                }
+            />
+
+            <Pwd
+                open={pwdModalVisible}
+                values={currentRow || {}}
+                onCancel={
+                    () => {
+                        setPwdModalVisible(false);
+                        setCurrentRow(undefined);
+                    }
+                }
+                onSubmit={async (values) => {
+                    let ok = false;
+                    if (values.id) {
+                        ok = await handlePwd({ ...values }, intl)
+                    }
+                    if (ok) {
+                        setPwdModalVisible(false);
+                        setCurrentRow(undefined);
+                        if (actionRef.current) {
+                            actionRef.current.reload();
+                        }
+                    }
+                }
+                }
+            />
+
+            <AssignRole
+                open={assignModalVisible}
+                values={currentRow || {}}
+                onCancel={
+                    () => {
+                        setAssignModalVisible(false);
+                        setCurrentRow(undefined);
+                    }
+                }
+                onSubmit={async (values) => {
+                    let ok = false;
+                    if (values.id) {
+                        ok = await handleUpdate({ ...values }, intl)
+                    }
+                    if (ok) {
+                        setAssignModalVisible(false);
+                        setCurrentRow(undefined);
+                        if (actionRef.current) {
+                            actionRef.current.reload();
+                        }
+                    }
+                }}
+            />
+
+        </PageContainer>
+    );
+};
+
+export default Main;

--
Gitblit v1.9.1