Browse Source

feat(menu): the route is automatically mapped to the menu

vben 3 years ago
parent
commit
913c22c84f
40 changed files with 159 additions and 889 deletions
  1. 8 0
      CHANGELOG.zh_CN.md
  2. 2 0
      src/enums/appEnum.ts
  3. 4 4
      src/hooks/web/usePermission.ts
  4. 2 2
      src/layouts/default/feature/index.vue
  5. 4 4
      src/router/guard/index.ts
  6. 4 4
      src/router/guard/permissionGuard.ts
  7. 2 0
      src/router/helper/routeHelper.ts
  8. 40 15
      src/router/menus/index.ts
  9. 0 11
      src/router/menus/modules/about.ts
  10. 0 22
      src/router/menus/modules/dashboard.ts
  11. 0 45
      src/router/menus/modules/demo/charts.ts
  12. 0 279
      src/router/menus/modules/demo/comp.ts
  13. 0 29
      src/router/menus/modules/demo/excel.ts
  14. 0 130
      src/router/menus/modules/demo/feat.ts
  15. 0 17
      src/router/menus/modules/demo/flow.ts
  16. 0 25
      src/router/menus/modules/demo/iframe.ts
  17. 0 37
      src/router/menus/modules/demo/level.ts
  18. 0 121
      src/router/menus/modules/demo/page.ts
  19. 0 49
      src/router/menus/modules/demo/permission.ts
  20. 0 14
      src/router/menus/modules/demo/setup.ts
  21. 0 34
      src/router/menus/modules/demo/system.ts
  22. 2 0
      src/router/routes/basic.ts
  23. 2 0
      src/router/routes/modules/about.ts
  24. 1 0
      src/router/routes/modules/dashboard.ts
  25. 1 0
      src/router/routes/modules/demo/charts.ts
  26. 1 0
      src/router/routes/modules/demo/comp.ts
  27. 1 0
      src/router/routes/modules/demo/feat.ts
  28. 1 0
      src/router/routes/modules/demo/flow.ts
  29. 1 0
      src/router/routes/modules/demo/iframe.ts
  30. 1 0
      src/router/routes/modules/demo/level.ts
  31. 1 0
      src/router/routes/modules/demo/page.ts
  32. 1 0
      src/router/routes/modules/demo/permission.ts
  33. 2 0
      src/router/routes/modules/demo/setup.ts
  34. 2 0
      src/router/routes/modules/demo/system.ts
  35. 1 1
      src/settings/projectSetting.ts
  36. 1 1
      src/store/modules/app.ts
  37. 70 42
      src/store/modules/permission.ts
  38. 1 1
      src/store/modules/user.ts
  39. 2 2
      src/utils/http/axios/checkStatus.ts
  40. 1 0
      types/vue-router.d.ts

+ 8 - 0
CHANGELOG.zh_CN.md

@@ -1,7 +1,15 @@
 ## Wip
 
+### ⚡ Performance Improvements
+
 - **Icon** 移除 Icon 组件全局注册,防止特定情况下热更新问题
 
+### ✨ Features
+
+- **Menu** 新增 `permissionMode=PermissionModeEnum.ROUTE_MAPPING`模式
+  - 项目默认改为该模式,删除原有菜单文件
+  - 如果之前已经写好了菜单,可以更改为`PermissionModeEnum.ROLE`模式即可
+
 ## 2.5.1(2021-06-26)
 
 ### ⚡ Performance Improvements

+ 2 - 0
src/enums/appEnum.ts

@@ -33,6 +33,8 @@ export enum PermissionModeEnum {
   ROLE = 'ROLE',
   // black
   BACK = 'BACK',
+  // route mapping
+  ROUTE_MAPPING = 'ROUTE_MAPPING',
 }
 
 //  Route switching animation

+ 4 - 4
src/hooks/web/usePermission.ts

