diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index 3baa142..d47f30a 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -1,47 +1,72 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService -from module_admin.service.menu_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.login_service import LoginService +from module_admin.service.menu_service import MenuService +from utils.log_util import logger +from utils.response_util import ResponseUtil menuController = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginService.get_current_user)]) -@menuController.get("/treeselect") -async def get_system_menu_tree(request: Request, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@menuController.get('/treeselect') +async def get_system_menu_tree( + request: Request, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user) logger.info('获取成功') return ResponseUtil.success(data=menu_query_result) -@menuController.get("/roleMenuTreeselect/{role_id}") -async def get_system_role_menu_tree(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@menuController.get('/roleMenuTreeselect/{role_id}') +async def get_system_role_menu_tree( + request: Request, + role_id: int, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user) logger.info('获取成功') return ResponseUtil.success(model_content=role_menu_query_result) -@menuController.get("/list", response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))]) -async def get_system_menu_list(request: Request, menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@menuController.get( + '/list', response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))] +) +async def get_system_menu_list( + request: Request, + menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user) logger.info('获取成功') return ResponseUtil.success(data=menu_query_result) -@menuController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) +@menuController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) @ValidateFields(validate_model='add_menu') @log_decorator(title='菜单管理', business_type=BusinessType.INSERT) -async def add_system_menu(request: Request, add_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_menu( + request: Request, + add_menu: MenuModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_menu.create_by = current_user.user.user_name add_menu.create_time = datetime.now() add_menu.update_by = current_user.user.user_name @@ -52,10 +77,15 @@ async def add_system_menu(request: Request, add_menu: MenuModel, query_db: Async return ResponseUtil.success(msg=add_menu_result.message) -@menuController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) +@menuController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) @ValidateFields(validate_model='edit_menu') @log_decorator(title='菜单管理', business_type=BusinessType.UPDATE) -async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_menu( + request: Request, + edit_menu: MenuModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_menu.update_by = current_user.user.user_name edit_menu.update_time = datetime.now() edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu) @@ -64,7 +94,7 @@ async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: Asy return ResponseUtil.success(msg=edit_menu_result.message) -@menuController.delete("/{menu_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) +@menuController.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) @log_decorator(title='菜单管理', business_type=BusinessType.DELETE) async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)): delete_menu = DeleteMenuModel(menuIds=menu_ids) @@ -74,7 +104,9 @@ async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_menu_result.message) -@menuController.get("/{menu_id}", response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))]) +@menuController.get( + '/{menu_id}', response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))] +) async def query_detail_system_menu(request: Request, menu_id: int, query_db: AsyncSession = Depends(get_db)): menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id) logger.info(f'获取menu_id为{menu_id}的信息成功') diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index dfa9ca2..223b84e 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -1,9 +1,9 @@ -from sqlalchemy import select, update, delete, and_, func +from sqlalchemy import and_, delete, func, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.menu_do import SysMenu -from module_admin.entity.do.user_do import SysUser, SysUserRole from module_admin.entity.do.role_do import SysRole, SysRoleMenu -from module_admin.entity.vo.menu_vo import * +from module_admin.entity.do.user_do import SysUser, SysUserRole +from module_admin.entity.vo.menu_vo import MenuModel, MenuQueryModel class MenuDao: @@ -19,10 +19,7 @@ class MenuDao: :param menu_id: 菜单id :return: 菜单信息对象 """ - menu_info = (await db.execute( - select(SysMenu) - .where(SysMenu.menu_id == menu_id) - )).scalars().first() + menu_info = (await db.execute(select(SysMenu).where(SysMenu.menu_id == menu_id))).scalars().first() return menu_info @@ -34,12 +31,19 @@ class MenuDao: :param menu: 菜单参数对象 :return: 菜单信息对象 """ - menu_info = (await db.execute( - select(SysMenu) - .where(SysMenu.parent_id == menu.parent_id if menu.parent_id else True, - SysMenu.menu_name == menu.menu_name if menu.menu_name else True, - SysMenu.menu_type == menu.menu_type if menu.menu_type else True) - )).scalars().first() + menu_info = ( + ( + await db.execute( + select(SysMenu).where( + SysMenu.parent_id == menu.parent_id if menu.parent_id else True, + SysMenu.menu_name == menu.menu_name if menu.menu_name else True, + SysMenu.menu_type == menu.menu_type if menu.menu_type else True, + ) + ) + ) + .scalars() + .first() + ) return menu_info @@ -54,26 +58,35 @@ class MenuDao: """ role_id_list = [item.role_id for item in role] if 1 in role_id_list: - menu_query_all = (await db.execute( - select(SysMenu) - .where(SysMenu.status == '0') - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + (await db.execute(select(SysMenu).where(SysMenu.status == '0').order_by(SysMenu.order_num).distinct())) + .scalars() + .all() + ) else: - menu_query_all = (await db.execute( - select(SysMenu) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), - isouter=True) - .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_( + SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0' + ), + isouter=True, + ) + .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return menu_query_all @@ -89,31 +102,52 @@ class MenuDao: """ role_id_list = [item.role_id for item in role] if 1 in role_id_list: - menu_query_all = (await db.execute( - select(SysMenu) - .where(SysMenu.status == page_object.status if page_object.status else True, - SysMenu.menu_name.like( - f'%{page_object.menu_name}%') if page_object.menu_name else True) - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .where( + SysMenu.status == page_object.status if page_object.status else True, + SysMenu.menu_name.like(f'%{page_object.menu_name}%') if page_object.menu_name else True, + ) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) else: - menu_query_all = (await db.execute( - select(SysMenu) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), - isouter=True) - .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, - SysMenu.status == page_object.status if page_object.status else True, - SysMenu.menu_name.like( - f'%{page_object.menu_name}%') if page_object.menu_name else True)) - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_( + SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0' + ), + isouter=True, + ) + .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) + .join( + SysMenu, + and_( + SysRoleMenu.menu_id == SysMenu.menu_id, + SysMenu.status == page_object.status if page_object.status else True, + SysMenu.menu_name.like(f'%{page_object.menu_name}%') if page_object.menu_name else True, + ), + ) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return menu_query_all @@ -139,10 +173,7 @@ class MenuDao: :param menu: 需要更新的菜单字典 :return: """ - await db.execute( - update(SysMenu), - [menu] - ) + await db.execute(update(SysMenu), [menu]) @classmethod async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel): @@ -152,10 +183,7 @@ class MenuDao: :param menu: 菜单对象 :return: """ - await db.execute( - delete(SysMenu) - .where(SysMenu.menu_id.in_([menu.menu_id])) - ) + await db.execute(delete(SysMenu).where(SysMenu.menu_id.in_([menu.menu_id]))) @classmethod async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int): @@ -165,11 +193,9 @@ class MenuDao: :param menu_id: 菜单id :return: 菜单关联子菜单的数量 """ - menu_count = (await db.execute( - select(func.count('*')) - .select_from(SysMenu) - .where(SysMenu.parent_id == menu_id) - )).scalar() + menu_count = ( + await db.execute(select(func.count('*')).select_from(SysMenu).where(SysMenu.parent_id == menu_id)) + ).scalar() return menu_count @@ -181,10 +207,8 @@ class MenuDao: :param menu_id: 菜单id :return: 菜单关联角色数量 """ - role_count = (await db.execute( - select(func.count('*')) - .select_from(SysRoleMenu) - .where(SysRoleMenu.menu_id == menu_id) - )).scalar() + role_count = ( + await db.execute(select(func.count('*')).select_from(SysRoleMenu).where(SysRoleMenu.menu_id == menu_id)) + ).scalar() return role_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py index 8f98be4..e7e5f50 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysMenu(Base): """ 菜单权限表 """ + __tablename__ = 'sys_menu' menu_id = Column(Integer, primary_key=True, autoincrement=True, comment='菜单ID') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py index 224015c..c5234d4 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py @@ -1,8 +1,8 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from datetime import datetime -from typing import Union, Optional, List, Literal +from typing import Literal, Optional from module_admin.annotation.pydantic_annotation import as_query @@ -10,6 +10,7 @@ class MenuModel(BaseModel): """ 菜单表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) menu_id: Optional[int] = Field(default=None, description='菜单ID') @@ -71,6 +72,7 @@ class MenuQueryModel(MenuModel): """ 菜单管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -79,6 +81,7 @@ class DeleteMenuModel(BaseModel): """ 删除菜单模型 """ + model_config = ConfigDict(alias_generator=to_camel) menu_ids: str = Field(description='需要删除的菜单ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index 3935495..f0f8ce2 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -1,10 +1,13 @@ -from module_admin.entity.vo.user_vo import CurrentUserModel -from module_admin.entity.vo.role_vo import RoleMenuQueryModel -from module_admin.entity.vo.common_vo import CrudResponseModel -from module_admin.dao.role_dao import RoleDao -from module_admin.dao.menu_dao import * +from sqlalchemy.ext.asyncio import AsyncSession +from typing import Optional from config.constant import CommonConstant, MenuConstant from exceptions.exception import ServiceException, ServiceWarning +from module_admin.dao.menu_dao import MenuDao +from module_admin.dao.role_dao import RoleDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuQueryModel, MenuModel +from module_admin.entity.vo.role_vo import RoleMenuQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel from utils.common_util import CamelCaseUtil from utils.string_util import StringUtil @@ -22,13 +25,17 @@ class MenuService: :param current_user: 当前用户对象 :return: 菜单树信息对象 """ - menu_list_result = await MenuDao.get_menu_list_for_tree(query_db, current_user.user.user_id, current_user.user.role) + menu_list_result = await MenuDao.get_menu_list_for_tree( + query_db, current_user.user.user_id, current_user.user.role + ) menu_tree_result = cls.list_to_tree(menu_list_result) return menu_tree_result @classmethod - async def get_role_menu_tree_services(cls, query_db: AsyncSession, role_id: int, current_user: Optional[CurrentUserModel] = None): + async def get_role_menu_tree_services( + cls, query_db: AsyncSession, role_id: int, current_user: Optional[CurrentUserModel] = None + ): """ 根据角色id获取菜单树信息service :param query_db: orm对象 @@ -36,20 +43,21 @@ class MenuService: :param current_user: 当前用户对象 :return: 当前角色id的菜单树信息对象 """ - menu_list_result = await MenuDao.get_menu_list_for_tree(query_db, current_user.user.user_id, current_user.user.role) + menu_list_result = await MenuDao.get_menu_list_for_tree( + query_db, current_user.user.user_id, current_user.user.role + ) menu_tree_result = cls.list_to_tree(menu_list_result) role = await RoleDao.get_role_detail_by_id(query_db, role_id) role_menu_list = await RoleDao.get_role_menu_dao(query_db, role) checked_keys = [row.menu_id for row in role_menu_list] - result = RoleMenuQueryModel( - menus=menu_tree_result, - checkedKeys=checked_keys - ) + result = RoleMenuQueryModel(menus=menu_tree_result, checkedKeys=checked_keys) return result @classmethod - async def get_menu_list_services(cls, query_db: AsyncSession, page_object: MenuQueryModel, current_user: Optional[CurrentUserModel] = None): + async def get_menu_list_services( + cls, query_db: AsyncSession, page_object: MenuQueryModel, current_user: Optional[CurrentUserModel] = None + ): """ 获取菜单列表信息service :param query_db: orm对象 @@ -57,7 +65,9 @@ class MenuService: :param current_user: 当前用户对象 :return: 菜单列表信息对象 """ - menu_list_result = await MenuDao.get_menu_list(query_db, page_object, current_user.user.user_id, current_user.user.role) + menu_list_result = await MenuDao.get_menu_list( + query_db, page_object, current_user.user.user_id, current_user.user.role + ) return CamelCaseUtil.transform_result(menu_list_result) @@ -172,7 +182,9 @@ class MenuService: :param permission_list: 菜单列表信息 :return: 菜单树形嵌套数据 """ - permission_list = [dict(id=item.menu_id, label=item.menu_name, parentId=item.parent_id) for item in permission_list] + permission_list = [ + dict(id=item.menu_id, label=item.menu_name, parentId=item.parent_id) for item in permission_list + ] # 转成id为key的字典 mapping: dict = dict(zip([i['id'] for i in permission_list], permission_list))