package admin_system_menu_manage import ( "context" "sort" "github.com/gogf/gf/v2/errors/gerror" "service.xpcool.com/internal/consts" "service.xpcool.com/internal/dao" "service.xpcool.com/internal/library/response" "service.xpcool.com/internal/model/do" "service.xpcool.com/internal/model/dto" "service.xpcool.com/internal/model/entity" ) // IMenuManage 管理菜单树(菜单 + 按钮权限)。 type IMenuManage interface { Tree(context.Context) ([]*dto.MenuNode, error) Create(context.Context, dto.MenuCreateInput) (uint64, error) Update(context.Context, dto.MenuUpdateInput) error Delete(context.Context, uint64) error } type menuManage struct{} var localMenuManage IMenuManage func NewMenuManage() IMenuManage { return &menuManage{} } func MenuManage() IMenuManage { if localMenuManage == nil { panic("MenuManage implementation not registered") } return localMenuManage } func RegisterMenuManage(i IMenuManage) { localMenuManage = i } // ---------------------- Menu manage ---------------------- func (s *menuManage) Tree(ctx context.Context) ([]*dto.MenuNode, error) { var list []entity.AdminMenu if err := dao.AdminMenu.Ctx(ctx).OrderAsc("sort").Scan(&list); err != nil { return nil, gerror.Wrap(err, "query menus") } byID := make(map[uint64]*dto.MenuNode, len(list)) for i := range list { m := &list[i] byID[m.Id] = &dto.MenuNode{ Id: m.Id, ParentId: m.ParentId, Name: m.Name, Icon: m.Icon, Type: m.Type, Path: m.Path, Component: m.Component, Permission: m.Permission, Sort: m.Sort, Status: m.Status, Hidden: m.Hidden, } } var roots []*dto.MenuNode for i := range list { m := &list[i] node := byID[m.Id] if m.ParentId == 0 { roots = append(roots, node) } else if p, ok := byID[m.ParentId]; ok { p.Children = append(p.Children, node) } } sort.Slice(roots, func(i, j int) bool { return roots[i].Sort < roots[j].Sort }) for _, r := range roots { sortMenuChildren(r) } return roots, nil } func sortMenuChildren(n *dto.MenuNode) { sort.Slice(n.Children, func(i, j int) bool { return n.Children[i].Sort < n.Children[j].Sort }) for _, c := range n.Children { sortMenuChildren(c) } } func (s *menuManage) Create(ctx context.Context, in dto.MenuCreateInput) (uint64, error) { count, err := dao.AdminMenu.Ctx(ctx).Where(do.AdminMenu{Permission: in.Permission}).Count() if err != nil { return 0, gerror.Wrap(err, "check menu permission") } if count > 0 { return 0, response.Error(consts.CodeInvalidParam, "permission already exists") } id, err := dao.AdminMenu.Ctx(ctx).Data(do.AdminMenu{ ParentId: in.ParentId, Name: in.Name, Icon: in.Icon, Type: in.Type, Path: in.Path, Component: in.Component, Permission: in.Permission, Sort: in.Sort, Status: in.Status, Hidden: in.Hidden, }).InsertAndGetId() if err != nil { return 0, gerror.Wrap(err, "insert menu") } return uint64(id), nil } func (s *menuManage) Update(ctx context.Context, in dto.MenuUpdateInput) error { count, err := dao.AdminMenu.Ctx(ctx).Where("permission = ? AND id != ?", in.Permission, in.Id).Count() if err != nil { return gerror.Wrap(err, "check menu permission") } if count > 0 { return response.Error(consts.CodeInvalidParam, "permission already exists") } _, err = dao.AdminMenu.Ctx(ctx).Where(do.AdminMenu{Id: in.Id}).Data(do.AdminMenu{ ParentId: in.ParentId, Name: in.Name, Icon: in.Icon, Type: in.Type, Path: in.Path, Component: in.Component, Permission: in.Permission, Sort: in.Sort, Status: in.Status, Hidden: in.Hidden, }).Update() if err != nil { return gerror.Wrap(err, "update menu") } return nil } func (s *menuManage) Delete(ctx context.Context, id uint64) error { // 删除前检查是否存在子节点。 cnt, err := dao.AdminMenu.Ctx(ctx).Where(do.AdminMenu{ParentId: id}).Count() if err != nil { return gerror.Wrap(err, "check menu children") } if cnt > 0 { return response.Error(consts.CodeInvalidParam, "delete children first") } if _, err = dao.AdminMenu.Ctx(ctx).Where(do.AdminMenu{Id: id}).Delete(); err != nil { return gerror.Wrap(err, "delete menu") } if _, err = dao.AdminRoleMenu.Ctx(ctx).Unscoped().Where(do.AdminRoleMenu{MenuId: id}).Delete(); err != nil { return gerror.Wrap(err, "delete role menu bindings") } return nil }