@@ -31,7 +31,7 @@ export function usePermission() {
     appStore.setProjectConfig({
       permissionMode:
         projectSetting.permissionMode === PermissionModeEnum.BACK
-          ? PermissionModeEnum.ROLE
+          ? PermissionModeEnum.ROUTE_MAPPING
           : PermissionModeEnum.BACK,
     });
     location.reload();
@@ -59,7 +59,7 @@ export function usePermission() {
   function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
     const permMode = projectSetting.permissionMode;
 
-    if (PermissionModeEnum.ROLE === permMode) {
+    if (PermissionModeEnum.ROUTE_MAPPING === permMode) {
       // Visible by default
       if (!value) {
         return def;
@@ -89,9 +89,9 @@ export function usePermission() {
    * @param roles
    */
   async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {
-    if (projectSetting.permissionMode !== PermissionModeEnum.ROLE) {
+    if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) {
       throw new Error(
-        'Please switch PermissionModeEnum to ROLE mode in the configuration to operate!'
+        'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!'
       );
     }
 

+ 2 - 2
src/layouts/default/feature/index.vue

@@ -5,7 +5,7 @@
   import { useRootSetting } from '/@/hooks/setting/useRootSetting';
   import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
   import { useDesign } from '/@/hooks/web/useDesign';
-  import { useUserStoreWidthOut } from '/@/store/modules/user';
+  import { useUserStoreWithOut } from '/@/store/modules/user';
 
   import { SettingButtonPositionEnum } from '/@/enums/appEnum';
   import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
@@ -22,7 +22,7 @@
     setup() {
       const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } =
         useRootSetting();
-      const userStore = useUserStoreWidthOut();
+      const userStore = useUserStoreWithOut();
       const { prefixCls } = useDesign('setting-drawer-fearure');
       const { getShowHeader } = useHeaderSetting();
 

+ 4 - 4
src/router/guard/index.ts

@@ -1,6 +1,6 @@
 import type { Router, RouteLocationNormalized } from 'vue-router';
-import { useAppStoreWidthOut } from '/@/store/modules/app';
-import { useUserStoreWidthOut } from '/@/store/modules/user';
+import { useAppStoreWithOut } from '/@/store/modules/app';
+import { useUserStoreWithOut } from '/@/store/modules/user';
 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
 import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
 import { Modal, notification } from 'ant-design-vue';
@@ -46,8 +46,8 @@ function createPageGuard(router: Router) {
 
 // Used to handle page loading status
 function createPageLoadingGuard(router: Router) {
-  const userStore = useUserStoreWidthOut();
-  const appStore = useAppStoreWidthOut();
+  const userStore = useUserStoreWithOut();
+  const appStore = useAppStoreWithOut();
   const { getOpenPageLoading } = useTransitionSetting();
   router.beforeEach(async (to) => {
     if (!userStore.getToken) {

+ 4 - 4
src/router/guard/permissionGuard.ts

@@ -1,9 +1,9 @@
 import type { Router, RouteRecordRaw } from 'vue-router';
 
-import { usePermissionStoreWidthOut } from '/@/store/modules/permission';
+import { usePermissionStoreWithOut } from '/@/store/modules/permission';
 
 import { PageEnum } from '/@/enums/pageEnum';
-import { useUserStoreWidthOut } from '/@/store/modules/user';
+import { useUserStoreWithOut } from '/@/store/modules/user';
 
 import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
 
@@ -12,8 +12,8 @@ const LOGIN_PATH = PageEnum.BASE_LOGIN;
 const whitePathList: PageEnum[] = [LOGIN_PATH];
 
 export function createPermissionGuard(router: Router) {
-  const userStore = useUserStoreWidthOut();
-  const permissionStore = usePermissionStoreWidthOut();
+  const userStore = useUserStoreWithOut();
+  const permissionStore = usePermissionStoreWithOut();
   router.beforeEach(async (to, from, next) => {
     // Jump to the 404 page after processing the login
     if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name) {

+ 2 - 0
src/router/helper/routeHelper.ts

@@ -65,6 +65,8 @@ function dynamicImport(
 
 // Turn background objects into routing objects
 export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
+  console.log(routeList);
+
   routeList.forEach((route) => {
     const component = route.component as string;
     if (component) {

+ 40 - 15
src/router/menus/index.ts

@@ -1,7 +1,7 @@
 import type { Menu, MenuModule } from '/@/router/types';
 import type { RouteRecordNormalized } from 'vue-router';
 
-import { useAppStoreWidthOut } from '/@/store/modules/app';
+import { useAppStoreWithOut } from '/@/store/modules/app';
 import { usePermissionStore } from '/@/store/modules/permission';
 import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper';
 import { filter } from '/@/utils/helper/treeHelper';
@@ -23,9 +23,21 @@ Object.keys(modules).forEach((key) => {
 // ===========================
 // ==========Helper===========
 // ===========================
+
+const getPermissionMode = () => {
+  const appStore = useAppStoreWithOut();
+  return appStore.getProjectConfig.permissionMode;
+};
 const isBackMode = () => {
-  const appStore = useAppStoreWidthOut();
-  return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
+  return getPermissionMode() === PermissionModeEnum.BACK;
+};
+
+const isRouteMappingMode = () => {
+  return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
+};
+
+const isRoleMode = () => {
+  return getPermissionMode() === PermissionModeEnum.ROLE;
 };
 
 const staticMenus: Menu[] = [];
@@ -41,40 +53,53 @@ const staticMenus: Menu[] = [];
 
 async function getAsyncMenus() {
   const permissionStore = usePermissionStore();
-  return !isBackMode() ? staticMenus : permissionStore.getBackMenuList;
+  if (isBackMode()) {
+    return permissionStore.getBackMenuList;
+  }
+  if (isRouteMappingMode()) {
+    return permissionStore.getFrontMenuList.filter((item) => !item.hideMenu);
+  }
+  return staticMenus;
 }
 
 export const getMenus = async (): Promise<Menu[]> => {
   const menus = await getAsyncMenus();
-  const routes = router.getRoutes();
-
-  return !isBackMode() ? filter(menus, basicFilter(routes)) : menus;
+  if (isRoleMode()) {
+    const routes = router.getRoutes();
+    return filter(menus, basicFilter(routes));
+  }
+  return menus;
 };
 
 export async function getCurrentParentPath(currentPath: string) {
   const menus = await getAsyncMenus();
-
   const allParentPath = await getAllParentPath(menus, currentPath);
-
   return allParentPath?.[0];
 }
 
 // Get the level 1 menu, delete children
 export async function getShallowMenus(): Promise<Menu[]> {
   const menus = await getAsyncMenus();
-  const routes = router.getRoutes();
   const shallowMenuList = menus.map((item) => ({ ...item, children: undefined }));
-  return !isBackMode() ? shallowMenuList.filter(basicFilter(routes)) : shallowMenuList;
+  if (isRoleMode()) {
+    const routes = router.getRoutes();
+    return shallowMenuList.filter(basicFilter(routes));
+  }
+  return shallowMenuList;
 }
 
 // Get the children of the menu
 export async function getChildrenMenus(parentPath: string) {
   const menus = await getMenus();
   const parent = menus.find((item) => item.path === parentPath);
-  if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) return [] as Menu[];
-  const routes = router.getRoutes();
-
-  return !isBackMode() ? filter(parent.children, basicFilter(routes)) : parent.children;
+  if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) {
+    return [] as Menu[];
+  }
+  if (isRoleMode()) {
+    const routes = router.getRoutes();
+    return filter(parent.children, basicFilter(routes));
+  }
+  return parent.children;
 }
 
 function basicFilter(routes: RouteRecordNormalized[]) {

+ 0 - 11
src/router/menus/modules/about.ts

@@ -1,11 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const about: MenuModule = {
-  orderNo: 100000,
-  menu: {
-    path: '/about/index',
-    name: t('routes.dashboard.about'),
-  },
-};
-export default about;

+ 0 - 22
src/router/menus/modules/dashboard.ts

@@ -1,22 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 10,
-  menu: {
-    name: t('routes.dashboard.dashboard'),
-    path: '/dashboard',
-
-    children: [
-      {
-        path: 'analysis',
-        name: t('routes.dashboard.analysis'),
-      },
-      {
-        path: 'workbench',
-        name: t('routes.dashboard.workbench'),
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 45
src/router/menus/modules/demo/charts.ts

@@ -1,45 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 500,
-  menu: {
-    name: t('routes.demo.charts.charts'),
-    path: '/charts',
-
-    children: [
-      {
-        path: 'aMap',
-        name: t('routes.demo.charts.aMap'),
-      },
-
-      {
-        path: 'baiduMap',
-        name: t('routes.demo.charts.baiduMap'),
-      },
-      {
-        path: 'googleMap',
-        name: t('routes.demo.charts.googleMap'),
-      },
-      {
-        path: 'echarts',
-        name: 'Echarts',
-        children: [
-          {
-            path: 'map',
-            name: t('routes.demo.charts.map'),
-          },
-          {
-            path: 'line',
-            name: t('routes.demo.charts.line'),
-          },
-          {
-            path: 'pie',
-            name: t('routes.demo.charts.pie'),
-          },
-        ],
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 279
src/router/menus/modules/demo/comp.ts

@@ -1,279 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 30,
-  menu: {
-    name: t('routes.demo.comp.comp'),
-    path: '/comp',
-    tag: { dot: true },
-    children: [
-      {
-        path: 'basic',
-        name: t('routes.demo.comp.basic'),
-      },
-      {
-        path: 'form',
-        name: t('routes.demo.form.form'),
-
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.form.basic'),
-          },
-          {
-            path: 'useForm',
-            name: t('routes.demo.form.useForm'),
-          },
-          {
-            path: 'refForm',
-            name: t('routes.demo.form.refForm'),
-          },
-          {
-            path: 'advancedForm',
-            name: t('routes.demo.form.advancedForm'),
-          },
-          {
-            path: 'ruleForm',
-            name: t('routes.demo.form.ruleForm'),
-          },
-          {
-            path: 'dynamicForm',
-            name: t('routes.demo.form.dynamicForm'),
-          },
-          {
-            path: 'customerForm',
-            name: t('routes.demo.form.customerForm'),
-          },
-          {
-            path: 'appendForm',
-            name: t('routes.demo.form.appendForm'),
-          },
-        ],
-      },
-      {
-        path: 'table',
-        name: t('routes.demo.table.table'),
-
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.table.basic'),
-          },
-          {
-            path: 'treeTable',
-            name: t('routes.demo.table.treeTable'),
-          },
-          {
-            path: 'fetchTable',
-            name: t('routes.demo.table.fetchTable'),
-          },
-          {
-            path: 'fixedColumn',
-            name: t('routes.demo.table.fixedColumn'),
-          },
-          {
-            path: 'customerCell',
-            name: t('routes.demo.table.customerCell'),
-          },
-          {
-            path: 'formTable',
-            name: t('routes.demo.table.formTable'),
-          },
-          {
-            path: 'useTable',
-            name: t('routes.demo.table.useTable'),
-          },
-          {
-            path: 'refTable',
-            name: t('routes.demo.table.refTable'),
-          },
-          {
-            path: 'multipleHeader',
-            name: t('routes.demo.table.multipleHeader'),
-          },
-          {
-            path: 'mergeHeader',
-            name: t('routes.demo.table.mergeHeader'),
-          },
-          {
-            path: 'expandTable',
-            name: t('routes.demo.table.expandTable'),
-          },
-          {
-            path: 'fixedHeight',
-            name: t('routes.demo.table.fixedHeight'),
-          },
-          {
-            path: 'footerTable',
-            name: t('routes.demo.table.footerTable'),
-          },
-          {
-            path: 'editCellTable',
-            name: t('routes.demo.table.editCellTable'),
-          },
-          {
-            path: 'editRowTable',
-            name: t('routes.demo.table.editRowTable'),
-          },
-          {
-            path: 'authColumn',
-            name: t('routes.demo.table.authColumn'),
-          },
-        ],
-      },
-      {
-        path: 'cropper',
-        name: t('routes.demo.comp.cropperImage'),
-        tag: {
-          content: 'new',
-        },
-      },
-      {
-        path: 'countTo',
-        name: t('routes.demo.comp.countTo'),
-      },
-      {
-        path: 'timestamp',
-        name: t('routes.demo.comp.time'),
-      },
-      {
-        path: 'transition',
-        name: t('routes.demo.comp.transition'),
-      },
-
-      {
-        path: 'modal',
-        name: t('routes.demo.comp.modal'),
-      },
-      {
-        path: 'drawer',
-        name: t('routes.demo.comp.drawer'),
-      },
-      {
-        path: 'desc',
-        name: t('routes.demo.comp.desc'),
-      },
-      {
-        path: 'qrcode',
-        name: t('routes.demo.comp.qrcode'),
-      },
-      {
-        path: 'strength-meter',
-        name: t('routes.demo.comp.strength'),
-      },
-      {
-        path: 'upload',
-        name: t('routes.demo.comp.upload'),
-      },
-      {
-        path: 'loading',
-        name: t('routes.demo.comp.loading'),
-      },
-      {
-        path: 'tree',
-        name: t('routes.demo.comp.tree'),
-
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.comp.treeBasic'),
-          },
-          {
-            path: 'editTree',
-            name: t('routes.demo.comp.editTree'),
-          },
-          {
-            path: 'actionTree',
-            name: t('routes.demo.comp.actionTree'),
-          },
-        ],
-      },
-      {
-        name: t('routes.demo.editor.editor'),
-        path: 'editor',
-        children: [
-          {
-            path: 'json',
-            name: t('routes.demo.editor.jsonEditor'),
-          },
-          {
-            path: 'markdown',
-            name: t('routes.demo.editor.markdown'),
-            children: [
-              {
-                path: 'index',
-                name: t('routes.demo.editor.tinymceBasic'),
-              },
-              {
-                path: 'editor',
-                name: t('routes.demo.editor.tinymceForm'),
-              },
-            ],
-          },
-          {
-            path: 'tinymce',
-            name: t('routes.demo.editor.tinymce'),
-            children: [
-              {
-                path: 'index',
-                name: t('routes.demo.editor.tinymceBasic'),
-              },
-              {
-                path: 'editor',
-                name: t('routes.demo.editor.tinymceForm'),
-              },
-            ],
-          },
-        ],
-      },
-      {
-        path: 'scroll',
-        name: t('routes.demo.comp.scroll'),
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.comp.scrollBasic'),
-          },
-          {
-            path: 'action',
-            name: t('routes.demo.comp.scrollAction'),
-          },
-          {
-            path: 'virtualScroll',
-            name: t('routes.demo.comp.virtualScroll'),
-          },
-        ],
-      },
-      {
-        path: 'lazy',
-        name: t('routes.demo.comp.lazy'),
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.comp.lazyBasic'),
-          },
-          {
-            path: 'transition',
-            name: t('routes.demo.comp.lazyTransition'),
-          },
-        ],
-      },
-      {
-        path: 'verify',
-        name: t('routes.demo.comp.verify'),
-        children: [
-          {
-            path: 'drag',
-            name: t('routes.demo.comp.verifyDrag'),
-          },
-          {
-            path: 'rotate',
-            name: t('routes.demo.comp.verifyRotate'),
-          },
-        ],
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 29
src/router/menus/modules/demo/excel.ts

@@ -1,29 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 500,
-  menu: {
-    name: t('routes.demo.excel.excel'),
-    path: '/excel',
-    children: [
-      {
-        path: 'customExport',
-        name: t('routes.demo.excel.customExport'),
-      },
-      {
-        path: 'jsonExport',
-        name: t('routes.demo.excel.jsonExport'),
-      },
-      {
-        path: 'arrayExport',
-        name: t('routes.demo.excel.arrayExport'),
-      },
-      {
-        path: 'importExcel',
-        name: t('routes.demo.excel.importExcel'),
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 130
src/router/menus/modules/demo/feat.ts

@@ -1,130 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 19,
-  menu: {
-    name: t('routes.demo.feat.feat'),
-    path: '/feat',
-    children: [
-      {
-        path: 'icon',
-        name: t('routes.demo.feat.icon'),
-      },
-      {
-        path: 'ws',
-        name: t('routes.demo.feat.ws'),
-      },
-      {
-        name: t('routes.demo.feat.sessionTimeout'),
-        path: 'session-timeout',
-      },
-      {
-        path: 'tabs',
-        name: t('routes.demo.feat.tabs'),
-      },
-
-      {
-        path: 'context-menu',
-        name: t('routes.demo.feat.contextMenu'),
-      },
-      {
-        path: 'download',
-        name: t('routes.demo.feat.download'),
-      },
-      {
-        path: 'print',
-        name: t('routes.demo.feat.print'),
-      },
-      {
-        path: 'click-out-side',
-        name: t('routes.demo.feat.clickOutSide'),
-      },
-      {
-        path: 'img-preview',
-        name: t('routes.demo.feat.imgPreview'),
-      },
-      {
-        path: 'copy',
-        name: t('routes.demo.feat.copy'),
-      },
-      {
-        path: 'msg',
-        name: t('routes.demo.feat.msg'),
-      },
-      {
-        path: 'watermark',
-        name: t('routes.demo.feat.watermark'),
-      },
-      {
-        path: 'ripple',
-        name: t('routes.demo.feat.ripple'),
-      },
-      {
-        path: 'full-screen',
-        name: t('routes.demo.feat.fullScreen'),
-      },
-      {
-        path: 'error-log',
-        name: t('routes.demo.feat.errorLog'),
-      },
-
-      {
-        name: t('routes.demo.excel.excel'),
-        path: 'excel',
-        children: [
-          {
-            path: 'customExport',
-            name: t('routes.demo.excel.customExport'),
-          },
-          {
-            path: 'jsonExport',
-            name: t('routes.demo.excel.jsonExport'),
-          },
-          {
-            path: 'arrayExport',
-            name: t('routes.demo.excel.arrayExport'),
-          },
-          {
-            path: 'importExcel',
-            name: t('routes.demo.excel.importExcel'),
-          },
-        ],
-      },
-      {
-        name: t('routes.demo.feat.breadcrumb'),
-        path: 'breadcrumb',
-
-        children: [
-          // {
-          //   path: 'flat',
-          //   name: t('routes.demo.feat.breadcrumbFlat'),
-          // },
-          // {
-          //   path: 'flatDetail',
-          //   name: t('routes.demo.feat.breadcrumbFlatDetail'),
-          // },
-          {
-            path: 'children',
-            name: t('routes.demo.feat.breadcrumbChildren'),
-          },
-        ],
-      },
-      {
-        path: 'testTab',
-        name: t('routes.demo.feat.tab'),
-        children: [
-          {
-            path: 'id1',
-            name: t('routes.demo.feat.tab1'),
-          },
-          {
-            path: 'id2',
-            name: t('routes.demo.feat.tab2'),
-          },
-        ],
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 17
src/router/menus/modules/demo/flow.ts

@@ -1,17 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 5000,
-  menu: {
-    name: t('routes.demo.flow.name'),
-    path: '/flow',
-    children: [
-      {
-        path: 'flowChart',
-        name: t('routes.demo.flow.flowChart'),
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 25
src/router/menus/modules/demo/iframe.ts

@@ -1,25 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 1000,
-  menu: {
-    name: t('routes.demo.iframe.frame'),
-    path: '/frame',
-    children: [
-      {
-        path: 'doc',
-        name: t('routes.demo.iframe.doc'),
-      },
-      {
-        path: 'antv',
-        name: t('routes.demo.iframe.antv'),
-      },
-      {
-        path: 'https://vvbin.cn/doc-next/',
-        name: t('routes.demo.iframe.docExternal'),
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 37
src/router/menus/modules/demo/level.ts

@@ -1,37 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 2000,
-  menu: {
-    name: t('routes.demo.level.level'),
-    path: '/level',
-    children: [
-      {
-        path: 'menu1',
-        name: 'Menu1',
-        children: [
-          {
-            path: 'menu1-1',
-            name: 'Menu1-1',
-            children: [
-              {
-                path: 'menu1-1-1',
-                name: 'Menu1-1-1',
-              },
-            ],
-          },
-          {
-            path: 'menu1-2',
-            name: 'Menu1-2',
-          },
-        ],
-      },
-      {
-        path: 'menu2',
-        name: 'Menu2',
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 121
src/router/menus/modules/demo/page.ts

@@ -1,121 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 20,
-  menu: {
-    name: t('routes.demo.page.page'),
-    path: '/page-demo',
-
-    children: [
-      {
-        path: 'form',
-        name: t('routes.demo.page.form'),
-
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.page.formBasic'),
-          },
-          {
-            path: 'step',
-            name: t('routes.demo.page.formStep'),
-          },
-          {
-            path: 'high',
-            name: t('routes.demo.page.formHigh'),
-          },
-        ],
-      },
-      {
-        path: 'desc',
-        name: t('routes.demo.page.desc'),
-
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.page.descBasic'),
-          },
-          {
-            path: 'high',
-            name: t('routes.demo.page.descHigh'),
-          },
-        ],
-      },
-      {
-        path: 'result',
-        name: t('routes.demo.page.result'),
-
-        children: [
-          {
-            path: 'success',
-            name: t('routes.demo.page.resultSuccess'),
-          },
-          {
-            path: 'fail',
-            name: t('routes.demo.page.resultFail'),
-          },
-        ],
-      },
-      {
-        path: 'exception',
-        name: t('routes.demo.page.exception'),
-        children: [
-          {
-            path: '403',
-            name: t('403'),
-          },
-          {
-            path: '404',
-            name: t('404'),
-          },
-          {
-            path: '500',
-            name: t('500'),
-          },
-          {
-            path: 'net-work-error',
-            name: t('routes.demo.page.netWorkError'),
-          },
-          {
-            path: 'not-data',
-            name: t('routes.demo.page.notData'),
-          },
-        ],
-      },
-      {
-        path: 'account',
-        name: t('routes.demo.page.account'),
-        children: [
-          {
-            path: 'center',
-            name: t('routes.demo.page.accountCenter'),
-          },
-          {
-            path: 'setting',
-            name: t('routes.demo.page.accountSetting'),
-          },
-        ],
-      },
-      {
-        path: 'list',
-        name: t('routes.demo.page.list'),
-        children: [
-          {
-            path: 'basic',
-            name: t('routes.demo.page.listBasic'),
-          },
-          {
-            path: 'card',
-            name: t('routes.demo.page.listCard'),
-          },
-          {
-            path: 'search',
-            name: t('routes.demo.page.listSearch'),
-          },
-        ],
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 49
src/router/menus/modules/demo/permission.ts

@@ -1,49 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 15,
-  menu: {
-    name: t('routes.demo.permission.permission'),
-    path: '/permission',
-    children: [
-      {
-        path: 'front',
-        name: t('routes.demo.permission.front'),
-        children: [
-          {
-            path: 'page',
-            name: t('routes.demo.permission.frontPage'),
-          },
-          {
-            path: 'btn',
-            name: t('routes.demo.permission.frontBtn'),
-          },
-          {
-            path: 'auth-pageA',
-            name: t('routes.demo.permission.frontTestA'),
-          },
-          {
-            path: 'auth-pageB',
-            name: t('routes.demo.permission.frontTestB'),
-          },
-        ],
-      },
-      {
-        path: 'back',
-        name: t('routes.demo.permission.back'),
-        children: [
-          {
-            path: 'page',
-            name: t('routes.demo.permission.backPage'),
-          },
-          {
-            path: 'btn',
-            name: t('routes.demo.permission.backBtn'),
-          },
-        ],
-      },
-    ],
-  },
-};
-export default menu;

+ 0 - 14
src/router/menus/modules/demo/setup.ts

@@ -1,14 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const setup: MenuModule = {
-  orderNo: 90000,
-  menu: {
-    path: '/setup/index',
-    name: t('routes.demo.setup.page'),
-    tag: {
-      content: 'new',
-    },
-  },
-};
-export default setup;

+ 0 - 34
src/router/menus/modules/demo/system.ts

@@ -1,34 +0,0 @@
-import type { MenuModule } from '/@/router/types';
-import { t } from '/@/hooks/web/useI18n';
-
-const menu: MenuModule = {
-  orderNo: 2000,
-  menu: {
-    name: t('routes.demo.system.moduleName'),
-    path: '/system',
-    children: [
-      {
-        path: 'account',
-        name: t('routes.demo.system.account'),
-      },
-      {
-        path: 'role',
-        name: t('routes.demo.system.role'),
-      },
-      {
-        path: 'menu',
-        name: t('routes.demo.system.menu'),
-      },
-      {
-        path: 'dept',
-        name: t('routes.demo.system.dept'),
-      },
-
-      {
-        path: 'changePassword',
-        name: t('routes.demo.system.password'),
-      },
-    ],
-  },
-};
-export default menu;

+ 2 - 0
src/router/routes/basic.ts

@@ -10,6 +10,7 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
   meta: {
     title: 'ErrorPage',
     hideBreadcrumb: true,
+    hideMenu: true,
   },
   children: [
     {
@@ -31,6 +32,7 @@ export const REDIRECT_ROUTE: AppRouteRecordRaw = {
   meta: {
     title: REDIRECT_NAME,
     hideBreadcrumb: true,
+    hideMenu: true,
   },
   children: [
     {

+ 2 - 0
src/router/routes/modules/about.ts

@@ -9,8 +9,10 @@ const dashboard: AppRouteModule = {
   component: LAYOUT,
   redirect: '/about/index',
   meta: {
+    hideChildrenInMenu: true,
     icon: 'simple-icons:about-dot-me',
     title: t('routes.dashboard.about'),
+    orderNo: 100000,
   },
   children: [
     {

+ 1 - 0
src/router/routes/modules/dashboard.ts

@@ -9,6 +9,7 @@ const dashboard: AppRouteModule = {
   component: LAYOUT,
   redirect: '/dashboard/analysis',
   meta: {
+    orderNo: 10,
     icon: 'ion:grid-outline',
     title: t('routes.dashboard.dashboard'),
   },

+ 1 - 0
src/router/routes/modules/demo/charts.ts

@@ -9,6 +9,7 @@ const charts: AppRouteModule = {
   component: LAYOUT,
   redirect: '/charts/echarts/map',
   meta: {
+    orderNo: 500,
     icon: 'ion:bar-chart-outline',
     title: t('routes.demo.charts.charts'),
   },

+ 1 - 0
src/router/routes/modules/demo/comp.ts

@@ -9,6 +9,7 @@ const comp: AppRouteModule = {
   component: LAYOUT,
   redirect: '/comp/basic',
   meta: {
+    orderNo: 30,
     icon: 'ion:layers-outline',
     title: t('routes.demo.comp.comp'),
   },

+ 1 - 0
src/router/routes/modules/demo/feat.ts

@@ -9,6 +9,7 @@ const feat: AppRouteModule = {
   component: LAYOUT,
   redirect: '/feat/icon',
   meta: {
+    orderNo: 19,
     icon: 'ion:git-compare-outline',
     title: t('routes.demo.feat.feat'),
   },

+ 1 - 0
src/router/routes/modules/demo/flow.ts

@@ -9,6 +9,7 @@ const charts: AppRouteModule = {
   component: LAYOUT,
   redirect: '/flow/flowChart',
   meta: {
+    orderNo: 5000,
     icon: 'tabler:chart-dots',
     title: t('routes.demo.flow.name'),
   },

+ 1 - 0
src/router/routes/modules/demo/iframe.ts

@@ -10,6 +10,7 @@ const iframe: AppRouteModule = {
   component: LAYOUT,
   redirect: '/frame/doc',
   meta: {
+    orderNo: 1000,
     icon: 'ion:tv-outline',
     title: t('routes.demo.iframe.frame'),
   },

+ 1 - 0
src/router/routes/modules/demo/level.ts

@@ -9,6 +9,7 @@ const permission: AppRouteModule = {
   component: LAYOUT,
   redirect: '/level/menu1/menu1-1/menu1-1-1',
   meta: {
+    orderNo: 2000,
     icon: 'ion:menu-outline',
     title: t('routes.demo.level.level'),
   },

+ 1 - 0
src/router/routes/modules/demo/page.ts

@@ -12,6 +12,7 @@ const page: AppRouteModule = {
   component: LAYOUT,
   redirect: '/page-demo/form/basic',
   meta: {
+    orderNo: 20,
     icon: 'ion:aperture-outline',
     title: t('routes.demo.page.page'),
   },

+ 1 - 0
src/router/routes/modules/demo/permission.ts

@@ -10,6 +10,7 @@ const permission: AppRouteModule = {
   component: LAYOUT,
   redirect: '/permission/front/page',
   meta: {
+    orderNo: 15,
     icon: 'ion:key-outline',
     title: t('routes.demo.permission.permission'),
   },

+ 2 - 0
src/router/routes/modules/demo/setup.ts

@@ -9,6 +9,8 @@ const setup: AppRouteModule = {
   component: LAYOUT,
   redirect: '/setup/index',
   meta: {
+    orderNo: 90000,
+    hideChildrenInMenu: true,
     icon: 'simple-icons:about-dot-me',
     title: t('routes.demo.setup.page'),
   },

+ 2 - 0
src/router/routes/modules/demo/system.ts

@@ -9,6 +9,7 @@ const system: AppRouteModule = {
   component: LAYOUT,
   redirect: '/system/account',
   meta: {
+    orderNo: 2000,
     icon: 'ion:settings-outline',
     title: t('routes.demo.system.moduleName'),
   },
@@ -26,6 +27,7 @@ const system: AppRouteModule = {
       path: 'account_detail/:id',
       name: 'AccountDetail',
       meta: {
+        hideMenu: true,
         title: t('routes.demo.system.account_detail'),
         ignoreKeepAlive: true,
         showMenu: false,

+ 1 - 1
src/settings/projectSetting.ts

@@ -24,7 +24,7 @@ const setting: ProjectConfig = {
   settingButtonPosition: SettingButtonPositionEnum.AUTO,
 
   // Permission mode
-  permissionMode: PermissionModeEnum.ROLE,
+  permissionMode: PermissionModeEnum.ROUTE_MAPPING,
 
   // Permission-related cache is stored in sessionStorage or localStorage
   permissionCacheType: CacheTypeEnum.LOCAL,

+ 1 - 1
src/store/modules/app.ts

@@ -103,6 +103,6 @@ export const useAppStore = defineStore({
 });
 
 // Need to be used outside the setup
-export function useAppStoreWidthOut() {
+export function useAppStoreWithOut() {
   return useAppStore(store);
 }

+ 70 - 42
src/store/modules/permission.ts

@@ -4,7 +4,7 @@ import { defineStore } from 'pinia';
 import { store } from '/@/store';
 import { useI18n } from '/@/hooks/web/useI18n';
 import { useUserStore } from './user';
-import { useAppStoreWidthOut } from './app';
+import { useAppStoreWithOut } from './app';
 import { toRaw } from 'vue';
 import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
 import { transformRouteToMenu } from '/@/router/helper/menuHelper';
@@ -32,6 +32,7 @@ interface PermissionState {
   lastBuildMenuTime: number;
   // Backstage menu list
   backMenuList: Menu[];
+  frontMenuList: Menu[];
 }
 export const usePermissionStore = defineStore({
   id: 'app-permission',
@@ -43,6 +44,8 @@ export const usePermissionStore = defineStore({
     lastBuildMenuTime: 0,
     // Backstage menu list
     backMenuList: [],
+    // menu List
+    frontMenuList: [],
   }),
   getters: {
     getPermCodeList(): string[] | number[] {
@@ -51,6 +54,9 @@ export const usePermissionStore = defineStore({
     getBackMenuList(): Menu[] {
       return this.backMenuList;
     },
+    getFrontMenuList(): Menu[] {
+      return this.frontMenuList;
+    },
     getLastBuildMenuTime(): number {
       return this.lastBuildMenuTime;
     },
@@ -68,6 +74,10 @@ export const usePermissionStore = defineStore({
       list?.length > 0 && this.setLastBuildMenuTime();
     },
 
+    setFrontMenuList(list: Menu[]) {
+      this.frontMenuList = list;
+    },
+
     setLastBuildMenuTime() {
       this.lastBuildMenuTime = new Date().getTime();
     },
@@ -88,52 +98,70 @@ export const usePermissionStore = defineStore({
     async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
       const { t } = useI18n();
       const userStore = useUserStore();
-      const appStore = useAppStoreWidthOut();
+      const appStore = useAppStoreWithOut();
 
       let routes: AppRouteRecordRaw[] = [];
       const roleList = toRaw(userStore.getRoleList) || [];
       const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
-      // role permissions
-      if (permissionMode === PermissionModeEnum.ROLE) {
-        const routeFilter = (route: AppRouteRecordRaw) => {
-          const { meta } = route;
-          const { roles } = meta || {};
-          if (!roles) return true;
-          return roleList.some((role) => roles.includes(role));
-        };
-        routes = filter(asyncRoutes, routeFilter);
-        routes = routes.filter(routeFilter);
-        // Convert multi-level routing to level 2 routing
-        routes = flatMultiLevelRoutes(routes);
+
+      const routeFilter = (route: AppRouteRecordRaw) => {
+        const { meta } = route;
+        const { roles } = meta || {};
+        if (!roles) return true;
+        return roleList.some((role) => roles.includes(role));
+      };
+
+      switch (permissionMode) {
+        case PermissionModeEnum.ROLE:
+          routes = filter(asyncRoutes, routeFilter);
+          routes = routes.filter(routeFilter);
+          // Convert multi-level routing to level 2 routing
+          routes = flatMultiLevelRoutes(routes);
+          break;
+
+        case PermissionModeEnum.ROUTE_MAPPING:
+          routes = filter(asyncRoutes, routeFilter);
+          routes = routes.filter(routeFilter);
+          const menuList = transformRouteToMenu(asyncRoutes);
+          menuList.sort((a, b) => {
+            return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
+          });
+          this.setFrontMenuList(menuList);
+          // Convert multi-level routing to level 2 routing
+          routes = flatMultiLevelRoutes(routes);
+          break;
+
         //  If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
-      } else if (permissionMode === PermissionModeEnum.BACK) {
-        const { createMessage } = useMessage();
-
-        createMessage.loading({
-          content: t('sys.app.menuLoading'),
-          duration: 1,
-        });
-
-        // !Simulate to obtain permission codes from the background,
-        // this function may only need to be executed once, and the actual project can be put at the right time by itself
-        let routeList: AppRouteRecordRaw[] = [];
-        try {
-          this.changePermissionCode();
-          routeList = (await getMenuList()) as AppRouteRecordRaw[];
-        } catch (error) {
-          console.error(error);
-        }
-
-        // Dynamically introduce components
-        routeList = transformObjToRoute(routeList);
-
-        //  Background routing to menu structure
-        const backMenuList = transformRouteToMenu(routeList);
-        this.setBackMenuList(backMenuList);
-
-        routeList = flatMultiLevelRoutes(routeList);
-        routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
+        case PermissionModeEnum.BACK:
+          const { createMessage } = useMessage();
+
+          createMessage.loading({
+            content: t('sys.app.menuLoading'),
+            duration: 1,
+          });
+
+          // !Simulate to obtain permission codes from the background,
+          // this function may only need to be executed once, and the actual project can be put at the right time by itself
+          let routeList: AppRouteRecordRaw[] = [];
+          try {
+            this.changePermissionCode();
+            routeList = (await getMenuList()) as AppRouteRecordRaw[];
+          } catch (error) {
+            console.error(error);
+          }
+
+          // Dynamically introduce components
+          routeList = transformObjToRoute(routeList);
+
+          //  Background routing to menu structure
+          const backMenuList = transformRouteToMenu(routeList);
+          this.setBackMenuList(backMenuList);
+
+          routeList = flatMultiLevelRoutes(routeList);
+          routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
+          break;
       }
+
       routes.push(ERROR_LOG_ROUTE);
       return routes;
     },
@@ -141,6 +169,6 @@ export const usePermissionStore = defineStore({
 });
 
 // Need to be used outside the setup
-export function usePermissionStoreWidthOut() {
+export function usePermissionStoreWithOut() {
   return usePermissionStore(store);
 }

+ 1 - 1
src/store/modules/user.ts

@@ -128,6 +128,6 @@ export const useUserStore = defineStore({
 });
 
 // Need to be used outside the setup
-export function useUserStoreWidthOut() {
+export function useUserStoreWithOut() {
   return useUserStore(store);
 }

+ 2 - 2
src/utils/http/axios/checkStatus.ts

@@ -3,7 +3,7 @@ import { useMessage } from '/@/hooks/web/useMessage';
 import { useI18n } from '/@/hooks/web/useI18n';
 // import router from '/@/router';
 // import { PageEnum } from '/@/enums/pageEnum';
-import { useUserStoreWidthOut } from '/@/store/modules/user';
+import { useUserStoreWithOut } from '/@/store/modules/user';
 import projectSetting from '/@/settings/projectSetting';
 import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum';
 
@@ -17,7 +17,7 @@ export function checkStatus(
   errorMessageMode: ErrorMessageMode = 'message'
 ): void {
   const { t } = useI18n();
-  const userStore = useUserStoreWidthOut();
+  const userStore = useUserStoreWithOut();
   let errMessage = '';
 
   switch (status) {

+ 1 - 0
types/vue-router.d.ts

@@ -2,6 +2,7 @@ export {};
 
 declare module 'vue-router' {
   interface RouteMeta extends Record<string | number | symbol, unknown> {
+    orderNo?: number;
     // title
     title: string;
     // Whether to ignore permissions