Files
server/users/departments.py

109 lines
3.6 KiB
Python

# api/departments.py
from typing import List
from django.db import IntegrityError
from django.shortcuts import get_object_or_404
from ninja import Router
from ninja.errors import HttpError
from users.models import Department
from users.permission import has_permission, require_permissions
from users.schema import DepartmentOut, DepartmentCreate, DepartmentUpdate
router = Router(tags=['depts'])
@router.get("/", response=List[DepartmentOut], summary="获取部门列表(扁平)")
@require_permissions("dept:list")
def list_departments(request):
return Department.objects.all()
@router.get("/tree/", response=List[dict], summary="获取部门树形结构")
@require_permissions("dept:list")
def get_department_tree(request):
depts = Department.objects.all().order_by('order')
return build_dept_tree(list(depts))
@router.post("/", response=DepartmentOut, summary="创建部门")
@require_permissions("dept:create")
def create_department(request, payload: DepartmentCreate):
if not has_permission(request.auth.id, "dept:create"):
raise HttpError(403, "权限不足")
# 👇 新增:校验根部门唯一性
if payload.parent_id is None:
if Department.objects.filter(parent__isnull=True).exists():
raise HttpError(400, "根部门已存在,无法创建新的根部门")
data = payload.dict()
parent_id = data.pop('parent_id', None)
if parent_id:
# 可以额外校验 parent_id 是否真实存在
if not Department.objects.filter(id=parent_id).exists():
raise HttpError(400, "指定的上级部门不存在")
data['parent_id'] = parent_id
try:
dept = Department.objects.create(**data)
return dept
except IntegrityError as e:
# 捕获数据库层面的唯一性冲突,提供统一错误信息
if "unique_root_department" in str(e):
raise HttpError(400, "根部门已存在,无法创建新的根部门")
else:
raise HttpError(400, "创建部门失败,请检查数据")
@router.get("/{dept_id}/", response=DepartmentOut, summary="获取部门详情")
@require_permissions("dept:view")
def get_department(request, dept_id: int):
dept = get_object_or_404(Department, id=dept_id)
return dept
@router.put("/{dept_id}/", response=DepartmentOut, summary="更新部门")
@require_permissions("dept:update")
def update_department(request, dept_id: int, payload: DepartmentUpdate):
dept = get_object_or_404(Department, id=dept_id)
data = payload.dict()
parent_id = data.pop('parent_id', None)
if parent_id:
data['parent_id'] = parent_id
else:
data['parent'] = None
for attr, value in data.items():
setattr(dept, attr, value)
dept.save()
return dept
@router.delete("/{dept_id}/", summary="删除部门")
@require_permissions("dept:delete")
def delete_department(request, dept_id: int):
dept = get_object_or_404(Department, id=dept_id)
# 可选:检查是否有子部门或用户
if dept.user_set.exists() or Department.objects.filter(parent=dept).exists():
return 400, {"detail": "部门包含用户或子部门,无法删除"}
dept.delete()
return {"success": True}
# 工具函数:构建部门树
def build_dept_tree(depts, parent_id=None):
tree = []
for dept in depts:
if dept.parent_id == parent_id:
node = {
'id': dept.id,
'name': dept.name,
'parent_id': dept.parent_id,
'order': dept.order,
'children': build_dept_tree(depts, dept.id) or None
}
tree.append(node)
return tree