209 lines
6.0 KiB
Python
209 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from sqlalchemy import and_
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.utils import generate_uuid
|
|
from app.models.models import SysMenu
|
|
|
|
|
|
def _row_to_dict(m: SysMenu) -> Dict[str, Any]:
|
|
return {
|
|
"id": m.id,
|
|
"menuName": m.menu_name,
|
|
"parentId": m.parent_id,
|
|
"menuType": m.menu_type or "M",
|
|
"path": m.path or "",
|
|
"component": m.component or "",
|
|
"perms": m.perms or "",
|
|
"isFrame": m.is_frame if m.is_frame is not None else 1,
|
|
"visible": m.visible or "1",
|
|
"status": m.status or "1",
|
|
"tenantNo": m.tenant_no,
|
|
"orderNum": m.order_num if m.order_num is not None else 0,
|
|
"remark": m.remark or "",
|
|
"createTime": m.create_time.strftime("%Y-%m-%d %H:%M:%S") if m.create_time else "",
|
|
"updateTime": m.update_time.strftime("%Y-%m-%d %H:%M:%S") if m.update_time else "",
|
|
}
|
|
|
|
|
|
def _build_tree(items: List[Dict[str, Any]], parent_id: str = "0") -> List[Dict[str, Any]]:
|
|
children = [item for item in items if item.get("parentId") == parent_id]
|
|
for child in children:
|
|
child["children"] = _build_tree(items, child["id"])
|
|
children.sort(key=lambda x: (x.get("orderNum", 0) or 0))
|
|
return children
|
|
|
|
|
|
def list_menus(
|
|
db: Session,
|
|
*,
|
|
keyword: Optional[str] = None,
|
|
tenant_no: Optional[str] = None,
|
|
) -> List[Dict[str, Any]]:
|
|
q = db.query(SysMenu).filter(SysMenu.del_flag == 0)
|
|
if tenant_no:
|
|
q = q.filter(SysMenu.tenant_no == tenant_no)
|
|
kw = (keyword or "").strip()
|
|
if kw:
|
|
like = f"%{kw}%"
|
|
q = q.filter(SysMenu.menu_name.like(like))
|
|
rows = q.order_by(SysMenu.order_num.asc(), SysMenu.create_time.desc()).all()
|
|
return [_row_to_dict(x) for x in rows]
|
|
|
|
|
|
def list_menus_tree(
|
|
db: Session,
|
|
*,
|
|
keyword: Optional[str] = None,
|
|
tenant_no: Optional[str] = None,
|
|
) -> List[Dict[str, Any]]:
|
|
flat = list_menus(db, keyword=keyword, tenant_no=tenant_no)
|
|
return _build_tree(flat, "0")
|
|
|
|
|
|
def get_menu(db: Session, menu_id: str) -> Optional[SysMenu]:
|
|
return (
|
|
db.query(SysMenu)
|
|
.filter(and_(SysMenu.id == menu_id, SysMenu.del_flag == 0))
|
|
.first()
|
|
)
|
|
|
|
|
|
def menu_name_exists(
|
|
db: Session,
|
|
name: str,
|
|
tenant_no: str,
|
|
exclude_id: Optional[str] = None,
|
|
) -> bool:
|
|
q = db.query(SysMenu).filter(
|
|
and_(SysMenu.menu_name == name, SysMenu.tenant_no == tenant_no, SysMenu.del_flag == 0)
|
|
)
|
|
if exclude_id:
|
|
q = q.filter(SysMenu.id != exclude_id)
|
|
return q.first() is not None
|
|
|
|
|
|
def create_menu(
|
|
db: Session,
|
|
*,
|
|
menu_name: str,
|
|
parent_id: str = "0",
|
|
menu_type: str = "M",
|
|
path: str = "",
|
|
component: Optional[str] = None,
|
|
perms: Optional[str] = None,
|
|
is_frame: int = 1,
|
|
visible: str = "1",
|
|
status: str = "1",
|
|
tenant_no: Optional[str] = None,
|
|
order_num: Optional[int] = None,
|
|
remark: Optional[str] = None,
|
|
user_id: Optional[str] = None,
|
|
) -> SysMenu:
|
|
name = (menu_name or "").strip()
|
|
if not name:
|
|
raise ValueError("菜单名称不能为空")
|
|
obj = SysMenu(
|
|
id=generate_uuid(),
|
|
menu_name=name,
|
|
parent_id=(parent_id or "0").strip(),
|
|
menu_type=menu_type or "M",
|
|
path=(path or "").strip(),
|
|
component=(component or "").strip() or None,
|
|
perms=(perms or "").strip() or None,
|
|
is_frame=is_frame if is_frame is not None else 1,
|
|
visible=visible or "1",
|
|
status=status or "1",
|
|
tenant_no=tenant_no or "zkxw",
|
|
order_num=order_num if order_num is not None else 0,
|
|
remark=(remark or "").strip() or None,
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=datetime.now(),
|
|
update_by=user_id,
|
|
update_time=datetime.now(),
|
|
del_flag=0,
|
|
)
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def update_menu(
|
|
db: Session,
|
|
menu_id: str,
|
|
*,
|
|
menu_name: Optional[str] = None,
|
|
parent_id: Optional[str] = None,
|
|
menu_type: Optional[str] = None,
|
|
path: Optional[str] = None,
|
|
component: Optional[str] = None,
|
|
perms: Optional[str] = None,
|
|
is_frame: Optional[int] = None,
|
|
visible: Optional[str] = None,
|
|
status: Optional[str] = None,
|
|
order_num: Optional[int] = None,
|
|
remark: Optional[str] = None,
|
|
user_id: Optional[str] = None,
|
|
) -> SysMenu:
|
|
obj = get_menu(db, menu_id)
|
|
if not obj:
|
|
raise ValueError("菜单不存在")
|
|
if menu_name is not None:
|
|
obj.menu_name = (menu_name or "").strip() or obj.menu_name
|
|
if parent_id is not None:
|
|
obj.parent_id = (parent_id or "0").strip()
|
|
if menu_type is not None:
|
|
obj.menu_type = menu_type
|
|
if path is not None:
|
|
obj.path = (path or "").strip()
|
|
if component is not None:
|
|
obj.component = (component or "").strip() or None
|
|
if perms is not None:
|
|
obj.perms = (perms or "").strip() or None
|
|
if is_frame is not None:
|
|
obj.is_frame = is_frame
|
|
if visible is not None:
|
|
obj.visible = visible
|
|
if status is not None:
|
|
obj.status = status
|
|
if order_num is not None:
|
|
obj.order_num = order_num
|
|
if remark is not None:
|
|
obj.remark = (remark or "").strip() or None
|
|
obj.update_by = user_id
|
|
obj.update_time = datetime.now()
|
|
db.add(obj)
|
|
db.commit()
|
|
db.refresh(obj)
|
|
return obj
|
|
|
|
|
|
def _cascade_soft_delete(db: Session, menu_id: str) -> None:
|
|
children = (
|
|
db.query(SysMenu)
|
|
.filter(and_(SysMenu.parent_id == menu_id, SysMenu.del_flag == 0))
|
|
.all()
|
|
)
|
|
for child in children:
|
|
_cascade_soft_delete(db, child.id)
|
|
child.del_flag = 1
|
|
child.update_time = datetime.now()
|
|
db.add(child)
|
|
|
|
|
|
def soft_delete_menu(db: Session, menu_id: str) -> None:
|
|
obj = get_menu(db, menu_id)
|
|
if not obj:
|
|
raise ValueError("菜单不存在")
|
|
_cascade_soft_delete(db, menu_id)
|
|
obj.del_flag = 1
|
|
obj.update_time = datetime.now()
|
|
db.add(obj)
|
|
db.commit()
|