1
0
Files
omc_api/features/sys_menu/service/service_sys_menu.go
2024-03-18 15:22:47 +08:00

409 lines
11 KiB
Go

package service
import (
"encoding/base64"
"strings"
"be.ems/features/sys_menu/consts"
"be.ems/features/sys_menu/model"
sysRoleService "be.ems/features/sys_role/service"
sysrolemenu "be.ems/features/sys_role_menu"
"be.ems/lib/core/utils/parse"
"be.ems/lib/core/utils/regular"
"be.ems/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
}