3 Star 0 Fork 0

neuro-netw0rk/server-golib

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
view.go 7.78 KB
一键复制 编辑 原始数据 按行查看 历史
LeoWang 提交于 2024-12-16 16:45 +08:00 . 整合golib和serverlib
package permission
import (
"context"
"fmt"
"gitee.com/neuro-netw0rk/server-golib/nlog"
"sort"
"strings"
)
type UPermissionExtend struct {
CheckedKeys []string `json:"checked_keys"`
HalfCheckedKeys []string `json:"half_checked_keys"`
PermissionMap []*UPermission `json:"permission_map"`
}
// UPermission 用户权限
type UPermission struct {
ID int64 `json:"-"`
Code string `json:"routerName"` // 前端菜单唯一表示
Title string `json:"title"` // 菜单名称
CheckLevel uint8 `json:"checkLevel"` // 0:未选 1:部分选择 2:全选
Parent *UPermission `json:"-"`
Children []*UPermission `json:"children"` // 子菜单
Component []*PageComponent `json:"pageApis"` // 某个菜单下属按钮、tab页面
}
type PageComponent struct {
Code string `json:"name"` // 按钮唯一标识
Description string `json:"description"` // 按钮描述
Parent *UPermission `json:"-"`
Effect uint8 `json:"effect"` // 按钮权限 1:正常显示 2:隐藏 3:禁用
}
// GetUserPermission 获取用户菜单信息
func (p *Permission) GetUserPermission(
ctx context.Context, id int64,
) (*UPermissionExtend, error) {
// 通过user_id获取对应角色可见菜单
codeList, err := p.opts.GetMenuOwned(ctx, id)
if err != nil {
nlog.Errorf(ctx,
fmt.Sprintf("[GetUserPermission] get owned err: %v", err),
)
return nil, err
}
codeMap := map[string]struct{}{}
for _, v := range codeList {
if _, ok := codeMap[v]; !ok {
codeMap[v] = struct{}{}
}
}
// 组装树形菜单
menuList, err := p.opts.GetMenu(ctx)
if err != nil || len(menuList) == 0 {
nlog.Errorf(ctx,
fmt.Sprintf("[GetUserPermission] get menu list: %v", err),
)
return nil, err
}
// 按层级组装树形菜单
// menuMap key:记录id value:由菜单记录创建的Permission对象
menuMap := map[string]*UPermission{}
// 将菜单项组装成嵌套结构,返回一级菜单列表
firstLayerList := AssembleMenuToTree(
ctx, menuList, menuMap,
)
// 标记菜单的选择状态
checkedKeys, halfCheckedKeys :=
markSelectStatus(
ctx,
menuList, menuMap, codeMap,
p.opts.GetLimited,
)
// 将返回的菜单项递归排序
firstLayerList = sortPermissionList(firstLayerList)
permissionExtend := &UPermissionExtend{
CheckedKeys: checkedKeys,
HalfCheckedKeys: halfCheckedKeys,
PermissionMap: firstLayerList,
}
return permissionExtend, nil
}
// AssembleMenuToTree 将平级的menu组装成树形
// menuAll 菜单全量记录列表
// menuMap 存放id到permission指针映射,方便子节点插入
func AssembleMenuToTree(ctx context.Context,
menuAll []*SysMenu,
menuMap map[string]*UPermission) []*UPermission {
var firstLayerList []*UPermission
// 根据完整路径长度升序排列,长度越短为菜单的深度越小,类似于树形结构
sort.Slice(menuAll, func(i, j int) bool {
iPath := strings.Split(menuAll[i].Code, "-")
jPath := strings.Split(menuAll[j].Code, "-")
return len(iPath) <= len(jPath)
})
// 根据前缀树组装菜单树
type trie map[string]trie
tree := trie{}
// 一级节点插入
for _, menu := range menuAll {
item := &UPermission{
ID: menu.ID,
Code: menu.Code,
Title: menu.Title,
}
menuMap[menu.Code] = item
// 顶级页面
if menu.MenuType == MenuTypeDirectory {
children := tree[menu.Code]
if children == nil {
tree[menu.Code] = trie{"#": trie{}}
}
firstLayerList = append(firstLayerList, item)
continue
}
cur := tree
parts := strings.Split(item.Code, "-")
// path[0]表示结点是否为终止结点, path[1]为结点值
// path = [][]string{
// {"#", " ", " ", "#"},
// {"host", "asset", "layout", "basic"},
// }
path := make([][]string, 2)
// 找到直接父节点code
for _, p := range parts {
if cur[p] == nil {
cur[p] = trie{}
}
cur = cur[p]
char := ""
if cur["#"] != nil {
char = "#"
}
path[0] = append(path[0], char)
path[1] = append(path[1], p)
}
cur["#"] = trie{}
for j := len(path[1]) - 1; j >= 0; j-- {
if path[0][j] == "#" {
path[1] = path[1][:j+1]
break
}
}
parents := menuMap[strings.Join(path[1], "-")]
if parents == nil {
nlog.Warnf(ctx,
"[AssembleMenuToTree] parent not found: %v, menu: %v",
strings.Join(path[1], "-"),
menu.Code,
)
continue
}
// 菜单放入父节点children中,按钮和tab页面放入component里面
if menu.MenuType == MenuTypePage {
parents.Children = append(parents.Children, item)
continue
} else {
_item := &PageComponent{
Code: menu.Code,
Description: menu.Title,
}
parents.Component = append(parents.Component, _item)
}
}
return firstLayerList
}
// MarkSelectStatus 标记页面、按钮的选择状态
func markSelectStatus(ctx context.Context,
menuAll []*SysMenu,
menuMap map[string]*UPermission,
codeMap map[string]struct{},
getExcluded ExcludeFunc,
) ([]string, []string) {
var checkedKeys []string
var halfCheckedKeys []string
// 根据tree_path路径长度降序排列,先从底层标记select状态
sort.Slice(menuAll, func(i, j int) bool {
iPath := strings.Split(menuAll[i].Code, "-")
jPath := strings.Split(menuAll[j].Code, "-")
return len(iPath) >= len(jPath)
})
// 待排除菜单列表
var err error
excludedMap := map[string]struct{}{}
if getExcluded != nil {
excludedMap, err = getExcluded(ctx)
if err != nil {
excludedMap = map[string]struct{}{}
}
}
for _, v := range menuAll {
// 统一处理
if _, ok := excludedMap[v.Code]; ok {
continue
}
item := menuMap[v.Code]
if len(item.Children) == 0 && len(item.Component) == 0 {
// 如果为叶子结点且存在记录,直接标记全选
if _, ok := codeMap[v.Code]; ok {
item.CheckLevel = CheckLevelAll
checkedKeys = append(checkedKeys, v.Code)
}
} else {
// 中间节点要根据叶子节点的选择情况标记
item.CheckLevel = checkChildrenSelectStatus(item.Children, item.Component)
switch item.CheckLevel {
case CheckLevelAll:
checkedKeys = append(checkedKeys, v.Code)
case CheckLevelHalf:
halfCheckedKeys = append(halfCheckedKeys, v.Code)
default:
}
}
}
return checkedKeys, halfCheckedKeys
}
// sortPermissionList 逐层对Permission按照id升序排列
// pList: 待排序
// pMap: permission与id映射map
func sortPermissionList(pList []*UPermission) []*UPermission {
var pStack []*UPermission
// sort一级节点
sort.Slice(pList, func(i, j int) bool {
return pList[i].ID < pList[j].ID
})
// 将一级节点放入栈内逐层排序
for i := len(pList) - 1; i >= 0; i-- {
pStack = append(pStack, pList[i])
}
for len(pStack) != 0 {
// 取栈顶元素
top := pStack[len(pStack)-1]
pStack = pStack[:len(pStack)-1]
// 子节点排序
if len(top.Children) != 0 {
cSlice := top.Children
sort.Slice(cSlice, func(i, j int) bool {
return cSlice[i].ID < cSlice[j].ID
})
for i := len(cSlice) - 1; i >= 0; i-- {
pStack = append(pStack, cSlice[i])
}
}
}
return pList
}
// checkChildrenSelectStatus check父节点下所有子节点的选择状态,返回父节点选择状态
func checkChildrenSelectStatus(children []*UPermission, compList []*PageComponent) uint8 {
selectAll := true
selectNone := true
if len(children) > 0 {
for _, v := range children {
if v.CheckLevel != CheckLevelAll {
selectAll = false
}
if v.CheckLevel == CheckLevelHalf || v.CheckLevel == CheckLevelAll {
selectNone = false
}
}
}
if len(compList) > 0 {
for _, v := range compList {
if v.Effect == EffectHidden {
selectAll = false
} else {
selectNone = false
}
}
}
switch {
case !selectAll && !selectNone:
return CheckLevelHalf
case selectAll && !selectNone:
return CheckLevelAll
default:
return CheckLevelNone
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/neuro-netw0rk/server-golib.git
git@gitee.com:neuro-netw0rk/server-golib.git
neuro-netw0rk
server-golib
server-golib
v0.0.5-beta2

搜索帮助