// Package tree // @Link https://github.com/bufanyun/hotgo // @Copyright Copyright (c) 2023 HotGo CLI // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE package tree import ( "fmt" "github.com/gogf/gf/v2/util/gconv" "strings" ) const ( treeDefaultId = "id" // 树ID treeDefaultPid = "pid" // 上级树ID treeDefaultChildren = "children" // 下级属性 treeBeginCut = "tr_" // 树标识开头 treeEndCut = " " // 树标识结尾 ) // GenOption 生成选项 type GenOption struct { IdField string PidField string ChildrenField string } // GenLabel 生成关系树标识 func GenLabel(basic string, appendId int64) string { return fmt.Sprintf("%v%v%v%v", basic, treeBeginCut, appendId, treeEndCut) } // GetIdLabel 获取指定Id的树标签 func GetIdLabel(id int64) string { return fmt.Sprintf("%v%v%v", treeBeginCut, id, treeEndCut) } // GetIds 获取上级ID集合 func GetIds(tree string) (ids []int64) { idsStr := strings.Split(tree, treeEndCut) if len(idsStr) == 0 { return } for _, v := range idsStr { newId := gconv.Int64(strings.ReplaceAll(v, treeBeginCut, "")) if newId > 0 { ids = append(ids, newId) } } return } // GenTree 生成关系树 func GenTree(menus []map[string]interface{}) (realMenu []map[string]interface{}) { return GenTreeWithField(menus, GenOption{ IdField: treeDefaultId, PidField: treeDefaultPid, ChildrenField: treeDefaultChildren, }) } // GenTreeWithField 生成关系树 自定义生成属性 func GenTreeWithField(menus []map[string]interface{}, op GenOption) (realMenu []map[string]interface{}) { if len(menus) < 1 { return } minPid := GetMinPid(menus, op.PidField) formatMenu := make(map[int]map[string]interface{}) for _, m := range menus { formatMenu[gconv.Int(m[op.IdField])] = m if gconv.Int(m[op.PidField]) == minPid { realMenu = append(realMenu, m) // 需要返回的顶级菜单 } } // 得益于都是地址操作,可以直接往父级塞 for _, m := range formatMenu { if formatMenu[gconv.Int(m[op.PidField])] == nil { continue } if formatMenu[gconv.Int(m[op.PidField])][op.ChildrenField] == nil { formatMenu[gconv.Int(m[op.PidField])][op.ChildrenField] = []map[string]interface{}{} } formatMenu[gconv.Int(m[op.PidField])][op.ChildrenField] = append(formatMenu[gconv.Int(m[op.PidField])][op.ChildrenField].([]map[string]interface{}), m) } return } func GetMinPid(menus []map[string]interface{}, pidField string) int { index := -1 for _, m := range menus { if index == -1 { index = gconv.Int(m[pidField]) continue } if gconv.Int(m[pidField]) < index { index = gconv.Int(m[pidField]) } } if index == -1 { return 0 } return index }