From 659f60e76574eb3f88087d8b45a8ceb16d85e4ed Mon Sep 17 00:00:00 2001 From: yuliang_guo Date: Mon, 2 Feb 2026 16:21:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=AF=BE=E7=A8=8B?= =?UTF-8?q?=E6=9D=83=E9=99=90=E5=92=8C=E6=B7=BB=E5=8A=A0409=E5=86=B2?= =?UTF-8?q?=E7=AA=81=E7=BB=9F=E4=B8=80=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 课程权限修复: - 创建课程: require_admin -> require_admin_or_manager - 更新课程: require_admin -> require_admin_or_manager - 现在manager角色也可以创建和编辑课程 2. 全局409冲突处理: - 添加IntegrityError异常处理器 - 自动识别常见冲突类型(用户名/邮箱/手机号/名称/编码) - 返回友好的中文错误提示 --- backend/app/api/v1/courses.py | 8 +++---- backend/app/main.py | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/backend/app/api/v1/courses.py b/backend/app/api/v1/courses.py index c5e9ac0..8af7df6 100644 --- a/backend/app/api/v1/courses.py +++ b/backend/app/api/v1/courses.py @@ -81,11 +81,11 @@ async def get_courses( async def create_course( course_in: CourseCreate, request: Request, - current_user: User = Depends(require_admin), + current_user: User = Depends(require_admin_or_manager), db: AsyncSession = Depends(get_db), ): """ - 创建课程(需要管理员权限) + 创建课程(需要管理员或经理权限) - **name**: 课程名称 - **description**: 课程描述 @@ -144,11 +144,11 @@ async def get_course( async def update_course( course_id: int, course_in: CourseUpdate, - current_user: User = Depends(require_admin), + current_user: User = Depends(require_admin_or_manager), db: AsyncSession = Depends(get_db), ): """ - 更新课程(需要管理员权限) + 更新课程(需要管理员或经理权限) - **course_id**: 课程ID - **course_in**: 更新的课程数据(所有字段都是可选的) diff --git a/backend/app/main.py b/backend/app/main.py index 32594f2..a14ede2 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -188,6 +188,46 @@ async def http_exception_handler(request: Request, exc: HTTPException): ) +# 数据库唯一约束冲突处理 (409) +from sqlalchemy.exc import IntegrityError +@app.exception_handler(IntegrityError) +async def integrity_error_handler(request: Request, exc: IntegrityError): + """处理数据库唯一约束冲突错误""" + error_msg = str(exc.orig) if exc.orig else str(exc) + logger.warning(f"数据库冲突 [{request.method} {request.url.path}]: {error_msg}") + + # 解析常见的冲突类型,提供友好的错误信息 + friendly_message = "数据冲突,该记录可能已存在" + + if "Duplicate entry" in error_msg: + # MySQL 唯一约束冲突 + if "username" in error_msg.lower(): + friendly_message = "用户名已存在,请使用其他用户名" + elif "email" in error_msg.lower(): + friendly_message = "邮箱已被注册,请使用其他邮箱" + elif "phone" in error_msg.lower(): + friendly_message = "手机号已被注册,请使用其他手机号" + elif "name" in error_msg.lower(): + friendly_message = "名称已存在,请使用其他名称" + elif "code" in error_msg.lower(): + friendly_message = "编码已存在,请使用其他编码" + else: + friendly_message = "该记录已存在,不能重复创建" + elif "FOREIGN KEY" in error_msg.upper(): + friendly_message = "关联的数据不存在或已被删除" + elif "cannot be null" in error_msg.lower(): + friendly_message = "必填字段不能为空" + + return JSONResponse( + status_code=409, + content={ + "code": 409, + "message": friendly_message, + "detail": error_msg if settings.DEBUG else None, + }, + ) + + # 全局异常处理 @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception):