package sysmenu import ( "fmt" "net/http" "be.ems/features/sys_menu/consts" "be.ems/features/sys_menu/model" "be.ems/features/sys_menu/service" "be.ems/lib/core/utils/ctx" "be.ems/lib/core/utils/regular" "be.ems/lib/core/vo/result" "be.ems/lib/midware" "be.ems/lib/services" "be.ems/restagent/config" srcConfig "be.ems/src/framework/config" ) // 菜单接口添加到路由 func Routers() []services.RouterItem { // 实例化控制层 SysMenuApi 结构体 var apis = &SysMenuApi{ sysMenuService: service.NewServiceSysMenu, } rs := [...]services.RouterItem{ { Method: "GET", Pattern: "/menus", Handler: apis.List, Middleware: midware.Authorize(nil), }, { Method: "GET", Pattern: "/menu/{menuId}", Handler: apis.Info, Middleware: midware.Authorize(nil), }, { Method: "POST", Pattern: "/menu", Handler: apis.Add, Middleware: midware.Authorize(nil), }, { Method: "PUT", Pattern: "/menu", Handler: apis.Edit, Middleware: midware.Authorize(nil), }, { Method: "DELETE", Pattern: "/menu/{menuId}", Handler: apis.Remove, Middleware: midware.Authorize(nil), }, { Method: "GET", Pattern: "/menus/treeSelect", Handler: apis.TreeSelect, Middleware: midware.Authorize(nil), }, { Method: "GET", Pattern: "/menu/roleMenuTreeSelect/{roleId}", Handler: apis.RoleMenuTreeSelect, Middleware: midware.Authorize(nil), }, // 添加更多的 Router 对象... } // 生成两组前缀路由 rsPrefix := []services.RouterItem{} for _, v := range rs { path := "/menuManage/{apiVersion}" + v.Pattern // 固定前缀 v.Pattern = config.DefaultUriPrefix + path rsPrefix = append(rsPrefix, v) // 可配置 v.Pattern = config.UriPrefix + path rsPrefix = append(rsPrefix, v) } return rsPrefix } // // 实例化控制层 SysMenuApi 结构体 // var NewSysMenu = &SysMenuApi{ // sysMenuService: NewServiceSysMenu, // } // 菜单信息 // // PATH /menuManage type SysMenuApi struct { // 菜单服务 sysMenuService *service.ServiceSysMenu } // 菜单列表 // // GET /list func (s *SysMenuApi) List(w http.ResponseWriter, r *http.Request) { query := model.SysMenu{} if v := ctx.GetQuery(r, "menuName"); v != "" { query.MenuName = v } if v := ctx.GetQuery(r, "status"); v != "" { query.Status = v } userId := ctx.LoginUserToUserID(r) if srcConfig.IsAdmin(userId) { userId = "*" } data := s.sysMenuService.SelectMenuList(query, userId) ctx.JSON(w, 200, result.OkData(data)) } // 菜单信息 // // GET /:menuId func (s *SysMenuApi) Info(w http.ResponseWriter, r *http.Request) { menuId := ctx.Param(r, "menuId") if menuId == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } data := s.sysMenuService.SelectMenuById(menuId) if data.MenuID == menuId { ctx.JSON(w, 200, result.OkData(data)) return } ctx.JSON(w, 200, result.Err(nil)) } // 菜单新增 // // POST / func (s *SysMenuApi) Add(w http.ResponseWriter, r *http.Request) { var body model.SysMenu err := ctx.ShouldBindJSON(r, &body) if err != nil || body.MenuID != "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } // 目录和菜单检查地址唯一 if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType { uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, "") if !uniqueNenuPath { msg := fmt.Sprintf("菜单新增【%s】失败,菜单路由地址已存在", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } } // 检查名称唯一 uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, "") if !uniqueNenuName { msg := fmt.Sprintf("菜单新增【%s】失败,菜单名称已存在", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } // 外链菜单需要符合网站http(s)开头 if body.IsFrame == "0" && !regular.ValidHttp(body.Path) { msg := fmt.Sprintf("菜单新增【%s】失败,非内部地址必须以http(s)://开头", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } body.CreateBy = ctx.LoginUserToUserName(r) insertId := s.sysMenuService.InsertMenu(body) if insertId != "" { ctx.JSON(w, 200, result.Ok(nil)) return } ctx.JSON(w, 200, result.Err(nil)) } // 菜单修改 // // PUT / func (s *SysMenuApi) Edit(w http.ResponseWriter, r *http.Request) { var body model.SysMenu err := ctx.ShouldBindJSON(r, &body) if err != nil || body.MenuID == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } // 上级菜单不能选自己 if body.MenuID == body.ParentID { msg := fmt.Sprintf("Menu modification failed for [%s], parent menu cannot select itself", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } // 检查数据是否存在 menuInfo := s.sysMenuService.SelectMenuById(body.MenuID) if menuInfo.MenuID != body.MenuID { ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data")) return } // 父级ID不为0是要检查 if body.ParentID != "0" { menuParent := s.sysMenuService.SelectMenuById(body.ParentID) if menuParent.MenuID != body.ParentID { ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data")) return } // 禁用菜单时检查父菜单是否使用 if body.Status == "1" && menuParent.Status == "0" { ctx.JSON(w, 200, result.ErrMsg("Parent menu not enabled!")) return } } // 目录和菜单检查地址唯一 if consts.TYPE_DIR == body.MenuType || consts.TYPE_MENU == body.MenuType { uniqueNenuPath := s.sysMenuService.CheckUniqueMenuPath(body.Path, body.MenuID) if !uniqueNenuPath { msg := fmt.Sprintf("菜单修改【%s】失败,菜单路由地址已存在", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } } // 检查名称唯一 uniqueNenuName := s.sysMenuService.CheckUniqueMenuName(body.MenuName, body.ParentID, body.MenuID) if !uniqueNenuName { msg := fmt.Sprintf("菜单修改【%s】失败,菜单名称已存在", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } // 外链菜单需要符合网站http(s)开头 if body.IsFrame == "0" && !regular.ValidHttp(body.Path) { msg := fmt.Sprintf("菜单修改【%s】失败,非内部地址必须以http(s)://开头", body.MenuName) ctx.JSON(w, 200, result.ErrMsg(msg)) return } // 禁用菜单时检查子菜单是否使用 if body.Status == "0" { hasStatus := s.sysMenuService.HasChildByMenuIdAndStatus(body.MenuID, "1") if hasStatus > 0 { msg := fmt.Sprintf("不允许禁用,存在使用子菜单数:%d", hasStatus) ctx.JSON(w, 200, result.ErrMsg(msg)) return } } body.UpdateBy = ctx.LoginUserToUserName(r) rows := s.sysMenuService.UpdateMenu(body) if rows > 0 { ctx.JSON(w, 200, result.Ok(nil)) return } ctx.JSON(w, 200, result.Err(nil)) } // 菜单删除 // // DELETE /:menuId func (s *SysMenuApi) Remove(w http.ResponseWriter, r *http.Request) { menuId := ctx.Param(r, "menuId") if menuId == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } // 检查数据是否存在 menu := s.sysMenuService.SelectMenuById(menuId) if menu.MenuID != menuId { ctx.JSON(w, 200, result.ErrMsg("No permission to access menu data!")) return } // 检查是否存在子菜单 hasChild := s.sysMenuService.HasChildByMenuIdAndStatus(menuId, "") if hasChild > 0 { msg := fmt.Sprintf("Deletion not allowed, there are sub orders: %d", hasChild) ctx.JSON(w, 200, result.ErrMsg(msg)) return } // 检查是否分配给角色 existRole := s.sysMenuService.CheckMenuExistRole(menuId) if existRole > 0 { msg := fmt.Sprintf("Deletion not allowed, menu already assigned to roles: %d", existRole) ctx.JSON(w, 200, result.ErrMsg(msg)) return } rows := s.sysMenuService.DeleteMenuById(menuId) if rows > 0 { msg := fmt.Sprintf("Successfully deleted: %d", rows) ctx.JSON(w, 200, result.OkMsg(msg)) return } ctx.JSON(w, 200, result.Err(nil)) } // 菜单树结构列表 // // GET /treeSelect func (s *SysMenuApi) TreeSelect(w http.ResponseWriter, r *http.Request) { query := model.SysMenu{} if v := ctx.GetQuery(r, "menuName"); v != "" { query.MenuName = v } if v := ctx.GetQuery(r, "status"); v != "" { query.Status = v } userId := ctx.LoginUserToUserID(r) if srcConfig.IsAdmin(userId) { userId = "*" } data := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId) ctx.JSON(w, 200, result.OkData(data)) } // 菜单树结构列表(指定角色) // // GET /roleMenuTreeSelect/:roleId func (s *SysMenuApi) RoleMenuTreeSelect(w http.ResponseWriter, r *http.Request) { roleId := ctx.Param(r, "roleId") if roleId == "" { ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } query := model.SysMenu{} if v := ctx.GetQuery(r, "menuName"); v != "" { query.MenuName = v } if v := ctx.GetQuery(r, "status"); v != "" { query.Status = v } userId := ctx.LoginUserToUserID(r) if srcConfig.IsAdmin(userId) { userId = "*" } menuTreeSelect := s.sysMenuService.SelectMenuTreeSelectByUserId(query, userId) checkedKeys := s.sysMenuService.SelectMenuListByRoleId(roleId) ctx.JSON(w, 200, result.OkData(map[string]any{ "menus": menuTreeSelect, "checkedKeys": checkedKeys, })) }