新增菜单和角色关联接口

This commit is contained in:
2025-06-04 08:56:08 +08:00
parent fedcd288e8
commit 00b889cfcc
25 changed files with 729 additions and 0 deletions

19
api/menu/menu.go Normal file
View File

@ -0,0 +1,19 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package menu
import (
"context"
"server/api/menu/v1"
)
type IMenuV1 interface {
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error)
Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error)
Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error)
BatchDelete(ctx context.Context, req *v1.BatchDeleteReq) (res *v1.BatchDeleteRes, err error)
}

78
api/menu/v1/menu.go Normal file
View File

@ -0,0 +1,78 @@
package v1
import "github.com/gogf/gf/v2/frame/g"
// ListReq 获取菜单列表请求
type ListReq struct {
g.Meta `path:"/menu" method:"get" tags:"Menu" summary:"(系统管理员)获取菜单列表"`
Page int `json:"page" dc:"页数"`
Size int `json:"size" dc:"每页数量"`
Status int `json:"status" dc:"状态1=启用2=禁用"`
}
// ListRes 获取菜单列表响应
type ListRes struct {
List interface{} `json:"list" dc:"菜单列表"`
Total int `json:"total" dc:"总数"`
}
// CreateReq 创建菜单请求
type CreateReq struct {
g.Meta `path:"/menu" method:"post" tags:"Menu" summary:"(系统管理员)创建菜单"`
Name string `json:"name" v:"required" dc:"菜单名称"`
ParentId int64 `json:"parent_id" dc:"父级菜单ID"`
Path string `json:"path" v:"required" dc:"前端路由路径"`
Component string `json:"component" dc:"前端组件路径"`
Type int `json:"type" v:"required" dc:"类型1=目录2=菜单"`
Icon string `json:"icon" dc:"图标"`
Sort int `json:"sort" dc:"排序"`
Hidden bool `json:"hidden" dc:"是否隐藏0=显示1=隐藏"`
Status int `json:"status" v:"required" dc:"状态1=启用2=禁用"`
}
// CreateRes 创建菜单响应
type CreateRes struct {
Id int64 `json:"id" dc:"菜单ID"`
}
// UpdateReq 更新菜单请求
type UpdateReq struct {
g.Meta `path:"/menu" method:"put" tags:"Menu" summary:"(系统管理员)更新菜单"`
Id int64 `json:"id" v:"required" dc:"菜单ID"`
Name string `json:"name" v:"required" dc:"菜单名称"`
ParentId int64 `json:"parent_id" dc:"父级菜单ID"`
Path string `json:"path" v:"required" dc:"前端路由路径"`
Component string `json:"component" dc:"前端组件路径"`
Type int `json:"type" v:"required" dc:"类型1=目录2=菜单"`
Icon string `json:"icon" dc:"图标"`
Sort int `json:"sort" dc:"排序"`
Hidden bool `json:"hidden" dc:"是否隐藏0=显示1=隐藏"`
Status int `json:"status" v:"required" dc:"状态1=启用2=禁用"`
}
// UpdateRes 更新菜单响应
type UpdateRes struct {
Success bool `json:"success" dc:"是否成功"`
}
// DeleteReq 删除菜单请求
type DeleteReq struct {
g.Meta `path:"/menu/{id}" method:"delete" tags:"Menu" summary:"(系统管理员)删除菜单"`
Id int64 `json:"id" v:"required" dc:"菜单ID"`
}
// DeleteRes 删除菜单响应
type DeleteRes struct {
Success bool `json:"success" dc:"是否成功"`
}
// BatchDeleteReq 批量删除菜单请求
type BatchDeleteReq struct {
g.Meta `path:"/menu" method:"delete" tags:"Menu" summary:"(系统管理员)批量删除菜单"`
Ids []int `json:"ids" v:"required" dc:"菜单ID列表"`
}
// BatchDeleteRes 批量删除菜单响应
type BatchDeleteRes struct {
Ids []int `json:"ids" dc:"返回未删除的 id 数组"`
}

16
api/roleMenu/roleMenu.go Normal file
View File

