From 96f83923f6d3925fc33e61c5f7e88bceeeff6aad Mon Sep 17 00:00:00 2001 From: chengkai3 Date: Thu, 18 Jun 2026 12:35:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:[FL-197][=E8=A7=92=E8=89=B2=E7=AE=A1?= =?UTF-8?q?=E7=90=86=20-=20=E4=BF=AE=E5=A4=8D=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E8=A1=A8=20user=5Frole=20=E4=B8=8D=E5=AD=98=E5=9C=A8=E9=94=99?= =?UTF-8?q?=E8=AF=AF]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复角色创建功能在使用现代表结构(roles)时因硬编码查询 user_role 表而导致的数据库错误。 问题分析: - admin.py:72 直接硬编码查询 user_role 表检查角色是否存在 - legacy_admin_rbac_service.py:201 也硬编码查询 user_role 表 - 实际项目使用的是现代表结构 roles(定义在 rbac.py) - 导致 psycopg.errors.UndefinedTable: relation "user_role" does not exist 修复方案: 1. 移除 admin.py 中的硬编码表查询,将重复检查逻辑委托给 create_role 服务函数 2. 在 create_role 函数中添加 role_source 检测逻辑 3. 根据检测结果使用正确的表名(user_role 或 roles)和字段 4. 确保 legacy 和 modern 模式下都能正常工作 影响范围: - 角色创建功能现在支持两种表结构 - 保持向后兼容性(legacy 模式仍使用 user_role) - 修复 modern 模式下的角色创建功能 Co-Authored-By: Claude Sonnet 4.6 Co-authored-by: multica-agent --- api/app/api/v1/admin.py | 8 +-- api/app/services/legacy_admin_rbac_service.py | 59 +++++++++++++------ 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/api/app/api/v1/admin.py b/api/app/api/v1/admin.py index 9a73f30..f9f0f2f 100644 --- a/api/app/api/v1/admin.py +++ b/api/app/api/v1/admin.py @@ -67,15 +67,9 @@ def create_role_endpoint( current_user: CurrentUser = Depends(require_permission("role.manage")), db: Session = Depends(get_db), ) -> RolePublic: - from sqlalchemy import text - # Check if role code already exists - existing = db.scalar(text("SELECT id FROM user_role WHERE id = :id"), {"id": payload.code.strip()}) - if existing: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="角色编码已存在,请使用其他编码") - created = create_role(db, payload, actor_user_id=current_user.user.id) if not created: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="创建角色失败,请检查菜单权限配置是否正确") + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="创建角色失败,角色编码已存在或菜单权限配置不正确") return created diff --git a/api/app/services/legacy_admin_rbac_service.py b/api/app/services/legacy_admin_rbac_service.py index 85f8909..2653f04 100644 --- a/api/app/services/legacy_admin_rbac_service.py +++ b/api/app/services/legacy_admin_rbac_service.py @@ -198,32 +198,55 @@ def create_role(db: Session, payload: RoleCreateRequest, *, actor_user_id: str | role_name = payload.name.strip() if not role_name: return None - existing = db.scalar(text("SELECT id FROM user_role WHERE id = :id"), {"id": role_id}) + + role_source = "legacy" if _legacy_role_table_exists(db) else "modern" + + # Check if role code already exists + if role_source == "legacy": + existing = db.scalar(text("SELECT id FROM user_role WHERE id = :id"), {"id": role_id}) + else: + existing = db.scalar(text("SELECT id FROM roles WHERE code = :code"), {"code": role_id}) + if existing: return None menu_ids = sorted(set(menu_id.strip() for menu_id in payload.menu_ids if menu_id.strip())) - if not _menu_ids_exist(db, menu_ids): + if not _menu_ids_exist(db, menu_ids, role_source=role_source): return None now = datetime.now() try: - db.execute( - text( - """ - INSERT INTO user_role (id, name, descr, state, create_date, update_date) - VALUES (:id, :name, :descr, 'ENABLED', :create_date, :update_date) - """ - ), - { - "id": role_id, - "name": role_name, - "descr": role_name, - "create_date": now, - "update_date": now, - }, - ) - _replace_role_menus_internal(db, role_id, menu_ids) + if role_source == "legacy": + db.execute( + text( + """ + INSERT INTO user_role (id, name, descr, state, create_date, update_date) + VALUES (:id, :name, :descr, 'ENABLED', :create_date, :update_date) + """ + ), + { + "id": role_id, + "name": role_name, + "descr": role_name, + "create_date": now, + "update_date": now, + }, + ) + else: + db.execute( + text( + """ + INSERT INTO roles (code, name) + VALUES (:code, :name) + """ + ), + { + "code": role_id, + "name": role_name, + }, + ) + + _replace_role_menus_internal(db, role_id, menu_ids, role_source=role_source) write_audit_log( db, action="role.create",