fix: 基于实际用户拥有菜单返回tree

main
NoahLan 4 months ago
parent 94010c8c2b
commit 269d453e07

@ -1,6 +1,6 @@
import copy import copy
from apiflask import APIBlueprint from apiflask import APIBlueprint
from flask_jwt_extended import jwt_required from flask_jwt_extended import jwt_required, current_user
from iti.applications.common.exceptions.biz_exp import BizException from iti.applications.common.exceptions.biz_exp import BizException
from iti.applications.extensions import db from iti.applications.extensions import db
from iti.applications.models import SysMenu, sys_role_menu from iti.applications.models import SysMenu, sys_role_menu
@ -10,7 +10,7 @@ from iti.applications.routes.sys.schemas.menu import (
MenuUpdateRequest, MenuUpdateRequest,
MenuExistsRequest, MenuExistsRequest,
) )
from iti.applications.service.sys_menu import get_menu_tree from iti.applications.service.sys_menu import get_menu_tree, get_user_menu_ids
from iti.applications.models import SysMenuSchema from iti.applications.models import SysMenuSchema
from iti.applications.common.enums import MenuTypeEnum from iti.applications.common.enums import MenuTypeEnum
from sqlalchemy import select, delete, func, exists from sqlalchemy import select, delete, func, exists
@ -40,7 +40,10 @@ def get_menu_tree_api():
过滤条件 过滤条件
- 状态为启用 - 状态为启用
- 类型为非按钮 - 类型为非按钮
- 基于当前用户实际拥有的菜单
""" """
# 获取当前用户拥有的菜单ID
user_menu_ids = get_user_menu_ids(current_user.id)
return success( return success(
get_menu_tree( get_menu_tree(
type_filter=[ type_filter=[
@ -48,7 +51,8 @@ def get_menu_tree_api():
MenuTypeEnum.CATALOG, MenuTypeEnum.CATALOG,
MenuTypeEnum.EMBEDDED, MenuTypeEnum.EMBEDDED,
MenuTypeEnum.LINK, MenuTypeEnum.LINK,
] ],
user_menu_ids=user_menu_ids,
) )
) )

@ -1,13 +1,31 @@
from sqlalchemy.orm import noload from sqlalchemy.orm import noload
from sqlalchemy.sql._typing import ColumnExpressionArgument from sqlalchemy.sql._typing import ColumnExpressionArgument
from typing import List, Dict, Any, Optional from typing import List, Dict, Any, Optional, Set
from iti.applications.extensions import db from iti.applications.extensions import db
from iti.applications.models import SysMenu from iti.applications.models import SysMenu
from iti.applications.models.sys_rel_role_menu import sys_role_menu
from iti.applications.models.sys_rel_user_role import sys_user_role
from iti.applications.common.enums import StatusEnum, MenuTypeEnum from iti.applications.common.enums import StatusEnum, MenuTypeEnum
from iti.applications.common.utils import ( from iti.applications.common.utils import (
build_tree_from_list, build_tree_from_list,
) )
from sqlalchemy import select from sqlalchemy import select, distinct
def get_user_menu_ids(user_id: str) -> Set[str]:
"""
获取用户拥有的所有菜单ID通过角色关联
Args:
user_id: 用户ID
Returns:
用户拥有的菜单ID集合
"""
menu_ids = db.session.scalars(
select(distinct(sys_role_menu.c.menu_id))
.join(sys_user_role, sys_role_menu.c.role_id == sys_user_role.c.role_id)
.filter(sys_user_role.c.user_id == user_id)
).all()
return set(menu_ids)
def get_menu_tree( def get_menu_tree(
@ -15,6 +33,7 @@ def get_menu_tree(
include_disabled: bool = True, include_disabled: bool = True,
type_filter: Optional[List[MenuTypeEnum]] = None, type_filter: Optional[List[MenuTypeEnum]] = None,
status_filter: Optional[List[StatusEnum]] = None, status_filter: Optional[List[StatusEnum]] = None,
user_menu_ids: Optional[Set[str]] = None,
) -> List[Dict[str, Any]]: ) -> List[Dict[str, Any]]:
""" """
获取菜单树 获取菜单树
@ -23,6 +42,7 @@ def get_menu_tree(
include_disabled: 是否包含禁用菜单 include_disabled: 是否包含禁用菜单
type_filter: 菜单类型过滤 不填为不限制 type_filter: 菜单类型过滤 不填为不限制
status_filter: 状态过滤 不填为不限制 status_filter: 状态过滤 不填为不限制
user_menu_ids: 用户拥有的菜单ID集合用于过滤用户实际拥有的菜单
""" """
# 获取所有菜单数据 # 获取所有菜单数据
cte_query = build_descendants_cte(SysMenu.parent_id == parent_id) cte_query = build_descendants_cte(SysMenu.parent_id == parent_id)
@ -32,6 +52,8 @@ def get_menu_tree(
cte_query = cte_query.filter(SysMenu.type.in_(type_filter)) cte_query = cte_query.filter(SysMenu.type.in_(type_filter))
if status_filter: if status_filter:
cte_query = cte_query.filter(SysMenu.status.in_(status_filter)) cte_query = cte_query.filter(SysMenu.status.in_(status_filter))
if user_menu_ids is not None:
cte_query = cte_query.filter(SysMenu.id.in_(user_menu_ids))
cte_query = cte_query.order_by(SysMenu.parent_id, SysMenu.sort).options( cte_query = cte_query.order_by(SysMenu.parent_id, SysMenu.sort).options(
noload(SysMenu.parent), noload(SysMenu.children) noload(SysMenu.parent), noload(SysMenu.children)
) )

Loading…
Cancel
Save