@ -0,0 +1,16 @@
// =================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package roleMenu
import (
"context"
"server/api/roleMenu/v1"
)
type IRoleMenuV1 interface {
List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error)
SaveRoleMenu(ctx context.Context, req *v1.SaveRoleMenuReq) (res *v1.SaveRoleMenuRes, err error)
}

View File

@ -0,0 +1,27 @@
package v1
import (
"github.com/gogf/gf/v2/frame/g"
)
// ListReq 角色菜单列表请求
type ListReq struct {
g.Meta `path:"/role-menu" method:"get" tags:"角色菜单" summary:"获取角色菜单列表"`
RoleId int64 `json:"roleId" v:"required#角色ID不能为空" dc:"角色ID"`
}
// ListRes 角色菜单列表响应
type ListRes struct {
List interface{} `json:"list" dc:"角色菜单列表"`
Total int `json:"total" dc:"总条数"`
}
type SaveRoleMenuReq struct {
g.Meta `path:"/role-menu" method:"post" tags:"角色菜单" summary:"保存角色菜单"`
RoleId int `json:"roleId" v:"required#角色ID不能为空" dc:"角色ID"`
MenuIds []int `json:"menuIds" v:"required#菜单ID列表不能为空" dc:"菜单ID列表"`
}
type SaveRoleMenuRes struct {
Success bool `json:"success" dc:"是否成功"`
}

View File

@ -7,6 +7,7 @@ import (
"github.com/gogf/gf/v2/os/gcmd"
"server/internal/controller/admin"
"server/internal/controller/auth"
"server/internal/controller/menu"
"server/internal/controller/role"
"server/internal/controller/wx"
"server/internal/middleware"
@ -32,6 +33,7 @@ var (
group.Bind(
admin.NewV1(),
role.NewV1(),
menu.NewV1(),
)
})
})

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package menu

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package menu
import (
"server/api/menu"
)
type ControllerV1 struct{}
func NewV1() menu.IMenuV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,17 @@
package menu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/menu/v1"
)
func (c *ControllerV1) BatchDelete(ctx context.Context, req *v1.BatchDeleteReq) (res *v1.BatchDeleteRes, err error) {
out, err := service.Menu().BatchDelete(ctx, &model.BatchDeleteIn{Ids: req.Ids})
if err != nil {
return nil, err
}
return &v1.BatchDeleteRes{Ids: out.Ids}, nil
}

View File

@ -0,0 +1,29 @@
package menu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/menu/v1"
)
func (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
out, err := service.Menu().Create(ctx, &model.MenuCreateInput{
Component: req.Component,
Hidden: req.Hidden,
Icon: req.Icon,
Name: req.Name,
ParentId: req.ParentId,
Path: req.Path,
Sort: req.Sort,
Status: req.Status,
Type: req.Type,
})
if err != nil {
return nil, err
}
return &v1.CreateRes{
Id: out.Id,
}, nil
}

View File

@ -0,0 +1,17 @@
package menu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/menu/v1"
)
func (c *ControllerV1) Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) {
out, err := service.Menu().Delete(ctx, &model.MenuDeleteInput{Id: req.Id})
if err != nil {
return nil, err
}
return &v1.DeleteRes{Success: out.Success}, nil
}

View File

@ -0,0 +1,20 @@
package menu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/menu/v1"
)
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
out, err := service.Menu().List(ctx, &model.MenuListInput{Page: req.Page, Size: req.Size, Status: req.Status})
if err != nil {
return nil, err
}
return &v1.ListRes{
List: out.List,
Total: out.Total,
}, nil
}

View File

