export type TreeNode = T & { id: number; parentId: number; children?: TreeNode[]; }; export type ListNode = T & { id: number; parentId: number; }; export function list2Tree( items: T, parentId: number | null = null ): TreeNode[] { return items .filter(item => item.parentId === parentId) .map(item => { const children = list2Tree(items, item.id); return { ...item, ...(children.length ? { children } : null), }; }); } /** * 过滤树,返回列表数据 * @param treeData * @param key 用于过滤的字段 * @param value 用于过滤的值 * @returns */ export function filterTree2List(treeData, key, value) { const filterChildrenTree = (resTree, treeItem) => { if (treeItem[key].includes(value)) { resTree.push(treeItem); return resTree; } if (Array.isArray(treeItem.children)) { const children = treeItem.children.reduce(filterChildrenTree, []); const data = { ...treeItem, children }; if (children.length) resTree.push({ ...data }); } return resTree; }; return treeData.reduce(filterChildrenTree, []); } /** * 过滤树,并保留原有的结构 * @param treeData * @param predicate * @returns */ export function filterTree( treeData: TreeNode[], predicate: (data: T) => boolean ): TreeNode[] { function filter(treeData: TreeNode[]): TreeNode[] { if (!treeData?.length) return treeData; return treeData.filter(data => { if (!predicate(data)) return false; data.children = filter(data.children); return true; }); } return filter(treeData) || []; } export function deleteEmptyChildren(arr: any) { arr?.forEach(node => { if (node.children?.length === 0) delete node.children; else deleteEmptyChildren(node.children); }); }