开发中心

侧栏的「开发中心」分组就是 Config.AddKnown 预声明的一个普通菜单分组,页面用 [Menu(Group = "development")] 直接挂进去;框架内置语言管理 / 在线用户 / 跟踪日志,宿主注入自定义项同样走 [Menu]。

最后更新

后台系统常有一组面向开发者 / 运维的辅助入口——语言词条、在线用户、跟踪日志之类。它们不属于业务导航, 却又需要随取随用。Known 把这类入口收进侧栏一个**「开发中心」分组**:内置项由框架提供,宿主项加一行特性即可注入。

这一组没有任何专属机制——它就是 Config.AddKnown 预先声明的一个普通菜单分组,页面用和其余侧栏菜单 完全相同的 [Menu] 特性、把 Group 指向它的 id 即可挂进来。声明一次、自动扫描、按角色裁剪, 理念与 [Menu] / [AppMenu] 一脉相承。

早期版本把它做成顶栏右上角的图标下拉,并配了一套 [DevMenu] 特性 + IDevCenterProvider 汇总器。 [DevMenu] 已删除:现在它既迁到了左侧菜单,分组本身又是普通菜单节点,那套专属机制就没有存在必要了。 手上还有 [DevMenu] 的代码改成 [Menu(Group = "development")] 即可,见下节。

它长什么样

登录进后台后,侧栏菜单树里会出现一个「开发中心」分组(图标 code),点开是一组子菜单, 默认包含三个框架内置项:

菜单项 路由 图标 Order
语言管理 /dev/languages language 1
在线用户 /dev/online-users users 2
跟踪日志 /dev/trace-logs activity 3

这三页是内置通用功能,落在框架的 Known/Platforms/ 下、各自标注了 [Menu(..., Group = "development")], 宿主无需实现、也不会去改它们。分组下没有任何当前用户可见项时,整组不渲染——空分组会被裁掉。

分组排序 order: 100,因此默认排在宿主自声明分组(如 system 用 90)之后、贴近菜单末尾。

往「开发中心」加一个页面

和加任何侧栏菜单项一模一样:给页面类加一行 [Menu],Group 填 development。 Config.AddModule 扫描到它,AuthProvider.BuildMenus 就把它归进该分组:

@page "/dev/demo-tools"
@attribute [Menu("示例自定义工具", Icon = "wrench", Group = "development", Order = 10)]

<div class="page-header">
    <h2>示例自定义工具</h2>
</div>
@* 你的开发中心页面内容 *@

Order = 10 让它排在三个内置项(Order 为 1 / 2 / 3)之后。[Menu] 不可重复标注 (不同于可标多条的 [AppMenu]),一个页面就是菜单里的一个条目。

[Menu] 各字段语义:

  • name:菜单文字(构造参数,必填)。可作为国际化 key,经 LocalService 解析,无译文时回退原文。
  • Icon:对应 Icon 组件的 Type;留空回退 circle。
  • Group:所属上级分组。填 Config.AddMenuGroup 声明过的分组 id(这里是 development);留空为根级菜单项; 也兼容旧的斜杠路径写法(如 "系统管理/权限"),未命中已声明 id 时按路径自动归并、分组无自定义图标。
  • Order:组内排序,越小越靠前。
  • Roles:逗号分隔的可见角色(如 "超级管理员,运维")——留空则所有已登录用户可见。
  • Hidden:为 true 时不进菜单(页面路由仍可直达)。

地址不在 [Menu] 上:菜单项的 URL 取自页面自身的 @page(Route)路由。页面没有 @page 就没有链接。

按角色显隐

角色过滤发生在 AuthProvider.BuildMenus 里,和其余菜单项同一条路径:Roles 留空的项人人可见, 填了的只有命中当前用户角色的才可见。AdminLayout 鉴权拿到当前 User 后才装配菜单, 因此未登录或角色不匹配的项自然不会出现在分组里。

@attribute [Menu("运维控制台", Icon = "terminal", Roles = "超级管理员,运维", Order = 20)]

