feat(admin, admin-ui): 实现RuoYi风格后台菜单管理,优化媒体资源处理
新增服务端菜单校验与归一化逻辑,完善菜单相关Schema;前端实现条件渲染的菜单编辑器,支持搜索式图标选择器与父级树过滤。新增媒体URL统一处理工具修复管理端本地静态资源路径映射问题,更新全部相关文档、技术决策记录与测试用例。本次变更不影响WonderQ-MiniAPP端。
This commit is contained in:
1 parent
6245159e7c
commit
4c245f0d1f
28 files changed
+625
-36
No files matched your search
@@ -0,0 +1,54 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
MENU_FIELDS = (
|
||||
"parentId",
|
||||
"name",
|
||||
"type",
|
||||
"path",
|
||||
"componentKey",
|
||||
"permissionCode",
|
||||
"icon",
|
||||
"sortOrder",
|
||||
"isVisible",
|
||||
"isActive",
|
||||
)
|
||||
|
||||
|
||||
def _clean_optional(value: Any) -> Any:
|
||||
if isinstance(value, str):
|
||||
return value.strip() or None
|
||||
return value
|
||||
|
||||
|
||||
def normalize_menu_values(values: dict[str, Any], *, partial: bool = False) -> dict[str, Any]:
|
||||
"""Normalize menu form values and enforce type-specific fields."""
|
||||
normalized = dict(values)
|
||||
for field in ("parentId", "name", "path", "componentKey", "permissionCode", "icon"):
|
||||
if field in normalized:
|
||||
normalized[field] = _clean_optional(normalized[field])
|
||||
|
||||
if "name" in normalized and not normalized["name"]:
|
||||
raise ValueError("菜单名称不能为空")
|
||||
|
||||
if partial or "type" not in normalized:
|
||||
return normalized
|
||||
|
||||
menu_type = normalized["type"]
|
||||
if menu_type == "button":
|
||||
if not normalized.get("permissionCode"):
|
||||
raise ValueError("按钮菜单必须填写权限标识")
|
||||
if normalized.get("path") or normalized.get("componentKey"):
|
||||
raise ValueError("按钮菜单不能填写路由地址或组件路径")
|
||||
normalized["icon"] = None
|
||||
else:
|
||||
if not normalized.get("path"):
|
||||
raise ValueError("目录或页面必须填写路由地址")
|
||||
if menu_type == "page" and not normalized.get("componentKey"):
|
||||
raise ValueError("页面菜单必须填写组件路径")
|
||||
if menu_type == "directory":
|
||||
normalized["permissionCode"] = None
|
||||
|
||||
return normalized
|
||||
Reference in new issue
Block a user