- 实现数据库迁移,创建部门表并向用户表添加department_id字段。 - 创建Department模型并与User模型建立关联关系。 - 开发部门管理API以支持增删改查操作。 - 添加DepartmentManagementComponent用于在UI中管理部门。 - 在UserManagementComponent中集成部门选择功能以进行用户分配。 - 更新用户存储以处理部门数据。 - 增强UI组件以改善样式和用户体验。
309 lines
9.6 KiB
Python
309 lines
9.6 KiB
Python
"""
|
|
部门管理路由
|
|
提供部门的增删改查接口,仅超级管理员可访问
|
|
"""
|
|
|
|
import re
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Request
|
|
from pydantic import BaseModel
|
|
from sqlalchemy import select, func
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from src.storage.db.models import Department, User
|
|
from server.utils.auth_middleware import get_superadmin_user, get_db
|
|
from server.utils.auth_utils import AuthUtils
|
|
from server.utils.common_utils import log_operation
|
|
from server.utils.user_utils import validate_username, is_valid_phone_number, generate_unique_user_id
|
|
from src.utils.datetime_utils import utc_now
|
|
|
|
# 创建路由器
|
|
department = APIRouter(prefix="/departments", tags=["department"])
|
|
|
|
|
|
# =============================================================================
|
|
# === 请求和响应模型 ===
|
|
# =============================================================================
|
|
|
|
|
|
class DepartmentCreate(BaseModel):
|
|
"""创建部门请求"""
|
|
name: str
|
|
description: str | None = None
|
|
# 必需的管理员信息
|
|
admin_user_id: str
|
|
admin_password: str
|
|
admin_phone: str | None = None
|
|
|
|
|
|
class DepartmentCreateWithoutAdmin(BaseModel):
|
|
"""创建部门请求(无管理员,用于兼容)"""
|
|
name: str
|
|
description: str | None = None
|
|
|
|
|
|
class DepartmentUpdate(BaseModel):
|
|
"""更新部门请求"""
|
|
name: str | None = None
|
|
description: str | None = None
|
|
|
|
|
|
class DepartmentResponse(BaseModel):
|
|
"""部门响应"""
|
|
id: int
|
|
name: str
|
|
description: str | None = None
|
|
created_at: str
|
|
user_count: int = 0
|
|
|
|
|
|
class DepartmentSimpleResponse(BaseModel):
|
|
"""部门简单响应(不含用户数量)"""
|
|
id: int
|
|
name: str
|
|
description: str | None = None
|
|
created_at: str
|
|
|
|
|
|
# =============================================================================
|
|
# === 部门管理路由 ===
|
|
# =============================================================================
|
|
|
|
|
|
@department.get("", response_model=list[DepartmentResponse])
|
|
async def get_departments(
|
|
current_user: User = Depends(get_superadmin_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""获取所有部门列表"""
|
|
result = await db.execute(select(Department).order_by(Department.created_at.desc()))
|
|
departments = result.scalars().all()
|
|
|
|
# 获取每个部门的用户数量
|
|
department_list = []
|
|
for dep in departments:
|
|
user_count_result = await db.execute(
|
|
select(func.count(User.id)).filter(
|
|
User.department_id == dep.id,
|
|
User.is_deleted == 0
|
|
)
|
|
)
|
|
user_count = user_count_result.scalar()
|
|
department_list.append({**dep.to_dict(), "user_count": user_count})
|
|
|
|
return department_list
|
|
|
|
|
|
@department.get("/{department_id}", response_model=DepartmentResponse)
|
|
async def get_department(
|
|
department_id: int,
|
|
current_user: User = Depends(get_superadmin_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""获取指定部门详情"""
|
|
result = await db.execute(select(Department).filter(Department.id == department_id))
|
|
department = result.scalar_one_or_none()
|
|
|
|
if not department:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="部门不存在"
|
|
)
|
|
|
|
# 获取部门下用户数量
|
|
user_count_result = await db.execute(
|
|
select(func.count(User.id)).filter(
|
|
User.department_id == department_id,
|
|
User.is_deleted == 0
|
|
)
|
|
)
|
|
user_count = user_count_result.scalar()
|
|
|
|
return {
|
|
**department.to_dict(),
|
|
"user_count": user_count
|
|
}
|
|
|
|
|
|
@department.post("", response_model=DepartmentResponse, status_code=status.HTTP_201_CREATED)
|
|
async def create_department(
|
|
department_data: DepartmentCreate,
|
|
request: Request,
|
|
current_user: User = Depends(get_superadmin_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""创建新部门,同时创建该部门的管理员"""
|
|
# 检查部门名称是否已存在
|
|
result = await db.execute(select(Department).filter(Department.name == department_data.name))
|
|
existing = result.scalar_one_or_none()
|
|
if existing:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="部门名称已存在"
|
|
)
|
|
|
|
# 验证管理员 user_id 格式
|
|
admin_user_id = department_data.admin_user_id
|
|
if not re.match(r"^[a-zA-Z0-9_]+$", admin_user_id):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="用户ID只能包含字母、数字和下划线",
|
|
)
|
|
|
|
if len(admin_user_id) < 3 or len(admin_user_id) > 20:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="用户ID长度必须在3-20个字符之间",
|
|
)
|
|
|
|
# 检查 user_id 是否已存在
|
|
result = await db.execute(select(User).filter(User.user_id == admin_user_id))
|
|
existing_user = result.scalar_one_or_none()
|
|
if existing_user:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="用户ID已存在",
|
|
)
|
|
|
|
# 检查手机号是否已存在(如果提供了)
|
|
admin_phone = department_data.admin_phone
|
|
if admin_phone:
|
|
if not is_valid_phone_number(admin_phone):
|
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="手机号格式不正确")
|
|
result = await db.execute(select(User).filter(User.phone_number == admin_phone))
|
|
existing_phone = result.scalar_one_or_none()
|
|
if existing_phone:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="手机号已存在",
|
|
)
|
|
|
|
new_department = Department(
|
|
name=department_data.name,
|
|
description=department_data.description
|
|
)
|
|
|
|
db.add(new_department)
|
|
await db.flush() # 获取部门ID
|
|
|
|
# 创建管理员用户
|
|
hashed_password = AuthUtils.hash_password(department_data.admin_password)
|
|
new_admin = User(
|
|
username=admin_user_id, # username 和 user_id 设置为相同值
|
|
user_id=admin_user_id,
|
|
phone_number=admin_phone,
|
|
password_hash=hashed_password,
|
|
role="admin",
|
|
department_id=new_department.id,
|
|
)
|
|
db.add(new_admin)
|
|
|
|
await db.commit()
|
|
await db.refresh(new_department)
|
|
|
|
# 记录操作
|
|
await log_operation(
|
|
db, current_user.id, "创建部门", f"创建部门: {department_data.name},并创建管理员: {admin_user_id}", request
|
|
)
|
|
|
|
return {
|
|
**new_department.to_dict(),
|
|
"user_count": 1
|
|
}
|
|
|
|
|
|
@department.put("/{department_id}", response_model=DepartmentResponse)
|
|
async def update_department(
|
|
department_id: int,
|
|
department_data: DepartmentUpdate,
|
|
request: Request,
|
|
current_user: User = Depends(get_superadmin_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""更新部门信息"""
|
|
result = await db.execute(select(Department).filter(Department.id == department_id))
|
|
department = result.scalar_one_or_none()
|
|
|
|
if not department:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="部门不存在"
|
|
)
|
|
|
|
# 如果要修改名称,检查新名称是否已存在
|
|
if department_data.name and department_data.name != department.name:
|
|
result = await db.execute(select(Department).filter(Department.name == department_data.name))
|
|
existing = result.scalar_one_or_none()
|
|
if existing:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="部门名称已存在"
|
|
)
|
|
department.name = department_data.name
|
|
|
|
if department_data.description is not None:
|
|
department.description = department_data.description
|
|
|
|
await db.commit()
|
|
await db.refresh(department)
|
|
|
|
# 记录操作
|
|
await log_operation(db, current_user.id, "更新部门", f"更新部门: {department.name}", request)
|
|
|
|
# 获取部门下用户数量
|
|
user_count_result = await db.execute(
|
|
select(func.count(User.id)).filter(
|
|
User.department_id == department_id,
|
|
User.is_deleted == 0
|
|
)
|
|
)
|
|
user_count = user_count_result.scalar()
|
|
|
|
return {
|
|
**department.to_dict(),
|
|
"user_count": user_count
|
|
}
|
|
|
|
|
|
@department.delete("/{department_id}", status_code=status.HTTP_200_OK)
|
|
async def delete_department(
|
|
department_id: int,
|
|
request: Request,
|
|
current_user: User = Depends(get_superadmin_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""删除部门"""
|
|
# 检查部门是否存在
|
|
result = await db.execute(select(Department).filter(Department.id == department_id))
|
|
department = result.scalar_one_or_none()
|
|
|
|
if not department:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="部门不存在"
|
|
)
|
|
|
|
# 检查部门下是否有用户
|
|
user_count_result = await db.execute(
|
|
select(func.count(User.id)).filter(
|
|
User.department_id == department_id,
|
|
User.is_deleted == 0
|
|
)
|
|
)
|
|
user_count = user_count_result.scalar()
|
|
|
|
if user_count > 0:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail=f"无法删除部门,该部门下还有 {user_count} 个用户"
|
|
)
|
|
|
|
department_name = department.name
|
|
await db.delete(department)
|
|
await db.commit()
|
|
|
|
# 记录操作
|
|
await log_operation(db, current_user.id, "删除部门", f"删除部门: {department_name}", request)
|
|
|
|
return {"success": True, "message": "部门已删除"}
|