package menu import ( "context" "sort" "strings" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/text/gstr" "service.xpcool.com/internal/dao" "service.xpcool.com/internal/model/dto" "service.xpcool.com/internal/model/entity" ) type IAdminMenu interface { // Routes returns the visible menu tree of an admin as vben route items. Routes(context.Context, uint64) ([]*dto.RouteItem, error) } type adminMenu struct{} func NewAdminMenu() IAdminMenu { return &adminMenu{} } var localAdminMenu IAdminMenu func AdminMenu() IAdminMenu { if localAdminMenu == nil { panic("AdminMenu implementation not registered") } return localAdminMenu } func RegisterAdminMenu(i IAdminMenu) { localAdminMenu = i } // routeName converts a permission code like "system:admin" to a unique // vben route name, e.g. "SystemAdmin". func routeName(permission string) string { if permission == "" { return "" } return gstr.CaseCamel(strings.ReplaceAll(permission, ":", "_")) } func (s *adminMenu) Routes(ctx context.Context, adminID uint64) ([]*dto.RouteItem, error) { // 当前管理员所有启用角色可见的菜单(type=1),含按钮行但不作为路由节点。 var list []entity.AdminMenu if err := dao.AdminUserRole.Ctx(ctx).As("ur"). LeftJoin("admin_role_menu rm", "ur.role_id=rm.role_id"). LeftJoin("admin_menu m", "rm.menu_id=m.id"). Where("ur.admin_user_id", adminID). Where("m.type", 1). Where("m.status", 1). Where("m.deleted_at IS NULL"). Fields("m.*"). Scan(&list); err != nil { return nil, gerror.Wrap(err, "query admin menu routes") } byID := make(map[uint64]*dto.RouteItem, len(list)) for i := range list { m := &list[i] byID[m.Id] = &dto.RouteItem{ Name: routeName(m.Permission), Path: m.Path, Component: m.Component, Meta: dto.RouteMeta{Title: m.Name, Icon: m.Icon, Order: m.Sort, HideInMenu: m.Hidden}, } } var roots []*dto.RouteItem for i := range list { m := &list[i] item := byID[m.Id] if m.ParentId == 0 { roots = append(roots, item) } else if p, ok := byID[m.ParentId]; ok { p.Children = append(p.Children, item) } } sort.Slice(roots, func(i, j int) bool { return roots[i].Meta.Order < roots[j].Meta.Order }) for _, r := range roots { sortRouteChildren(r) } return roots, nil } func sortRouteChildren(r *dto.RouteItem) { sort.Slice(r.Children, func(i, j int) bool { return r.Children[i].Meta.Order < r.Children[j].Meta.Order }) for _, c := range r.Children { sortRouteChildren(c) } }