19 changed files with 799 additions and 1198 deletions
@ -0,0 +1,354 @@ |
|||||||
|
package controller |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"strconv" |
||||||
|
"gofaster/internal/auth/model" |
||||||
|
"gofaster/internal/auth/service" |
||||||
|
"gofaster/internal/shared/response" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"go.uber.org/zap" |
||||||
|
) |
||||||
|
|
||||||
|
// MenuGroupController 菜单分组控制器
|
||||||
|
type MenuGroupController struct { |
||||||
|
menuGroupService *service.MenuGroupService |
||||||
|
logger *zap.Logger |
||||||
|
} |
||||||
|
|
||||||
|
// NewMenuGroupController 创建菜单分组控制器实例
|
||||||
|
func NewMenuGroupController(menuGroupService *service.MenuGroupService, logger *zap.Logger) *MenuGroupController { |
||||||
|
return &MenuGroupController{ |
||||||
|
menuGroupService: menuGroupService, |
||||||
|
logger: logger, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// CreateMenuGroup 创建菜单分组
|
||||||
|
// @Summary 创建菜单分组
|
||||||
|
// @Description 创建新的菜单分组
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param menuGroup body model.MenuGroup true "菜单分组信息"
|
||||||
|
// @Success 200 {object} response.Response{data=model.MenuGroup}
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups [post]
|
||||||
|
func (c *MenuGroupController) CreateMenuGroup(ctx *gin.Context) { |
||||||
|
var menuGroup model.MenuGroup |
||||||
|
if err := ctx.ShouldBindJSON(&menuGroup); err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
if menuGroup.Name == "" { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "分组名称不能为空") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err := c.menuGroupService.CreateMenuGroup(&menuGroup); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "创建菜单分组失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "创建菜单分组成功", menuGroup) |
||||||
|
} |
||||||
|
|
||||||
|
// GetMenuGroup 获取菜单分组详情
|
||||||
|
// @Summary 获取菜单分组详情
|
||||||
|
// @Description 根据ID获取菜单分组详情
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "菜单分组ID"
|
||||||
|
// @Success 200 {object} response.Response{data=model.MenuGroup}
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 404 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/{id} [get]
|
||||||
|
func (c *MenuGroupController) GetMenuGroup(ctx *gin.Context) { |
||||||
|
idStr := ctx.Param("id") |
||||||
|
id, err := strconv.ParseUint(idStr, 10, 32) |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "ID格式错误") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
menuGroup, err := c.menuGroupService.GetMenuGroupByID(uint(id)) |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusNotFound, "菜单分组不存在", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "获取菜单分组成功", menuGroup) |
||||||
|
} |
||||||
|
|
||||||
|
// ListMenuGroups 获取菜单分组列表
|
||||||
|
// @Summary 获取菜单分组列表
|
||||||
|
// @Description 获取所有菜单分组列表
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param status query int false "状态筛选" Enums(0,1)
|
||||||
|
// @Success 200 {object} response.Response{data=[]model.MenuGroup}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups [get]
|
||||||
|
func (c *MenuGroupController) ListMenuGroups(ctx *gin.Context) { |
||||||
|
statusStr := ctx.Query("status") |
||||||
|
|
||||||
|
var menuGroups []*model.MenuGroup |
||||||
|
var err error |
||||||
|
|
||||||
|
if statusStr != "" { |
||||||
|
status, parseErr := strconv.Atoi(statusStr) |
||||||
|
if parseErr != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "状态参数格式错误") |
||||||
|
return |
||||||
|
} |
||||||
|
menuGroups, err = c.menuGroupService.ListMenuGroupsByStatus(status) |
||||||
|
} else { |
||||||
|
menuGroups, err = c.menuGroupService.ListMenuGroups() |
||||||
|
} |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "获取菜单分组列表失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "获取菜单分组列表成功", menuGroups) |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateMenuGroup 更新菜单分组
|
||||||
|
// @Summary 更新菜单分组
|
||||||
|
// @Description 更新菜单分组信息
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "菜单分组ID"
|
||||||
|
// @Param menuGroup body model.MenuGroup true "菜单分组信息"
|
||||||
|
// @Success 200 {object} response.Response{data=model.MenuGroup}
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 404 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/{id} [put]
|
||||||
|
func (c *MenuGroupController) UpdateMenuGroup(ctx *gin.Context) { |
||||||
|
idStr := ctx.Param("id") |
||||||
|
id, err := strconv.ParseUint(idStr, 10, 32) |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "ID格式错误") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var menuGroup model.MenuGroup |
||||||
|
if err := ctx.ShouldBindJSON(&menuGroup); err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// 验证必填字段
|
||||||
|
if menuGroup.Name == "" { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "分组名称不能为空") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
menuGroup.ID = uint(id) |
||||||
|
|
||||||
|
if err := c.menuGroupService.UpdateMenuGroup(&menuGroup); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "更新菜单分组失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "更新菜单分组成功", menuGroup) |
||||||
|
} |
||||||
|
|
||||||
|
// DeleteMenuGroup 删除菜单分组
|
||||||
|
// @Summary 删除菜单分组
|
||||||
|
// @Description 根据ID删除菜单分组
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "菜单分组ID"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 404 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/{id} [delete]
|
||||||
|
func (c *MenuGroupController) DeleteMenuGroup(ctx *gin.Context) { |
||||||
|
idStr := ctx.Param("id") |
||||||
|
id, err := strconv.ParseUint(idStr, 10, 32) |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "ID格式错误") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err := c.menuGroupService.DeleteMenuGroup(uint(id)); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "删除菜单分组失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "删除菜单分组成功", nil) |
||||||
|
} |
||||||
|
|
||||||
|
// BatchDeleteMenuGroups 批量删除菜单分组
|
||||||
|
// @Summary 批量删除菜单分组
|
||||||
|
// @Description 批量删除菜单分组
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param ids body []uint true "菜单分组ID列表"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/batch-delete [post]
|
||||||
|
func (c *MenuGroupController) BatchDeleteMenuGroups(ctx *gin.Context) { |
||||||
|
var request struct { |
||||||
|
IDs []uint `json:"ids" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
if err := ctx.ShouldBindJSON(&request); err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if len(request.IDs) == 0 { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "ID列表不能为空") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err := c.menuGroupService.BatchDeleteMenuGroups(request.IDs); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "批量删除菜单分组失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "批量删除菜单分组成功", nil) |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateMenuGroupStatus 更新菜单分组状态
|
||||||
|
// @Summary 更新菜单分组状态
|
||||||
|
// @Description 更新菜单分组状态
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "菜单分组ID"
|
||||||
|
// @Param request body map[string]int true "状态信息" SchemaExample({"status": 1})
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 404 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/{id}/status [put]
|
||||||
|
func (c *MenuGroupController) UpdateMenuGroupStatus(ctx *gin.Context) { |
||||||
|
idStr := ctx.Param("id") |
||||||
|
id, err := strconv.ParseUint(idStr, 10, 32) |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "ID格式错误") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var request struct { |
||||||
|
Status int `json:"status" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
if err := ctx.ShouldBindJSON(&request); err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err := c.menuGroupService.UpdateMenuGroupStatus(uint(id), request.Status); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "更新菜单分组状态失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "更新菜单分组状态成功", nil) |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateMenuGroupSort 更新菜单分组排序
|
||||||
|
// @Summary 更新菜单分组排序
|
||||||
|
// @Description 更新菜单分组排序
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "菜单分组ID"
|
||||||
|
// @Param request body map[string]int true "排序信息" SchemaExample({"sort": 1})
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 404 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/{id}/sort [put]
|
||||||
|
func (c *MenuGroupController) UpdateMenuGroupSort(ctx *gin.Context) { |
||||||
|
idStr := ctx.Param("id") |
||||||
|
id, err := strconv.ParseUint(idStr, 10, 32) |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "ID格式错误") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var request struct { |
||||||
|
Sort int `json:"sort" binding:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
if err := ctx.ShouldBindJSON(&request); err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err := c.menuGroupService.UpdateMenuGroupSort(uint(id), request.Sort); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "更新菜单分组排序失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "更新菜单分组排序成功", nil) |
||||||
|
} |
||||||
|
|
||||||
|
// BatchUpdateMenuGroupSort 批量更新菜单分组排序
|
||||||
|
// @Summary 批量更新菜单分组排序
|
||||||
|
// @Description 批量更新菜单分组排序
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body map[uint]int true "排序信息" SchemaExample({"1": 1, "2": 2})
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Failure 400 {object} response.Response
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/batch-sort [put]
|
||||||
|
func (c *MenuGroupController) BatchUpdateMenuGroupSort(ctx *gin.Context) { |
||||||
|
var request map[uint]int |
||||||
|
|
||||||
|
if err := ctx.ShouldBindJSON(&request); err != nil { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if len(request) == 0 { |
||||||
|
response.Error(ctx, http.StatusBadRequest, "请求参数错误", "排序数据不能为空") |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if err := c.menuGroupService.BatchUpdateMenuGroupSort(request); err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "批量更新菜单分组排序失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "批量更新菜单分组排序成功", nil) |
||||||
|
} |
||||||
|
|
||||||
|
// GetMenuGroupStats 获取菜单分组统计信息
|
||||||
|
// @Summary 获取菜单分组统计信息
|
||||||
|
// @Description 获取菜单分组统计信息
|
||||||
|
// @Tags 菜单分组管理
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
||||||
|
// @Failure 500 {object} response.Response
|
||||||
|
// @Router /api/menu-groups/stats [get]
|
||||||
|
func (c *MenuGroupController) GetMenuGroupStats(ctx *gin.Context) { |
||||||
|
stats, err := c.menuGroupService.GetMenuGroupStats() |
||||||
|
if err != nil { |
||||||
|
response.Error(ctx, http.StatusInternalServerError, "获取菜单分组统计信息失败", err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
response.Success(ctx, "获取菜单分组统计信息成功", stats) |
||||||
|
} |
@ -1,366 +0,0 @@ |
|||||||
package controller |
|
||||||
|
|
||||||
import ( |
|
||||||
"net/http" |
|
||||||
"strconv" |
|
||||||
|
|
||||||
"gofaster/internal/auth/model" |
|
||||||
"gofaster/internal/auth/service" |
|
||||||
"gofaster/internal/shared/response" |
|
||||||
|
|
||||||
"github.com/gin-gonic/gin" |
|
||||||
"go.uber.org/zap" |
|
||||||
) |
|
||||||
|
|
||||||
// MenuRouteController 菜单路由关联表控制器
|
|
||||||
type MenuRouteController struct { |
|
||||||
menuRouteService *service.MenuRouteService |
|
||||||
log *zap.Logger |
|
||||||
} |
|
||||||
|
|
||||||
// NewMenuRouteController 创建菜单路由关联表控制器
|
|
||||||
func NewMenuRouteController(menuRouteService *service.MenuRouteService, log *zap.Logger) *MenuRouteController { |
|
||||||
return &MenuRouteController{ |
|
||||||
menuRouteService: menuRouteService, |
|
||||||
log: log, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// CreateMenuRoute 创建菜单路由关联
|
|
||||||
// @Summary 创建菜单路由关联
|
|
||||||
// @Description 创建菜单与路由的多对多关联关系
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param menuRoute body model.MenuRoute true "菜单路由关联信息"
|
|
||||||
// @Success 200 {object} response.Response{data=model.MenuRoute}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menu-routes [post]
|
|
||||||
func (c *MenuRouteController) CreateMenuRoute(ctx *gin.Context) { |
|
||||||
var menuRoute model.MenuRoute |
|
||||||
if err := ctx.ShouldBindJSON(&menuRoute); err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if err := c.menuRouteService.CreateMenuRoute(&menuRoute); err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "创建菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "创建菜单路由关联成功", menuRoute) |
|
||||||
} |
|
||||||
|
|
||||||
// CreateMenuRoutes 批量创建菜单路由关联
|
|
||||||
// @Summary 批量创建菜单路由关联
|
|
||||||
// @Description 为指定菜单批量创建路由关联
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param menuID path int true "菜单ID"
|
|
||||||
// @Param routeMappingIDs body []uint true "路由映射ID列表"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menus/{menuID}/routes [post]
|
|
||||||
func (c *MenuRouteController) CreateMenuRoutes(ctx *gin.Context) { |
|
||||||
menuIDStr := ctx.Param("menuID") |
|
||||||
menuID, err := strconv.ParseUint(menuIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "菜单ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
var routeMappingIDs []uint |
|
||||||
if err := ctx.ShouldBindJSON(&routeMappingIDs); err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if err := c.menuRouteService.CreateMenuRoutes(uint(menuID), routeMappingIDs); err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "批量创建菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "批量创建菜单路由关联成功", nil) |
|
||||||
} |
|
||||||
|
|
||||||
// GetMenuRoutes 获取菜单的路由关联
|
|
||||||
// @Summary 获取菜单的路由关联
|
|
||||||
// @Description 获取指定菜单的所有路由关联
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param menuID path int true "菜单ID"
|
|
||||||
// @Success 200 {object} response.Response{data=[]model.MenuRoute}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menus/{menuID}/routes [get]
|
|
||||||
func (c *MenuRouteController) GetMenuRoutes(ctx *gin.Context) { |
|
||||||
menuIDStr := ctx.Param("menuID") |
|
||||||
menuID, err := strconv.ParseUint(menuIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "菜单ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
menuRoutes, err := c.menuRouteService.GetMenuRoutes(uint(menuID)) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "获取菜单路由关联成功", menuRoutes) |
|
||||||
} |
|
||||||
|
|
||||||
// GetRouteMenus 获取路由的菜单关联
|
|
||||||
// @Summary 获取路由的菜单关联
|
|
||||||
// @Description 获取指定路由的所有菜单关联
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param routeMappingID path int true "路由映射ID"
|
|
||||||
// @Success 200 {object} response.Response{data=[]model.MenuRoute}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/route-mappings/{routeMappingID}/menus [get]
|
|
||||||
func (c *MenuRouteController) GetRouteMenus(ctx *gin.Context) { |
|
||||||
routeMappingIDStr := ctx.Param("routeMappingID") |
|
||||||
routeMappingID, err := strconv.ParseUint(routeMappingIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "路由映射ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
menuRoutes, err := c.menuRouteService.GetRouteMenus(uint(routeMappingID)) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "获取路由菜单关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "获取路由菜单关联成功", menuRoutes) |
|
||||||
} |
|
||||||
|
|
||||||
// GetMenuWithRoutes 获取菜单及其关联的路由信息
|
|
||||||
// @Summary 获取菜单及其关联的路由信息
|
|
||||||
// @Description 获取菜单详细信息及其关联的所有路由
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param menuID path int true "菜单ID"
|
|
||||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menus/{menuID}/routes/detail [get]
|
|
||||||
func (c *MenuRouteController) GetMenuWithRoutes(ctx *gin.Context) { |
|
||||||
menuIDStr := ctx.Param("menuID") |
|
||||||
menuID, err := strconv.ParseUint(menuIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "菜单ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
menu, routes, err := c.menuRouteService.GetMenuWithRoutes(uint(menuID)) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单及路由信息失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
result := map[string]interface{}{ |
|
||||||
"menu": menu, |
|
||||||
"routes": routes, |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "获取菜单及路由信息成功", result) |
|
||||||
} |
|
||||||
|
|
||||||
// GetRouteWithMenus 获取路由及其关联的菜单信息
|
|
||||||
// @Summary 获取路由及其关联的菜单信息
|
|
||||||
// @Description 获取路由详细信息及其关联的所有菜单
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param routeMappingID path int true "路由映射ID"
|
|
||||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/route-mappings/{routeMappingID}/menus/detail [get]
|
|
||||||
func (c *MenuRouteController) GetRouteWithMenus(ctx *gin.Context) { |
|
||||||
routeMappingIDStr := ctx.Param("routeMappingID") |
|
||||||
routeMappingID, err := strconv.ParseUint(routeMappingIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "路由映射ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
route, menus, err := c.menuRouteService.GetRouteWithMenus(uint(routeMappingID)) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "获取路由及菜单信息失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
result := map[string]interface{}{ |
|
||||||
"route": route, |
|
||||||
"menus": menus, |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "获取路由及菜单信息成功", result) |
|
||||||
} |
|
||||||
|
|
||||||
// UpdateMenuRoute 更新菜单路由关联
|
|
||||||
// @Summary 更新菜单路由关联
|
|
||||||
// @Description 更新菜单路由关联信息
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param id path int true "关联ID"
|
|
||||||
// @Param menuRoute body model.MenuRoute true "菜单路由关联信息"
|
|
||||||
// @Success 200 {object} response.Response{data=model.MenuRoute}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menu-routes/{id} [put]
|
|
||||||
func (c *MenuRouteController) UpdateMenuRoute(ctx *gin.Context) { |
|
||||||
idStr := ctx.Param("id") |
|
||||||
id, err := strconv.ParseUint(idStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
var menuRoute model.MenuRoute |
|
||||||
if err := ctx.ShouldBindJSON(&menuRoute); err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
menuRoute.ID = uint(id) |
|
||||||
if err := c.menuRouteService.UpdateMenuRoute(&menuRoute); err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "更新菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "更新菜单路由关联成功", menuRoute) |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteMenuRoute 删除菜单路由关联
|
|
||||||
// @Summary 删除菜单路由关联
|
|
||||||
// @Description 删除指定的菜单路由关联
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param id path int true "关联ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menu-routes/{id} [delete]
|
|
||||||
func (c *MenuRouteController) DeleteMenuRoute(ctx *gin.Context) { |
|
||||||
idStr := ctx.Param("id") |
|
||||||
id, err := strconv.ParseUint(idStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if err := c.menuRouteService.DeleteMenuRoute(uint(id)); err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "删除菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "删除菜单路由关联成功", nil) |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteMenuRoutes 删除菜单的所有路由关联
|
|
||||||
// @Summary 删除菜单的所有路由关联
|
|
||||||
// @Description 删除指定菜单的所有路由关联
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param menuID path int true "菜单ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menus/{menuID}/routes [delete]
|
|
||||||
func (c *MenuRouteController) DeleteMenuRoutes(ctx *gin.Context) { |
|
||||||
menuIDStr := ctx.Param("menuID") |
|
||||||
menuID, err := strconv.ParseUint(menuIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "菜单ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if err := c.menuRouteService.DeleteMenuRoutes(uint(menuID)); err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "删除菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "删除菜单路由关联成功", nil) |
|
||||||
} |
|
||||||
|
|
||||||
// SyncMenuRoutes 同步菜单路由关联
|
|
||||||
// @Summary 同步菜单路由关联
|
|
||||||
// @Description 同步菜单的路由关联(删除现有关联并创建新关联)
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param menuID path int true "菜单ID"
|
|
||||||
// @Param routeMappingIDs body []uint true "路由映射ID列表"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menus/{menuID}/routes/sync [post]
|
|
||||||
func (c *MenuRouteController) SyncMenuRoutes(ctx *gin.Context) { |
|
||||||
menuIDStr := ctx.Param("menuID") |
|
||||||
menuID, err := strconv.ParseUint(menuIDStr, 10, 32) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "菜单ID格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
var routeMappingIDs []uint |
|
||||||
if err := ctx.ShouldBindJSON(&routeMappingIDs); err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "请求参数错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
if err := c.menuRouteService.SyncMenuRoutes(uint(menuID), routeMappingIDs); err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "同步菜单路由关联失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "同步菜单路由关联成功", nil) |
|
||||||
} |
|
||||||
|
|
||||||
// ListMenuRoutes 获取菜单路由关联列表
|
|
||||||
// @Summary 获取菜单路由关联列表
|
|
||||||
// @Description 分页获取菜单路由关联列表
|
|
||||||
// @Tags 菜单路由关联
|
|
||||||
// @Accept json
|
|
||||||
// @Produce json
|
|
||||||
// @Param page query int false "页码" default(1)
|
|
||||||
// @Param pageSize query int false "每页数量" default(10)
|
|
||||||
// @Success 200 {object} response.Response{data=map[string]interface{}}
|
|
||||||
// @Failure 400 {object} response.Response
|
|
||||||
// @Router /api/menu-routes [get]
|
|
||||||
func (c *MenuRouteController) ListMenuRoutes(ctx *gin.Context) { |
|
||||||
pageStr := ctx.DefaultQuery("page", "1") |
|
||||||
pageSizeStr := ctx.DefaultQuery("pageSize", "10") |
|
||||||
|
|
||||||
page, err := strconv.Atoi(pageStr) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "页码格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
pageSize, err := strconv.Atoi(pageSizeStr) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusBadRequest, "每页数量格式错误", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
menuRoutes, total, err := c.menuRouteService.ListMenuRoutes(page, pageSize) |
|
||||||
if err != nil { |
|
||||||
response.Error(ctx, http.StatusInternalServerError, "获取菜单路由关联列表失败", err.Error()) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
result := map[string]interface{}{ |
|
||||||
"list": menuRoutes, |
|
||||||
"total": total, |
|
||||||
"page": page, |
|
||||||
"pageSize": pageSize, |
|
||||||
"pageCount": (total + int64(pageSize) - 1) / int64(pageSize), |
|
||||||
} |
|
||||||
|
|
||||||
response.Success(ctx, "获取菜单路由关联列表成功", result) |
|
||||||
} |
|
@ -1,27 +0,0 @@ |
|||||||
package model |
|
||||||
|
|
||||||
import ( |
|
||||||
"gofaster/internal/shared/model" |
|
||||||
) |
|
||||||
|
|
||||||
// Menu 菜单模型
|
|
||||||
type Menu struct { |
|
||||||
model.BaseModel |
|
||||||
Name string `json:"name"` // 菜单名称
|
|
||||||
Path string `json:"path"` // 前台路由路径
|
|
||||||
Component string `json:"component"` // Vue组件路径
|
|
||||||
Icon string `json:"icon"` // 图标
|
|
||||||
Sort int `json:"sort"` // 排序
|
|
||||||
ParentID *uint `json:"parent_id"` // 父菜单ID
|
|
||||||
Level int `json:"level"` // 菜单层级
|
|
||||||
IsVisible bool `json:"is_visible"` // 是否可见
|
|
||||||
IsExternal bool `json:"is_external"` // 是否外部链接
|
|
||||||
Meta string `json:"meta"` // 元数据(JSON)
|
|
||||||
Module string `json:"module"` // 所属模块
|
|
||||||
Status int `gorm:"default:1" json:"status"` // 状态:1-启用,0-禁用
|
|
||||||
} |
|
||||||
|
|
||||||
// TableName 指定表名
|
|
||||||
func (Menu) TableName() string { |
|
||||||
return "menus" |
|
||||||
} |
|
@ -0,0 +1,20 @@ |
|||||||
|
package model |
||||||
|
|
||||||
|
import ( |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
// MenuGroup 菜单分组模型
|
||||||
|
type MenuGroup struct { |
||||||
|
ID uint `gorm:"primarykey" json:"id"` |
||||||
|
UpdatedAt time.Time `json:"updated_at"` |
||||||
|
Name string `json:"name"` // 分组名称
|
||||||
|
Description string `json:"description"` // 分组描述
|
||||||
|
Sort int `gorm:"default:0" json:"sort"` // 排序
|
||||||
|
Status int `gorm:"default:1" json:"status"` // 状态:1-启用,0-禁用
|
||||||
|
} |
||||||
|
|
||||||
|
// TableName 指定表名
|
||||||
|
func (MenuGroup) TableName() string { |
||||||
|
return "menu_groups" |
||||||
|
} |
@ -1,20 +0,0 @@ |
|||||||
package model |
|
||||||
|
|
||||||
import ( |
|
||||||
"gofaster/internal/shared/model" |
|
||||||
) |
|
||||||
|
|
||||||
// MenuRoute 菜单路由关联表(多对多关系)
|
|
||||||
type MenuRoute struct { |
|
||||||
model.BaseModel |
|
||||||
MenuID uint `gorm:"primaryKey;index" json:"menu_id"` // 菜单ID
|
|
||||||
RouteMappingID uint `gorm:"primaryKey;index" json:"route_mapping_id"` // 路由映射ID
|
|
||||||
Sort int `gorm:"default:0" json:"sort"` // 排序
|
|
||||||
IsDefault bool `gorm:"default:false" json:"is_default"` // 是否为默认路由
|
|
||||||
Status int `gorm:"default:1" json:"status"` // 状态:1-启用,0-禁用
|
|
||||||
} |
|
||||||
|
|
||||||
// TableName 指定表名
|
|
||||||
func (MenuRoute) TableName() string { |
|
||||||
return "menu_routes" |
|
||||||
} |
|
@ -1,22 +0,0 @@ |
|||||||
package model |
|
||||||
|
|
||||||
import ( |
|
||||||
"time" |
|
||||||
) |
|
||||||
|
|
||||||
// RouteMapping 路由映射模型
|
|
||||||
type RouteMapping struct { |
|
||||||
ID uint `gorm:"primarykey" json:"id"` |
|
||||||
UpdatedAt time.Time `json:"updated_at"` |
|
||||||
BackendRoute string `json:"backend_route"` // 后台API路径
|
|
||||||
HTTPMethod string `json:"http_method"` // HTTP方法
|
|
||||||
ResourceID *uint `json:"resource_id"` // 关联的资源ID
|
|
||||||
Module string `json:"module"` // 所属模块
|
|
||||||
Description string `json:"description"` // 描述
|
|
||||||
Status int `gorm:"default:1" json:"status"` // 状态:1-启用,0-禁用
|
|
||||||
} |
|
||||||
|
|
||||||
// TableName 指定表名
|
|
||||||
func (RouteMapping) TableName() string { |
|
||||||
return "route_mappings" |
|
||||||
} |
|
@ -0,0 +1,127 @@ |
|||||||
|
package repository |
||||||
|
|
||||||
|
import ( |
||||||
|
"gofaster/internal/auth/model" |
||||||
|
|
||||||
|
"gorm.io/gorm" |
||||||
|
) |
||||||
|
|
||||||
|
// MenuGroupRepository 菜单分组仓库
|
||||||
|
type MenuGroupRepository struct { |
||||||
|
db *gorm.DB |
||||||
|
} |
||||||
|
|
||||||
|
// NewMenuGroupRepository 创建菜单分组仓库实例
|
||||||
|
func NewMenuGroupRepository(db *gorm.DB) *MenuGroupRepository { |
||||||
|
return &MenuGroupRepository{db: db} |
||||||
|
} |
||||||
|
|
||||||
|
// Create 创建菜单分组
|
||||||
|
func (r *MenuGroupRepository) Create(menuGroup *model.MenuGroup) error { |
||||||
|
return r.db.Create(menuGroup).Error |
||||||
|
} |
||||||
|
|
||||||
|
// FindByID 根据ID查找菜单分组
|
||||||
|
func (r *MenuGroupRepository) FindByID(id uint) (*model.MenuGroup, error) { |
||||||
|
var menuGroup model.MenuGroup |
||||||
|
err := r.db.Where("id = ?", id).First(&menuGroup).Error |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return &menuGroup, nil |
||||||
|
} |
||||||
|
|
||||||
|
// FindByName 根据名称查找菜单分组
|
||||||
|
func (r *MenuGroupRepository) FindByName(name string) (*model.MenuGroup, error) { |
||||||
|
var menuGroup model.MenuGroup |
||||||
|
err := r.db.Where("name = ?", name).First(&menuGroup).Error |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return &menuGroup, nil |
||||||
|
} |
||||||
|
|
||||||
|
// List 获取菜单分组列表
|
||||||
|
func (r *MenuGroupRepository) List() ([]*model.MenuGroup, error) { |
||||||
|
var menuGroups []*model.MenuGroup |
||||||
|
err := r.db.Order("sort ASC, id ASC").Find(&menuGroups).Error |
||||||
|
return menuGroups, err |
||||||
|
} |
||||||
|
|
||||||
|
// ListByStatus 根据状态获取菜单分组列表
|
||||||
|
func (r *MenuGroupRepository) ListByStatus(status int) ([]*model.MenuGroup, error) { |
||||||
|
var menuGroups []*model.MenuGroup |
||||||
|
err := r.db.Where("status = ?", status).Order("sort ASC, id ASC").Find(&menuGroups).Error |
||||||
|
return menuGroups, err |
||||||
|
} |
||||||
|
|
||||||
|
// Update 更新菜单分组
|
||||||
|
func (r *MenuGroupRepository) Update(menuGroup *model.MenuGroup) error { |
||||||
|
return r.db.Save(menuGroup).Error |
||||||
|
} |
||||||
|
|
||||||
|
// Delete 删除菜单分组
|
||||||
|
func (r *MenuGroupRepository) Delete(id uint) error { |
||||||
|
return r.db.Delete(&model.MenuGroup{}, id).Error |
||||||
|
} |
||||||
|
|
||||||
|
// BatchDelete 批量删除菜单分组
|
||||||
|
func (r *MenuGroupRepository) BatchDelete(ids []uint) error { |
||||||
|
return r.db.Where("id IN ?", ids).Delete(&model.MenuGroup{}).Error |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateStatus 更新菜单分组状态
|
||||||
|
func (r *MenuGroupRepository) UpdateStatus(id uint, status int) error { |
||||||
|
return r.db.Model(&model.MenuGroup{}).Where("id = ?", id).Update("status", status).Error |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateSort 更新菜单分组排序
|
||||||
|
func (r *MenuGroupRepository) UpdateSort(id uint, sort int) error { |
||||||
|
return r.db.Model(&model.MenuGroup{}).Where("id = ?", id).Update("sort", sort).Error |
||||||
|
} |
||||||
|
|
||||||
|
// BatchUpdateSort 批量更新菜单分组排序
|
||||||
|
func (r *MenuGroupRepository) BatchUpdateSort(sorts map[uint]int) error { |
||||||
|
for id, sort := range sorts { |
||||||
|
if err := r.UpdateSort(id, sort); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetStats 获取菜单分组统计信息
|
||||||
|
func (r *MenuGroupRepository) GetStats() (map[string]interface{}, error) { |
||||||
|
var total int64 |
||||||
|
var statusStats []struct { |
||||||
|
Status int `json:"status"` |
||||||
|
Count int64 `json:"count"` |
||||||
|
} |
||||||
|
|
||||||
|
if err := r.db.Model(&model.MenuGroup{}).Count(&total).Error; err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
if err := r.db.Model(&model.MenuGroup{}). |
||||||
|
Select("status, count(*) as count"). |
||||||
|
Group("status"). |
||||||
|
Scan(&statusStats).Error; err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return map[string]interface{}{ |
||||||
|
"total": total, |
||||||
|
"status_stats": statusStats, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// ExistsByName 检查名称是否存在(排除指定ID)
|
||||||
|
func (r *MenuGroupRepository) ExistsByName(name string, excludeID ...uint) bool { |
||||||
|
query := r.db.Model(&model.MenuGroup{}).Where("name = ?", name) |
||||||
|
if len(excludeID) > 0 && excludeID[0] > 0 { |
||||||
|
query = query.Where("id != ?", excludeID[0]) |
||||||
|
} |
||||||
|
var count int64 |
||||||
|
query.Count(&count) |
||||||
|
return count > 0 |
||||||
|
} |
@ -1,89 +0,0 @@ |
|||||||
package repository |
|
||||||
|
|
||||||
import ( |
|
||||||
"gofaster/internal/auth/model" |
|
||||||
"gofaster/internal/shared/repository" |
|
||||||
|
|
||||||
"gorm.io/gorm" |
|
||||||
) |
|
||||||
|
|
||||||
// MenuRepository 菜单仓库
|
|
||||||
type MenuRepository struct { |
|
||||||
repository.BaseRepo |
|
||||||
} |
|
||||||
|
|
||||||
// NewMenuRepository 创建菜单仓库实例
|
|
||||||
func NewMenuRepository(db *gorm.DB) *MenuRepository { |
|
||||||
return &MenuRepository{ |
|
||||||
BaseRepo: *repository.NewBaseRepo(db), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Create 创建菜单
|
|
||||||
func (r *MenuRepository) Create(menu *model.Menu) error { |
|
||||||
return r.DB().Create(menu).Error |
|
||||||
} |
|
||||||
|
|
||||||
// Update 更新菜单
|
|
||||||
func (r *MenuRepository) Update(menu *model.Menu) error { |
|
||||||
return r.DB().Save(menu).Error |
|
||||||
} |
|
||||||
|
|
||||||
// Delete 删除菜单
|
|
||||||
func (r *MenuRepository) Delete(id uint) error { |
|
||||||
return r.DB().Delete(&model.Menu{}, id).Error |
|
||||||
} |
|
||||||
|
|
||||||
// FindByID 根据ID查找菜单
|
|
||||||
func (r *MenuRepository) FindByID(id uint) (*model.Menu, error) { |
|
||||||
var menu model.Menu |
|
||||||
err := r.DB().First(&menu, id).Error |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &menu, nil |
|
||||||
} |
|
||||||
|
|
||||||
// FindByPath 根据路径查找菜单
|
|
||||||
func (r *MenuRepository) FindByPath(path string) (*model.Menu, error) { |
|
||||||
var menu model.Menu |
|
||||||
err := r.DB().Where("path = ?", path).First(&menu).Error |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &menu, nil |
|
||||||
} |
|
||||||
|
|
||||||
// FindAll 查找所有菜单
|
|
||||||
func (r *MenuRepository) FindAll() ([]model.Menu, error) { |
|
||||||
var menus []model.Menu |
|
||||||
err := r.DB().Order("sort ASC, id ASC").Find(&menus).Error |
|
||||||
return menus, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindByModule 根据模块查找菜单
|
|
||||||
func (r *MenuRepository) FindByModule(module string) ([]model.Menu, error) { |
|
||||||
var menus []model.Menu |
|
||||||
err := r.DB().Where("module = ?", module).Order("sort ASC, id ASC").Find(&menus).Error |
|
||||||
return menus, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindByParentID 根据父ID查找子菜单
|
|
||||||
func (r *MenuRepository) FindByParentID(parentID *uint) ([]model.Menu, error) { |
|
||||||
var menus []model.Menu |
|
||||||
query := r.DB() |
|
||||||
if parentID == nil { |
|
||||||
query = query.Where("parent_id IS NULL") |
|
||||||
} else { |
|
||||||
query = query.Where("parent_id = ?", *parentID) |
|
||||||
} |
|
||||||
err := query.Order("sort ASC, id ASC").Find(&menus).Error |
|
||||||
return menus, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindTree 查找菜单树
|
|
||||||
func (r *MenuRepository) FindTree() ([]model.Menu, error) { |
|
||||||
var menus []model.Menu |
|
||||||
err := r.DB().Order("sort ASC, id ASC").Find(&menus).Error |
|
||||||
return menus, err |
|
||||||
} |
|
@ -1,142 +0,0 @@ |
|||||||
package repository |
|
||||||
|
|
||||||
import ( |
|
||||||
"gofaster/internal/auth/model" |
|
||||||
|
|
||||||
"gorm.io/gorm" |
|
||||||
) |
|
||||||
|
|
||||||
// MenuRouteRepository 菜单路由关联表仓储
|
|
||||||
type MenuRouteRepository struct { |
|
||||||
db *gorm.DB |
|
||||||
} |
|
||||||
|
|
||||||
// NewMenuRouteRepository 创建菜单路由关联表仓储
|
|
||||||
func NewMenuRouteRepository(db *gorm.DB) *MenuRouteRepository { |
|
||||||
return &MenuRouteRepository{db: db} |
|
||||||
} |
|
||||||
|
|
||||||
// Create 创建菜单路由关联
|
|
||||||
func (r *MenuRouteRepository) Create(menuRoute *model.MenuRoute) error { |
|
||||||
return r.db.Create(menuRoute).Error |
|
||||||
} |
|
||||||
|
|
||||||
// CreateBatch 批量创建菜单路由关联
|
|
||||||
func (r *MenuRouteRepository) CreateBatch(menuRoutes []*model.MenuRoute) error { |
|
||||||
return r.db.CreateInBatches(menuRoutes, 100).Error |
|
||||||
} |
|
||||||
|
|
||||||
// GetByID 根据ID获取菜单路由关联
|
|
||||||
func (r *MenuRouteRepository) GetByID(id uint) (*model.MenuRoute, error) { |
|
||||||
var menuRoute model.MenuRoute |
|
||||||
err := r.db.Where("id = ?", id).First(&menuRoute).Error |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &menuRoute, nil |
|
||||||
} |
|
||||||
|
|
||||||
// GetByMenuAndRoute 根据菜单ID和路由ID获取关联
|
|
||||||
func (r *MenuRouteRepository) GetByMenuAndRoute(menuID, routeMappingID uint) (*model.MenuRoute, error) { |
|
||||||
var menuRoute model.MenuRoute |
|
||||||
err := r.db.Where("menu_id = ? AND route_mapping_id = ?", menuID, routeMappingID).First(&menuRoute).Error |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &menuRoute, nil |
|
||||||
} |
|
||||||
|
|
||||||
// GetByMenuID 根据菜单ID获取所有关联的路由
|
|
||||||
func (r *MenuRouteRepository) GetByMenuID(menuID uint) ([]*model.MenuRoute, error) { |
|
||||||
var menuRoutes []*model.MenuRoute |
|
||||||
err := r.db.Where("menu_id = ?", menuID).Order("sort ASC").Find(&menuRoutes).Error |
|
||||||
return menuRoutes, err |
|
||||||
} |
|
||||||
|
|
||||||
// GetByRouteMappingID 根据路由映射ID获取所有关联的菜单
|
|
||||||
func (r *MenuRouteRepository) GetByRouteMappingID(routeMappingID uint) ([]*model.MenuRoute, error) { |
|
||||||
var menuRoutes []*model.MenuRoute |
|
||||||
err := r.db.Where("route_mapping_id = ?", routeMappingID).Order("sort ASC").Find(&menuRoutes).Error |
|
||||||
return menuRoutes, err |
|
||||||
} |
|
||||||
|
|
||||||
// List 获取菜单路由关联列表
|
|
||||||
func (r *MenuRouteRepository) List(page, pageSize int) ([]*model.MenuRoute, int64, error) { |
|
||||||
var menuRoutes []*model.MenuRoute |
|
||||||
var total int64 |
|
||||||
|
|
||||||
// 获取总数
|
|
||||||
if err := r.db.Model(&model.MenuRoute{}).Count(&total).Error; err != nil { |
|
||||||
return nil, 0, err |
|
||||||
} |
|
||||||
|
|
||||||
// 获取分页数据
|
|
||||||
offset := (page - 1) * pageSize |
|
||||||
err := r.db.Offset(offset).Limit(pageSize).Order("created_at DESC").Find(&menuRoutes).Error |
|
||||||
return menuRoutes, total, err |
|
||||||
} |
|
||||||
|
|
||||||
// Update 更新菜单路由关联
|
|
||||||
func (r *MenuRouteRepository) Update(menuRoute *model.MenuRoute) error { |
|
||||||
return r.db.Save(menuRoute).Error |
|
||||||
} |
|
||||||
|
|
||||||
// Delete 删除菜单路由关联
|
|
||||||
func (r *MenuRouteRepository) Delete(id uint) error { |
|
||||||
return r.db.Delete(&model.MenuRoute{}, id).Error |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteByMenuID 根据菜单ID删除所有关联
|
|
||||||
func (r *MenuRouteRepository) DeleteByMenuID(menuID uint) error { |
|
||||||
return r.db.Where("menu_id = ?", menuID).Delete(&model.MenuRoute{}).Error |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteByRouteMappingID 根据路由映射ID删除所有关联
|
|
||||||
func (r *MenuRouteRepository) DeleteByRouteMappingID(routeMappingID uint) error { |
|
||||||
return r.db.Where("route_mapping_id = ?", routeMappingID).Delete(&model.MenuRoute{}).Error |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteByMenuAndRoute 根据菜单ID和路由ID删除关联
|
|
||||||
func (r *MenuRouteRepository) DeleteByMenuAndRoute(menuID, routeMappingID uint) error { |
|
||||||
return r.db.Where("menu_id = ? AND route_mapping_id = ?", menuID, routeMappingID).Delete(&model.MenuRoute{}).Error |
|
||||||
} |
|
||||||
|
|
||||||
// GetMenuWithRoutes 获取菜单及其关联的路由信息
|
|
||||||
func (r *MenuRouteRepository) GetMenuWithRoutes(menuID uint) (*model.Menu, []*model.RouteMapping, error) { |
|
||||||
var menu model.Menu |
|
||||||
var routeMappings []*model.RouteMapping |
|
||||||
|
|
||||||
// 获取菜单信息
|
|
||||||
if err := r.db.First(&menu, menuID).Error; err != nil { |
|
||||||
return nil, nil, err |
|
||||||
} |
|
||||||
|
|
||||||
// 获取关联的路由映射
|
|
||||||
err := r.db.Table("route_mappings"). |
|
||||||
Joins("JOIN menu_routes ON route_mappings.id = menu_routes.route_mapping_id"). |
|
||||||
Where("menu_routes.menu_id = ?", menuID). |
|
||||||
Order("menu_routes.sort ASC"). |
|
||||||
Find(&routeMappings).Error |
|
||||||
|
|
||||||
return &menu, routeMappings, err |
|
||||||
} |
|
||||||
|
|
||||||
// GetRouteWithMenus 获取路由及其关联的菜单信息
|
|
||||||
func (r *MenuRouteRepository) GetRouteWithMenus(routeMappingID uint) (*model.RouteMapping, []*model.Menu, error) { |
|
||||||
var routeMapping model.RouteMapping |
|
||||||
var menus []*model.Menu |
|
||||||
|
|
||||||
// 获取路由映射信息
|
|
||||||
if err := r.db.First(&routeMapping, routeMappingID).Error; err != nil { |
|
||||||
return nil, nil, err |
|
||||||
} |
|
||||||
|
|
||||||
// 获取关联的菜单
|
|
||||||
err := r.db.Table("menus"). |
|
||||||
Joins("JOIN menu_routes ON menus.id = menu_routes.menu_id"). |
|
||||||
Where("menu_routes.route_mapping_id = ?", routeMappingID). |
|
||||||
Order("menu_routes.sort ASC"). |
|
||||||
Find(&menus).Error |
|
||||||
|
|
||||||
return &routeMapping, menus, err |
|
||||||
} |
|
@ -1,108 +0,0 @@ |
|||||||
package repository |
|
||||||
|
|
||||||
import ( |
|
||||||
"gofaster/internal/auth/model" |
|
||||||
"gofaster/internal/shared/repository" |
|
||||||
|
|
||||||
"gorm.io/gorm" |
|
||||||
) |
|
||||||
|
|
||||||
// RouteMappingRepository 路由映射仓库
|
|
||||||
type RouteMappingRepository struct { |
|
||||||
repository.BaseRepo |
|
||||||
} |
|
||||||
|
|
||||||
// NewRouteMappingRepository 创建路由映射仓库实例
|
|
||||||
func NewRouteMappingRepository(db *gorm.DB) *RouteMappingRepository { |
|
||||||
return &RouteMappingRepository{ |
|
||||||
BaseRepo: *repository.NewBaseRepo(db), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Create 创建路由映射
|
|
||||||
func (r *RouteMappingRepository) Create(mapping *model.RouteMapping) error { |
|
||||||
return r.DB().Create(mapping).Error |
|
||||||
} |
|
||||||
|
|
||||||
// Update 更新路由映射
|
|
||||||
func (r *RouteMappingRepository) Update(mapping *model.RouteMapping) error { |
|
||||||
return r.DB().Save(mapping).Error |
|
||||||
} |
|
||||||
|
|
||||||
// Delete 删除路由映射
|
|
||||||
func (r *RouteMappingRepository) Delete(id uint) error { |
|
||||||
return r.DB().Delete(&model.RouteMapping{}, id).Error |
|
||||||
} |
|
||||||
|
|
||||||
// FindByID 根据ID查找路由映射
|
|
||||||
func (r *RouteMappingRepository) FindByID(id uint) (*model.RouteMapping, error) { |
|
||||||
var mapping model.RouteMapping |
|
||||||
err := r.DB().First(&mapping, id).Error |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &mapping, nil |
|
||||||
} |
|
||||||
|
|
||||||
// FindByBackendRoute 根据后台路由查找映射
|
|
||||||
func (r *RouteMappingRepository) FindByBackendRoute(backendRoute, httpMethod string) (*model.RouteMapping, error) { |
|
||||||
var mapping model.RouteMapping |
|
||||||
err := r.DB().Where("backend_route = ? AND http_method = ?", backendRoute, httpMethod).First(&mapping).Error |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &mapping, nil |
|
||||||
} |
|
||||||
|
|
||||||
// FindByFrontendRoute 根据前台路由查找映射
|
|
||||||
func (r *RouteMappingRepository) FindByFrontendRoute(frontendRoute string) ([]model.RouteMapping, error) { |
|
||||||
var mappings []model.RouteMapping |
|
||||||
err := r.DB().Where("frontend_route = ?", frontendRoute).Find(&mappings).Error |
|
||||||
return mappings, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindAll 查找所有路由映射
|
|
||||||
func (r *RouteMappingRepository) FindAll() ([]model.RouteMapping, error) { |
|
||||||
var mappings []model.RouteMapping |
|
||||||
err := r.DB().Order("id ASC").Find(&mappings).Error |
|
||||||
return mappings, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindByModule 根据模块查找路由映射
|
|
||||||
func (r *RouteMappingRepository) FindByModule(module string) ([]model.RouteMapping, error) { |
|
||||||
var mappings []model.RouteMapping |
|
||||||
err := r.DB().Where("module = ?", module).Order("id ASC").Find(&mappings).Error |
|
||||||
return mappings, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindByResourceID 根据资源ID查找路由映射
|
|
||||||
func (r *RouteMappingRepository) FindByResourceID(resourceID uint) ([]model.RouteMapping, error) { |
|
||||||
var mappings []model.RouteMapping |
|
||||||
err := r.DB().Where("resource_id = ?", resourceID).Find(&mappings).Error |
|
||||||
return mappings, err |
|
||||||
} |
|
||||||
|
|
||||||
// FindByMenuID 根据菜单ID查找路由映射
|
|
||||||
func (r *RouteMappingRepository) FindByMenuID(menuID uint) ([]model.RouteMapping, error) { |
|
||||||
var mappings []model.RouteMapping |
|
||||||
err := r.DB().Where("menu_id = ?", menuID).Find(&mappings).Error |
|
||||||
return mappings, err |
|
||||||
} |
|
||||||
|
|
||||||
// CreateOrUpdate 创建或更新路由映射(用于增量同步)
|
|
||||||
func (r *RouteMappingRepository) CreateOrUpdate(mapping *model.RouteMapping) error { |
|
||||||
var existing model.RouteMapping |
|
||||||
err := r.DB().Where("backend_route = ? AND http_method = ?", mapping.BackendRoute, mapping.HTTPMethod).First(&existing).Error |
|
||||||
|
|
||||||
if err != nil { |
|
||||||
if err == gorm.ErrRecordNotFound { |
|
||||||
// 不存在则创建
|
|
||||||
return r.Create(mapping) |
|
||||||
} |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// 存在则更新
|
|
||||||
mapping.ID = existing.ID |
|
||||||
return r.Update(mapping) |
|
||||||
} |
|
@ -0,0 +1,45 @@ |
|||||||
|
package routes |
||||||
|
|
||||||
|
import ( |
||||||
|
"gofaster/internal/auth/controller" |
||||||
|
"gofaster/internal/auth/repository" |
||||||
|
"gofaster/internal/auth/service" |
||||||
|
"gofaster/internal/shared/middleware" |
||||||
|
|
||||||
|
"github.com/gin-gonic/gin" |
||||||
|
"go.uber.org/zap" |
||||||
|
"gorm.io/gorm" |
||||||
|
) |
||||||
|
|
||||||
|
func RegisterMenuGroupRoutes(router *gin.RouterGroup, db *gorm.DB, logger *zap.Logger) { |
||||||
|
// 初始化依赖
|
||||||
|
menuGroupRepo := repository.NewMenuGroupRepository(db) |
||||||
|
menuGroupService := service.NewMenuGroupService(menuGroupRepo, logger) |
||||||
|
menuGroupController := controller.NewMenuGroupController(menuGroupService, logger) |
||||||
|
|
||||||
|
// 菜单分组管理路由组
|
||||||
|
menuGroupGroup := router.Group("/menu-groups") |
||||||
|
{ |
||||||
|
// 需要权限验证的路由
|
||||||
|
menuGroupGroup.Use(middleware.JWTAuth()) // 暂时只检查JWT,不检查权限
|
||||||
|
{ |
||||||
|
// 菜单分组CRUD操作
|
||||||
|
menuGroupGroup.GET("", menuGroupController.ListMenuGroups) // 获取菜单分组列表
|
||||||
|
menuGroupGroup.POST("", menuGroupController.CreateMenuGroup) // 创建菜单分组
|
||||||
|
menuGroupGroup.GET("/:id", menuGroupController.GetMenuGroup) // 获取菜单分组详情
|
||||||
|
menuGroupGroup.PUT("/:id", menuGroupController.UpdateMenuGroup) // 更新菜单分组
|
||||||
|
menuGroupGroup.DELETE("/:id", menuGroupController.DeleteMenuGroup) // 删除菜单分组
|
||||||
|
|
||||||
|
// 批量操作
|
||||||
|
menuGroupGroup.POST("/batch-delete", menuGroupController.BatchDeleteMenuGroups) // 批量删除菜单分组
|
||||||
|
menuGroupGroup.PUT("/batch-sort", menuGroupController.BatchUpdateMenuGroupSort) // 批量更新排序
|
||||||
|
|
||||||
|
// 状态和排序管理
|
||||||
|
menuGroupGroup.PUT("/:id/status", menuGroupController.UpdateMenuGroupStatus) // 更新状态
|
||||||
|
menuGroupGroup.PUT("/:id/sort", menuGroupController.UpdateMenuGroupSort) // 更新排序
|
||||||
|
|
||||||
|
// 统计信息
|
||||||
|
menuGroupGroup.GET("/stats", menuGroupController.GetMenuGroupStats) // 获取统计信息
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,52 +0,0 @@ |
|||||||
package routes |
|
||||||
|
|
||||||
import ( |
|
||||||
"gofaster/internal/auth/controller" |
|
||||||
"gofaster/internal/shared/middleware" |
|
||||||
|
|
||||||
"github.com/gin-gonic/gin" |
|
||||||
) |
|
||||||
|
|
||||||
// RegisterMenuRouteRoutes 注册菜单路由关联表路由
|
|
||||||
func RegisterMenuRouteRoutes(r *gin.RouterGroup, menuRouteController *controller.MenuRouteController) { |
|
||||||
// 菜单路由关联表路由组
|
|
||||||
menuRouteGroup := r.Group("/menu-routes") |
|
||||||
{ |
|
||||||
// 需要认证的接口
|
|
||||||
menuRouteGroup.Use(middleware.JWTAuth()) |
|
||||||
{ |
|
||||||
// 基础CRUD操作
|
|
||||||
menuRouteGroup.POST("", menuRouteController.CreateMenuRoute) // 创建菜单路由关联
|
|
||||||
menuRouteGroup.GET("", menuRouteController.ListMenuRoutes) // 获取菜单路由关联列表
|
|
||||||
menuRouteGroup.PUT("/:id", menuRouteController.UpdateMenuRoute) // 更新菜单路由关联
|
|
||||||
menuRouteGroup.DELETE("/:id", menuRouteController.DeleteMenuRoute) // 删除菜单路由关联
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 菜单相关路由
|
|
||||||
menuGroup := r.Group("/menus") |
|
||||||
{ |
|
||||||
// 需要认证的接口
|
|
||||||
menuGroup.Use(middleware.JWTAuth()) |
|
||||||
{ |
|
||||||
// 菜单路由关联操作
|
|
||||||
menuGroup.POST("/:menuID/routes", menuRouteController.CreateMenuRoutes) // 批量创建菜单路由关联
|
|
||||||
menuGroup.GET("/:menuID/routes", menuRouteController.GetMenuRoutes) // 获取菜单的路由关联
|
|
||||||
menuGroup.GET("/:menuID/routes/detail", menuRouteController.GetMenuWithRoutes) // 获取菜单及其关联的路由信息
|
|
||||||
menuGroup.DELETE("/:menuID/routes", menuRouteController.DeleteMenuRoutes) // 删除菜单的所有路由关联
|
|
||||||
menuGroup.POST("/:menuID/routes/sync", menuRouteController.SyncMenuRoutes) // 同步菜单路由关联
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 路由映射相关路由
|
|
||||||
routeMappingGroup := r.Group("/route-mappings") |
|
||||||
{ |
|
||||||
// 需要认证的接口
|
|
||||||
routeMappingGroup.Use(middleware.JWTAuth()) |
|
||||||
{ |
|
||||||
// 路由菜单关联操作
|
|
||||||
routeMappingGroup.GET("/:routeMappingID/menus", menuRouteController.GetRouteMenus) // 获取路由的菜单关联
|
|
||||||
routeMappingGroup.GET("/:routeMappingID/menus/detail", menuRouteController.GetRouteWithMenus) // 获取路由及其关联的菜单信息
|
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,229 @@ |
|||||||
|
package service |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"gofaster/internal/auth/model" |
||||||
|
"gofaster/internal/auth/repository" |
||||||
|
|
||||||
|
"go.uber.org/zap" |
||||||
|
) |
||||||
|
|
||||||
|
// MenuGroupService 菜单分组服务
|
||||||
|
type MenuGroupService struct { |
||||||
|
menuGroupRepo *repository.MenuGroupRepository |
||||||
|
logger *zap.Logger |
||||||
|
} |
||||||
|
|
||||||
|
// NewMenuGroupService 创建菜单分组服务实例
|
||||||
|
func NewMenuGroupService(menuGroupRepo *repository.MenuGroupRepository, logger *zap.Logger) *MenuGroupService { |
||||||
|
return &MenuGroupService{ |
||||||
|
menuGroupRepo: menuGroupRepo, |
||||||
|
logger: logger, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// CreateMenuGroup 创建菜单分组
|
||||||
|
func (s *MenuGroupService) CreateMenuGroup(menuGroup *model.MenuGroup) error { |
||||||
|
s.logger.Info("开始创建菜单分组", zap.String("name", menuGroup.Name)) |
||||||
|
|
||||||
|
// 检查名称是否已存在
|
||||||
|
if s.menuGroupRepo.ExistsByName(menuGroup.Name) { |
||||||
|
return fmt.Errorf("菜单分组名称已存在: %s", menuGroup.Name) |
||||||
|
} |
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
if menuGroup.Sort == 0 { |
||||||
|
menuGroup.Sort = 999 // 默认排序值
|
||||||
|
} |
||||||
|
if menuGroup.Status == 0 { |
||||||
|
menuGroup.Status = 1 // 默认启用
|
||||||
|
} |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.Create(menuGroup); err != nil { |
||||||
|
s.logger.Error("创建菜单分组失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("创建菜单分组失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("菜单分组创建成功", zap.String("name", menuGroup.Name), zap.Uint("id", menuGroup.ID)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetMenuGroupByID 根据ID获取菜单分组
|
||||||
|
func (s *MenuGroupService) GetMenuGroupByID(id uint) (*model.MenuGroup, error) { |
||||||
|
menuGroup, err := s.menuGroupRepo.FindByID(id) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("获取菜单分组失败", zap.Uint("id", id), zap.Error(err)) |
||||||
|
return nil, fmt.Errorf("获取菜单分组失败: %w", err) |
||||||
|
} |
||||||
|
return menuGroup, nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetMenuGroupByName 根据名称获取菜单分组
|
||||||
|
func (s *MenuGroupService) GetMenuGroupByName(name string) (*model.MenuGroup, error) { |
||||||
|
menuGroup, err := s.menuGroupRepo.FindByName(name) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("获取菜单分组失败", zap.String("name", name), zap.Error(err)) |
||||||
|
return nil, fmt.Errorf("获取菜单分组失败: %w", err) |
||||||
|
} |
||||||
|
return menuGroup, nil |
||||||
|
} |
||||||
|
|
||||||
|
// ListMenuGroups 获取菜单分组列表
|
||||||
|
func (s *MenuGroupService) ListMenuGroups() ([]*model.MenuGroup, error) { |
||||||
|
menuGroups, err := s.menuGroupRepo.List() |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("获取菜单分组列表失败", zap.Error(err)) |
||||||
|
return nil, fmt.Errorf("获取菜单分组列表失败: %w", err) |
||||||
|
} |
||||||
|
return menuGroups, nil |
||||||
|
} |
||||||
|
|
||||||
|
// ListMenuGroupsByStatus 根据状态获取菜单分组列表
|
||||||
|
func (s *MenuGroupService) ListMenuGroupsByStatus(status int) ([]*model.MenuGroup, error) { |
||||||
|
menuGroups, err := s.menuGroupRepo.ListByStatus(status) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("根据状态获取菜单分组列表失败", zap.Int("status", status), zap.Error(err)) |
||||||
|
return nil, fmt.Errorf("根据状态获取菜单分组列表失败: %w", err) |
||||||
|
} |
||||||
|
return menuGroups, nil |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateMenuGroup 更新菜单分组
|
||||||
|
func (s *MenuGroupService) UpdateMenuGroup(menuGroup *model.MenuGroup) error { |
||||||
|
s.logger.Info("开始更新菜单分组", zap.Uint("id", menuGroup.ID), zap.String("name", menuGroup.Name)) |
||||||
|
|
||||||
|
// 检查菜单分组是否存在
|
||||||
|
existing, err := s.menuGroupRepo.FindByID(menuGroup.ID) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("菜单分组不存在", zap.Uint("id", menuGroup.ID), zap.Error(err)) |
||||||
|
return fmt.Errorf("菜单分组不存在: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
// 检查名称是否已被其他记录使用
|
||||||
|
if s.menuGroupRepo.ExistsByName(menuGroup.Name, menuGroup.ID) { |
||||||
|
return fmt.Errorf("菜单分组名称已存在: %s", menuGroup.Name) |
||||||
|
} |
||||||
|
|
||||||
|
// 更新字段
|
||||||
|
existing.Name = menuGroup.Name |
||||||
|
existing.Description = menuGroup.Description |
||||||
|
existing.Sort = menuGroup.Sort |
||||||
|
existing.Status = menuGroup.Status |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.Update(existing); err != nil { |
||||||
|
s.logger.Error("更新菜单分组失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("更新菜单分组失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("菜单分组更新成功", zap.Uint("id", menuGroup.ID)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// DeleteMenuGroup 删除菜单分组
|
||||||
|
func (s *MenuGroupService) DeleteMenuGroup(id uint) error { |
||||||
|
s.logger.Info("开始删除菜单分组", zap.Uint("id", id)) |
||||||
|
|
||||||
|
// 检查菜单分组是否存在
|
||||||
|
_, err := s.menuGroupRepo.FindByID(id) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("菜单分组不存在", zap.Uint("id", id), zap.Error(err)) |
||||||
|
return fmt.Errorf("菜单分组不存在: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.Delete(id); err != nil { |
||||||
|
s.logger.Error("删除菜单分组失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("删除菜单分组失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("菜单分组删除成功", zap.Uint("id", id)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// BatchDeleteMenuGroups 批量删除菜单分组
|
||||||
|
func (s *MenuGroupService) BatchDeleteMenuGroups(ids []uint) error { |
||||||
|
s.logger.Info("开始批量删除菜单分组", zap.Uints("ids", ids)) |
||||||
|
|
||||||
|
if len(ids) == 0 { |
||||||
|
return fmt.Errorf("删除ID列表不能为空") |
||||||
|
} |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.BatchDelete(ids); err != nil { |
||||||
|
s.logger.Error("批量删除菜单分组失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("批量删除菜单分组失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("批量删除菜单分组成功", zap.Uints("ids", ids)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateMenuGroupStatus 更新菜单分组状态
|
||||||
|
func (s *MenuGroupService) UpdateMenuGroupStatus(id uint, status int) error { |
||||||
|
s.logger.Info("开始更新菜单分组状态", zap.Uint("id", id), zap.Int("status", status)) |
||||||
|
|
||||||
|
// 检查菜单分组是否存在
|
||||||
|
_, err := s.menuGroupRepo.FindByID(id) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("菜单分组不存在", zap.Uint("id", id), zap.Error(err)) |
||||||
|
return fmt.Errorf("菜单分组不存在: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
// 验证状态值
|
||||||
|
if status != 0 && status != 1 { |
||||||
|
return fmt.Errorf("状态值无效,只能是0或1") |
||||||
|
} |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.UpdateStatus(id, status); err != nil { |
||||||
|
s.logger.Error("更新菜单分组状态失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("更新菜单分组状态失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("菜单分组状态更新成功", zap.Uint("id", id), zap.Int("status", status)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateMenuGroupSort 更新菜单分组排序
|
||||||
|
func (s *MenuGroupService) UpdateMenuGroupSort(id uint, sort int) error { |
||||||
|
s.logger.Info("开始更新菜单分组排序", zap.Uint("id", id), zap.Int("sort", sort)) |
||||||
|
|
||||||
|
// 检查菜单分组是否存在
|
||||||
|
_, err := s.menuGroupRepo.FindByID(id) |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("菜单分组不存在", zap.Uint("id", id), zap.Error(err)) |
||||||
|
return fmt.Errorf("菜单分组不存在: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.UpdateSort(id, sort); err != nil { |
||||||
|
s.logger.Error("更新菜单分组排序失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("更新菜单分组排序失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("菜单分组排序更新成功", zap.Uint("id", id), zap.Int("sort", sort)) |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// BatchUpdateMenuGroupSort 批量更新菜单分组排序
|
||||||
|
func (s *MenuGroupService) BatchUpdateMenuGroupSort(sorts map[uint]int) error { |
||||||
|
s.logger.Info("开始批量更新菜单分组排序", zap.Any("sorts", sorts)) |
||||||
|
|
||||||
|
if len(sorts) == 0 { |
||||||
|
return fmt.Errorf("排序数据不能为空") |
||||||
|
} |
||||||
|
|
||||||
|
if err := s.menuGroupRepo.BatchUpdateSort(sorts); err != nil { |
||||||
|
s.logger.Error("批量更新菜单分组排序失败", zap.Error(err)) |
||||||
|
return fmt.Errorf("批量更新菜单分组排序失败: %w", err) |
||||||
|
} |
||||||
|
|
||||||
|
s.logger.Info("批量更新菜单分组排序成功") |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetMenuGroupStats 获取菜单分组统计信息
|
||||||
|
func (s *MenuGroupService) GetMenuGroupStats() (map[string]interface{}, error) { |
||||||
|
stats, err := s.menuGroupRepo.GetStats() |
||||||
|
if err != nil { |
||||||
|
s.logger.Error("获取菜单分组统计信息失败", zap.Error(err)) |
||||||
|
return nil, fmt.Errorf("获取菜单分组统计信息失败: %w", err) |
||||||
|
} |
||||||
|
return stats, nil |
||||||
|
} |
@ -1,180 +0,0 @@ |
|||||||
package service |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"gofaster/internal/auth/model" |
|
||||||
"gofaster/internal/auth/repository" |
|
||||||
|
|
||||||
"go.uber.org/zap" |
|
||||||
) |
|
||||||
|
|
||||||
// MenuRouteService 菜单路由关联表服务
|
|
||||||
type MenuRouteService struct { |
|
||||||
menuRouteRepo *repository.MenuRouteRepository |
|
||||||
menuRepo *repository.MenuRepository |
|
||||||
routeRepo *repository.RouteMappingRepository |
|
||||||
log *zap.Logger |
|
||||||
} |
|
||||||
|
|
||||||
// NewMenuRouteService 创建菜单路由关联表服务
|
|
||||||
func NewMenuRouteService( |
|
||||||
menuRouteRepo *repository.MenuRouteRepository, |
|
||||||
menuRepo *repository.MenuRepository, |
|
||||||
routeRepo *repository.RouteMappingRepository, |
|
||||||
log *zap.Logger, |
|
||||||
) *MenuRouteService { |
|
||||||
return &MenuRouteService{ |
|
||||||
menuRouteRepo: menuRouteRepo, |
|
||||||
menuRepo: menuRepo, |
|
||||||
routeRepo: routeRepo, |
|
||||||
log: log, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// CreateMenuRoute 创建菜单路由关联
|
|
||||||
func (s *MenuRouteService) CreateMenuRoute(menuRoute *model.MenuRoute) error { |
|
||||||
// 验证菜单是否存在
|
|
||||||
if _, err := s.menuRepo.FindByID(menuRoute.MenuID); err != nil { |
|
||||||
return fmt.Errorf("菜单不存在") |
|
||||||
} |
|
||||||
|
|
||||||
// 验证路由映射是否存在
|
|
||||||
if _, err := s.routeRepo.FindByID(menuRoute.RouteMappingID); err != nil { |
|
||||||
return fmt.Errorf("路由映射不存在") |
|
||||||
} |
|
||||||
|
|
||||||
// 检查关联是否已存在
|
|
||||||
if existing, err := s.menuRouteRepo.GetByMenuAndRoute(menuRoute.MenuID, menuRoute.RouteMappingID); err == nil && existing != nil { |
|
||||||
return fmt.Errorf("菜单路由关联已存在") |
|
||||||
} |
|
||||||
|
|
||||||
return s.menuRouteRepo.Create(menuRoute) |
|
||||||
} |
|
||||||
|
|
||||||
// CreateMenuRoutes 批量创建菜单路由关联
|
|
||||||
func (s *MenuRouteService) CreateMenuRoutes(menuID uint, routeMappingIDs []uint) error { |
|
||||||
// 验证菜单是否存在
|
|
||||||
if _, err := s.menuRepo.FindByID(menuID); err != nil { |
|
||||||
return fmt.Errorf("菜单不存在") |
|
||||||
} |
|
||||||
|
|
||||||
// 验证所有路由映射是否存在
|
|
||||||
for _, routeID := range routeMappingIDs { |
|
||||||
if _, err := s.routeRepo.FindByID(routeID); err != nil { |
|
||||||
return fmt.Errorf("路由映射不存在") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// 删除现有关联
|
|
||||||
if err := s.menuRouteRepo.DeleteByMenuID(menuID); err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// 创建新关联
|
|
||||||
var menuRoutes []*model.MenuRoute |
|
||||||
for i, routeID := range routeMappingIDs { |
|
||||||
menuRoute := &model.MenuRoute{ |
|
||||||
MenuID: menuID, |
|
||||||
RouteMappingID: routeID, |
|
||||||
Sort: i, |
|
||||||
IsDefault: i == 0, // 第一个设为默认
|
|
||||||
Status: 1, |
|
||||||
} |
|
||||||
menuRoutes = append(menuRoutes, menuRoute) |
|
||||||
} |
|
||||||
|
|
||||||
return s.menuRouteRepo.CreateBatch(menuRoutes) |
|
||||||
} |
|
||||||
|
|
||||||
// GetMenuRoutes 获取菜单的路由关联
|
|
||||||
func (s *MenuRouteService) GetMenuRoutes(menuID uint) ([]*model.MenuRoute, error) { |
|
||||||
return s.menuRouteRepo.GetByMenuID(menuID) |
|
||||||
} |
|
||||||
|
|
||||||
// GetRouteMenus 获取路由的菜单关联
|
|
||||||
func (s *MenuRouteService) GetRouteMenus(routeMappingID uint) ([]*model.MenuRoute, error) { |
|
||||||
return s.menuRouteRepo.GetByRouteMappingID(routeMappingID) |
|
||||||
} |
|
||||||
|
|
||||||
// GetMenuWithRoutes 获取菜单及其关联的路由信息
|
|
||||||
func (s *MenuRouteService) GetMenuWithRoutes(menuID uint) (*model.Menu, []*model.RouteMapping, error) { |
|
||||||
return s.menuRouteRepo.GetMenuWithRoutes(menuID) |
|
||||||
} |
|
||||||
|
|
||||||
// GetRouteWithMenus 获取路由及其关联的菜单信息
|
|
||||||
func (s *MenuRouteService) GetRouteWithMenus(routeMappingID uint) (*model.RouteMapping, []*model.Menu, error) { |
|
||||||
return s.menuRouteRepo.GetRouteWithMenus(routeMappingID) |
|
||||||
} |
|
||||||
|
|
||||||
// UpdateMenuRoute 更新菜单路由关联
|
|
||||||
func (s *MenuRouteService) UpdateMenuRoute(menuRoute *model.MenuRoute) error { |
|
||||||
// 验证关联是否存在
|
|
||||||
if _, err := s.menuRouteRepo.GetByID(menuRoute.ID); err != nil { |
|
||||||
return fmt.Errorf("菜单路由关联不存在") |
|
||||||
} |
|
||||||
|
|
||||||
return s.menuRouteRepo.Update(menuRoute) |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteMenuRoute 删除菜单路由关联
|
|
||||||
func (s *MenuRouteService) DeleteMenuRoute(id uint) error { |
|
||||||
return s.menuRouteRepo.Delete(id) |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteMenuRoutes 删除菜单的所有路由关联
|
|
||||||
func (s *MenuRouteService) DeleteMenuRoutes(menuID uint) error { |
|
||||||
return s.menuRouteRepo.DeleteByMenuID(menuID) |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteRouteMenus 删除路由的所有菜单关联
|
|
||||||
func (s *MenuRouteService) DeleteRouteMenus(routeMappingID uint) error { |
|
||||||
return s.menuRouteRepo.DeleteByRouteMappingID(routeMappingID) |
|
||||||
} |
|
||||||
|
|
||||||
// DeleteMenuRouteByMenuAndRoute 根据菜单ID和路由ID删除关联
|
|
||||||
func (s *MenuRouteService) DeleteMenuRouteByMenuAndRoute(menuID, routeMappingID uint) error { |
|
||||||
return s.menuRouteRepo.DeleteByMenuAndRoute(menuID, routeMappingID) |
|
||||||
} |
|
||||||
|
|
||||||
// ListMenuRoutes 获取菜单路由关联列表
|
|
||||||
func (s *MenuRouteService) ListMenuRoutes(page, pageSize int) ([]*model.MenuRoute, int64, error) { |
|
||||||
return s.menuRouteRepo.List(page, pageSize) |
|
||||||
} |
|
||||||
|
|
||||||
// SyncMenuRoutes 同步菜单路由关联(用于批量操作)
|
|
||||||
func (s *MenuRouteService) SyncMenuRoutes(menuID uint, routeMappingIDs []uint) error { |
|
||||||
s.log.Info("开始同步菜单路由关联", zap.Uint("menuID", menuID), zap.Any("routeMappingIDs", routeMappingIDs)) |
|
||||||
|
|
||||||
// 删除现有关联
|
|
||||||
if err := s.menuRouteRepo.DeleteByMenuID(menuID); err != nil { |
|
||||||
s.log.Error("删除现有菜单路由关联失败", zap.Error(err)) |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// 如果没有新的路由映射,直接返回
|
|
||||||
if len(routeMappingIDs) == 0 { |
|
||||||
s.log.Info("没有新的路由映射,同步完成") |
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// 创建新关联
|
|
||||||
var menuRoutes []*model.MenuRoute |
|
||||||
for i, routeID := range routeMappingIDs { |
|
||||||
menuRoute := &model.MenuRoute{ |
|
||||||
MenuID: menuID, |
|
||||||
RouteMappingID: routeID, |
|
||||||
Sort: i, |
|
||||||
IsDefault: i == 0, // 第一个设为默认
|
|
||||||
Status: 1, |
|
||||||
} |
|
||||||
menuRoutes = append(menuRoutes, menuRoute) |
|
||||||
} |
|
||||||
|
|
||||||
if err := s.menuRouteRepo.CreateBatch(menuRoutes); err != nil { |
|
||||||
s.log.Error("创建菜单路由关联失败", zap.Error(err)) |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
s.log.Info("菜单路由关联同步完成", zap.Int("关联数量", len(menuRoutes))) |
|
||||||
return nil |
|
||||||
} |
|
Loading…
Reference in new issue