| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- import { fetchDeleteDept } from '@/services/dept';
- import { ReloadOutlined } from '@ant-design/icons';
- import { PageContainer, ProCard } from '@ant-design/pro-components';
- import { useIntl } from '@umijs/max';
- import { Button, Empty, Popconfirm, Space, Spin, Tooltip, Tree, message } from 'antd';
- import type { DataNode } from 'antd/es/tree';
- import { DeptForm } from './components/Form';
- import { DeptUserTable } from './components/UserTable';
- import { useDeptPage } from './hooks/useDeptPage';
- export default function DeptPage() {
- const intl = useIntl();
- const {
- loading,
- treeData,
- selectedDeptId,
- setSelectedDeptId,
- selectedDeptIds,
- selectedDeptName,
- filteredUsers,
- noDeptUsers,
- loadData,
- productRolesBase,
- } = useDeptPage();
- const handleDelete = async (id: number) => {
- const res = await fetchDeleteDept({ id });
- if (!res.success) return;
- message.success('删除成功');
- if (selectedDeptId === id) setSelectedDeptId(undefined);
- loadData();
- };
- const renderTitle = (node: API.DeptItem) => (
- <Space>
- <span>{node.name}</span>
- <Space onClick={(e) => e.stopPropagation()}>
- <DeptForm
- mode="edit"
- initialValues={node}
- onSuccess={loadData}
- trigger={<a className="text-xs">编辑</a>}
- />
- <DeptForm
- mode="add"
- initialValues={{ parentId: node.id }}
- onSuccess={loadData}
- trigger={<a className="text-xs">新建子部门</a>}
- />
- <Popconfirm title={`确认删除「${node.name}」?`} onConfirm={() => handleDelete(node.id)}>
- <a className="text-xs text-(--ant-color-error)">删除</a>
- </Popconfirm>
- </Space>
- </Space>
- );
- const renderNodes = (items: API.DeptItem[]): DataNode[] =>
- items.map((item) => ({
- key: item.id,
- title: renderTitle(item),
- children: item.children ? renderNodes(item.children) : undefined,
- }));
- return (
- <PageContainer title={intl.formatMessage({ id: 'admin.dept.title' })}>
- <ProCard>
- <div className="flex gap-4">
- <div className="flex flex-col">
- <div className="flex gap-2 items-center py-4">
- <DeptForm
- mode="add"
- initialValues={{ parentId: 0 }}
- onSuccess={loadData}
- trigger={
- <Button type="primary">
- {intl.formatMessage({ id: 'admin.dept.createRoot' })}
- </Button>
- }
- />
- <Tooltip title="刷新">
- <span
- className="cursor-pointer text-(--ant-color-text) hover:text-(--ant-color-primary) transition-colors"
- onClick={loadData}
- >
- <ReloadOutlined style={{ fontSize: 16 }} />
- </span>
- </Tooltip>
- </div>
- <div className="w-80 shrink-0 bg-(--ant-color-fill-quaternary) rounded-lg p-2">
- <Spin spinning={loading}>
- {treeData.length > 0 && (
- <Tree
- className="bg-transparent!"
- treeData={renderNodes(treeData)}
- defaultExpandAll
- showLine
- height={window.innerHeight - 400}
- selectedKeys={selectedDeptId ? [selectedDeptId] : []}
- onSelect={(keys) => setSelectedDeptId(keys[0] as number | undefined)}
- />
- )}
- </Spin>
- </div>
- </div>
- <div className="flex-1 min-w-0">
- {selectedDeptIds ? (
- <DeptUserTable
- users={filteredUsers}
- productRolesBase={productRolesBase}
- deptId={selectedDeptId!}
- deptName={selectedDeptName ?? ''}
- noDeptUsers={noDeptUsers}
- onMemberChange={loadData}
- />
- ) : (
- <Empty description="请在左侧选择部门" className="py-16" />
- )}
- </div>
- </div>
- </ProCard>
- </PageContainer>
- );
- }
|