匹配是拿 Roles 拆出的每一项与 user.Role 精确相等比较(UserInfo.Role 是单个角色名,不是角色列表), 所以填的角色名要和登录时签发的那个字符串一致。

改名、换图标与整体接管

「开发中心」这个名字、code 图标、order: 100,都来自 Config.AddKnown 里的一次普通声明:

// Known/Config.cs —— AddKnown 内部
AddMenuGroup("development", "开发中心", icon: "code", order: 100);

AddMenuGroup 对相同 id 是后写覆盖,所以宿主想调整这一组,不必接管整套菜单,在 AddKnown 之后再声明一次即可:

services.AddKnown(option => { /* ... */ });
Config.AddModule(assembly);

// 改名换图标,仍挂在原位置
Config.AddMenuGroup("development", "运维工具", icon: "terminal", order: 100);

要完全主导这一组(混入自己的排序、拆并子分组),也可以给 AdminLayout 显式传 Menus—— 一旦传了,框架就不再走 [Menu] 扫描装配,整棵菜单树由宿主说了算。

更细粒度的权限(数据库 / 配置驱动)则继承 AuthProvider 覆写 BuildMenus 或 CanSee(两者皆为 virtual), 页面与布局无需改动。

顶栏标题与命令面板

开发中心页面不需要逐页传 PageTitle:AdminLayout 会拿当前 URL 在整棵菜单树里匹配出链路 (ActiveTrail),取末位名称作顶栏标题、其余作面包屑。因为开发中心项本就是菜单树的普通节点, 这条推导对它们和业务页完全一致——进 /dev/languages 标题显示「语言管理」、面包屑显示「开发中心 ›」。

同理,Ctrl+K 命令面板的数据源也是同一棵菜单树,开发中心的项自动可检索跳转,无需另行登记。

装配链路

理解这条链有助于排查「加了特性却不显示」:

  1. Config.AddModule<T>() 扫描 T 所在程序集,凡带 [Menu] 的类型收进 Config.MenuTypes。
  2. Config.AddKnown 登记分组 development(宿主自己的分组用 Config.AddMenuGroup 声明)。
  3. AuthProvider.BuildMenus(user) 遍历 MenuTypes:跳过 Hidden 与角色不匹配项,读页面 @page 作 URL, 按 Group 归入对应分组(未声明的按斜杠路径归并),本地化名称,组内按 Order→名称排序, 子树为空的分组直接裁掉。
  4. AdminLayout 鉴权拿到当前用户后调用它,把结果交给侧栏与命令面板渲染。

常见坑

  • 加了 [Menu(Group = "development")] 却不显示 → 标注所在程序集必须被 Config.AddModule 扫描到。 放在未登记的程序集里,特性收集不到。
  • 分组整个不见了 → 该组下当前用户可见项为空,空分组会被裁掉。先确认至少一项的 Roles / Hidden 放行。
  • Group 填了 "开发中心" → 无效。Group 填的是分组 id development;填中文会被当成未声明的路径分组另起一节点。
  • 图标空白 / 回退成圆点 → Icon 用了 IconData 未收录的名字会回退 circle;用已存在的图标名(如 language / users / activity / wrench / terminal)。
  • 想给一个页面配多个菜单入口 → [Menu] 不可重复标注,一个页面一个条目。确要多入口就拆成多个页面,或显式传 Menus。
  • Roles 写了却不生效 / 一直不显示 → 角色是与 user.Role 精确相等的单值比较,不是集合包含;确认角色字符串与登录时一致。
  • 内置三页想删掉 / 改掉 → 它们是框架内置通用功能,落在 Known/Platforms/;一般不动。真要精简, 用各页 [Menu] 的 Hidden / Roles 让可见项清空、分组自然消失,或显式传 Menus 接管,不建议直接改框架内置页。
  • 代码里还留着 [DevMenu] → 该特性已从框架移除,编译不过。改成 [Menu(..., Group = "development")], 原来的 Url 字段也不再有——地址一律取页面 @page。

相关

微信公众号二维码 扫码关注公众号
QQ 交流群二维码 扫码加入 QQ 群