@ -0,0 +1,30 @@
package menu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/menu/v1"
)
func (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {
out, err := service.Menu().Update(ctx, &model.MenuUpdateInput{
Id: req.Id,
Component: req.Component,
Hidden: req.Hidden,
Icon: req.Icon,
Name: req.Name,
ParentId: req.ParentId,
Path: req.Path,
Sort: req.Sort,
Status: req.Status,
Type: req.Type,
})
if err != nil {
return nil, err
}
return &v1.UpdateRes{
Success: out.Success,
}, nil
}

View File

@ -0,0 +1,5 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package roleMenu

View File

@ -0,0 +1,15 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package roleMenu
import (
"server/api/roleMenu"
)
type ControllerV1 struct{}
func NewV1() roleMenu.IRoleMenuV1 {
return &ControllerV1{}
}

View File

@ -0,0 +1,20 @@
package roleMenu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/roleMenu/v1"
)
func (c *ControllerV1) List(ctx context.Context, req *v1.ListReq) (res *v1.ListRes, err error) {
list, err := service.RoleMenu().List(ctx, &model.RoleMenuListInput{RoleId: req.RoleId})
if err != nil {
return nil, err
}
return &v1.ListRes{
List: list.List,
Total: list.Total,
}, nil
}

View File

@ -0,0 +1,20 @@
package roleMenu
import (
"context"
"server/internal/model"
"server/internal/service"
"server/api/roleMenu/v1"
)
func (c *ControllerV1) SaveRoleMenu(ctx context.Context, req *v1.SaveRoleMenuReq) (res *v1.SaveRoleMenuRes, err error) {
out, err := service.RoleMenu().Save(ctx, &model.RoleMenuSaveInput{RoleId: req.RoleId, MenuIds: req.MenuIds})
if err != nil {
return nil, err
}
return &v1.SaveRoleMenuRes{
Success: out.Success,
}, nil
}

View File

@ -6,8 +6,10 @@ package logic
import (
_ "server/internal/logic/admin"
_ "server/internal/logic/menu"
_ "server/internal/logic/merchantAdmin"
_ "server/internal/logic/role"
_ "server/internal/logic/roleMenu"
_ "server/internal/logic/storeAdmin"
_ "server/internal/logic/user"
)

189
internal/logic/menu/menu.go Normal file
View File

