""" 菜单服务层 """ from typing import Optional, List, Dict, Any from sqlalchemy import select, and_ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from app.models.models import Menu, MenuType class MenuService: """菜单服务""" @staticmethod async def get_tree(db: AsyncSession, visible_only: bool = True) -> List[Dict[str, Any]]: """获取菜单树形结构""" query = select(Menu).options(selectinload(Menu.children)) if visible_only: query = query.where(Menu.is_visible == True, Menu.is_active == True) query = query.where(Menu.parent_id.is_(None)) query = query.order_by(Menu.sort_order, Menu.id) result = await db.execute(query) menus = result.scalars().all() return [MenuService._menu_to_dict(menu) for menu in menus] @staticmethod async def get_list( db: AsyncSession, menu_type: Optional[str] = None, is_visible: Optional[bool] = None ) -> List[Menu]: """获取菜单列表""" query = select(Menu).options(selectinload(Menu.children)) conditions = [] if menu_type: conditions.append(Menu.menu_type == menu_type) if is_visible is not None: conditions.append(Menu.is_visible == is_visible) if conditions: query = query.where(and_(*conditions)) query = query.order_by(Menu.sort_order, Menu.id) result = await db.execute(query) return result.scalars().all() @staticmethod async def get_by_id(db: AsyncSession, menu_id: int) -> Optional[Menu]: """根据 ID 获取菜单""" result = await db.execute( select(Menu).where(Menu.id == menu_id) ) return result.scalar_one_or_none() @staticmethod async def create(db: AsyncSession, menu_data: dict) -> Menu: """创建菜单""" menu = Menu(**menu_data) db.add(menu) await db.commit() await db.refresh(menu) return menu @staticmethod async def update(db: AsyncSession, menu_id: int, menu_data: dict) -> Optional[Menu]: """更新菜单""" menu = await MenuService.get_by_id(db, menu_id) if not menu: return None for key, value in menu_data.items(): if value is not None and hasattr(menu, key): setattr(menu, key, value) await db.commit() await db.refresh(menu) return menu @staticmethod async def delete(db: AsyncSession, menu_id: int) -> bool: """删除菜单""" menu = await MenuService.get_by_id(db, menu_id) if not menu: return False # 检查是否有子菜单 if menu.children: return False await db.delete(menu) await db.commit() return True @staticmethod def _menu_to_dict(menu: Menu) -> Dict[str, Any]: """将菜单对象转换为字典""" return { "id": menu.id, "menu_name": menu.menu_name, "menu_icon": menu.menu_icon, "path": menu.path, "children": [MenuService._menu_to_dict(child) for child in menu.children] } @staticmethod async def init_default_menus(db: AsyncSession) -> None: """初始化默认菜单""" # 检查是否已有菜单 result = await db.execute(select(Menu)) if result.scalar_one_or_none(): return # 默认菜单数据 default_menus = [ {"menu_name": "工作台", "menu_icon": "HomeFilled", "path": "/dashboard", "component": "Dashboard", "sort_order": 1}, {"menu_name": "科室管理", "menu_icon": "OfficeBuilding", "path": "/departments", "component": "Departments", "sort_order": 2}, {"menu_name": "员工管理", "menu_icon": "User", "path": "/staff", "component": "Staff", "sort_order": 3}, {"menu_name": "考核指标", "menu_icon": "DataAnalysis", "path": "/indicators", "component": "Indicators", "sort_order": 4}, {"menu_name": "考核管理", "menu_icon": "Document", "path": "/assessments", "component": "Assessments", "sort_order": 5}, {"menu_name": "绩效计划", "menu_icon": "Setting", "path": "/plans", "component": "Plans", "sort_order": 6}, {"menu_name": "工资核算", "menu_icon": "Money", "path": "/salary", "component": "Salary", "sort_order": 7}, {"menu_name": "经济核算", "menu_icon": "Coin", "path": "/finance", "component": "Finance", "sort_order": 8}, {"menu_name": "统计报表", "menu_icon": "TrendCharts", "path": "/reports", "component": "Reports", "sort_order": 9}, ] for menu_data in default_menus: menu = Menu(**menu_data) db.add(menu) await db.commit()