kra/internal/biz/system/menu.go

294 lines
7.3 KiB
Go

package system
import (
"context"
"errors"
"strconv"
)
// BaseMenu 基础菜单实体
type BaseMenu struct {
ID uint
ParentId uint
Path string
Name string
Hidden bool
Component string
Sort int
ActiveName string
KeepAlive bool
DefaultMenu bool
Title string
Icon string
CloseTab bool
TransitionType string
Parameters []*MenuParameter
MenuBtn []*MenuBtn
Children []*BaseMenu
}
// MenuParameter 菜单参数
type MenuParameter struct {
ID uint
SysBaseMenuID uint
Type string
Key string
Value string
}
// MenuBtn 菜单按钮
type MenuBtn struct {
ID uint
SysBaseMenuID uint
Name string
Desc string
}
// Menu 菜单(带权限)
type Menu struct {
BaseMenu
AuthorityId uint
MenuId uint
Btns map[string]uint
Children []*Menu
}
// AuthorityBtn 角色按钮权限
type AuthorityBtn struct {
AuthorityId uint
SysMenuID uint
SysBaseMenuBtnID uint
BtnName string
}
// MenuRepo 菜单仓储接口
type MenuRepo interface {
CreateBaseMenu(ctx context.Context, menu *BaseMenu) error
UpdateBaseMenu(ctx context.Context, menu *BaseMenu) error
DeleteBaseMenu(ctx context.Context, id uint) error
FindBaseMenuByID(ctx context.Context, id uint) (*BaseMenu, error)
FindAllBaseMenus(ctx context.Context) ([]*BaseMenu, error)
FindBaseMenusByIds(ctx context.Context, ids []string) ([]*BaseMenu, error)
FindAuthorityMenuIds(ctx context.Context, authorityId uint) ([]string, error)
FindAuthorityBtns(ctx context.Context, authorityId uint) ([]*AuthorityBtn, error)
SetMenuAuthority(ctx context.Context, authorityId uint, menuIds []uint) error
}
// MenuUsecase 菜单用例
type MenuUsecase struct {
repo MenuRepo
authRepo AuthorityRepo
useStrictAuth bool
}
// NewMenuUsecase 创建菜单用例
func NewMenuUsecase(repo MenuRepo, authRepo AuthorityRepo, useStrictAuth bool) *MenuUsecase {
return &MenuUsecase{
repo: repo,
authRepo: authRepo,
useStrictAuth: useStrictAuth,
}
}
// AddBaseMenu 添加基础菜单
func (uc *MenuUsecase) AddBaseMenu(ctx context.Context, menu *BaseMenu) error {
return uc.repo.CreateBaseMenu(ctx, menu)
}
// UpdateBaseMenu 更新基础菜单
func (uc *MenuUsecase) UpdateBaseMenu(ctx context.Context, menu *BaseMenu) error {
return uc.repo.UpdateBaseMenu(ctx, menu)
}
// DeleteBaseMenu 删除基础菜单
func (uc *MenuUsecase) DeleteBaseMenu(ctx context.Context, id uint) error {
return uc.repo.DeleteBaseMenu(ctx, id)
}
// GetBaseMenuById 根据ID获取基础菜单
func (uc *MenuUsecase) GetBaseMenuById(ctx context.Context, id uint) (*BaseMenu, error) {
return uc.repo.FindBaseMenuByID(ctx, id)
}
// GetMenuTree 获取动态菜单树
func (uc *MenuUsecase) GetMenuTree(ctx context.Context, authorityId uint) ([]*Menu, error) {
treeMap, err := uc.getMenuTreeMap(ctx, authorityId)
if err != nil {
return nil, err
}
menus := treeMap[0]
for i := range menus {
uc.getChildrenList(menus[i], treeMap)
}
return menus, nil
}
func (uc *MenuUsecase) getMenuTreeMap(ctx context.Context, authorityId uint) (map[uint][]*Menu, error) {
treeMap := make(map[uint][]*Menu)
// 获取角色的菜单ID
menuIds, err := uc.repo.FindAuthorityMenuIds(ctx, authorityId)
if err != nil {
return nil, err
}
// 获取基础菜单
baseMenus, err := uc.repo.FindBaseMenusByIds(ctx, menuIds)
if err != nil {
return nil, err
}
// 获取按钮权限
btns, err := uc.repo.FindAuthorityBtns(ctx, authorityId)
if err != nil {
return nil, err
}
// 构建按钮map
btnMap := make(map[uint]map[string]uint)
for _, b := range btns {
if btnMap[b.SysMenuID] == nil {
btnMap[b.SysMenuID] = make(map[string]uint)
}
btnMap[b.SysMenuID][b.BtnName] = authorityId
}
// 构建菜单树
for _, base := range baseMenus {
menu := &Menu{
BaseMenu: *base,
AuthorityId: authorityId,
MenuId: base.ID,
Btns: btnMap[base.ID],
}
treeMap[base.ParentId] = append(treeMap[base.ParentId], menu)
}
return treeMap, nil
}
func (uc *MenuUsecase) getChildrenList(menu *Menu, treeMap map[uint][]*Menu) {
menu.Children = treeMap[menu.MenuId]
for i := range menu.Children {
uc.getChildrenList(menu.Children[i], treeMap)
}
}
// GetBaseMenuTree 获取基础菜单树
func (uc *MenuUsecase) GetBaseMenuTree(ctx context.Context, authorityID uint) ([]*BaseMenu, error) {
treeMap, err := uc.getBaseMenuTreeMap(ctx, authorityID)
if err != nil {
return nil, err
}
menus := treeMap[0]
for i := range menus {
uc.getBaseChildrenList(menus[i], treeMap)
}
return menus, nil
}
func (uc *MenuUsecase) getBaseMenuTreeMap(ctx context.Context, authorityID uint) (map[uint][]*BaseMenu, error) {
parentAuthorityID, err := uc.authRepo.GetParentAuthorityID(ctx, authorityID)
if err != nil {
return nil, err
}
var allMenus []*BaseMenu
treeMap := make(map[uint][]*BaseMenu)
// 当开启了严格的树角色并且父角色不为0时需要进行菜单筛选
if uc.useStrictAuth && parentAuthorityID != 0 {
menuIds, err := uc.repo.FindAuthorityMenuIds(ctx, authorityID)
if err != nil {
return nil, err
}
allMenus, err = uc.repo.FindBaseMenusByIds(ctx, menuIds)
if err != nil {
return nil, err
}
} else {
allMenus, err = uc.repo.FindAllBaseMenus(ctx)
if err != nil {
return nil, err
}
}
for _, m := range allMenus {
treeMap[m.ParentId] = append(treeMap[m.ParentId], m)
}
return treeMap, nil
}
func (uc *MenuUsecase) getBaseChildrenList(menu *BaseMenu, treeMap map[uint][]*BaseMenu) {
menu.Children = treeMap[menu.ID]
for i := range menu.Children {
uc.getBaseChildrenList(menu.Children[i], treeMap)
}
}
// GetInfoList 获取菜单列表(树形)
func (uc *MenuUsecase) GetInfoList(ctx context.Context, authorityID uint) ([]*BaseMenu, error) {
return uc.GetBaseMenuTree(ctx, authorityID)
}
// AddMenuAuthority 为角色增加菜单权限
func (uc *MenuUsecase) AddMenuAuthority(ctx context.Context, menus []*BaseMenu, adminAuthorityID, authorityId uint) error {
// 检查权限
parentAuthorityID, err := uc.authRepo.GetParentAuthorityID(ctx, adminAuthorityID)
if err != nil {
return err
}
// 当开启了严格的树角色并且父角色不为0时需要进行菜单筛选
if uc.useStrictAuth && parentAuthorityID != 0 {
menuIds, err := uc.repo.FindAuthorityMenuIds(ctx, adminAuthorityID)
if err != nil {
return err
}
for _, menu := range menus {
hasMenu := false
idStr := strconv.Itoa(int(menu.ID))
for _, mid := range menuIds {
if idStr == mid {
hasMenu = true
break
}
}
if !hasMenu {
return errors.New("添加失败,请勿跨级操作")
}
}
}
// 设置菜单权限
menuIds := make([]uint, len(menus))
for i, m := range menus {
menuIds[i] = m.ID
}
return uc.repo.SetMenuAuthority(ctx, authorityId, menuIds)
}
// GetMenuAuthority 获取角色的菜单权限
func (uc *MenuUsecase) GetMenuAuthority(ctx context.Context, authorityId uint) ([]*Menu, error) {
menuIds, err := uc.repo.FindAuthorityMenuIds(ctx, authorityId)
if err != nil {
return nil, err
}
baseMenus, err := uc.repo.FindBaseMenusByIds(ctx, menuIds)
if err != nil {
return nil, err
}
menus := make([]*Menu, len(baseMenus))
for i, base := range baseMenus {
menus[i] = &Menu{
BaseMenu: *base,
AuthorityId: authorityId,
MenuId: base.ID,
}
}
return menus, nil
}