feat(权限): 实现权限树形结构管理

- 在权限模型中添加 parentid 字段支持树形结构
- 新增权限树形结构 API 接口
- 更新初始化脚本以支持权限树形结构
- 调整权限字段长度限制
This commit is contained in:
jayhgq 2026-04-30 16:01:05 +08:00
parent a3206bb0f6
commit 5632b0d69c
9 changed files with 159 additions and 45 deletions

View File

@ -2,12 +2,14 @@ from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select from sqlalchemy import select
from fastcrud import FastCRUD from fastcrud import FastCRUD
from typing import Dict, Any
from database import get_db from database import get_db
from models import Permission, Role from models import Permission, Role
from schemas import ( from schemas import (
PermissionCreate, PermissionCreate,
PermissionResponse, PermissionResponse,
PermissionTreeResponse,
RolePermissionAssign, RolePermissionAssign,
RolePermissionResponse, RolePermissionResponse,
) )
@ -37,6 +39,7 @@ async def create_permission(
db_permission = Permission( db_permission = Permission(
name=permission_data.name, name=permission_data.name,
code=permission_data.code, code=permission_data.code,
parentid=permission_data.parentid,
description=permission_data.description, description=permission_data.description,
) )
@ -58,6 +61,40 @@ async def get_permissions(
return permissions return permissions
@router.get("/tree", response_model=list[PermissionTreeResponse])
async def get_permission_tree(
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""获取权限树形结构(基于 parentid"""
# 获取所有权限
result = await db.execute(select(Permission))
permissions = result.scalars().all()
# 转换为字典,便于查找
perm_dict = {perm.id: {
"id": perm.id,
"name": perm.name,
"code": perm.code,
"parentid": perm.parentid,
"description": perm.description,
"children": []
} for perm in 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) @router.get("/{permission_id}", response_model=PermissionResponse)
async def get_permission( async def get_permission(
permission_id: int, permission_id: int,

Binary file not shown.

View File

@ -1,66 +1,129 @@
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select from sqlalchemy import select, text
from models import Role, User, Permission from models import Role, User, Permission
from utils.password import get_password_hash from utils.password import get_password_hash
async def ensure_permission_table_structure(db: AsyncSession):
"""确保 permission 表结构符合最新要求"""
print("检查并更新 permission 表结构...")
# 检查表是否存在
result = await db.execute(
text("SELECT table_name FROM information_schema.tables WHERE table_name = 'permission'")
)
table_exists = result.scalar_one_or_none()
if not table_exists:
print("permission 表不存在,将由 SQLAlchemy 创建")
return
# 检查是否缺少 parentid 字段
result = await db.execute(
text("SELECT column_name FROM information_schema.columns WHERE table_name = 'permission'")
)
existing_columns = {row[0] for row in result.fetchall()}
# 添加 parentid 字段
if 'parentid' not in existing_columns:
try:
await db.execute(text("ALTER TABLE permission ADD COLUMN IF NOT EXISTS parentid INTEGER DEFAULT 0"))
print("添加 parentid 字段成功")
except Exception as e:
print(f"添加 parentid 字段失败: {e}")
# 删除旧字段(如果存在)
for old_column in ['module', 'submodule', 'action']:
if old_column in existing_columns:
try:
await db.execute(text(f"ALTER TABLE permission DROP COLUMN IF EXISTS {old_column}"))
print(f"删除旧字段 {old_column} 成功")
except Exception as e:
print(f"删除旧字段 {old_column} 失败: {e}")
await db.commit()
print("permission 表结构更新完成")
async def init_permissions(db: AsyncSession): async def init_permissions(db: AsyncSession):
"""初始化权限数据""" """初始化权限数据(树形结构)"""
# 定义需要初始化的权限 # 定义需要初始化的权限(树形结构)
required_permissions = [ # parentid: 0 = 顶级模块, >0 = 子权限
{"name": "用户管理", "code": "user:manage", "description": "用户管理权限"}, permission_tree = [
{"name": "用户查询", "code": "user:read", "description": "用户查询权限"}, # 顶级模块
{"name": "用户创建", "code": "user:create", "description": "用户创建权限"}, {"name": "权限管理", "code": "perm", "parentid": 0, "description": "权限管理模块"},
{"name": "用户更新", "code": "user:update", "description": "用户更新权限"},
{"name": "用户删除", "code": "user:delete", "description": "用户删除权限"}, # 二级子模块
{"name": "角色管理", "code": "role:manage", "description": "角色管理权限"}, {"name": "用户管理", "code": "perm:user", "parentid": 1, "description": "用户管理子模块"},
{"name": "角色查询", "code": "role:read", "description": "角色查询权限"}, {"name": "角色管理", "code": "perm:role", "parentid": 1, "description": "角色管理子模块"},
{"name": "角色创建", "code": "role:create", "description": "角色创建权限"}, {"name": "权限配置", "code": "perm:config", "parentid": 1, "description": "权限配置子模块"},
{"name": "角色更新", "code": "role:update", "description": "角色更新权限"},
{"name": "角色删除", "code": "role:delete", "description": "角色删除权限"}, # 用户管理操作
{"name": "权限管理", "code": "permission:manage", "description": "权限管理权限"}, {"name": "查看列表", "code": "perm:user:list", "parentid": 2, "description": "查看用户列表"},
{"name": "权限查询", "code": "permission:read", "description": "权限查询权限"}, {"name": "查看详情", "code": "perm:user:detail", "parentid": 2, "description": "查看用户详情"},
{"name": "权限创建", "code": "permission:create", "description": "权限创建权限"}, {"name": "搜索", "code": "perm:user:search", "parentid": 2, "description": "搜索用户"},
{"name": "权限更新", "code": "permission:update", "description": "权限更新权限"}, {"name": "创建", "code": "perm:user:create", "parentid": 2, "description": "创建新用户"},
{"name": "权限删除", "code": "permission:delete", "description": "权限删除权限"}, {"name": "编辑", "code": "perm:user:edit", "parentid": 2, "description": "编辑用户信息"},
{"name": "删除", "code": "perm:user:delete", "parentid": 2, "description": "删除用户"},
{"name": "导出", "code": "perm:user:export", "parentid": 2, "description": "导出用户数据"},
# 角色管理操作
{"name": "查看列表", "code": "perm:role:list", "parentid": 3, "description": "查看角色列表"},
{"name": "查看详情", "code": "perm:role:detail", "parentid": 3, "description": "查看角色详情"},
{"name": "搜索", "code": "perm:role:search", "parentid": 3, "description": "搜索角色"},
{"name": "创建", "code": "perm:role:create", "parentid": 3, "description": "创建新角色"},
{"name": "编辑", "code": "perm:role:edit", "parentid": 3, "description": "编辑角色信息"},
{"name": "删除", "code": "perm:role:delete", "parentid": 3, "description": "删除角色"},
{"name": "导出", "code": "perm:role:export", "parentid": 3, "description": "导出角色数据"},
{"name": "分配权限", "code": "perm:role:assign", "parentid": 3, "description": "为角色分配权限"},
# 权限配置操作
{"name": "查看列表", "code": "perm:config:list", "parentid": 4, "description": "查看权限列表"},
{"name": "查看详情", "code": "perm:config:detail", "parentid": 4, "description": "查看权限详情"},
{"name": "搜索", "code": "perm:config:search", "parentid": 4, "description": "搜索权限"},
{"name": "创建", "code": "perm:config:create", "parentid": 4, "description": "创建新权限"},
{"name": "编辑", "code": "perm:config:edit", "parentid": 4, "description": "编辑权限信息"},
{"name": "删除", "code": "perm:config:delete", "parentid": 4, "description": "删除权限"},
{"name": "导出", "code": "perm:config:export", "parentid": 4, "description": "导岀权限数据"},
] ]
# 检查现有权限 # 检查现有权限
result = await db.execute(select(Permission)) result = await db.execute(select(Permission))
existing_permissions = result.scalars().all() existing_permissions = result.scalars().all()
existing_permission_codes = {perm.code for perm in existing_permissions} existing_permission_codes = {perm.code: perm for perm in existing_permissions}
# 检查需要创建或更新的权限 # 创建或更新权限
permissions_to_add = [] created_count = 0
permissions_to_update = [] updated_count = 0
for perm_data in required_permissions: for perm_data in permission_tree:
perm_code = perm_data["code"] perm_code = perm_data["code"]
if perm_code not in existing_permission_codes: if perm_code not in existing_permission_codes:
# 权限不存在,需要创建 # 权限不存在,需要创建
permissions_to_add.append(Permission(**perm_data)) db.add(Permission(**perm_data))
created_count += 1
else: else:
# 权限存在,检查是否需要更新 # 权限存在,检查是否需要更新
existing_perm = next( existing_perm = existing_permission_codes[perm_code]
perm for perm in existing_permissions if perm.code == perm_code update_needed = False
)
if existing_perm.name != perm_data["name"] or existing_perm.description != perm_data["description"]: if existing_perm.name != perm_data["name"]:
existing_perm.name = perm_data["name"] existing_perm.name = perm_data["name"]
update_needed = True
if existing_perm.parentid != perm_data["parentid"]:
existing_perm.parentid = perm_data["parentid"]
update_needed = True
if existing_perm.description != perm_data["description"]:
existing_perm.description = perm_data["description"] existing_perm.description = perm_data["description"]
permissions_to_update.append(existing_perm) update_needed = True
if update_needed:
updated_count += 1
# 执行创建和更新操作 if created_count > 0 or updated_count > 0:
if permissions_to_add:
for perm in permissions_to_add:
db.add(perm)
await db.commit() await db.commit()
print(f"创建了 {len(permissions_to_add)} 个权限") print(f"创建了 {created_count} 个权限,更新了 {updated_count} 个权限")
else:
if permissions_to_update:
await db.commit()
print(f"更新了 {len(permissions_to_update)} 个权限")
if not permissions_to_add and not permissions_to_update:
print("权限数据已存在且无需更新,跳过初始化") print("权限数据已存在且无需更新,跳过初始化")
print("权限数据初始化/更新完成") print("权限数据初始化/更新完成")
@ -293,6 +356,7 @@ async def init_test_user(db: AsyncSession):
async def init_all_data(db: AsyncSession): async def init_all_data(db: AsyncSession):
"""初始化所有数据""" """初始化所有数据"""
print("开始初始化数据库数据...") print("开始初始化数据库数据...")
await ensure_permission_table_structure(db)
await init_roles(db) await init_roles(db)
await init_permissions(db) await init_permissions(db)
await init_role_permissions(db) await init_role_permissions(db)

View File

@ -56,8 +56,9 @@ class Permission(Base):
__tablename__ = "permission" __tablename__ = "permission"
id = Column(Integer, primary_key=True, index=True, comment="权限ID") id = Column(Integer, primary_key=True, index=True, comment="权限ID")
name = Column(String(50), nullable=False, comment="权限名称") name = Column(String(100), nullable=False, comment="权限名称")
code = Column(String(50), nullable=False, unique=True, comment="权限编码") code = Column(String(100), nullable=False, unique=True, comment="权限编码")
parentid = Column(Integer, default=0, comment="父权限ID0表示顶级模块")
description = Column(String(255), nullable=True, comment="权限描述") description = Column(String(255), nullable=True, comment="权限描述")
createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间") createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间")
updatetime = Column( updatetime = Column(

View File

@ -112,8 +112,9 @@ class RoleResponse(RoleBase):
class PermissionBase(BaseModel): class PermissionBase(BaseModel):
"""权限基础模型""" """权限基础模型"""
name: str = Field(..., max_length=50, description="权限名称") name: str = Field(..., max_length=100, description="权限名称")
code: str = Field(..., max_length=50, description="权限编码") code: str = Field(..., max_length=100, description="权限编码")
parentid: int = Field(0, description="父权限ID0表示顶级模块")
description: Optional[str] = Field(None, max_length=255, description="权限描述") description: Optional[str] = Field(None, max_length=255, description="权限描述")
@ -133,6 +134,17 @@ class PermissionResponse(PermissionBase):
from_attributes = True from_attributes = True
class PermissionTreeResponse(BaseModel):
"""权限树响应模型"""
id: int = Field(..., description="权限ID")
name: str = Field(..., description="权限名称")
code: str = Field(..., description="权限编码")
parentid: int = Field(..., description="父权限ID")
description: Optional[str] = Field(None, description="权限描述")
children: list = Field([], description="子权限列表")
# 角色权限关联相关模型 # 角色权限关联相关模型
class RolePermissionAssign(BaseModel): class RolePermissionAssign(BaseModel):
"""角色权限分配模型""" """角色权限分配模型"""