index.tsx 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { fetchDeleteDept } from '@/services/dept';
  2. import { PageContainer } from '@ant-design/pro-components';
  3. import { useIntl } from '@umijs/max';
  4. import { Button, Empty, Popconfirm, Space, Spin, Tree, message } from 'antd';
  5. import type { DataNode } from 'antd/es/tree';
  6. import { DeptForm } from './components/Form';
  7. import { DeptUserTable } from './components/UserTable';
  8. import { useDeptPage } from './hooks/useDeptPage';
  9. export default function DeptPage() {
  10. const intl = useIntl();
  11. const {
  12. loading,
  13. treeData,
  14. selectedDeptId,
  15. setSelectedDeptId,
  16. selectedDeptIds,
  17. filteredUsers,
  18. loadData,
  19. } = useDeptPage();
  20. const handleDelete = async (id: number) => {
  21. const res = await fetchDeleteDept({ id });
  22. if (res.success) {
  23. message.success('删除成功');
  24. if (selectedDeptId === id) setSelectedDeptId(undefined);
  25. loadData();
  26. }
  27. };
  28. const renderTitle = (node: API.DeptItem) => (
  29. <Space>
  30. <span>{node.name}</span>
  31. <DeptForm
  32. mode="edit"
  33. initialValues={node}
  34. onSuccess={loadData}
  35. trigger={<a className="text-xs">编辑</a>}
  36. />
  37. <DeptForm
  38. mode="add"
  39. initialValues={{ parentId: node.id }}
  40. onSuccess={loadData}
  41. trigger={<a className="text-xs">新建子部门</a>}
  42. />
  43. <Popconfirm title="确认删除?" onConfirm={() => handleDelete(node.id)}>
  44. <a className="text-xs text-red-500">删除</a>
  45. </Popconfirm>
  46. </Space>
  47. );
  48. const renderNodes = (items: API.DeptItem[]): DataNode[] =>
  49. items.map((item) => ({
  50. key: item.id,
  51. title: renderTitle(item),
  52. children: item.children ? renderNodes(item.children) : undefined,
  53. }));
  54. return (
  55. <PageContainer title={intl.formatMessage({ id: 'admin.dept.title' })}>
  56. <div className="mb-4">
  57. <DeptForm
  58. mode="add"
  59. initialValues={{ parentId: 0 }}
  60. onSuccess={loadData}
  61. trigger={
  62. <Button type="primary">{intl.formatMessage({ id: 'admin.dept.createRoot' })}</Button>
  63. }
  64. />
  65. </div>
  66. <div className="flex gap-4">
  67. <div className="w-80 shrink-0 border border-gray-100 rounded p-3 bg-white">
  68. <Spin spinning={loading}>
  69. {treeData.length > 0 && (
  70. <Tree
  71. treeData={renderNodes(treeData)}
  72. defaultExpandAll
  73. showLine
  74. selectedKeys={selectedDeptId ? [selectedDeptId] : []}
  75. onSelect={(keys) => setSelectedDeptId(keys[0] as number | undefined)}
  76. />
  77. )}
  78. </Spin>
  79. </div>
  80. <div className="flex-1 min-w-0">
  81. {selectedDeptIds ? (
  82. <DeptUserTable users={filteredUsers} />
  83. ) : (
  84. <Empty description="请在左侧选择部门" className="py-16" />
  85. )}
  86. </div>
  87. </div>
  88. </PageContainer>
  89. );
  90. }