270 lines
9.7 KiB
Python
270 lines
9.7 KiB
Python
"""
|
||
企业后台管理 API(需 role=admin,与主站共用 JWT:/api/auth/login)
|
||
"""
|
||
import asyncpg
|
||
from typing import Optional
|
||
|
||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||
|
||
from admin.schemas import (
|
||
AdminUserCreate,
|
||
AdminUserListItem,
|
||
AdminUserListResponse,
|
||
AdminUserUpdate,
|
||
DepartmentCreate,
|
||
DepartmentResponse,
|
||
DepartmentUpdate,
|
||
EnterpriseResponse,
|
||
EnterpriseUpdate,
|
||
)
|
||
from core.dependencies import get_db, get_current_admin_user
|
||
from models.user import User
|
||
from services.admin_user_service import AdminUserService
|
||
from services.department_service import DepartmentService
|
||
from services.enterprise_service import EnterpriseService
|
||
from utils.helpers import BaseResponse
|
||
|
||
admin_router = APIRouter(prefix="/api/admin", tags=["后台管理"])
|
||
|
||
|
||
@admin_router.get("/enterprise", response_model=BaseResponse, summary="当前企业信息")
|
||
async def get_enterprise(
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
if admin.enterprise_id is None:
|
||
raise HTTPException(status_code=400, detail="用户未关联企业")
|
||
row = await EnterpriseService.get_by_id(conn, admin.enterprise_id)
|
||
if not row:
|
||
raise HTTPException(status_code=404, detail="企业不存在")
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="ok",
|
||
data=EnterpriseResponse(**row).model_dump(),
|
||
)
|
||
|
||
|
||
@admin_router.put("/enterprise", response_model=BaseResponse, summary="更新企业信息")
|
||
async def update_enterprise(
|
||
body: EnterpriseUpdate,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
if admin.enterprise_id is None:
|
||
raise HTTPException(status_code=400, detail="用户未关联企业")
|
||
row = await EnterpriseService.update_profile(
|
||
conn,
|
||
admin.enterprise_id,
|
||
name=body.name,
|
||
ai_display_name=body.ai_display_name,
|
||
)
|
||
if not row:
|
||
raise HTTPException(status_code=404, detail="企业不存在")
|
||
return BaseResponse(code=200, msg="更新成功", data=EnterpriseResponse(**row).model_dump())
|
||
|
||
|
||
@admin_router.get("/departments", response_model=BaseResponse, summary="部门列表")
|
||
async def list_departments(
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
rows = await DepartmentService.list_by_enterprise(conn, admin.enterprise_id)
|
||
items = [
|
||
DepartmentResponse(
|
||
id=r["id"],
|
||
enterprise_id=r["enterprise_id"],
|
||
name=r["name"],
|
||
parent_id=r["parent_id"],
|
||
created_at=r["created_at"],
|
||
).model_dump()
|
||
for r in rows
|
||
]
|
||
return BaseResponse(code=200, msg="ok", data={"items": items})
|
||
|
||
|
||
@admin_router.post("/departments", response_model=BaseResponse, summary="创建部门")
|
||
async def create_department(
|
||
body: DepartmentCreate,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
if body.parent_id is not None:
|
||
parent = await DepartmentService.get_by_id(conn, body.parent_id, admin.enterprise_id)
|
||
if not parent:
|
||
raise HTTPException(status_code=400, detail="上级部门不存在")
|
||
try:
|
||
row = await DepartmentService.create(
|
||
conn, admin.enterprise_id, body.name, body.parent_id
|
||
)
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="创建成功",
|
||
data=DepartmentResponse(
|
||
id=row["id"],
|
||
enterprise_id=row["enterprise_id"],
|
||
name=row["name"],
|
||
parent_id=row["parent_id"],
|
||
created_at=row["created_at"],
|
||
).model_dump(),
|
||
)
|
||
except asyncpg.UniqueViolationError:
|
||
raise HTTPException(status_code=400, detail="同企业下部门名称已存在")
|
||
|
||
|
||
@admin_router.put("/departments/{dept_id}", response_model=BaseResponse, summary="更新部门")
|
||
async def update_department(
|
||
dept_id: int,
|
||
body: DepartmentUpdate,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
if body.parent_id is not None:
|
||
parent = await DepartmentService.get_by_id(conn, body.parent_id, admin.enterprise_id)
|
||
if not parent:
|
||
raise HTTPException(status_code=400, detail="上级部门不存在")
|
||
row = await DepartmentService.update(
|
||
conn, dept_id, admin.enterprise_id, name=body.name, parent_id=body.parent_id
|
||
)
|
||
if not row:
|
||
raise HTTPException(status_code=404, detail="部门不存在")
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="更新成功",
|
||
data=DepartmentResponse(
|
||
id=row["id"],
|
||
enterprise_id=row["enterprise_id"],
|
||
name=row["name"],
|
||
parent_id=row["parent_id"],
|
||
created_at=row["created_at"],
|
||
).model_dump(),
|
||
)
|
||
|
||
|
||
@admin_router.delete("/departments/{dept_id}", response_model=BaseResponse, summary="删除部门")
|
||
async def delete_department(
|
||
dept_id: int,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
err = await DepartmentService.delete(conn, dept_id, admin.enterprise_id)
|
||
if err:
|
||
raise HTTPException(status_code=400, detail=err)
|
||
return BaseResponse(code=200, msg="删除成功", data=None)
|
||
|
||
|
||
@admin_router.get("/users", response_model=BaseResponse, summary="用户列表")
|
||
async def list_users(
|
||
page: int = Query(1, ge=1),
|
||
page_size: int = Query(20, ge=1, le=100),
|
||
username: Optional[str] = Query(None, description="用户名(模糊)"),
|
||
email: Optional[str] = Query(None, description="邮箱(模糊)"),
|
||
phone: Optional[str] = Query(None, description="手机号(模糊)"),
|
||
display_name: Optional[str] = Query(None, description="显示名(模糊)"),
|
||
department_id: Optional[int] = Query(None, description="按部门 ID 精确筛选"),
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
if department_id is not None:
|
||
d = await DepartmentService.get_by_id(conn, department_id, admin.enterprise_id)
|
||
if not d:
|
||
raise HTTPException(status_code=400, detail="部门不存在")
|
||
rows, total = await AdminUserService.list_users(
|
||
conn,
|
||
admin.enterprise_id,
|
||
page,
|
||
page_size,
|
||
username=username,
|
||
email=email,
|
||
phone=phone,
|
||
display_name=display_name,
|
||
department_id=department_id,
|
||
)
|
||
items = [AdminUserListItem(**r).model_dump() for r in rows]
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="ok",
|
||
data=AdminUserListResponse(total=total, items=items).model_dump(),
|
||
)
|
||
|
||
|
||
@admin_router.post("/users", response_model=BaseResponse, summary="创建用户")
|
||
async def create_user(
|
||
body: AdminUserCreate,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
if body.department_id is not None:
|
||
d = await DepartmentService.get_by_id(conn, body.department_id, admin.enterprise_id)
|
||
if not d:
|
||
raise HTTPException(status_code=400, detail="部门不存在")
|
||
try:
|
||
row = await AdminUserService.create_user(conn, admin.enterprise_id, body)
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="创建成功",
|
||
data=AdminUserListItem(**row).model_dump(),
|
||
)
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|
||
@admin_router.get("/users/{user_id}", response_model=BaseResponse, summary="用户详情")
|
||
async def get_user(
|
||
user_id: int,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
row = await AdminUserService.get_user(conn, admin.enterprise_id, user_id)
|
||
if not row:
|
||
raise HTTPException(status_code=404, detail="用户不存在")
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="ok",
|
||
data=AdminUserListItem(**row).model_dump(),
|
||
)
|
||
|
||
|
||
@admin_router.put("/users/{user_id}", response_model=BaseResponse, summary="更新用户")
|
||
async def update_user(
|
||
user_id: int,
|
||
body: AdminUserUpdate,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
unset = body.model_dump(exclude_unset=True)
|
||
if "department_id" in unset and unset["department_id"] is not None:
|
||
d = await DepartmentService.get_by_id(conn, unset["department_id"], admin.enterprise_id)
|
||
if not d:
|
||
raise HTTPException(status_code=400, detail="部门不存在")
|
||
try:
|
||
row = await AdminUserService.update_user(conn, admin, user_id, body)
|
||
if not row:
|
||
raise HTTPException(status_code=404, detail="用户不存在")
|
||
return BaseResponse(
|
||
code=200,
|
||
msg="更新成功",
|
||
data=AdminUserListItem(**row).model_dump(),
|
||
)
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
|
||
|
||
@admin_router.delete("/users/{user_id}", response_model=BaseResponse, summary="删除用户")
|
||
async def delete_user(
|
||
user_id: int,
|
||
admin: User = Depends(get_current_admin_user),
|
||
conn: asyncpg.Connection = Depends(get_db),
|
||
):
|
||
try:
|
||
ok = await AdminUserService.delete_user(conn, admin, user_id)
|
||
if not ok:
|
||
raise HTTPException(status_code=404, detail="用户不存在")
|
||
return BaseResponse(code=200, msg="删除成功", data=None)
|
||
except ValueError as e:
|
||
raise HTTPException(status_code=400, detail=str(e))
|
||
except asyncpg.ForeignKeyViolationError:
|
||
raise HTTPException(
|
||
status_code=400,
|
||
detail="该用户仍存在关联数据(如会话、知识库归属等),无法直接删除,请先禁用账号",
|
||
)
|