251 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			251 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package admin_menu | |||
|  | 
 | |||
|  | import ( | |||
|  | 	"context" | |||
|  | 	"sort" | |||
|  | 	"strconv" | |||
|  | 
 | |||
|  | 	"aedata-server/app/main/api/internal/svc" | |||
|  | 	"aedata-server/app/main/api/internal/types" | |||
|  | 	"aedata-server/common/ctxdata" | |||
|  | 	"aedata-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 | |||
|  | } |