tree_dept.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package tree_dept
  2. import (
  3. "sort"
  4. "ulink-admin/modules/system/models/model"
  5. )
  6. // Tree 统一定义菜单树的数据结构,也可以自定义添加其他字段
  7. type Tree struct {
  8. Id int64 `json:"id"`
  9. Data interface{} `json:"-"` //自定义对象
  10. Label string `json:"label"`
  11. Leaf bool `json:"-"` //叶子节点
  12. Selected bool `json:"-"` //选中
  13. PartialSelected bool `json:"-"` //部分选中
  14. Children []Tree `json:"children"` //子节点
  15. }
  16. // ConvertToINodeArray 其他的结构体想要生成菜单树,直接实现这个接口
  17. type INode interface {
  18. GetId() int64
  19. GetLabel() string
  20. GetParentId() int64
  21. GetData() interface{}
  22. // IsRoot 判断当前节点是否是顶层根节点
  23. IsRoot() bool
  24. }
  25. type INodes []INode
  26. func (nodes INodes) Len() int {
  27. return len(nodes)
  28. }
  29. func (nodes INodes) Swap(i, j int) {
  30. nodes[i], nodes[j] = nodes[j], nodes[i]
  31. }
  32. func (nodes INodes) Less(i, j int) bool {
  33. return nodes[i].GetId() < nodes[j].GetId()
  34. }
  35. // GenerateTree 自定义的结构体实现 INode 接口后调用此方法生成树结构
  36. // nodes 需要生成树的节点
  37. // selectedNode 生成树后选中的节点
  38. // menuTrees 生成成功后的树结构对象
  39. func GenerateTree(nodes, selectedNodes []INode) (trees []Tree) {
  40. trees = []Tree{}
  41. // 定义顶层根和子节点
  42. var roots, childs []INode
  43. for _, v := range nodes {
  44. if v.IsRoot() {
  45. // 判断顶层根节点
  46. roots = append(roots, v)
  47. }
  48. childs = append(childs, v)
  49. }
  50. for _, v := range roots {
  51. childTree := &Tree{
  52. Id: v.GetId(),
  53. Label: v.GetLabel(),
  54. Data: v.GetData(),
  55. }
  56. // 递归之前,根据父节点确认 childTree 的选中状态
  57. childTree.Selected = nodeSelected(v, selectedNodes, childTree.Children)
  58. // 递归
  59. recursiveTree(childTree, childs, selectedNodes)
  60. // 递归之后,根据子节点确认 childTree 的选中状态
  61. if !childTree.Selected {
  62. childTree.Selected = nodeSelected(v, selectedNodes, childTree.Children)
  63. }
  64. // 递归之后,根据子节点确认 childTree 的半选中状态
  65. childTree.PartialSelected = nodePartialSelected(childTree.Children)
  66. // 递归之后,根据子节确认是否是叶子节点
  67. childTree.Leaf = len(childTree.Children) == 0
  68. trees = append(trees, *childTree)
  69. }
  70. return
  71. }
  72. // recursiveTree 递归生成树结构
  73. // tree 递归的树对象
  74. // nodes 递归的节点
  75. // selectedNodes 选中的节点
  76. func recursiveTree(tree *Tree, nodes, selectedNodes []INode) {
  77. data := tree.Data.(INode)
  78. for _, v := range nodes {
  79. if v.IsRoot() {
  80. // 如果当前节点是顶层根节点就跳过
  81. continue
  82. }
  83. if data.GetId() == v.GetParentId() {
  84. childTree := &Tree{
  85. Id: v.GetId(),
  86. Label: v.GetLabel(),
  87. Data: v.GetData(),
  88. }
  89. // 递归之前,根据子节点和父节点确认 childTree 的选中状态
  90. childTree.Selected = nodeSelected(v, selectedNodes, childTree.Children) || tree.Selected
  91. recursiveTree(childTree, nodes, selectedNodes)
  92. if !childTree.Selected {
  93. // 递归之后,根据子节点确认 childTree 的选中状态
  94. childTree.Selected = nodeSelected(v, selectedNodes, childTree.Children)
  95. }
  96. // 递归之后,根据子节点确认 childTree 的半选中状态
  97. childTree.PartialSelected = nodePartialSelected(childTree.Children)
  98. // 递归之后,根据子节确认是否是叶子节点
  99. childTree.Leaf = len(childTree.Children) == 0
  100. tree.Children = append(tree.Children, *childTree)
  101. }
  102. }
  103. }
  104. // FindRelationNode 在 allTree 中查询 nodes 中节点的所有父节点
  105. // nodes 要查询父节点的子节点数组
  106. // allTree 所有节点数组
  107. func FindRelationNode(nodes, allNodes []INode) (respNodes []INode) {
  108. nodeMap := make(map[int64]INode)
  109. for _, v := range nodes {
  110. recursiveFindRelationNode(nodeMap, allNodes, v, 0)
  111. }
  112. for _, v := range nodeMap {
  113. respNodes = append(respNodes, v)
  114. }
  115. sort.Sort(INodes(respNodes))
  116. return
  117. }
  118. // recursiveFindRelationNode 递归查询关联父子节点
  119. // nodeMap 查询结果搜集到map中
  120. // allNodes 所有节点
  121. // node 递归节点
  122. // t 递归查找类型:0 查找父、子节点;1 只查找父节点;2 只查找子节点
  123. func recursiveFindRelationNode(nodeMap map[int64]INode, allNodes []INode, node INode, t int) {
  124. nodeMap[node.GetId()] = node
  125. for _, v := range allNodes {
  126. if _, ok := nodeMap[v.GetId()]; ok {
  127. continue
  128. }
  129. // 查找父节点
  130. if t == 0 || t == 1 {
  131. if node.GetParentId() == v.GetId() {
  132. nodeMap[v.GetId()] = v
  133. if v.IsRoot() {
  134. // 是顶层根节点时,不再进行递归
  135. continue
  136. }
  137. recursiveFindRelationNode(nodeMap, allNodes, v, 1)
  138. }
  139. }
  140. // 查找子节点
  141. if t == 0 || t == 2 {
  142. if node.GetId() == v.GetParentId() {
  143. nodeMap[v.GetId()] = v
  144. recursiveFindRelationNode(nodeMap, allNodes, v, 2)
  145. }
  146. }
  147. }
  148. }
  149. // nodeSelected 判断节点的选中状态
  150. // node 进行判断节点
  151. func nodeSelected(node INode, selectedNodes []INode, children []Tree) bool {
  152. for _, v := range selectedNodes {
  153. if node.GetId() == v.GetId() {
  154. // 1. 如果选择节点数组中存在当前节点
  155. return true
  156. }
  157. }
  158. if len(children) == 0 {
  159. // 2. 不满足前置条件1,且没有子节点
  160. return false
  161. }
  162. selectedNum := 0
  163. for _, v := range children {
  164. if v.Selected {
  165. selectedNum++
  166. }
  167. }
  168. if selectedNum == len(children) {
  169. // 不满足前置条件1,2 ,且子节点全部是选中状态
  170. return true
  171. }
  172. return false
  173. }
  174. // nodePartialSelected 判断节点的半选中状态
  175. func nodePartialSelected(trees []Tree) bool {
  176. selectedNum := 0
  177. for _, v := range trees {
  178. if v.Selected {
  179. selectedNum++
  180. }
  181. }
  182. if selectedNum == len(trees) || selectedNum == 0 {
  183. // 子节点全选中,或一个也没有选中
  184. return false
  185. }
  186. return true
  187. }
  188. type DeptList []model.SysDept
  189. // ConvertToINodeArray 将当前数组转换成父类 INode 接口 数组
  190. func (s DeptList) ConvertToINodeArray() (nodes []INode) {
  191. for _, v := range s {
  192. nodes = append(nodes, v)
  193. }
  194. return
  195. }
  196. // GetTree 获取树结构
  197. func (s DeptList) GetTree() []Tree {
  198. array := s.ConvertToINodeArray()
  199. return GenerateTree(array, nil)
  200. }