package biz import ( "context" "time" ) type MenuButton struct { CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time ID uint Name string Description string MenuID uint AuthorityID uint } type MenuParameter struct { CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time ID uint MenuID uint Type string Key string Value string } type Menu struct { CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time ID uint MenuID 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 Children []*Menu Buttons []*MenuButton Parameters []*MenuParameter } type MenuRepo interface { Create(context.Context, *Menu) error Update(context.Context, *Menu) error Delete(context.Context, uint) error Find(context.Context, uint) (*Menu, error) List(context.Context) ([]*Menu, error) SetAuthorityMenus(context.Context, uint, []uint) error AuthorityMenuIDs(context.Context, uint) ([]uint, error) MenuRoleIDs(context.Context, uint) ([]uint, error) DefaultRouterRoleIDs(context.Context, uint) ([]uint, error) SetMenuRoles(context.Context, uint, []uint) error } type MenuUsecase struct{ repo MenuRepo } func NewMenuUsecase(repo MenuRepo) *MenuUsecase { return &MenuUsecase{repo: repo} } func (uc *MenuUsecase) List(ctx context.Context) ([]*Menu, error) { return uc.repo.List(ctx) } func (uc *MenuUsecase) Tree(ctx context.Context) ([]*Menu, error) { items, err := uc.repo.List(ctx) if err != nil { return nil, err } byID := make(map[uint]*Menu, len(items)) for _, item := range items { item.Children = []*Menu{} byID[item.ID] = item } roots := make([]*Menu, 0) for _, item := range items { if parent := byID[item.ParentID]; parent != nil { parent.Children = append(parent.Children, item) } else if item.ParentID == 0 { roots = append(roots, item) } } return roots, nil } func (uc *MenuUsecase) Create(ctx context.Context, menu *Menu) error { return uc.repo.Create(ctx, menu) } func (uc *MenuUsecase) Update(ctx context.Context, menu *Menu) error { return uc.repo.Update(ctx, menu) } func (uc *MenuUsecase) Delete(ctx context.Context, id uint) error { return uc.repo.Delete(ctx, id) } func (uc *MenuUsecase) Find(ctx context.Context, id uint) (*Menu, error) { return uc.repo.Find(ctx, id) } func (uc *MenuUsecase) SetAuthorityMenus(ctx context.Context, authorityID uint, ids []uint) error { return uc.repo.SetAuthorityMenus(ctx, authorityID, ids) } func (uc *MenuUsecase) AuthorityMenus(ctx context.Context, authorityID uint) ([]*Menu, error) { ids, err := uc.repo.AuthorityMenuIDs(ctx, authorityID) if err != nil { return nil, err } items, err := uc.repo.List(ctx) if err != nil { return nil, err } selected := make(map[uint]struct{}, len(ids)) for _, id := range ids { selected[id] = struct{}{} } result := make([]*Menu, 0, len(ids)) for _, item := range items { if _, ok := selected[item.ID]; ok { // The authority-menu endpoint returns menu relations only. Keep its // existing contract: button details are loaded by the dedicated // authority-button endpoints. The compatible query does not preload either // relation here, so parameters must remain absent as well. item.Buttons = nil item.Parameters = nil result = append(result, item) } } return result, nil } func (uc *MenuUsecase) RoleIDs(ctx context.Context, menuID uint) ([]uint, error) { return uc.repo.MenuRoleIDs(ctx, menuID) } func (uc *MenuUsecase) DefaultRouterRoleIDs(ctx context.Context, menuID uint) ([]uint, error) { return uc.repo.DefaultRouterRoleIDs(ctx, menuID) } func (uc *MenuUsecase) SetRoles(ctx context.Context, menuID uint, ids []uint) error { return uc.repo.SetMenuRoles(ctx, menuID, ids) }