409 lines
11 KiB
Go
409 lines
11 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"strings"
|
|
|
|
"ems.agt/features/sys_menu/consts"
|
|
"ems.agt/features/sys_menu/model"
|
|
sysRoleService "ems.agt/features/sys_role/service"
|
|
sysrolemenu "ems.agt/features/sys_role_menu"
|
|
"ems.agt/lib/core/utils/parse"
|
|
"ems.agt/lib/core/utils/regular"
|
|
"ems.agt/lib/core/vo"
|
|
)
|
|
|
|
// 实例化服务层 ServiceSysMenu 结构体
|
|
var NewServiceSysMenu = &ServiceSysMenu{
|
|
sysMenuRepository: NewRepoSysMenu,
|
|
sysRoleMenuRepository: sysrolemenu.NewRepoSysRoleMenu,
|
|
sysRoleRepository: sysRoleService.NewRepoSysRole,
|
|
}
|
|
|
|
// ServiceSysMenu 菜单 服务层处理
|
|
type ServiceSysMenu struct {
|
|
// 菜单服务
|
|
sysMenuRepository *RepoSysMenu
|
|
// 角色与菜单关联服务
|
|
sysRoleMenuRepository *sysrolemenu.RepoSysRoleMenu
|
|
// 角色服务
|
|
sysRoleRepository *sysRoleService.RepoSysRole
|
|
}
|
|
|
|
// SelectMenuList 查询系统菜单列表
|
|
func (r *ServiceSysMenu) SelectMenuList(sysMenu model.SysMenu, userId string) []model.SysMenu {
|
|
return r.sysMenuRepository.SelectMenuList(sysMenu, userId)
|
|
}
|
|
|
|
// SelectMenuPermsByUserId 根据用户ID查询权限
|
|
func (r *ServiceSysMenu) SelectMenuPermsByUserId(userId string) []string {
|
|
return r.sysMenuRepository.SelectMenuPermsByUserId(userId)
|
|
}
|
|
|
|
// SelectMenuTreeByUserId 根据用户ID查询菜单
|
|
func (r *ServiceSysMenu) SelectMenuTreeByUserId(userId string) []model.SysMenu {
|
|
sysMenus := r.sysMenuRepository.SelectMenuTreeByUserId(userId)
|
|
return r.parseDataToTree(sysMenus)
|
|
}
|
|
|
|
// SelectMenuTreeSelectByUserId 根据用户ID查询菜单树结构信息
|
|
func (r *ServiceSysMenu) SelectMenuTreeSelectByUserId(sysMenu model.SysMenu, userId string) []vo.TreeSelect {
|
|
sysMenus := r.sysMenuRepository.SelectMenuList(sysMenu, userId)
|
|
|
|
// 过滤旧前端菜单
|
|
sysMenusF := []model.SysMenu{}
|
|
for _, v := range sysMenus {
|
|
if v.Perms != "page" {
|
|
continue
|
|
}
|
|
sysMenusF = append(sysMenusF, v)
|
|
}
|
|
|
|
menus := r.parseDataToTree(sysMenusF)
|
|
tree := make([]vo.TreeSelect, 0)
|
|
for _, menu := range menus {
|
|
tree = append(tree, sysMenuTreeSelect(menu))
|
|
}
|
|
return tree
|
|
}
|
|
|
|
// sysMenuTreeSelect 使用给定的 SysMenu 对象解析为 TreeSelect 对象
|
|
func sysMenuTreeSelect(sysMenu model.SysMenu) vo.TreeSelect {
|
|
t := vo.TreeSelect{}
|
|
t.ID = sysMenu.MenuID
|
|
t.Label = sysMenu.MenuName
|
|
t.Title = sysMenu.MenuName
|
|
|
|
if len(sysMenu.Children) > 0 {
|
|
for _, menu := range sysMenu.Children {
|
|
child := sysMenuTreeSelect(menu)
|
|
t.Children = append(t.Children, child)
|
|
}
|
|
} else {
|
|
t.Children = []vo.TreeSelect{}
|
|
}
|
|
|
|
return t
|
|
}
|
|
|
|
// SelectMenuListByRoleId 根据角色ID查询菜单树信息 TODO
|
|
func (r *ServiceSysMenu) SelectMenuListByRoleId(roleId string) []string {
|
|
roles := r.sysRoleRepository.SelectRoleByIds([]string{roleId})
|
|
if len(roles) > 0 {
|
|
role := roles[0]
|
|
if role.RoleID == roleId {
|
|
return r.sysMenuRepository.SelectMenuListByRoleId(
|
|
role.RoleID,
|
|
role.MenuCheckStrictly == "1",
|
|
)
|
|
}
|
|
}
|
|
return []string{}
|
|
}
|
|
|
|
// SelectMenuById 根据菜单ID查询信息
|
|
func (r *ServiceSysMenu) SelectMenuById(menuId string) model.SysMenu {
|
|
if menuId == "" {
|
|
return model.SysMenu{}
|
|
}
|
|
menus := r.sysMenuRepository.SelectMenuByIds([]string{menuId})
|
|
if len(menus) > 0 {
|
|
return menus[0]
|
|
}
|
|
return model.SysMenu{}
|
|
}
|
|
|
|
// HasChildByMenuIdAndStatus 存在菜单子节点数量与状态
|
|
func (r *ServiceSysMenu) HasChildByMenuIdAndStatus(menuId, status string) int64 {
|
|
return r.sysMenuRepository.HasChildByMenuIdAndStatus(menuId, status)
|
|
}
|
|
|
|
// CheckMenuExistRole 查询菜单是否存在角色
|
|
func (r *ServiceSysMenu) CheckMenuExistRole(menuId string) int64 {
|
|
return r.sysRoleMenuRepository.CheckMenuExistRole(menuId)
|
|
}
|
|
|
|
// InsertMenu 新增菜单信息
|
|
func (r *ServiceSysMenu) InsertMenu(sysMenu model.SysMenu) string {
|
|
return r.sysMenuRepository.InsertMenu(sysMenu)
|
|
}
|
|
|
|
// UpdateMenu 修改菜单信息
|
|
func (r *ServiceSysMenu) UpdateMenu(sysMenu model.SysMenu) int64 {
|
|
return r.sysMenuRepository.UpdateMenu(sysMenu)
|
|
}
|
|
|
|
// DeleteMenuById 删除菜单管理信息
|
|
func (r *ServiceSysMenu) DeleteMenuById(menuId string) int64 {
|
|
// 删除菜单与角色关联
|
|
r.sysRoleMenuRepository.DeleteMenuRole([]string{menuId})
|
|
return r.sysMenuRepository.DeleteMenuById(menuId)
|
|
}
|
|
|
|
// CheckUniqueMenuName 校验菜单名称是否唯一
|
|
func (r *ServiceSysMenu) CheckUniqueMenuName(menuName, parentId, menuId string) bool {
|
|
uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{
|
|
MenuName: menuName,
|
|
ParentID: parentId,
|
|
})
|
|
if uniqueId == menuId {
|
|
return true
|
|
}
|
|
return uniqueId == ""
|
|
}
|
|
|
|
// CheckUniqueMenuPath 校验路由地址是否唯一(针对目录和菜单)
|
|
func (r *ServiceSysMenu) CheckUniqueMenuPath(path, menuId string) bool {
|
|
uniqueId := r.sysMenuRepository.CheckUniqueMenu(model.SysMenu{
|
|
Path: path,
|
|
})
|
|
if uniqueId == menuId {
|
|
return true
|
|
}
|
|
return uniqueId == ""
|
|
}
|
|
|
|
// BuildRouteMenus 构建前端路由所需要的菜单
|
|
func (r *ServiceSysMenu) BuildRouteMenus(sysMenus []model.SysMenu, prefix string) []vo.Router {
|
|
routers := []vo.Router{}
|
|
for _, item := range sysMenus {
|
|
router := vo.Router{}
|
|
router.Name = r.getRouteName(item)
|
|
router.Path = r.getRouterPath(item)
|
|
router.Component = r.getComponent(item)
|
|
router.Meta = r.getRouteMeta(item)
|
|
|
|
// 子项菜单 目录类型 非路径链接
|
|
cMenus := item.Children
|
|
if len(cMenus) > 0 && item.MenuType == consts.TYPE_DIR && !regular.ValidHttp(item.Path) {
|
|
// 获取重定向地址
|
|
redirectPrefix, redirectPath := r.getRouteRedirect(
|
|
cMenus,
|
|
router.Path,
|
|
prefix,
|
|
)
|
|
router.Redirect = redirectPath
|
|
// 子菜单进入递归
|
|
router.Children = r.BuildRouteMenus(cMenus, redirectPrefix)
|
|
} else if item.ParentID == "0" && item.IsFrame == "1" && item.MenuType == consts.TYPE_MENU {
|
|
// 父菜单 内部跳转 菜单类型
|
|
menuPath := "/" + item.MenuID
|
|
childPath := menuPath + r.getRouterPath(item)
|
|
children := vo.Router{
|
|
Name: r.getRouteName(item),
|
|
Path: childPath,
|
|
Component: item.Component,
|
|
Meta: r.getRouteMeta(item),
|
|
}
|
|
router.Meta.HideChildInMenu = true
|
|
router.Children = append(router.Children, children)
|
|
router.Name = item.MenuID
|
|
router.Path = menuPath
|
|
router.Redirect = childPath
|
|
router.Component = consts.COMPONENT_LAYOUT_BASIC
|
|
} else if item.ParentID == "0" && item.IsFrame == "1" && regular.ValidHttp(item.Path) {
|
|
// 父菜单 内部跳转 路径链接
|
|
menuPath := "/" + item.MenuID
|
|
childPath := menuPath + r.getRouterPath(item)
|
|
children := vo.Router{
|
|
Name: r.getRouteName(item),
|
|
Path: childPath,
|
|
Component: consts.COMPONENT_LAYOUT_LINK,
|
|
Meta: r.getRouteMeta(item),
|
|
}
|
|
router.Meta.HideChildInMenu = true
|
|
router.Children = append(router.Children, children)
|
|
router.Name = item.MenuID
|
|
router.Path = menuPath
|
|
router.Redirect = childPath
|
|
router.Component = consts.COMPONENT_LAYOUT_BASIC
|
|
}
|
|
|
|
routers = append(routers, router)
|
|
}
|
|
return routers
|
|
}
|
|
|
|
// getRouteName 获取路由名称 路径英文首字母大写
|
|
func (r *ServiceSysMenu) getRouteName(sysMenu model.SysMenu) string {
|
|
routerName := parse.FirstUpper(sysMenu.Path)
|
|
// 路径链接
|
|
if regular.ValidHttp(sysMenu.Path) {
|
|
return routerName[:5] + "Link" + sysMenu.MenuID
|
|
}
|
|
return routerName
|
|
}
|
|
|
|
// getRouterPath 获取路由地址
|
|
func (r *ServiceSysMenu) getRouterPath(sysMenu model.SysMenu) string {
|
|
routerPath := sysMenu.Path
|
|
|
|
// 显式路径
|
|
if routerPath == "" || strings.HasPrefix(routerPath, "/") {
|
|
return routerPath
|
|
}
|
|
|
|
// 路径链接 内部跳转
|
|
if regular.ValidHttp(routerPath) && sysMenu.IsFrame == "1" {
|
|
routerPath = regular.Replace(routerPath, `/^http(s)?:\/\/+/`, "")
|
|
routerPath = base64.StdEncoding.EncodeToString([]byte(routerPath))
|
|
}
|
|
|
|
// 父菜单 内部跳转
|
|
if sysMenu.ParentID == "0" && sysMenu.IsFrame == "1" {
|
|
routerPath = "/" + routerPath
|
|
}
|
|
|
|
return routerPath
|
|
}
|
|
|
|
// getComponent 获取组件信息
|
|
func (r *ServiceSysMenu) getComponent(sysMenu model.SysMenu) string {
|
|
// 内部跳转 路径链接
|
|
if sysMenu.IsFrame == "1" && regular.ValidHttp(sysMenu.Path) {
|
|
return consts.COMPONENT_LAYOUT_LINK
|
|
}
|
|
|
|
// 非父菜单 目录类型
|
|
if sysMenu.ParentID != "0" && sysMenu.MenuType == consts.TYPE_DIR {
|
|
return consts.COMPONENT_LAYOUT_BLANK
|
|
}
|
|
|
|
// 组件路径 内部跳转 菜单类型
|
|
if sysMenu.Component != "" && sysMenu.IsFrame == "1" && sysMenu.MenuType == consts.TYPE_MENU {
|
|
// 父菜单套外层布局
|
|
if sysMenu.ParentID == "0" {
|
|
return consts.COMPONENT_LAYOUT_BASIC
|
|
}
|
|
return sysMenu.Component
|
|
}
|
|
|
|
return consts.COMPONENT_LAYOUT_BASIC
|
|
}
|
|
|
|
// getRouteMeta 获取路由元信息
|
|
func (r *ServiceSysMenu) getRouteMeta(sysMenu model.SysMenu) vo.RouterMeta {
|
|
meta := vo.RouterMeta{}
|
|
if sysMenu.Icon == "#" {
|
|
meta.Icon = ""
|
|
} else {
|
|
meta.Icon = sysMenu.Icon
|
|
}
|
|
meta.Title = sysMenu.MenuName
|
|
meta.HideChildInMenu = false
|
|
meta.HideInMenu = sysMenu.Visible == "0"
|
|
meta.Cache = sysMenu.IsCache == "1"
|
|
meta.Target = ""
|
|
|
|
// 路径链接 非内部跳转
|
|
if regular.ValidHttp(sysMenu.Path) && sysMenu.IsFrame == "0" {
|
|
meta.Target = "_blank"
|
|
}
|
|
|
|
return meta
|
|
}
|
|
|
|
// getRouteRedirect 获取路由重定向地址(针对目录)
|
|
//
|
|
// cMenus 子菜单数组
|
|
// routerPath 当前菜单路径
|
|
// prefix 菜单重定向路径前缀
|
|
func (r *ServiceSysMenu) getRouteRedirect(cMenus []model.SysMenu, routerPath string, prefix string) (string, string) {
|
|
redirectPath := ""
|
|
|
|
// 重定向为首个显示并启用的子菜单
|
|
var firstChild *model.SysMenu
|
|
for _, item := range cMenus {
|
|
if item.IsFrame == "1" && item.Visible == "1" {
|
|
firstChild = &item
|
|
break
|
|
}
|
|
}
|
|
|
|
// 检查内嵌隐藏菜单是否可做重定向
|
|
if firstChild == nil {
|
|
for _, item := range cMenus {
|
|
if item.IsFrame == "1" && item.Visible == "1" && strings.Contains(item.Path, consts.PATH_INLINE) {
|
|
firstChild = &item
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if firstChild != nil {
|
|
firstChildPath := r.getRouterPath(*firstChild)
|
|
if strings.HasPrefix(firstChildPath, "/") {
|
|
redirectPath = firstChildPath
|
|
} else {
|
|
// 拼接追加路径
|
|
if !strings.HasPrefix(routerPath, "/") {
|
|
prefix += "/"
|
|
}
|
|
prefix = prefix + routerPath
|
|
redirectPath = prefix + "/" + firstChildPath
|
|
}
|
|
}
|
|
|
|
return prefix, redirectPath
|
|
}
|
|
|
|
// parseDataToTree 将数据解析为树结构,构建前端所需要下拉树结构
|
|
func (r *ServiceSysMenu) parseDataToTree(sysMenus []model.SysMenu) []model.SysMenu {
|
|
// 节点分组
|
|
nodesMap := make(map[string][]model.SysMenu)
|
|
// 节点id
|
|
treeIds := []string{}
|
|
// 树节点
|
|
tree := []model.SysMenu{}
|
|
|
|
for _, item := range sysMenus {
|
|
parentID := item.ParentID
|
|
// 分组
|
|
mapItem, ok := nodesMap[parentID]
|
|
if !ok {
|
|
mapItem = []model.SysMenu{}
|
|
}
|
|
mapItem = append(mapItem, item)
|
|
nodesMap[parentID] = mapItem
|
|
// 记录节点ID
|
|
treeIds = append(treeIds, item.MenuID)
|
|
}
|
|
|
|
for key, value := range nodesMap {
|
|
// 选择不是节点ID的作为树节点
|
|
found := false
|
|
for _, id := range treeIds {
|
|
if id == key {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
tree = append(tree, value...)
|
|
}
|
|
}
|
|
|
|
for i, node := range tree {
|
|
iN := r.parseDataToTreeComponet(node, &nodesMap)
|
|
tree[i] = iN
|
|
}
|
|
|
|
return tree
|
|
}
|
|
|
|
// parseDataToTreeComponet 递归函数处理子节点
|
|
func (r *ServiceSysMenu) parseDataToTreeComponet(node model.SysMenu, nodesMap *map[string][]model.SysMenu) model.SysMenu {
|
|
id := node.MenuID
|
|
children, ok := (*nodesMap)[id]
|
|
if ok {
|
|
node.Children = children
|
|
}
|
|
if len(node.Children) > 0 {
|
|
for i, child := range node.Children {
|
|
icN := r.parseDataToTreeComponet(child, nodesMap)
|
|
node.Children[i] = icN
|
|
}
|
|
}
|
|
return node
|
|
}
|