Files
hospital_performance/backend/app/services/menu_service.py
2026-02-28 15:06:52 +08:00

137 lines
4.9 KiB
Python

"""
菜单服务层
"""
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()