Files
shanxia2.0/backend/app/crud/menu_favorite.py
T
2026-08-08 20:43:48 +08:00

213 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""用户菜单收藏 CRUD"""
from __future__ import annotations
import uuid
from datetime import datetime
from typing import Any, Dict, List, Optional
from sqlalchemy.orm import Session
from app.models.models import SysUserMenuFavorite
MAX_FAVORITES = 10
def normalize_menu_path(path: str) -> str:
p = (path or "").strip()
if not p:
return ""
if not p.startswith("/"):
p = "/" + p
return p
def _row_to_dict(row: SysUserMenuFavorite) -> Dict[str, Any]:
return {
"id": row.id,
"path": row.menu_path or "",
"orderNum": row.order_num,
"createTime": row.create_time.isoformat(sep=" ", timespec="seconds") if row.create_time else None,
}
def _next_order_num(db: Session, *, user_id: str, tenant_no: str) -> int:
max_order = (
db.query(SysUserMenuFavorite.order_num)
.filter(
SysUserMenuFavorite.del_flag == 0,
SysUserMenuFavorite.user_id == user_id,
SysUserMenuFavorite.tenant_no == tenant_no,
)
.order_by(SysUserMenuFavorite.order_num.desc())
.first()
)
return (max_order[0] if max_order and max_order[0] is not None else 0) + 1
def list_favorites(
db: Session,
*,
user_id: str,
tenant_no: str,
) -> List[Dict[str, Any]]:
rows = (
db.query(SysUserMenuFavorite)
.filter(
SysUserMenuFavorite.del_flag == 0,
SysUserMenuFavorite.user_id == user_id,
SysUserMenuFavorite.tenant_no == tenant_no,
)
.order_by(
SysUserMenuFavorite.order_num.asc(),
SysUserMenuFavorite.create_time.asc(),
)
.all()
)
return [_row_to_dict(r) for r in rows]
def count_active(db: Session, *, user_id: str, tenant_no: str) -> int:
return (
db.query(SysUserMenuFavorite)
.filter(
SysUserMenuFavorite.del_flag == 0,
SysUserMenuFavorite.user_id == user_id,
SysUserMenuFavorite.tenant_no == tenant_no,
)
.count()
)
def find_active(
db: Session, *, user_id: str, tenant_no: str, menu_path: str
) -> Optional[SysUserMenuFavorite]:
return (
db.query(SysUserMenuFavorite)
.filter(
SysUserMenuFavorite.del_flag == 0,
SysUserMenuFavorite.user_id == user_id,
SysUserMenuFavorite.tenant_no == tenant_no,
SysUserMenuFavorite.menu_path == menu_path,
)
.first()
)
def find_soft_deleted(
db: Session, *, user_id: str, tenant_no: str, menu_path: str
) -> Optional[SysUserMenuFavorite]:
return (
db.query(SysUserMenuFavorite)
.filter(
SysUserMenuFavorite.del_flag == 1,
SysUserMenuFavorite.user_id == user_id,
SysUserMenuFavorite.tenant_no == tenant_no,
SysUserMenuFavorite.menu_path == menu_path,
)
.first()
)
def add_favorite(
db: Session,
*,
user_id: str,
tenant_no: str,
menu_path: str,
create_dept_id: str = "",
) -> Dict[str, Any]:
path = normalize_menu_path(menu_path)
if not path:
raise ValueError("菜单路径无效")
existing = find_active(db, user_id=user_id, tenant_no=tenant_no, menu_path=path)
if existing:
return _row_to_dict(existing)
if count_active(db, user_id=user_id, tenant_no=tenant_no) >= MAX_FAVORITES:
raise ValueError(f"最多收藏 {MAX_FAVORITES} 个菜单")
now = datetime.now()
next_order = _next_order_num(db, user_id=user_id, tenant_no=tenant_no)
deleted = find_soft_deleted(db, user_id=user_id, tenant_no=tenant_no, menu_path=path)
if deleted:
deleted.del_flag = 0
deleted.order_num = next_order
deleted.update_by = user_id
deleted.update_time = now
db.commit()
db.refresh(deleted)
return _row_to_dict(deleted)
row = SysUserMenuFavorite(
id=str(uuid.uuid4()),
user_id=user_id,
menu_path=path,
tenant_no=tenant_no,
order_num=next_order,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=now,
update_by=user_id,
update_time=now,
del_flag=0,
)
db.add(row)
db.commit()
db.refresh(row)
return _row_to_dict(row)
def soft_delete_favorite(
db: Session,
*,
user_id: str,
tenant_no: str,
menu_path: str,
) -> bool:
path = normalize_menu_path(menu_path)
row = find_active(db, user_id=user_id, tenant_no=tenant_no, menu_path=path)
if not row:
return False
row.del_flag = 1
row.update_by = user_id
row.update_time = datetime.now()
db.commit()
return True
def reorder_favorites(
db: Session,
*,
user_id: str,
tenant_no: str,
paths: List[str],
) -> List[Dict[str, Any]]:
"""按传入 paths 顺序重写 order_num(1-based)。paths 须覆盖当前全部有效收藏。"""
normalized: List[str] = []
seen = set()
for raw in paths or []:
p = normalize_menu_path(raw)
if not p or p in seen:
continue
seen.add(p)
normalized.append(p)
current = list_favorites(db, user_id=user_id, tenant_no=tenant_no)
current_paths = {item["path"] for item in current}
if set(normalized) != current_paths or len(normalized) != len(current_paths):
raise ValueError("排序列表与当前收藏不一致")
now = datetime.now()
for idx, path in enumerate(normalized, start=1):
row = find_active(db, user_id=user_id, tenant_no=tenant_no, menu_path=path)
if not row:
raise ValueError("排序列表与当前收藏不一致")
row.order_num = idx
row.update_by = user_id
row.update_time = now
db.commit()
return list_favorites(db, user_id=user_id, tenant_no=tenant_no)