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