halo-admin/docs/routes-generation
Ryan Wang 54755c5842
refactor: router and menu generation (#651)
#### What type of PR is this?

/kind api-change
/kind improvement
/milestone 2.0

#### What this PR does / why we need it:

Ref https://github.com/halo-dev/halo/issues/2595

重构路由和侧边菜单生成的逻辑,**注意,此 PR 对插件的 Console 入口文件中的路由和菜单定义包含破坏性更新。**

1. 移除 `definePlugin` 方法的 `menus` 字段,改为在 route 的 meta 中定义。
2. 将 `RoutesMenu` 组件从 `@halo-dev/components` 包中移出。
3. 将 `BasicLayout` 组件从 `@halo-dev/console-shared` 包中移出。

定义路由的方式:

```ts
import { definePlugin } from "@halo-dev/console-shared";
import BasicLayout from "@/layouts/BasicLayout.vue";
import AttachmentList from "./AttachmentList.vue";
import AttachmentSelectorModal from "./components/AttachmentSelectorModal.vue";
import { IconFolder } from "@halo-dev/components";
import { markRaw } from "vue";

export default definePlugin({
  name: "attachmentModule",
  components: [AttachmentSelectorModal],
  routes: [
    {
      path: "/attachments",
      component: BasicLayout,
      children: [
        {
          path: "",
          name: "Attachments",
          component: AttachmentList,
          meta: {
            title: "附件",
            permissions: ["system:attachments:view"],
            menu: {
              name: "附件",
              group: "内容",
              icon: markRaw(IconFolder),
              priority: 4,
              mobile: true,
            },
          },
        },
      ],
    },
  ],
});
```

menu 字段类型:

```ts
interface RouteMeta {
  title?: string;
  searchable?: boolean;
  permissions?: string[];
  menu?: {
    name: string;
    group?: string;
    icon?: Component;
    priority: number;
    mobile?: true;
  };
}
```

插件适配需要做的改动:

1. 移除 `definePlugin` 中的 menus 字段。
2. 在需要添加到菜单的 route 中提供 `meta.menu` 对象,可参考上方的 menu 字段类型。

详细文档可查阅:https://github.com/ruibaby/halo-console/tree/refactor/route-map-setting/docs/routes-generation

todolist:

- [x] 完善预设的菜单分组定义。
- [x] 绑定权限,根据权限决定是否需要将路由添加到菜单。
- [x] 优化菜单排序的定义方式。

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/2595

#### Special notes for your reviewer:

/cc @halo-dev/sig-halo-console 

测试方式:

1. 需要 `pnpm build:packages`
2. 测试后台的菜单及路由是否有异常。
3. 新建角色测试路由和菜单对权限的绑定。
4. 按照 https://github.com/ruibaby/halo-console/tree/refactor/route-map-setting/docs/routes-generation 文档,创建插件,测试插件添加路由和菜单是否正常。

#### Does this PR introduce a user-facing change?

```release-note
重构路由和侧边菜单生成的逻辑。
```
2022-10-19 08:54:13 +00:00
..
README.md refactor: router and menu generation (#651) 2022-10-19 08:54:13 +00:00

README.md

路由和 Console 端菜单的生成

简述

目前的路由以及菜单都是动态生成的,由 基础路由核心模块路由插件模块路由 三部分组成。

定义文件位置:

  • 基础路由:src/router/routes.config.ts,
  • 核心模块路由:src/modules/**/module.ts,

定义方式

统一由 @halo-dev/console-shared 包中的 definePlugin 方法配置。如:

import { definePlugin } from "@halo-dev/console-shared";
import BasicLayout from "@/layouts/BasicLayout.vue";
import AttachmentList from "./AttachmentList.vue";
import AttachmentSelectorModal from "./components/AttachmentSelectorModal.vue";
import { IconFolder } from "@halo-dev/components";
import { markRaw } from "vue";

export default definePlugin({
  name: "attachmentModule",
  components: [AttachmentSelectorModal],
  routes: [
    {
      path: "/attachments",
      component: BasicLayout,
      children: [
        {
          path: "",
          name: "Attachments",
          component: AttachmentList,
          meta: {
            title: "附件",
            permissions: ["system:attachments:view"],
            menu: {
              name: "附件",
              group: "content",
              icon: markRaw(IconFolder),
              priority: 3,
              mobile: true,
            },
          },
        },
      ],
    },
  ],
});

其中,如果要将路由添加到侧边的菜单,那么需要在 meta 中定义好 menu 对象menu 对象类型详解如下:

interface RouteMeta {
  title?: string;
  searchable?: boolean;
  permissions?: string[];
  core?: boolean;
  menu?: {
    name: string;               // 菜单名称
    group?: CoreMenuGroupId;    // 菜单分组 ID详见下方 CoreMenuGroupId 定义
    icon?: Component;           // 菜单图标,类型为 Vue 组件,可以使用 `@halo-dev/components` 包中的图标组件,或者自行接入 https://github.com/antfu/unplugin-icons
    priority: number;           // 排序字段,相对于 group插件中提供的菜单将始终放在最后
    mobile?: boolean;           // 是否添加到移动端底部的菜单
  };
}

CoreMenuGroupId

declare type CoreMenuGroupId = "dashboard" | "content" | "interface" | "system" | "tool";

这是核心内置的菜单分组,但如果插件需要自定义分组,可以直接填写分组名,如:

{
  name: "帖子",
  group: "社区",
  icon: markRaw(IconCummunity),
  priority: 1,
  mobile: false,
}

插件接入

定义方式与系统核心模块的定义方式一致,在 definePlugin 方法配置即可。主要额外注意的是,如果插件的路由需要基础布局(继承 BasicLayout需要配置 parentName,如:

export default definePlugin({
  routes: [
    {
      parentName: "Root",
      route: {
        path: "/migrate",
        children: [
          {
            path: "",
            name: "Migrate",
            component: MigrateView,
            meta: {
              title: "迁移",
              searchable: true,
              menu: {
                name: "迁移",
                group: "tool",
                icon: markRaw(IconGrid),
                priority: 0,
              },
            },
          },
        ],
      },
    },
  ]
})

权限

meta 中配置 permissions 即可。类型为 UI 权限标识的数组,如 ["system:attachments:view"]。如果当前用户没有对应权限,那么将不会注册路由和菜单。