kra/internal/biz/system/menu.go

311 lines
8.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
FindBaseMenuByName(ctx context.Context, name string) (*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
CheckMenuInAuthority(ctx context.Context, authorityId uint, menuName string) (bool, 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
}
// UserAuthorityDefaultRouter 用户角色默认路由检查
// 如果用户的默认路由不在其权限菜单中则设置为404
func (uc *MenuUsecase) UserAuthorityDefaultRouter(ctx context.Context, authorityId uint, defaultRouter string) string {
if defaultRouter == "" {
return "404"
}
// 检查默认路由是否在用户的权限菜单中
exists, err := uc.repo.CheckMenuInAuthority(ctx, authorityId, defaultRouter)
if err != nil || !exists {
return "404"
}
return defaultRouter
}