tree.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * @description 提取菜单树中的每一项uniqueId
  3. * @param tree 树
  4. * @returns 每一项uniqueId组成的数组
  5. */
  6. export const extractPathList = (tree: any[]): any => {
  7. if (!Array.isArray(tree)) {
  8. console.warn("tree must be an array");
  9. return [];
  10. }
  11. if (!tree || tree.length === 0) return [];
  12. const expandedPaths: Array<number | string> = [];
  13. for (const node of tree) {
  14. const hasChildren = node.children && node.children.length > 0;
  15. if (hasChildren) {
  16. extractPathList(node.children);
  17. }
  18. expandedPaths.push(node.uniqueId);
  19. }
  20. return expandedPaths;
  21. };
  22. /**
  23. * @description 如果父级下children的length为1,删除children并自动组建唯一uniqueId
  24. * @param tree 树
  25. * @param pathList 每一项的id组成的数组
  26. * @returns 组件唯一uniqueId后的树
  27. */
  28. export const deleteChildren = (tree: any[], pathList = []): any => {
  29. if (!Array.isArray(tree)) {
  30. console.warn("menuTree must be an array");
  31. return [];
  32. }
  33. if (!tree || tree.length === 0) return [];
  34. for (const [key, node] of tree.entries()) {
  35. if (node.children && node.children.length === 1) delete node.children;
  36. node.id = key;
  37. node.parentId = pathList.length ? pathList[pathList.length - 1] : null;
  38. node.pathList = [...pathList, node.id];
  39. node.uniqueId =
  40. node.pathList.length > 1 ? node.pathList.join("-") : node.pathList[0];
  41. const hasChildren = node.children && node.children.length > 0;
  42. if (hasChildren) {
  43. deleteChildren(node.children, node.pathList);
  44. }
  45. }
  46. return tree;
  47. };
  48. /**
  49. * @description 创建层级关系
  50. * @param tree 树
  51. * @param pathList 每一项的id组成的数组
  52. * @returns 创建层级关系后的树
  53. */
  54. export const buildHierarchyTree = (tree: any[], pathList = []): any => {
  55. if (!Array.isArray(tree)) {
  56. console.warn("tree must be an array");
  57. return [];
  58. }
  59. if (!tree || tree.length === 0) return [];
  60. for (const [key, node] of tree.entries()) {
  61. node.id = key;
  62. node.parentId = pathList.length ? pathList[pathList.length - 1] : null;
  63. node.pathList = [...pathList, node.id];
  64. const hasChildren = node.children && node.children.length > 0;
  65. if (hasChildren) {
  66. buildHierarchyTree(node.children, node.pathList);
  67. }
  68. }
  69. return tree;
  70. };
  71. /**
  72. * @description 广度优先遍历,根据唯一uniqueId找当前节点信息
  73. * @param tree 树
  74. * @param uniqueId 唯一uniqueId
  75. * @returns 当前节点信息
  76. */
  77. export const getNodeByUniqueId = (
  78. tree: any[],
  79. uniqueId: number | string
  80. ): any => {
  81. if (!Array.isArray(tree)) {
  82. console.warn("menuTree must be an array");
  83. return [];
  84. }
  85. if (!tree || tree.length === 0) return [];
  86. const item = tree.find(node => node.uniqueId === uniqueId);
  87. if (item) return item;
  88. const childrenList = tree
  89. .filter(node => node.children)
  90. .map(i => i.children)
  91. .flat(1) as unknown;
  92. return getNodeByUniqueId(childrenList as any[], uniqueId);
  93. };
  94. /**
  95. * @description 向当前唯一uniqueId节点中追加字段
  96. * @param tree 树
  97. * @param uniqueId 唯一uniqueId
  98. * @param fields 需要追加的字段
  99. * @returns 追加字段后的树
  100. */
  101. export const appendFieldByUniqueId = (
  102. tree: any[],
  103. uniqueId: number | string,
  104. fields: object
  105. ): any => {
  106. if (!Array.isArray(tree)) {
  107. console.warn("menuTree must be an array");
  108. return [];
  109. }
  110. if (!tree || tree.length === 0) return [];
  111. for (const node of tree) {
  112. const hasChildren = node.children && node.children.length > 0;
  113. if (
  114. node.uniqueId === uniqueId &&
  115. Object.prototype.toString.call(fields) === "[object Object]"
  116. )
  117. Object.assign(node, fields);
  118. if (hasChildren) {
  119. appendFieldByUniqueId(node.children, uniqueId, fields);
  120. }
  121. }
  122. return tree;
  123. };
  124. /**
  125. * @description 构造树型结构数据
  126. * @param data 数据源
  127. * @param id id字段 默认id
  128. * @param parentId 父节点字段,默认parentId
  129. * @param children 子节点字段,默认children
  130. * @returns 追加字段后的树
  131. */
  132. export const handleTree = (
  133. data: any[],
  134. id?: string,
  135. parentId?: string,
  136. children?: string
  137. ): any => {
  138. if (!Array.isArray(data)) {
  139. console.warn("data must be an array");
  140. return [];
  141. }
  142. const config = {
  143. id: id || "id",
  144. parentId: parentId || "parentId",
  145. childrenList: children || "children"
  146. };
  147. const childrenListMap: any = {};
  148. const nodeIds: any = {};
  149. const tree = [];
  150. for (const d of data) {
  151. const parentId = d[config.parentId];
  152. if (childrenListMap[parentId] == null) {
  153. childrenListMap[parentId] = [];
  154. }
  155. nodeIds[d[config.id]] = d;
  156. childrenListMap[parentId].push(d);
  157. }
  158. for (const d of data) {
  159. const parentId = d[config.parentId];
  160. if (nodeIds[parentId] == null) {
  161. tree.push(d);
  162. }
  163. }
  164. for (const t of tree) {
  165. adaptToChildrenList(t);
  166. }
  167. function adaptToChildrenList(o: Record<string, any>) {
  168. if (childrenListMap[o[config.id]] !== null) {
  169. o[config.childrenList] = childrenListMap[o[config.id]];
  170. }
  171. if (o[config.childrenList]) {
  172. for (const c of o[config.childrenList]) {
  173. adaptToChildrenList(c);
  174. }
  175. }
  176. }
  177. return tree;
  178. };