|
|
@@ -0,0 +1,68 @@
|
|
|
+// 树形节点接口
|
|
|
+export interface TreeNode {
|
|
|
+ id: number;
|
|
|
+ [key: string]: any;
|
|
|
+ children?: TreeNode[];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 将扁平数组转换为树形结构
|
|
|
+ * @param list 扁平数组
|
|
|
+ * @param idKey ID字段名,默认为 'id'
|
|
|
+ * @param parentIdKey 父ID字段名,默认为 'parentId'
|
|
|
+ * @param childrenKey 子节点字段名,默认为 'children'
|
|
|
+ * @returns 树形结构数组
|
|
|
+ */
|
|
|
+export function handleTree<T extends TreeNode>(
|
|
|
+ list: T[],
|
|
|
+ idKey: string = 'id',
|
|
|
+ parentIdKey: string = 'parentId',
|
|
|
+ childrenKey: string = 'children'
|
|
|
+): T[] {
|
|
|
+ const map = new Map<number, T>();
|
|
|
+ const roots: T[] = [];
|
|
|
+
|
|
|
+ // 第一遍:创建所有节点的映射
|
|
|
+ list.forEach((item) => {
|
|
|
+ const id = item[idKey] as number;
|
|
|
+ map.set(id, { ...item, [childrenKey]: [] });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 第二遍:建立父子关系
|
|
|
+ list.forEach((item) => {
|
|
|
+ const id = item[idKey] as number;
|
|
|
+ const parentId = item[parentIdKey] as number;
|
|
|
+ const node = map.get(id);
|
|
|
+
|
|
|
+ if (!node) return;
|
|
|
+
|
|
|
+ if (parentId === 0 || parentId === null || parentId === undefined) {
|
|
|
+ // 根节点
|
|
|
+ roots.push(node);
|
|
|
+ } else {
|
|
|
+ // 子节点
|
|
|
+ const parent = map.get(parentId);
|
|
|
+ if (parent) {
|
|
|
+ if (!parent[childrenKey]) {
|
|
|
+ parent[childrenKey] = [];
|
|
|
+ }
|
|
|
+ parent[childrenKey].push(node);
|
|
|
+ } else {
|
|
|
+ // 找不到父节点,作为根节点处理
|
|
|
+ roots.push(node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return roots;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 树形结构的默认属性配置(用于 el-tree-select 等组件)
|
|
|
+ */
|
|
|
+export const defaultProps = {
|
|
|
+ children: 'children',
|
|
|
+ label: 'name',
|
|
|
+ value: 'id',
|
|
|
+};
|
|
|
+
|