import { useEffect, useState } from 'react'; import { Tree, Card, Spin } from 'antd'; import type { DataNode } from 'antd/es/tree'; import { getDeptList } from '@/api/system/dept'; import type { SystemDept } from '@/api/system/dept'; import { useTranslation } from 'react-i18next'; /** Build a tree from a flat dept list */ function buildDeptTree(list: SystemDept[]): DataNode[] { const map = new Map(); const roots: DataNode[] = []; for (const item of list) { map.set(item.id!, { key: item.id!, title: item.name, children: [], }); } for (const item of list) { const node = map.get(item.id!)!; if (item.parentId === 0 || !map.has(item.parentId)) { roots.push(node); } else { map.get(item.parentId)!.children.push(node); } } return roots; } interface DeptTreeProps { onSelect: (deptId: number | undefined) => void; } const DeptTree: React.FC = ({ onSelect }) => { const { t } = useTranslation('system/user'); const [treeData, setTreeData] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setLoading(true); getDeptList() .then(({ data }) => { setTreeData(buildDeptTree(data)); }) .catch(() => { // Error already shown by request interceptor }) .finally(() => setLoading(false)); }, []); return ( { onSelect(keys.length > 0 ? (keys[0] as number) : undefined); }} /> ); }; export default DeptTree;