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 import select
from fastcrud import FastCRUD
from typing import Dict, Any
from database import get_db
from models import Permission, Role
from schemas import (
PermissionCreate,
PermissionResponse,
PermissionTreeResponse,
RolePermissionAssign,
RolePermissionResponse,
)
@ -37,6 +39,7 @@ async def create_permission(
db_permission = Permission(
name=permission_data.name,
code=permission_data.code,
parentid=permission_data.parentid,
description=permission_data.description,
)
@ -58,6 +61,40 @@ async def get_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)
async def get_permission(
permission_id: int,

Binary file not shown.

View File

@ -1,66 +1,129 @@
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from sqlalchemy import select, text
from models import Role, User, Permission
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):
"""初始化权限数据"""
# 定义需要初始化的权限
required_permissions = [
{"name": "用户管理", "code": "user:manage", "description": "用户管理权限"},
{"name": "用户查询", "code": "user:read", "description": "用户查询权限"},
{"name": "用户创建", "code": "user:create", "description": "用户创建权限"},
{"name": "用户更新", "code": "user:update", "description": "用户更新权限"},
{"name": "用户删除", "code": "user:delete", "description": "用户删除权限"},
{"name": "角色管理", "code": "role:manage", "description": "角色管理权限"},
{"name": "角色查询", "code": "role:read", "description": "角色查询权限"},
{"name": "角色创建", "code": "role:create", "description": "角色创建权限"},
{"name": "角色更新", "code": "role:update", "description": "角色更新权限"},
{"name": "角色删除", "code": "role:delete", "description": "角色删除权限"},
{"name": "权限管理", "code": "permission:manage", "description": "权限管理权限"},
{"name": "权限查询", "code": "permission:read", "description": "权限查询权限"},
{"name": "权限创建", "code": "permission:create", "description": "权限创建权限"},
{"name": "权限更新", "code": "permission:update", "description": "权限更新权限"},
{"name": "权限删除", "code": "permission:delete", "description": "权限删除权限"},
"""初始化权限数据(树形结构)"""
# 定义需要初始化的权限(树形结构)
# parentid: 0 = 顶级模块, >0 = 子权限
permission_tree = [
# 顶级模块
{"name": "权限管理", "code": "perm", "parentid": 0, "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:list", "parentid": 2, "description": "查看用户列表"},
{"name": "查看详情", "code": "perm:user:detail", "parentid": 2, "description": "查看用户详情"},
{"name": "搜索", "code": "perm:user:search", "parentid": 2, "description": "搜索用户"},
{"name": "创建", "code": "perm:user:create", "parentid": 2, "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))
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 = []
permissions_to_update = []
# 创建或更新权限
created_count = 0
updated_count = 0
for perm_data in required_permissions:
for perm_data in permission_tree:
perm_code = perm_data["code"]
if perm_code not in existing_permission_codes:
# 权限不存在,需要创建
permissions_to_add.append(Permission(**perm_data))
db.add(Permission(**perm_data))
created_count += 1
else:
# 权限存在,检查是否需要更新
existing_perm = next(
perm for perm in existing_permissions if perm.code == perm_code
)
if existing_perm.name != perm_data["name"] or existing_perm.description != perm_data["description"]:
existing_perm = existing_permission_codes[perm_code]
update_needed = False
if 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"]
permissions_to_update.append(existing_perm)
update_needed = True
# 执行创建和更新操作
if permissions_to_add:
for perm in permissions_to_add:
db.add(perm)
if update_needed:
updated_count += 1
if created_count > 0 or updated_count > 0:
await db.commit()
print(f"创建了 {len(permissions_to_add)} 个权限")
if permissions_to_update:
await db.commit()
print(f"更新了 {len(permissions_to_update)} 个权限")
if not permissions_to_add and not permissions_to_update:
print(f"创建了 {created_count} 个权限,更新了 {updated_count} 个权限")
else:
print("权限数据已存在且无需更新,跳过初始化")
print("权限数据初始化/更新完成")
@ -293,6 +356,7 @@ async def init_test_user(db: AsyncSession):
async def init_all_data(db: AsyncSession):
"""初始化所有数据"""
print("开始初始化数据库数据...")
await ensure_permission_table_structure(db)
await init_roles(db)
await init_permissions(db)
await init_role_permissions(db)

View File

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

View File

@ -112,8 +112,9 @@ class RoleResponse(RoleBase):
class PermissionBase(BaseModel):
"""权限基础模型"""
name: str = Field(..., max_length=50, description="权限名称")
code: str = Field(..., max_length=50, description="权限编码")
name: str = Field(..., max_length=100, description="权限名称")
code: str = Field(..., max_length=100, description="权限编码")
parentid: int = Field(0, description="父权限ID0表示顶级模块")
description: Optional[str] = Field(None, max_length=255, description="权限描述")
@ -133,6 +134,17 @@ class PermissionResponse(PermissionBase):
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):
"""角色权限分配模型"""