77 lines
2.5 KiB
Python
77 lines
2.5 KiB
Python
"""组织架构:CRUD + 树构建。"""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import status
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.exceptions import AppError
|
|
from app.models import Organization
|
|
from app.schemas.organization import OrgCreate, OrgTreeNode, OrgUpdate
|
|
|
|
|
|
async def list_all(db: AsyncSession) -> list[Organization]:
|
|
res = await db.execute(select(Organization).order_by(Organization.sort, Organization.id))
|
|
return list(res.scalars().all())
|
|
|
|
|
|
async def get(db: AsyncSession, oid: int) -> Organization:
|
|
org = await db.get(Organization, oid)
|
|
if org is None:
|
|
raise AppError("组织不存在", code=404, http_status=status.HTTP_404_NOT_FOUND)
|
|
return org
|
|
|
|
|
|
async def create(db: AsyncSession, data: OrgCreate) -> Organization:
|
|
exists = await db.execute(select(Organization).where(Organization.code == data.code))
|
|
if exists.scalar_one_or_none():
|
|
raise AppError("code 已存在", code=409, http_status=status.HTTP_409_CONFLICT)
|
|
org = Organization(**data.model_dump())
|
|
db.add(org)
|
|
await db.commit()
|
|
await db.refresh(org)
|
|
return org
|
|
|
|
|
|
async def update(db: AsyncSession, oid: int, data: OrgUpdate) -> Organization:
|
|
org = await get(db, oid)
|
|
for k, v in data.model_dump(exclude_unset=True).items():
|
|
setattr(org, k, v)
|
|
await db.commit()
|
|
await db.refresh(org)
|
|
return org
|
|
|
|
|
|
async def delete(db: AsyncSession, oid: int) -> None:
|
|
org = await get(db, oid)
|
|
# 不允许删除有子节点的组织
|
|
res = await db.execute(select(Organization.id).where(Organization.parent_id == oid))
|
|
if res.first():
|
|
raise AppError("存在子组织,无法删除", code=409, http_status=status.HTTP_409_CONFLICT)
|
|
await db.delete(org)
|
|
await db.commit()
|
|
|
|
|
|
def build_tree(items: list[Organization]) -> list[OrgTreeNode]:
|
|
nodes: dict[int, OrgTreeNode] = {}
|
|
for o in items:
|
|
nodes[o.id] = OrgTreeNode(
|
|
id=o.id, parent_id=o.parent_id, name=o.name, code=o.code,
|
|
type=o.type, sort=o.sort, description=o.description,
|
|
)
|
|
roots: list[OrgTreeNode] = []
|
|
for o in items:
|
|
n = nodes[o.id]
|
|
if o.parent_id and o.parent_id in nodes:
|
|
nodes[o.parent_id].children.append(n)
|
|
else:
|
|
roots.append(n)
|
|
|
|
def _sort(lst: list[OrgTreeNode]) -> None:
|
|
lst.sort(key=lambda x: (x.sort, x.id))
|
|
for it in lst:
|
|
_sort(it.children)
|
|
|
|
_sort(roots)
|
|
return roots
|