137 lines
4.9 KiB
Python
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()
|