feat: 菜单管理添加排序功能
- Permission 模型新增 sort 字段
- 后端 API 按 sort 升序排列树形菜单
- 前端菜单管理页面增加排序列
- 初始数据添加排序号
- 修复 GET /permissions/{id} 详情接口 bug
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0545d68018
commit
9586c7467a
@ -44,7 +44,9 @@ async def create_permission(
|
||||
name=permission_data.name,
|
||||
code=permission_data.code,
|
||||
parentid=permission_data.parentid,
|
||||
route=permission_data.route,
|
||||
description=permission_data.description,
|
||||
sort=permission_data.sort,
|
||||
)
|
||||
|
||||
db.add(db_permission)
|
||||
@ -112,6 +114,7 @@ async def get_permission_tree(
|
||||
"parentid": perm.parentid,
|
||||
"route": perm.route,
|
||||
"description": perm.description,
|
||||
"sort": perm.sort or 0,
|
||||
"createtime": perm.createtime,
|
||||
"updatetime": perm.updatetime,
|
||||
"children": []
|
||||
@ -128,6 +131,16 @@ async def get_permission_tree(
|
||||
# 子节点,添加到父节点的 children
|
||||
perm_dict[parentid]["children"].append(perm_data)
|
||||
|
||||
# 递归排序:按 sort 字段升序排列
|
||||
def sort_tree(nodes):
|
||||
nodes.sort(key=lambda n: n.get("sort", 0))
|
||||
for node in nodes:
|
||||
if node.get("children"):
|
||||
sort_tree(node["children"])
|
||||
return nodes
|
||||
|
||||
tree = sort_tree(tree)
|
||||
|
||||
# 记录查询日志
|
||||
await create_operation_log(
|
||||
db, current_user.id, current_user.username, "search", "permission",
|
||||
@ -187,6 +200,7 @@ async def get_menu(
|
||||
"parentid": perm.parentid,
|
||||
"route": perm.route,
|
||||
"description": perm.description,
|
||||
"sort": perm.sort or 0,
|
||||
"createtime": perm.createtime,
|
||||
"updatetime": perm.updatetime,
|
||||
"children": []
|
||||
@ -203,6 +217,16 @@ async def get_menu(
|
||||
# 子节点,添加到父节点的 children
|
||||
perm_dict[parentid]["children"].append(perm_data)
|
||||
|
||||
# 递归排序:按 sort 字段升序排列
|
||||
def sort_tree(nodes):
|
||||
nodes.sort(key=lambda n: n.get("sort", 0))
|
||||
for node in nodes:
|
||||
if node.get("children"):
|
||||
sort_tree(node["children"])
|
||||
return nodes
|
||||
|
||||
tree = sort_tree(tree)
|
||||
|
||||
# 记录查询日志
|
||||
await create_operation_log(
|
||||
db, current_user.id, current_user.username, "search", "permission",
|
||||
@ -222,7 +246,7 @@ async def get_permission(
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""获取单个权限"""
|
||||
permission = await permission_crud.get(db, id=permission_id)
|
||||
permission = await permission_crud.get(db, id=permission_id, schema_to_select=PermissionResponse, return_as_model=True)
|
||||
if not permission:
|
||||
raise HTTPException(status_code=404, detail="权限不存在")
|
||||
|
||||
@ -271,7 +295,7 @@ async def update_permission(
|
||||
raise HTTPException(status_code=404, detail="权限不存在")
|
||||
# 记录操作日志
|
||||
changed = {}
|
||||
for field in ["name", "code", "parentid", "description"]:
|
||||
for field in ["name", "code", "parentid", "route", "sort", "description"]:
|
||||
old_val = getattr(old_permission, field, None)
|
||||
new_val = update_data.get(field)
|
||||
if old_val != new_val:
|
||||
@ -452,6 +476,7 @@ async def get_current_user_permissions(
|
||||
"parentid": perm.parentid,
|
||||
"route": perm.route,
|
||||
"description": perm.description,
|
||||
"sort": perm.sort or 0,
|
||||
"createtime": perm.createtime,
|
||||
"updatetime": perm.updatetime,
|
||||
"children": []
|
||||
@ -468,6 +493,16 @@ async def get_current_user_permissions(
|
||||
# 子节点,添加到父节点的 children
|
||||
perm_dict[parentid]["children"].append(perm_data)
|
||||
|
||||
# 递归排序:按 sort 字段升序排列
|
||||
def sort_tree(nodes):
|
||||
nodes.sort(key=lambda n: n.get("sort", 0))
|
||||
for node in nodes:
|
||||
if node.get("children"):
|
||||
sort_tree(node["children"])
|
||||
return nodes
|
||||
|
||||
menu_tree = sort_tree(menu_tree)
|
||||
|
||||
# 记录查询日志
|
||||
await create_operation_log(
|
||||
db, current_user.id, current_user.username, "search", "permission",
|
||||
|
||||
@ -12,79 +12,75 @@ async def init_permissions(db: AsyncSession):
|
||||
# ========================================
|
||||
# 顶级模块 (DB ID: 1,2,3)
|
||||
# ========================================
|
||||
{"name": "权限管理", "code": "perm", "parentid": 0, "route": "/admin/permissions", "description": "权限管理模块"},
|
||||
{"name": "系统设置", "code": "system", "parentid": 0, "route": "/admin/settings", "description": "系统设置模块"},
|
||||
{"name": "日志管理", "code": "log", "parentid": 0, "route": "/admin/logs", "description": "日志管理模块"},
|
||||
{"name": "权限管理", "code": "perm", "parentid": 0, "route": "/admin/permissions", "description": "权限管理模块", "sort": 1},
|
||||
{"name": "系统设置", "code": "system", "parentid": 0, "route": "/admin/settings", "description": "系统设置模块", "sort": 2},
|
||||
{"name": "日志管理", "code": "log", "parentid": 0, "route": "/admin/logs", "description": "日志管理模块", "sort": 3},
|
||||
|
||||
# ========================================
|
||||
# 权限管理 -> 二级子模块 (parentid=1, DB ID: 4,5,6)
|
||||
# ========================================
|
||||
{"name": "用户管理", "code": "perm:user", "parentid": 1, "route": "/admin/users", "description": "用户管理子模块"},
|
||||
{"name": "角色管理", "code": "perm:role", "parentid": 1, "route": "/admin/roles", "description": "角色管理子模块"},
|
||||
{"name": "菜单管理", "code": "perm:menu", "parentid": 1, "route": "/admin/menu", "description": "菜单管理子模块"},
|
||||
{"name": "用户管理", "code": "perm:user", "parentid": 1, "route": "/admin/users", "description": "用户管理子模块", "sort": 1},
|
||||
{"name": "角色管理", "code": "perm:role", "parentid": 1, "route": "/admin/roles", "description": "角色管理子模块", "sort": 2},
|
||||
{"name": "菜单管理", "code": "perm:menu", "parentid": 1, "route": "/admin/menu", "description": "菜单管理子模块", "sort": 3},
|
||||
|
||||
# ========================================
|
||||
# 用户管理操作 (parentid=4, DB ID: 7-14)
|
||||
# ========================================
|
||||
{"name": "查看列表", "code": "perm:user:list", "parentid": 4, "description": "查看用户列表"},
|
||||
{"name": "查看详情", "code": "perm:user:detail", "parentid": 4, "description": "查看用户详情"},
|
||||
{"name": "搜索", "code": "perm:user:search", "parentid": 4, "description": "搜索用户"},
|
||||
{"name": "创建", "code": "perm:user:create", "parentid": 4, "description": "创建新用户"},
|
||||
{"name": "编辑", "code": "perm:user:edit", "parentid": 4, "description": "编辑用户信息"},
|
||||
{"name": "删除", "code": "perm:user:delete", "parentid": 4, "description": "删除用户"},
|
||||
{"name": "导出", "code": "perm:user:export", "parentid": 4, "description": "导出用户数据"},
|
||||
{"name": "批量操作", "code": "perm:user:batch", "parentid": 4, "description": "批量操作用户"},
|
||||
{"name": "查看列表", "code": "perm:user:list", "parentid": 4, "description": "查看用户列表", "sort": 1},
|
||||
{"name": "查看详情", "code": "perm:user:detail", "parentid": 4, "description": "查看用户详情", "sort": 2},
|
||||
{"name": "搜索", "code": "perm:user:search", "parentid": 4, "description": "搜索用户", "sort": 3},
|
||||
{"name": "创建", "code": "perm:user:create", "parentid": 4, "description": "创建新用户", "sort": 4},
|
||||
{"name": "编辑", "code": "perm:user:edit", "parentid": 4, "description": "编辑用户信息", "sort": 5},
|
||||
{"name": "删除", "code": "perm:user:delete", "parentid": 4, "description": "删除用户", "sort": 6},
|
||||
{"name": "导出", "code": "perm:user:export", "parentid": 4, "description": "导出用户数据", "sort": 7},
|
||||
{"name": "批量操作", "code": "perm:user:batch", "parentid": 4, "description": "批量操作用户", "sort": 8},
|
||||
|
||||
# ========================================
|
||||
# 角色管理操作 (parentid=5, DB ID: 15-22)
|
||||
# ========================================
|
||||
{"name": "查看列表", "code": "perm:role:list", "parentid": 5, "description": "查看角色列表"},
|
||||
{"name": "查看详情", "code": "perm:role:detail", "parentid": 5, "description": "查看角色详情"},
|
||||
{"name": "搜索", "code": "perm:role:search", "parentid": 5, "description": "搜索角色"},
|
||||
{"name": "创建", "code": "perm:role:create", "parentid": 5, "description": "创建新角色"},
|
||||
{"name": "编辑", "code": "perm:role:edit", "parentid": 5, "description": "编辑角色信息"},
|
||||
{"name": "删除", "code": "perm:role:delete", "parentid": 5, "description": "删除角色"},
|
||||
{"name": "导出", "code": "perm:role:export", "parentid": 5, "description": "导出角色数据"},
|
||||
{"name": "分配权限", "code": "perm:role:assign", "parentid": 5, "description": "为角色分配权限"},
|
||||
{"name": "查看列表", "code": "perm:role:list", "parentid": 5, "description": "查看角色列表", "sort": 1},
|
||||
{"name": "查看详情", "code": "perm:role:detail", "parentid": 5, "description": "查看角色详情", "sort": 2},
|
||||
{"name": "搜索", "code": "perm:role:search", "parentid": 5, "description": "搜索角色", "sort": 3},
|
||||
{"name": "创建", "code": "perm:role:create", "parentid": 5, "description": "创建新角色", "sort": 4},
|
||||
{"name": "编辑", "code": "perm:role:edit", "parentid": 5, "description": "编辑角色信息", "sort": 5},
|
||||
{"name": "删除", "code": "perm:role:delete", "parentid": 5, "description": "删除角色", "sort": 6},
|
||||
{"name": "导出", "code": "perm:role:export", "parentid": 5, "description": "导出角色数据", "sort": 7},
|
||||
{"name": "分配权限", "code": "perm:role:assign", "parentid": 5, "description": "为角色分配权限", "sort": 8},
|
||||
|
||||
# ========================================
|
||||
# 菜单管理操作 (parentid=6, DB ID: 23-29)
|
||||
# ========================================
|
||||
{"name": "查看列表", "code": "perm:menu:list", "parentid": 6, "description": "查看菜单列表"},
|
||||
{"name": "查看详情", "code": "perm:menu:detail", "parentid": 6, "description": "查看菜单详情"},
|
||||
{"name": "搜索", "code": "perm:menu:search", "parentid": 6, "description": "搜索菜单"},
|
||||
{"name": "创建", "code": "perm:menu:create", "parentid": 6, "description": "创建新菜单"},
|
||||
{"name": "编辑", "code": "perm:menu:edit", "parentid": 6, "description": "编辑菜单信息"},
|
||||
{"name": "删除", "code": "perm:menu:delete", "parentid": 6, "description": "删除菜单"},
|
||||
{"name": "导出", "code": "perm:menu:export", "parentid": 6, "description": "导出菜单数据"},
|
||||
{"name": "查看列表", "code": "perm:menu:list", "parentid": 6, "description": "查看菜单列表", "sort": 1},
|
||||
{"name": "查看详情", "code": "perm:menu:detail", "parentid": 6, "description": "查看菜单详情", "sort": 2},
|
||||
{"name": "搜索", "code": "perm:menu:search", "parentid": 6, "description": "搜索菜单", "sort": 3},
|
||||
{"name": "创建", "code": "perm:menu:create", "parentid": 6, "description": "创建新菜单", "sort": 4},
|
||||
{"name": "编辑", "code": "perm:menu:edit", "parentid": 6, "description": "编辑菜单信息", "sort": 5},
|
||||
{"name": "删除", "code": "perm:menu:delete", "parentid": 6, "description": "删除菜单", "sort": 6},
|
||||
{"name": "导出", "code": "perm:menu:export", "parentid": 6, "description": "导出菜单数据", "sort": 7},
|
||||
|
||||
# ========================================
|
||||
# 系统设置 -> 子权限 (parentid=2, DB ID: 30)
|
||||
# ========================================
|
||||
{"name": "系统设置", "code": "system:view", "parentid": 2, "description": "查看和修改系统设置"},
|
||||
{"name": "系统设置", "code": "system:view", "parentid": 2, "description": "查看和修改系统设置", "sort": 1},
|
||||
|
||||
# ========================================
|
||||
# 日志管理 -> 子模块 (parentid=3, DB ID: 31,32)
|
||||
# 日志管理 -> 子模块 (parentid=3, DB ID: 31,32,37)
|
||||
# ========================================
|
||||
{"name": "登录日志", "code": "log:login", "parentid": 3, "route": "/admin/login-logs", "description": "登录日志查看"},
|
||||
{"name": "操作日志", "code": "log:operation", "parentid": 3, "route": "/admin/operation-logs", "description": "操作日志查看"},
|
||||
{"name": "登录日志", "code": "log:login", "parentid": 3, "route": "/admin/login-logs", "description": "登录日志查看", "sort": 1},
|
||||
{"name": "操作日志", "code": "log:operation", "parentid": 3, "route": "/admin/operation-logs", "description": "操作日志查看", "sort": 2},
|
||||
{"name": "清理日志", "code": "log:clean", "parentid": 3, "description": "清理旧日志", "sort": 3},
|
||||
|
||||
# ========================================
|
||||
# 登录日志操作 (parentid=31, DB ID: 33,34)
|
||||
# ========================================
|
||||
{"name": "查看列表", "code": "log:login:list", "parentid": 31, "description": "查看登录日志列表"},
|
||||
{"name": "搜索", "code": "log:login:search", "parentid": 31, "description": "搜索登录日志"},
|
||||
{"name": "查看列表", "code": "log:login:list", "parentid": 31, "description": "查看登录日志列表", "sort": 1},
|
||||
{"name": "搜索", "code": "log:login:search", "parentid": 31, "description": "搜索登录日志", "sort": 2},
|
||||
|
||||
# ========================================
|
||||
# 操作日志操作 (parentid=32, DB ID: 35,36)
|
||||
# ========================================
|
||||
{"name": "查看列表", "code": "log:operation:list", "parentid": 32, "description": "查看操作日志列表"},
|
||||
{"name": "搜索", "code": "log:operation:search", "parentid": 32, "description": "搜索操作日志"},
|
||||
|
||||
# ========================================
|
||||
# 日志清理 (parentid=3, DB ID: 37)
|
||||
# ========================================
|
||||
{"name": "清理日志", "code": "log:clean", "parentid": 3, "description": "清理旧日志"},
|
||||
{"name": "查看列表", "code": "log:operation:list", "parentid": 32, "description": "查看操作日志列表", "sort": 1},
|
||||
{"name": "搜索", "code": "log:operation:search", "parentid": 32, "description": "搜索操作日志", "sort": 2},
|
||||
]
|
||||
|
||||
# 检查现有权限
|
||||
@ -119,6 +115,9 @@ async def init_permissions(db: AsyncSession):
|
||||
if existing_perm.description != perm_data["description"]:
|
||||
existing_perm.description = perm_data["description"]
|
||||
update_needed = True
|
||||
if existing_perm.sort != perm_data.get("sort", 0):
|
||||
existing_perm.sort = perm_data.get("sort", 0)
|
||||
update_needed = True
|
||||
|
||||
if update_needed:
|
||||
updated_count += 1
|
||||
|
||||
@ -12,6 +12,7 @@ from init_data import init_all_data
|
||||
from pathlib import Path
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import JSONResponse
|
||||
from sqlalchemy import text
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
@ -20,6 +21,15 @@ async def lifespan(app: FastAPI):
|
||||
async with engine.begin() as conn:
|
||||
# 创建所有表
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
# 为已有表添加 sort 列(兼容 PostgreSQL 和 SQLite)
|
||||
try:
|
||||
await conn.execute(text("ALTER TABLE permission ADD COLUMN IF NOT EXISTS sort INTEGER DEFAULT 0"))
|
||||
except Exception:
|
||||
# SQLite 不支持 IF NOT EXISTS
|
||||
try:
|
||||
await conn.execute(text("ALTER TABLE permission ADD COLUMN sort INTEGER DEFAULT 0"))
|
||||
except Exception:
|
||||
pass # 列已存在则忽略
|
||||
|
||||
# 初始化数据
|
||||
async for db in get_db():
|
||||
|
||||
@ -61,6 +61,7 @@ class Permission(Base):
|
||||
parentid = Column(Integer, default=0, comment="父权限ID(0表示顶级模块)")
|
||||
route = Column(String(255), nullable=True, comment="前端路由路径")
|
||||
description = Column(String(255), nullable=True, comment="权限描述")
|
||||
sort = Column(Integer, default=0, comment="排序号(升序排列)")
|
||||
createtime = Column(DateTime, default=datetime.utcnow, comment="创建时间")
|
||||
updatetime = Column(
|
||||
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, comment="更新时间"
|
||||
|
||||
@ -141,6 +141,7 @@ class PermissionBase(BaseModel):
|
||||
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="权限描述")
|
||||
sort: int = Field(0, description="排序号(升序排列)")
|
||||
|
||||
|
||||
class PermissionCreate(PermissionBase):
|
||||
@ -170,6 +171,7 @@ class PermissionTreeResponse(BaseModel):
|
||||
createtime: Optional[datetime] = Field(None, description="创建时间")
|
||||
updatetime: Optional[datetime] = Field(None, description="更新时间")
|
||||
description: Optional[str] = Field(None, description="权限描述")
|
||||
sort: int = Field(0, description="排序号")
|
||||
children: list = Field([], description="子权限列表")
|
||||
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ export type PermissionRow = {
|
||||
parentid: number;
|
||||
route?: string | null;
|
||||
description?: string | null;
|
||||
sort: number;
|
||||
createtime: string;
|
||||
updatetime: string;
|
||||
children?: PermissionRow[];
|
||||
@ -144,6 +145,17 @@ export const createPermissionCrudOptions: CreateCrudOptions<PermissionRow> = ()
|
||||
placeholder: "如:/admin/users",
|
||||
},
|
||||
},
|
||||
sort: {
|
||||
title: "排序",
|
||||
key: "sort",
|
||||
type: "number",
|
||||
column: { width: 80, align: "center" },
|
||||
form: {
|
||||
value: 0,
|
||||
rules: [{ required: true, message: "必填" }],
|
||||
helper: "数字越小,排序越靠前",
|
||||
},
|
||||
},
|
||||
createtime: {
|
||||
title: "创建时间",
|
||||
key: "createtime",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user