@ -0,0 +1,189 @@
package menu
import (
"context"
"server/internal/dao"
"server/internal/model"
"server/internal/model/do"
"server/internal/model/entity"
"server/internal/service"
"server/utility/ecode"
)
type sMenu struct {
}
func New() service.IMenu {
return &sMenu{}
}
func init() {
service.RegisterMenu(New())
}
// Create 创建菜单
func (s *sMenu) Create(ctx context.Context, in *model.MenuCreateInput) (out *model.CreateOut, err error) {
// 检查菜单名称是否已存在
exist, err := dao.Menus.Ctx(ctx).Where(do.Menus{Name: in.Name}).Exist()
if err != nil {
return nil, ecode.Fail.Sub("插入菜单查重出现异常")
}
if exist {
return nil, ecode.Params.Sub("菜单名称已存在")
}
id, err := dao.Menus.Ctx(ctx).InsertAndGetId(do.Menus{
ParentId: in.ParentId,
Name: in.Name,
Path: in.Path,
Component: in.Component,
Type: in.Type,
Icon: in.Icon,
Sort: in.Sort,
Hidden: in.Hidden,
Status: in.Status,
})
if err != nil {
return nil, err
}
return &model.CreateOut{Id: id}, nil
}
// Delete 删除菜单
func (s *sMenu) Delete(ctx context.Context, in *model.MenuDeleteInput) (out *model.DeleteOut, err error) {
// 检查是否存在子菜单
count, err := dao.Menus.Ctx(ctx).Where(do.Menus{ParentId: in.Id}).Count()
if err != nil {
return nil, err
}
if count > 0 {
return nil, ecode.Params.Sub("存在子菜单,请先删除子菜单")
}
// 删除菜单
_, err = dao.Menus.Ctx(ctx).Where(do.Menus{Id: in.Id}).Delete()
if err != nil {
return nil, err
}
return &model.DeleteOut{}, nil
}
// BatchDelete 批量删除菜单
func (s *sMenu) BatchDelete(ctx context.Context, in *model.BatchDeleteIn) (out *model.BatchDeleteOut, err error) {
// 检查是否存在子菜单
var menus []*entity.Menus
err = dao.Menus.Ctx(ctx).WhereIn(dao.Menus.Columns().ParentId, in.Ids).Scan(&menus)
if err != nil {
return nil, err
}
// 获取有子菜单的ID
hasChildrenIds := make(map[int]bool)
for _, menu := range menus {
hasChildrenIds[int(menu.ParentId)] = true
}
// 找出可以删除的ID
var deletableIds []int
var undeletableIds []int
for _, id := range in.Ids {
if hasChildrenIds[id] {
undeletableIds = append(undeletableIds, id)
} else {
deletableIds = append(deletableIds, id)
}
}
// 如果有可删除的ID执行删除操作
if len(deletableIds) > 0 {
_, err = dao.Menus.Ctx(ctx).WhereIn(dao.Menus.Columns().Id, deletableIds).Delete()
if err != nil {
return nil, err
}
}
return &model.BatchDeleteOut{
Ids: undeletableIds,
}, nil
}
// Update 更新菜单
func (s *sMenu) Update(ctx context.Context, in *model.MenuUpdateInput) (out *model.UpdateOut, err error) {
// 检查菜单是否存在
exist, err := dao.Menus.Ctx(ctx).WherePri(in.Id).Exist()
if err != nil {
return nil, ecode.Fail.Sub("查询菜单失败")
}
if !exist {
return nil, ecode.Params.Sub("菜单不存在")
}
exist, err = dao.Menus.Ctx(ctx).Where(do.Menus{Name: in.Name}).WhereNot(dao.Menus.Columns().Id, in.Id).Exist()
if err != nil {
return nil, ecode.Fail.Sub("查询菜单失败")
}
if exist {
return nil, ecode.Params.Sub("菜单名称已存在")
}
// 更新菜单
_, err = dao.Menus.Ctx(ctx).Where(do.Menus{
Id: in.Id,
}).Update(do.Menus{
ParentId: in.ParentId,
Name: in.Name,
Path: in.Path,
Component: in.Component,
Type: in.Type,
Icon: in.Icon,
Sort: in.Sort,
Hidden: in.Hidden,
Status: in.Status,
})
if err != nil {
return nil, err
}
return &model.UpdateOut{}, nil
}
// List 获取菜单列表
func (s *sMenu) List(ctx context.Context, in *model.MenuListInput) (out *model.MenuListOutput, err error) {
m := dao.Menus.Ctx(ctx)
// 构建查询条件
if in.ParentId > 0 {
m = m.Where(do.Menus{
ParentId: in.ParentId,
})
}
if in.Name != "" {
m = m.WhereLike(dao.Menus.Columns().Name, "%"+in.Name+"%")
}
if in.Path != "" {
m = m.WhereLike(dao.Menus.Columns().Path, "%"+in.Path+"%")
}
if in.Type > 0 {
m = m.Where(do.Menus{
Type: in.Type,
})
}
if in.Status > 0 {
m = m.Where(do.Menus{
Status: in.Status,
})
}
// 分页查询
list := make([]model.Menu, 0)
var total int
err = m.Page(in.Page, in.Size).OrderAsc(dao.Menus.Columns().Sort).ScanAndCount(&list, &total, false)
if err != nil {
return nil, err
}
return &model.MenuListOutput{
List: list,
Total: total,
}, nil
}

View File

@ -0,0 +1,28 @@
package roleMenu
import (
"context"
"server/internal/model"
"server/internal/service"
)
type sRoleMenu struct {
}
func New() service.IRoleMenu {
return &sRoleMenu{}
}
func init() {
service.RegisterRoleMenu(New())
}
func init() {
}
func (s *sRoleMenu) List(ctx context.Context, in *model.RoleMenuListInput) (out *model.MenuListOutput, err error) {
return
}
func (s *sRoleMenu) Save(ctx context.Context, in *model.RoleMenuSaveInput) (out *model.UpdateOut, err error) {
return
}

View File

@ -3,6 +3,9 @@ package model
type BatchDeleteIn struct {
Ids []int
}
type BatchDeleteOut struct {
Ids []int
}
type LoginOut struct {
Token string
}

74
internal/model/menu.go Normal file
View File

