fix: 修复菜单挂载到根目录时路由加载异常等一系列相关问题
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import re
|
||||
from pydantic import BaseModel, ConfigDict, model_validator
|
||||
from pydantic.alias_generators import to_camel
|
||||
from typing import Optional
|
||||
from typing import Optional, List, Union
|
||||
from exceptions.exception import ModelValidatorException
|
||||
from module_admin.entity.vo.menu_vo import MenuModel
|
||||
|
||||
|
||||
class UserLogin(BaseModel):
|
||||
@@ -52,4 +53,31 @@ class SmsCode(BaseModel):
|
||||
is_success: Optional[bool] = None
|
||||
sms_code: str
|
||||
session_id: str
|
||||
message: Optional[str] = None
|
||||
message: Optional[str] = None
|
||||
|
||||
|
||||
class MenuTreeModel(MenuModel):
|
||||
children: Optional[Union[List['MenuTreeModel'], None]] = None
|
||||
|
||||
|
||||
class MetaModel(BaseModel):
|
||||
model_config = ConfigDict(alias_generator=to_camel)
|
||||
|
||||
title: Optional[str] = None
|
||||
icon: Optional[str] = None
|
||||
no_cache: Optional[bool] = None
|
||||
link: Optional[str] = None
|
||||
|
||||
|
||||
class RouterModel(BaseModel):
|
||||
model_config = ConfigDict(alias_generator=to_camel)
|
||||
|
||||
name: Optional[str] = None
|
||||
path: Optional[str] = None
|
||||
hidden: Optional[bool] = None
|
||||
redirect: Optional[str] = None
|
||||
component: Optional[str] = None
|
||||
query: Optional[str] = None
|
||||
always_show: Optional[bool] = None
|
||||
meta: Optional[MetaModel] = None
|
||||
children: Optional[Union[List['RouterModel'], None]] = None
|
||||
|
@@ -24,6 +24,7 @@ class CustomOAuth2PasswordRequestForm(OAuth2PasswordRequestForm):
|
||||
"""
|
||||
自定义OAuth2PasswordRequestForm类,增加验证码及会话编号参数
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
grant_type: str = Form(default=None, regex="password"),
|
||||
@@ -47,6 +48,7 @@ class LoginService:
|
||||
"""
|
||||
登录模块服务层
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
async def authenticate_user(cls, request: Request, query_db: AsyncSession, login_user: UserLogin):
|
||||
"""
|
||||
@@ -231,57 +233,95 @@ class LoginService:
|
||||
"""
|
||||
query_user = await UserDao.get_user_by_id(query_db, user_id=user_id)
|
||||
user_router_menu = sorted([row for row in query_user.get('user_menu_info') if row.menu_type in ['M', 'C']], key=lambda x: x.order_num)
|
||||
user_router = cls.__generate_user_router_menu(0, user_router_menu)
|
||||
return user_router
|
||||
menus = cls.__generate_menus(0, user_router_menu)
|
||||
user_router = cls.__generate_user_router_menu(menus)
|
||||
return [router.model_dump(exclude_unset=True, by_alias=True) for router in user_router]
|
||||
|
||||
@classmethod
|
||||
def __generate_user_router_menu(cls, pid: int, permission_list):
|
||||
def __generate_menus(cls, pid: int, permission_list: List[SysMenu]):
|
||||
"""
|
||||
工具方法:根据菜单信息生成路由信息树形嵌套数据
|
||||
工具方法:根据菜单信息生成菜单信息树形嵌套数据
|
||||
:param pid: 菜单id
|
||||
:param permission_list: 菜单列表信息
|
||||
:return: 路由信息树形嵌套数据
|
||||
:return: 菜单信息树形嵌套数据
|
||||
"""
|
||||
router_list = []
|
||||
menu_list: List[MenuTreeModel] = []
|
||||
for permission in permission_list:
|
||||
if permission.parent_id == pid:
|
||||
children = cls.__generate_user_router_menu(permission.menu_id, permission_list)
|
||||
router_list_data = {}
|
||||
if permission.menu_type == 'M':
|
||||
router_list_data['name'] = permission.path.capitalize()
|
||||
router_list_data['hidden'] = False if permission.visible == '0' else True
|
||||
if permission.parent_id == 0:
|
||||
router_list_data['component'] = 'Layout'
|
||||
router_list_data['path'] = f'/{permission.path}'
|
||||
else:
|
||||
router_list_data['component'] = 'ParentView'
|
||||
router_list_data['path'] = permission.path
|
||||
if permission.is_frame == 1:
|
||||
router_list_data['redirect'] = 'noRedirect'
|
||||
else:
|
||||
router_list_data['path'] = permission.path
|
||||
if children:
|
||||
router_list_data['alwaysShow'] = True
|
||||
router_list_data['children'] = children
|
||||
router_list_data['meta'] = {
|
||||
'title': permission.menu_name,
|
||||
'icon': permission.icon,
|
||||
'noCache': False if permission.is_cache == '0' else True,
|
||||
'link': permission.path if permission.is_frame == 0 else None
|
||||
}
|
||||
elif permission.menu_type == 'C':
|
||||
router_list_data['name'] = permission.path.capitalize()
|
||||
router_list_data['path'] = permission.path
|
||||
router_list_data['query'] = permission.query
|
||||
router_list_data['hidden'] = False if permission.visible == '0' else True
|
||||
router_list_data['component'] = permission.component
|
||||
router_list_data['meta'] = {
|
||||
'title': permission.menu_name,
|
||||
'icon': permission.icon,
|
||||
'noCache': False if permission.is_cache == '0' else True,
|
||||
'link': permission.path if permission.is_frame == 0 else None
|
||||
}
|
||||
router_list.append(router_list_data)
|
||||
children = cls.__generate_menus(permission.menu_id, permission_list)
|
||||
menu_list_data = MenuTreeModel(**CamelCaseUtil.transform_result(permission))
|
||||
if children:
|
||||
menu_list_data.children = children
|
||||
menu_list.append(menu_list_data)
|
||||
|
||||
return menu_list
|
||||
|
||||
@classmethod
|
||||
def __generate_user_router_menu(cls, permission_list: List[MenuTreeModel]):
|
||||
"""
|
||||
工具方法:根据菜单树信息生成路由信息树形嵌套数据
|
||||
:param permission_list: 菜单树列表信息
|
||||
:return: 路由信息树形嵌套数据
|
||||
"""
|
||||
router_list: List[RouterModel] = []
|
||||
for permission in permission_list:
|
||||
router = RouterModel(
|
||||
hidden=True if permission.visible == '1' else False,
|
||||
name=RouterUtil.get_router_name(permission),
|
||||
path=RouterUtil.get_router_path(permission),
|
||||
component=RouterUtil.get_component(permission),
|
||||
query=permission.query,
|
||||
meta=MetaModel(
|
||||
title=permission.menu_name,
|
||||
icon=permission.icon,
|
||||
noCache=True if permission.is_cache == 1 else False,
|
||||
link=permission.path if RouterUtil.is_http(permission.path) else None
|
||||
)
|
||||
)
|
||||
c_menus = permission.children
|
||||
if c_menus and permission.menu_type == 'M':
|
||||
router.always_show = True
|
||||
router.redirect = 'noRedirect'
|
||||
router.children = cls.__generate_user_router_menu(c_menus)
|
||||
elif RouterUtil.is_menu_frame(permission):
|
||||
router.meta = None
|
||||
children_list: List[RouterModel] = []
|
||||
children = RouterModel(
|
||||
path=permission.path,
|
||||
component=permission.component,
|
||||
name=permission.path.capitalize(),
|
||||
meta=MetaModel(
|
||||
title=permission.menu_name,
|
||||
icon=permission.icon,
|
||||
noCache=True if permission.is_cache == 1 else False,
|
||||
link=permission.path if RouterUtil.is_http(permission.path) else None
|
||||
),
|
||||
query=permission.query
|
||||
)
|
||||
children_list.append(children)
|
||||
router.children = children_list
|
||||
elif permission.parent_id == 0 and RouterUtil.is_inner_link(permission):
|
||||
router.meta = MetaModel(
|
||||
title=permission.menu_name,
|
||||
icon=permission.icon
|
||||
)
|
||||
router.path = '/'
|
||||
children_list: List[RouterModel] = []
|
||||
router_path = RouterUtil.inner_link_replace_each(permission.path)
|
||||
children = RouterModel(
|
||||
path=router_path,
|
||||
component='InnerLink',
|
||||
name=router_path.capitalize(),
|
||||
meta=MetaModel(
|
||||
title=permission.menu_name,
|
||||
icon=permission.icon,
|
||||
link=permission.path if RouterUtil.is_http(permission.path) else None
|
||||
)
|
||||
)
|
||||
children_list.append(children)
|
||||
router.children = children_list
|
||||
|
||||
router_list.append(router)
|
||||
|
||||
return router_list
|
||||
|
||||
@@ -386,3 +426,106 @@ class LoginService:
|
||||
# await request.app.state.redis.delete(f'{current_user.user.user_id}_session_id')
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class RouterUtil:
|
||||
"""
|
||||
路由处理工具类
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_router_name(cls, menu: MenuTreeModel):
|
||||
"""
|
||||
获取路由名称
|
||||
:param menu: 菜单数对象
|
||||
:return: 路由名称
|
||||
"""
|
||||
router_name = menu.path.capitalize()
|
||||
if cls.is_menu_frame(menu):
|
||||
router_name = ''
|
||||
|
||||
return router_name
|
||||
|
||||
@classmethod
|
||||
def get_router_path(cls, menu: MenuTreeModel):
|
||||
"""
|
||||
获取路由地址
|
||||
:param menu: 菜单数对象
|
||||
:return: 路由地址
|
||||
"""
|
||||
# 内链打开外网方式
|
||||
router_path = menu.path
|
||||
if menu.parent_id != 0 and cls.is_inner_link(menu):
|
||||
router_path = cls.inner_link_replace_each(router_path)
|
||||
# 非外链并且是一级目录(类型为目录)
|
||||
if menu.parent_id == 0 and menu.menu_type == 'M' and menu.is_frame == 1:
|
||||
router_path = f'/{menu.path}'
|
||||
# 非外链并且是一级目录(类型为菜单)
|
||||
elif cls.is_menu_frame(menu):
|
||||
router_path = '/'
|
||||
return router_path
|
||||
|
||||
@classmethod
|
||||
def get_component(cls, menu: MenuTreeModel):
|
||||
"""
|
||||
获取组件信息
|
||||
:param menu: 菜单数对象
|
||||
:return: 组件信息
|
||||
"""
|
||||
component = 'Layout'
|
||||
if menu.component and not cls.is_menu_frame(menu):
|
||||
component = menu.component
|
||||
elif menu.component and menu.parent_id != 0 and cls.is_inner_link(menu):
|
||||
component = 'InnerLink'
|
||||
elif menu.component and cls.is_parent_view(menu):
|
||||
component = 'ParentView'
|
||||
return component
|
||||
|
||||
@classmethod
|
||||
def is_menu_frame(cls, menu: MenuTreeModel):
|
||||
"""
|
||||
判断是否为菜单内部跳转
|
||||
:param menu: 菜单数对象
|
||||
:return: 是否为菜单内部跳转
|
||||
"""
|
||||
return menu.parent_id == 0 and menu.menu_type == 'C' and menu.is_frame == 1
|
||||
|
||||
@classmethod
|
||||
def is_inner_link(cls, menu: MenuTreeModel):
|
||||
"""
|
||||
判断是否为内链组件
|
||||
:param menu: 菜单数对象
|
||||
:return: 是否为内链组件
|
||||
"""
|
||||
return menu.is_frame == 1 and cls.is_http(menu.path)
|
||||
|
||||
@classmethod
|
||||
def is_parent_view(cls, menu: MenuTreeModel):
|
||||
"""
|
||||
判断是否为parent_view组件
|
||||
:param menu: 菜单数对象
|
||||
:return: 是否为parent_view组件
|
||||
"""
|
||||
return menu.parent_id != 0 and menu.menu_type == 'M'
|
||||
|
||||
@classmethod
|
||||
def is_http(cls, link: str):
|
||||
"""
|
||||
判断是否为http(s)://开头
|
||||
:param link: 链接
|
||||
:return: 是否为http(s)://开头
|
||||
"""
|
||||
return link.startswith('http://') or link.startswith('https://')
|
||||
|
||||
@classmethod
|
||||
def inner_link_replace_each(cls, path: str):
|
||||
"""
|
||||
内链域名特殊字符替换
|
||||
:param path: 内链域名
|
||||
:return: 替换后的内链域名
|
||||
"""
|
||||
old_values = ["http://", "https://", "www.", ".", ":"]
|
||||
new_values = ["", "", "", "/", "/"]
|
||||
for old, new in zip(old_values, new_values):
|
||||
path = path.replace(old, new)
|
||||
return path
|
||||
|
Reference in New Issue
Block a user