251 lines
6.2 KiB
Go
251 lines
6.2 KiB
Go
|
package admin_menu
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"sort"
|
|||
|
"strconv"
|
|||
|
|
|||
|
"ycc-server/app/main/api/internal/svc"
|
|||
|
"ycc-server/app/main/api/internal/types"
|
|||
|
"ycc-server/common/ctxdata"
|
|||
|
"ycc-server/common/xerr"
|
|||
|
|
|||
|
"github.com/Masterminds/squirrel"
|
|||
|
"github.com/bytedance/sonic"
|
|||
|
"github.com/pkg/errors"
|
|||
|
"github.com/samber/lo"
|
|||
|
"github.com/zeromicro/go-zero/core/logx"
|
|||
|
"github.com/zeromicro/go-zero/core/mr"
|
|||
|
)
|
|||
|
|
|||
|
type GetMenuAllLogic struct {
|
|||
|
logx.Logger
|
|||
|
ctx context.Context
|
|||
|
svcCtx *svc.ServiceContext
|
|||
|
}
|
|||
|
|
|||
|
func NewGetMenuAllLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMenuAllLogic {
|
|||
|
return &GetMenuAllLogic{
|
|||
|
Logger: logx.WithContext(ctx),
|
|||
|
ctx: ctx,
|
|||
|
svcCtx: svcCtx,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
func (l *GetMenuAllLogic) GetMenuAll(req *types.GetMenuAllReq) (resp *[]types.GetMenuAllResp, err error) {
|
|||
|
userId, err := ctxdata.GetUidFromCtx(l.ctx)
|
|||
|
if err != nil {
|
|||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败, %+v", err)
|
|||
|
}
|
|||
|
|
|||
|
// 使用MapReduceVoid并发获取用户角色
|
|||
|
var roleIds []int64
|
|||
|
var permissions []*struct {
|
|||
|
RoleId int64
|
|||
|
}
|
|||
|
|
|||
|
type UserRoleResult struct {
|
|||
|
RoleId int64
|
|||
|
}
|
|||
|
|
|||
|
err = mr.MapReduceVoid(
|
|||
|
func(source chan<- interface{}) {
|
|||
|
adminUserRoleBuilder := l.svcCtx.AdminUserRoleModel.SelectBuilder().Where(squirrel.Eq{"user_id": userId})
|
|||
|
source <- adminUserRoleBuilder
|
|||
|
},
|
|||
|
func(item interface{}, writer mr.Writer[*UserRoleResult], cancel func(error)) {
|
|||
|
builder := item.(squirrel.SelectBuilder)
|
|||
|
result, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, builder, "role_id DESC")
|
|||
|
if err != nil {
|
|||
|
cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户角色信息失败, %+v", err))
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
for _, r := range result {
|
|||
|
writer.Write(&UserRoleResult{RoleId: r.RoleId})
|
|||
|
}
|
|||
|
},
|
|||
|
func(pipe <-chan *UserRoleResult, cancel func(error)) {
|
|||
|
for item := range pipe {
|
|||
|
permissions = append(permissions, &struct{ RoleId int64 }{RoleId: item.RoleId})
|
|||
|
}
|
|||
|
},
|
|||
|
)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
for _, permission := range permissions {
|
|||
|
roleIds = append(roleIds, permission.RoleId)
|
|||
|
}
|
|||
|
|
|||
|
// 使用MapReduceVoid并发获取角色菜单
|
|||
|
var menuIds []int64
|
|||
|
var roleMenus []*struct {
|
|||
|
MenuId int64
|
|||
|
}
|
|||
|
|
|||
|
type RoleMenuResult struct {
|
|||
|
MenuId int64
|
|||
|
}
|
|||
|
|
|||
|
err = mr.MapReduceVoid(
|
|||
|
func(source chan<- interface{}) {
|
|||
|
getRoleMenuBuilder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().Where(squirrel.Eq{"role_id": roleIds})
|
|||
|
source <- getRoleMenuBuilder
|
|||
|
},
|
|||
|
func(item interface{}, writer mr.Writer[*RoleMenuResult], cancel func(error)) {
|
|||
|
builder := item.(squirrel.SelectBuilder)
|
|||
|
result, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, builder, "id DESC")
|
|||
|
if err != nil {
|
|||
|
cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取角色菜单信息失败, %+v", err))
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
for _, r := range result {
|
|||
|
writer.Write(&RoleMenuResult{MenuId: r.MenuId})
|
|||
|
}
|
|||
|
},
|
|||
|
func(pipe <-chan *RoleMenuResult, cancel func(error)) {
|
|||
|
for item := range pipe {
|
|||
|
roleMenus = append(roleMenus, &struct{ MenuId int64 }{MenuId: item.MenuId})
|
|||
|
}
|
|||
|
},
|
|||
|
)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
for _, roleMenu := range roleMenus {
|
|||
|
menuIds = append(menuIds, roleMenu.MenuId)
|
|||
|
}
|
|||
|
|
|||
|
// 使用MapReduceVoid并发获取菜单
|
|||
|
type AdminMenuStruct struct {
|
|||
|
Id int64
|
|||
|
Pid int64
|
|||
|
Name string
|
|||
|
Path string
|
|||
|
Component string
|
|||
|
Redirect struct {
|
|||
|
String string
|
|||
|
Valid bool
|
|||
|
}
|
|||
|
Meta string
|
|||
|
Sort int64
|
|||
|
Type int64
|
|||
|
Status int64
|
|||
|
}
|
|||
|
|
|||
|
var menus []*AdminMenuStruct
|
|||
|
|
|||
|
err = mr.MapReduceVoid(
|
|||
|
func(source chan<- interface{}) {
|
|||
|
adminMenuBuilder := l.svcCtx.AdminMenuModel.SelectBuilder().Where(squirrel.Eq{"id": menuIds})
|
|||
|
source <- adminMenuBuilder
|
|||
|
},
|
|||
|
func(item interface{}, writer mr.Writer[*AdminMenuStruct], cancel func(error)) {
|
|||
|
builder := item.(squirrel.SelectBuilder)
|
|||
|
result, err := l.svcCtx.AdminMenuModel.FindAll(l.ctx, builder, "sort ASC")
|
|||
|
if err != nil {
|
|||
|
cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取菜单信息失败, %+v", err))
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
for _, r := range result {
|
|||
|
menu := &AdminMenuStruct{
|
|||
|
Id: r.Id,
|
|||
|
Pid: r.Pid,
|
|||
|
Name: r.Name,
|
|||
|
Path: r.Path,
|
|||
|
Component: r.Component,
|
|||
|
Redirect: r.Redirect,
|
|||
|
Meta: r.Meta,
|
|||
|
Sort: r.Sort,
|
|||
|
Type: r.Type,
|
|||
|
Status: r.Status,
|
|||
|
}
|
|||
|
writer.Write(menu)
|
|||
|
}
|
|||
|
},
|
|||
|
func(pipe <-chan *AdminMenuStruct, cancel func(error)) {
|
|||
|
for item := range pipe {
|
|||
|
menus = append(menus, item)
|
|||
|
}
|
|||
|
},
|
|||
|
)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
// 转换为types.Menu结构并存储到映射表
|
|||
|
menuMap := make(map[string]types.GetMenuAllResp)
|
|||
|
for _, menu := range menus {
|
|||
|
// 只处理状态正常的菜单
|
|||
|
if menu.Status != 1 {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
meta := make(map[string]interface{})
|
|||
|
err = sonic.Unmarshal([]byte(menu.Meta), &meta)
|
|||
|
if err != nil {
|
|||
|
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解析菜单Meta信息失败, %+v", err)
|
|||
|
}
|
|||
|
|
|||
|
redirect := func() string {
|
|||
|
if menu.Redirect.Valid {
|
|||
|
return menu.Redirect.String
|
|||
|
}
|
|||
|
return ""
|
|||
|
}()
|
|||
|
|
|||
|
menuId := strconv.FormatInt(menu.Id, 10)
|
|||
|
menuMap[menuId] = types.GetMenuAllResp{
|
|||
|
Name: menu.Name,
|
|||
|
Path: menu.Path,
|
|||
|
Redirect: redirect,
|
|||
|
Component: menu.Component,
|
|||
|
Sort: menu.Sort,
|
|||
|
Meta: meta,
|
|||
|
Children: make([]types.GetMenuAllResp, 0),
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 按ParentId将菜单分组
|
|||
|
menuGroups := lo.GroupBy(menus, func(item *AdminMenuStruct) int64 {
|
|||
|
return item.Pid
|
|||
|
})
|
|||
|
|
|||
|
// 递归构建菜单树
|
|||
|
var buildMenuTree func(parentId int64) []types.GetMenuAllResp
|
|||
|
buildMenuTree = func(parentId int64) []types.GetMenuAllResp {
|
|||
|
children := make([]types.GetMenuAllResp, 0)
|
|||
|
|
|||
|
childMenus, ok := menuGroups[parentId]
|
|||
|
if !ok {
|
|||
|
return children
|
|||
|
}
|
|||
|
|
|||
|
// 按Sort排序
|
|||
|
sort.Slice(childMenus, func(i, j int) bool {
|
|||
|
return childMenus[i].Sort < childMenus[j].Sort
|
|||
|
})
|
|||
|
|
|||
|
for _, childMenu := range childMenus {
|
|||
|
menuId := strconv.FormatInt(childMenu.Id, 10)
|
|||
|
if menu, exists := menuMap[menuId]; exists && childMenu.Status == 1 {
|
|||
|
// 递归构建子菜单
|
|||
|
menu.Children = buildMenuTree(childMenu.Id)
|
|||
|
children = append(children, menu)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return children
|
|||
|
}
|
|||
|
|
|||
|
// 从根菜单开始构建(ParentId为0的是根菜单)
|
|||
|
menuTree := buildMenuTree(0)
|
|||
|
|
|||
|
return &menuTree, nil
|
|||
|
}
|