@ -0,0 +1,74 @@
package model
import (
"github.com/gogf/gf/v2/frame/g"
)
// Menu 菜单信息
type Menu struct {
g.Meta `orm:"table:menus"`
Id int64 `json:"id" dc:"菜单ID" orm:"id"`
ParentId int64 `json:"parentId" dc:"父级菜单ID" orm:"parent_id"`
Name string `json:"name" dc:"菜单名称" orm:"name"`
Path string `json:"path" dc:"前端路由路径" orm:"path"`
Component string `json:"component" dc:"前端组件路径" orm:"component"`
Type int `json:"type" dc:"类型1=目录2=菜单" orm:"type"`
Icon string `json:"icon" dc:"图标" orm:"icon"`
Sort int `json:"sort" dc:"排序" orm:"sort"`
Hidden bool `json:"hidden" dc:"是否隐藏0=显示1=隐藏" orm:"hidden"`
Status int `json:"status" dc:"状态1=启用2=禁用" orm:"status"`
}
// MenuCreateInput 创建菜单输入参数
type MenuCreateInput struct {
ParentId int64
Name string
Path string
Component string
Type int
Icon string
Sort int
Hidden bool
Status int
}
// MenuUpdateInput 更新菜单输入参数
type MenuUpdateInput struct {
Id int64
ParentId int64
Name string
Path string
Component string
Type int
Icon string
Sort int
Hidden bool
Status int
}
// MenuListInput 获取菜单列表输入参数
type MenuListInput struct {
Page int
Size int
ParentId int64
Name string
Path string
Type int
Status int
}
// MenuListOutput 获取菜单列表输出参数
type MenuListOutput struct {
List []Menu
Total int
}
// MenuGetByIdInput 根据ID获取菜单输入参数
type MenuGetByIdInput struct {
Id int64
}
// MenuDeleteInput 删除菜单输入参数
type MenuDeleteInput struct {
Id int64
}

View File

@ -0,0 +1,24 @@
package model
import "github.com/gogf/gf/v2/frame/g"
type RoleMenu struct {
g.Meta `orm:"table:role_menus"`
Id int64 `json:"id" orm:"id" dc:"角色菜单ID"`
RoleId int64 `json:"roleId" orm:"role_id" dc:"角色ID"`
MenuId int64 `json:"menuId" orm:"menu_id" dc:"菜单ID"`
}
type RoleMenuListInput struct {
Page int
Size int
RoleId int64
}
type RoleMenuListOutput struct {
List []RoleMenu
Total int
}
type RoleMenuSaveInput struct {
RoleId int
MenuIds []int
}

41
internal/service/menu.go Normal file
View File

@ -0,0 +1,41 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
"context"
"server/internal/model"
)
type (
IMenu interface {
// Create 创建菜单
Create(ctx context.Context, in *model.MenuCreateInput) (out *model.CreateOut, err error)
// Delete 删除菜单
Delete(ctx context.Context, in *model.MenuDeleteInput) (out *model.DeleteOut, err error)
// BatchDelete 批量删除菜单
BatchDelete(ctx context.Context, in *model.BatchDeleteIn) (out *model.BatchDeleteOut, err error)
// Update 更新菜单
Update(ctx context.Context, in *model.MenuUpdateInput) (out *model.UpdateOut, err error)
// List 获取菜单列表
List(ctx context.Context, in *model.MenuListInput) (out *model.MenuListOutput, err error)
}
)
var (
localMenu IMenu
)
func Menu() IMenu {
if localMenu == nil {
panic("implement not found for interface IMenu, forgot register?")
}
return localMenu
}
func RegisterMenu(i IMenu) {
localMenu = i
}

View File

@ -0,0 +1,33 @@
// ================================================================================
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
"context"
"server/internal/model"
)
type (
IRoleMenu interface {
List(ctx context.Context, in *model.RoleMenuListInput) (out *model.MenuListOutput, err error)
Save(ctx context.Context, in *model.RoleMenuSaveInput) (out *model.UpdateOut, err error)
}
)
var (
localRoleMenu IRoleMenu
)
func RoleMenu() IRoleMenu {
if localRoleMenu == nil {
panic("implement not found for interface IRoleMenu, forgot register?")
}
return localRoleMenu
}
func RegisterRoleMenu(i IRoleMenu) {
localRoleMenu = i
}