diff --git a/backend/auth/apps/permissions/urls.py b/backend/auth/apps/permissions/urls.py index 8835897..ec8bfa8 100644 --- a/backend/auth/apps/permissions/urls.py +++ b/backend/auth/apps/permissions/urls.py @@ -107,6 +107,70 @@ async def get_permission_tree( return tree +@router.get("/menu", response_model=list[PermissionTreeResponse]) +async def get_menu( + db: AsyncSession = Depends(get_db), + current_user: User = Depends(get_current_user), +): + """获取当前用户的菜单树形结构(仅包含有路由的权限)""" + # 获取用户角色的权限 + result = await db.execute( + select(Role) + .options(selectinload(Role.permissions)) + .filter(Role.id == current_user.role_id) + ) + role = result.scalar_one_or_none() + + if not role: + raise HTTPException(status_code=404, detail="角色不存在") + + # 获取用户有权限的权限编码集合 + user_permission_codes = {perm.code for perm in role.permissions} + + # 获取所有顶级模块和二级模块权限(有route字段的) + result = await db.execute( + select(Permission) + .filter(Permission.route.isnot(None)) + ) + all_menu_permissions = result.scalars().all() + + # 过滤用户有权限的菜单 + user_menu_permissions = [] + for perm in all_menu_permissions: + # 检查用户是否有该权限或其子权限 + has_access = False + for user_perm_code in user_permission_codes: + if user_perm_code.startswith(perm.code): + has_access = True + break + if has_access: + user_menu_permissions.append(perm) + + # 转换为字典,便于查找 + perm_dict = {perm.id: { + "id": perm.id, + "name": perm.name, + "code": perm.code, + "parentid": perm.parentid, + "route": perm.route, + "description": perm.description, + "children": [] + } for perm in user_menu_permissions} + + # 构建树形结构 + tree = [] + for perm_id, perm_data in perm_dict.items(): + parentid = perm_data["parentid"] + if parentid == 0: + # 顶级节点 + tree.append(perm_data) + elif parentid in perm_dict: + # 子节点,添加到父节点的 children + perm_dict[parentid]["children"].append(perm_data) + + return tree + + @router.get("/{permission_id}", response_model=PermissionResponse) async def get_permission( permission_id: int, @@ -227,7 +291,7 @@ async def get_current_user_permissions( db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): - """获取当前登录用户的权限列表""" + """获取当前登录用户的权限列表和菜单""" # 获取用户角色的权限 result = await db.execute( select(Role) @@ -239,9 +303,54 @@ async def get_current_user_permissions( if not role: raise HTTPException(status_code=404, detail="角色不存在") - # 返回用户权限信息 + # 获取用户有权限的权限编码集合 + user_permission_codes = {perm.code for perm in role.permissions} + + # 获取所有顶级模块和二级模块权限(有route字段的) + result = await db.execute( + select(Permission) + .filter(Permission.route.isnot(None)) + ) + all_menu_permissions = result.scalars().all() + + # 过滤用户有权限的菜单 + user_menu_permissions = [] + for perm in all_menu_permissions: + # 检查用户是否有该权限或其子权限 + has_access = False + for user_perm_code in user_permission_codes: + if user_perm_code.startswith(perm.code): + has_access = True + break + if has_access: + user_menu_permissions.append(perm) + + # 转换为字典,便于查找 + perm_dict = {perm.id: { + "id": perm.id, + "name": perm.name, + "code": perm.code, + "parentid": perm.parentid, + "route": perm.route, + "description": perm.description, + "children": [] + } for perm in user_menu_permissions} + + # 构建树形结构 + menu_tree = [] + for perm_id, perm_data in perm_dict.items(): + parentid = perm_data["parentid"] + if parentid == 0: + # 顶级节点 + menu_tree.append(perm_data) + elif parentid in perm_dict: + # 子节点,添加到父节点的 children + perm_dict[parentid]["children"].append(perm_data) + + # 返回用户权限信息和菜单 return RolePermissionResponse( role_id=role.id, role_name=role.name, - permissions=[PermissionResponse.from_orm(p) for p in role.permissions] - ) \ No newline at end of file + permissions=[PermissionResponse.from_orm(p) for p in role.permissions], + menu=menu_tree + ) diff --git a/backend/auth/init_data.py b/backend/auth/init_data.py index d4838b6..1775375 100644 --- a/backend/auth/init_data.py +++ b/backend/auth/init_data.py @@ -1,6 +1,6 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, text -from models import Role, User, Permission +from models import Role, User, Permission, SystemSetting from utils.password import get_password_hash @@ -32,6 +32,14 @@ async def ensure_permission_table_structure(db: AsyncSession): except Exception as e: print(f"添加 parentid 字段失败: {e}") + # 添加 route 字段 + if 'route' not in existing_columns: + try: + await db.execute(text("ALTER TABLE permission ADD COLUMN IF NOT EXISTS route VARCHAR(255)")) + print("添加 route 字段成功") + except Exception as e: + print(f"添加 route 字段失败: {e}") + # 删除旧字段(如果存在) for old_column in ['module', 'submodule', 'action']: if old_column in existing_columns: @@ -53,21 +61,21 @@ async def init_permissions(db: AsyncSession): # ======================================== # 顶级模块 # ======================================== - {"name": "权限管理", "code": "perm", "parentid": 0, "description": "权限管理模块"}, - {"name": "系统设置", "code": "system", "parentid": 0, "description": "系统设置模块"}, + {"name": "权限管理", "code": "perm", "parentid": 0, "route": "/admin/permissions", "description": "权限管理模块"}, + {"name": "系统设置", "code": "system", "parentid": 0, "route": "/admin/settings", "description": "系统设置模块"}, # ======================================== # 权限管理 -> 二级子模块 # ======================================== - {"name": "用户管理", "code": "perm:user", "parentid": 1, "description": "用户管理子模块"}, - {"name": "角色管理", "code": "perm:role", "parentid": 1, "description": "角色管理子模块"}, - {"name": "权限配置", "code": "perm:config", "parentid": 1, "description": "权限配置子模块"}, + {"name": "用户管理", "code": "perm:user", "parentid": 1, "route": "/admin/users", "description": "用户管理子模块"}, + {"name": "角色管理", "code": "perm:role", "parentid": 1, "route": "/admin/roles", "description": "角色管理子模块"}, + {"name": "权限配置", "code": "perm:config", "parentid": 1, "route": "/admin/permissions", "description": "权限配置子模块"}, # ======================================== # 系统设置 -> 二级子模块 # ======================================== - {"name": "基础配置", "code": "system:basic", "parentid": 2, "description": "系统基础配置"}, - {"name": "高级配置", "code": "system:advanced", "parentid": 2, "description": "系统高级配置"}, + {"name": "基础配置", "code": "system:basic", "parentid": 2, "route": "/admin/settings", "description": "系统基础配置"}, + {"name": "高级配置", "code": "system:advanced", "parentid": 2, "route": "/admin/settings", "description": "系统高级配置"}, # ======================================== # 用户管理操作(parentid=3) @@ -143,6 +151,9 @@ async def init_permissions(db: AsyncSession): if existing_perm.parentid != perm_data["parentid"]: existing_perm.parentid = perm_data["parentid"] update_needed = True + if existing_perm.route != perm_data.get("route"): + existing_perm.route = perm_data.get("route") + update_needed = True if existing_perm.description != perm_data["description"]: existing_perm.description = perm_data["description"] update_needed = True @@ -383,6 +394,60 @@ async def init_test_user(db: AsyncSession): print("测试用户初始化/更新完成") +async def init_system_settings(db: AsyncSession): + """初始化系统设置数据""" + # 定义需要初始化的系统设置 + system_settings = [ + { + "key": "系统标题", + "value": "图书管理系统", + "type": "string", + "description": "系统显示标题" + }, + ] + + # 检查现有系统设置 + result = await db.execute(select(SystemSetting)) + existing_settings = result.scalars().all() + existing_setting_keys = {setting.key: setting for setting in existing_settings} + + # 创建或更新系统设置 + created_count = 0 + updated_count = 0 + + for setting_data in system_settings: + setting_key = setting_data["key"] + if setting_key not in existing_setting_keys: + # 设置不存在,需要创建 + db.add(SystemSetting(**setting_data)) + created_count += 1 + else: + # 设置存在,检查是否需要更新 + existing_setting = existing_setting_keys[setting_key] + update_needed = False + + if existing_setting.value != setting_data["value"]: + existing_setting.value = setting_data["value"] + update_needed = True + if existing_setting.type != setting_data["type"]: + existing_setting.type = setting_data["type"] + update_needed = True + if existing_setting.description != setting_data.get("description"): + existing_setting.description = setting_data.get("description") + update_needed = True + + if update_needed: + updated_count += 1 + + if created_count > 0 or updated_count > 0: + await db.commit() + print(f"创建了 {created_count} 个系统设置,更新了 {updated_count} 个系统设置") + else: + print("系统设置数据已存在且无需更新,跳过初始化") + + print("系统设置数据初始化/更新完成") + + async def init_all_data(db: AsyncSession): """初始化所有数据""" print("开始初始化数据库数据...") @@ -392,4 +457,5 @@ async def init_all_data(db: AsyncSession): await init_role_permissions(db) await init_admin_user(db) await init_test_user(db) + await init_system_settings(db) print("数据库数据初始化完成") diff --git a/backend/auth/models.py b/backend/auth/models.py index e602496..dacd443 100644 --- a/backend/auth/models.py +++ b/backend/auth/models.py @@ -59,6 +59,7 @@ class Permission(Base): name = Column(String(100), nullable=False, comment="权限名称") code = Column(String(100), nullable=False, unique=True, comment="权限编码") parentid = Column(Integer, default=0, comment="父权限ID(0表示顶级模块)") + route = Column(String(255), nullable=True, comment="前端路由路径") description = Column(String(255), nullable=True, comment="权限描述") createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间") updatetime = Column( diff --git a/backend/auth/schemas.py b/backend/auth/schemas.py index 1bf5961..67dafd6 100644 --- a/backend/auth/schemas.py +++ b/backend/auth/schemas.py @@ -139,6 +139,7 @@ class PermissionBase(BaseModel): name: str = Field(..., max_length=100, description="权限名称") code: str = Field(..., max_length=100, description="权限编码") parentid: int = Field(0, description="父权限ID(0表示顶级模块)") + route: Optional[str] = Field(None, max_length=255, description="前端路由路径") description: Optional[str] = Field(None, max_length=255, description="权限描述") @@ -165,6 +166,7 @@ class PermissionTreeResponse(BaseModel): name: str = Field(..., description="权限名称") code: str = Field(..., description="权限编码") parentid: int = Field(..., description="父权限ID") + route: Optional[str] = Field(None, description="前端路由路径") description: Optional[str] = Field(None, description="权限描述") children: list = Field([], description="子权限列表") @@ -183,6 +185,7 @@ class RolePermissionResponse(BaseModel): role_id: int = Field(..., description="角色ID") role_name: str = Field(..., description="角色名称") permissions: list[PermissionResponse] = Field(..., description="权限列表") + menu: list = Field([], description="菜单树形结构") # 系统设置相关模型 diff --git a/frontend/src/modules/admin/layout/AdminLayout.vue b/frontend/src/modules/admin/layout/AdminLayout.vue index 838eccb..0bdab64 100644 --- a/frontend/src/modules/admin/layout/AdminLayout.vue +++ b/frontend/src/modules/admin/layout/AdminLayout.vue @@ -9,47 +9,34 @@ text-color="#e2e8f0" active-text-color="#38bdf8" > - - - - + @@ -72,9 +59,9 @@