Commit 913c22c84fc9a4221fdfff6bae0e79a68fd09b17

Authored by vben
1 parent 327d71b8

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

CHANGELOG.zh_CN.md
1 1 ## Wip
2 2  
  3 +### ⚡ Performance Improvements
  4 +
3 5 - **Icon** 移除 Icon 组件全局注册,防止特定情况下热更新问题
4 6  
  7 +### ✨ Features
  8 +
  9 +- **Menu** 新增 `permissionMode=PermissionModeEnum.ROUTE_MAPPING`模式
  10 + - 项目默认改为该模式,删除原有菜单文件
  11 + - 如果之前已经写好了菜单,可以更改为`PermissionModeEnum.ROLE`模式即可
  12 +
5 13 ## 2.5.1(2021-06-26)
6 14  
7 15 ### ⚡ Performance Improvements
... ...
src/enums/appEnum.ts
... ... @@ -33,6 +33,8 @@ export enum PermissionModeEnum {
33 33 ROLE = 'ROLE',
34 34 // black
35 35 BACK = 'BACK',
  36 + // route mapping
  37 + ROUTE_MAPPING = 'ROUTE_MAPPING',
36 38 }
37 39  
38 40 // Route switching animation
... ...
src/hooks/web/usePermission.ts
... ... @@ -31,7 +31,7 @@ export function usePermission() {
31 31 appStore.setProjectConfig({
32 32 permissionMode:
33 33 projectSetting.permissionMode === PermissionModeEnum.BACK
34   - ? PermissionModeEnum.ROLE
  34 + ? PermissionModeEnum.ROUTE_MAPPING
35 35 : PermissionModeEnum.BACK,
36 36 });
37 37 location.reload();
... ... @@ -59,7 +59,7 @@ export function usePermission() {
59 59 function hasPermission(value?: RoleEnum | RoleEnum[] | string | string[], def = true): boolean {
60 60 const permMode = projectSetting.permissionMode;
61 61  
62   - if (PermissionModeEnum.ROLE === permMode) {
  62 + if (PermissionModeEnum.ROUTE_MAPPING === permMode) {
63 63 // Visible by default
64 64 if (!value) {
65 65 return def;
... ... @@ -89,9 +89,9 @@ export function usePermission() {
89 89 * @param roles
90 90 */
91 91 async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> {
92   - if (projectSetting.permissionMode !== PermissionModeEnum.ROLE) {
  92 + if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) {
93 93 throw new Error(
94   - 'Please switch PermissionModeEnum to ROLE mode in the configuration to operate!'
  94 + 'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!'
95 95 );
96 96 }
97 97  
... ...
src/layouts/default/feature/index.vue
... ... @@ -5,7 +5,7 @@
5 5 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
6 6 import { useHeaderSetting } from '/@/hooks/setting/useHeaderSetting';
7 7 import { useDesign } from '/@/hooks/web/useDesign';
8   - import { useUserStoreWidthOut } from '/@/store/modules/user';
  8 + import { useUserStoreWithOut } from '/@/store/modules/user';
9 9  
10 10 import { SettingButtonPositionEnum } from '/@/enums/appEnum';
11 11 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
... ... @@ -22,7 +22,7 @@
22 22 setup() {
23 23 const { getUseOpenBackTop, getShowSettingButton, getSettingButtonPosition, getFullContent } =
24 24 useRootSetting();
25   - const userStore = useUserStoreWidthOut();
  25 + const userStore = useUserStoreWithOut();
26 26 const { prefixCls } = useDesign('setting-drawer-fearure');
27 27 const { getShowHeader } = useHeaderSetting();
28 28  
... ...
src/router/guard/index.ts
1 1 import type { Router, RouteLocationNormalized } from 'vue-router';
2   -import { useAppStoreWidthOut } from '/@/store/modules/app';
3   -import { useUserStoreWidthOut } from '/@/store/modules/user';
  2 +import { useAppStoreWithOut } from '/@/store/modules/app';
  3 +import { useUserStoreWithOut } from '/@/store/modules/user';
4 4 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
5 5 import { AxiosCanceler } from '/@/utils/http/axios/axiosCancel';
6 6 import { Modal, notification } from 'ant-design-vue';
... ... @@ -46,8 +46,8 @@ function createPageGuard(router: Router) {
46 46  
47 47 // Used to handle page loading status
48 48 function createPageLoadingGuard(router: Router) {
49   - const userStore = useUserStoreWidthOut();
50   - const appStore = useAppStoreWidthOut();
  49 + const userStore = useUserStoreWithOut();
  50 + const appStore = useAppStoreWithOut();
51 51 const { getOpenPageLoading } = useTransitionSetting();
52 52 router.beforeEach(async (to) => {
53 53 if (!userStore.getToken) {
... ...
src/router/guard/permissionGuard.ts
1 1 import type { Router, RouteRecordRaw } from 'vue-router';
2 2  
3   -import { usePermissionStoreWidthOut } from '/@/store/modules/permission';
  3 +import { usePermissionStoreWithOut } from '/@/store/modules/permission';
4 4  
5 5 import { PageEnum } from '/@/enums/pageEnum';
6   -import { useUserStoreWidthOut } from '/@/store/modules/user';
  6 +import { useUserStoreWithOut } from '/@/store/modules/user';
7 7  
8 8 import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
9 9  
... ... @@ -12,8 +12,8 @@ const LOGIN_PATH = PageEnum.BASE_LOGIN;
12 12 const whitePathList: PageEnum[] = [LOGIN_PATH];
13 13  
14 14 export function createPermissionGuard(router: Router) {
15   - const userStore = useUserStoreWidthOut();
16   - const permissionStore = usePermissionStoreWidthOut();
  15 + const userStore = useUserStoreWithOut();
  16 + const permissionStore = usePermissionStoreWithOut();
17 17 router.beforeEach(async (to, from, next) => {
18 18 // Jump to the 404 page after processing the login
19 19 if (from.path === LOGIN_PATH && to.name === PAGE_NOT_FOUND_ROUTE.name) {
... ...
src/router/helper/routeHelper.ts
... ... @@ -65,6 +65,8 @@ function dynamicImport(
65 65  
66 66 // Turn background objects into routing objects
67 67 export function transformObjToRoute<T = AppRouteModule>(routeList: AppRouteModule[]): T[] {
  68 + console.log(routeList);
  69 +
68 70 routeList.forEach((route) => {
69 71 const component = route.component as string;
70 72 if (component) {
... ...
src/router/menus/index.ts
1 1 import type { Menu, MenuModule } from '/@/router/types';
2 2 import type { RouteRecordNormalized } from 'vue-router';
3 3  
4   -import { useAppStoreWidthOut } from '/@/store/modules/app';
  4 +import { useAppStoreWithOut } from '/@/store/modules/app';
5 5 import { usePermissionStore } from '/@/store/modules/permission';
6 6 import { transformMenuModule, getAllParentPath } from '/@/router/helper/menuHelper';
7 7 import { filter } from '/@/utils/helper/treeHelper';
... ... @@ -23,9 +23,21 @@ Object.keys(modules).forEach((key) =&gt; {
23 23 // ===========================
24 24 // ==========Helper===========
25 25 // ===========================
  26 +
  27 +const getPermissionMode = () => {
  28 + const appStore = useAppStoreWithOut();
  29 + return appStore.getProjectConfig.permissionMode;
  30 +};
26 31 const isBackMode = () => {
27   - const appStore = useAppStoreWidthOut();
28   - return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
  32 + return getPermissionMode() === PermissionModeEnum.BACK;
  33 +};
  34 +
  35 +const isRouteMappingMode = () => {
  36 + return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
  37 +};
  38 +
  39 +const isRoleMode = () => {
  40 + return getPermissionMode() === PermissionModeEnum.ROLE;
29 41 };
30 42  
31 43 const staticMenus: Menu[] = [];
... ... @@ -41,40 +53,53 @@ const staticMenus: Menu[] = [];
41 53  
42 54 async function getAsyncMenus() {
43 55 const permissionStore = usePermissionStore();
44   - return !isBackMode() ? staticMenus : permissionStore.getBackMenuList;
  56 + if (isBackMode()) {
  57 + return permissionStore.getBackMenuList;
  58 + }
  59 + if (isRouteMappingMode()) {
  60 + return permissionStore.getFrontMenuList.filter((item) => !item.hideMenu);
  61 + }
  62 + return staticMenus;
45 63 }
46 64  
47 65 export const getMenus = async (): Promise<Menu[]> => {
48 66 const menus = await getAsyncMenus();
49   - const routes = router.getRoutes();
50   -
51   - return !isBackMode() ? filter(menus, basicFilter(routes)) : menus;
  67 + if (isRoleMode()) {
  68 + const routes = router.getRoutes();
  69 + return filter(menus, basicFilter(routes));
  70 + }
  71 + return menus;
52 72 };
53 73  
54 74 export async function getCurrentParentPath(currentPath: string) {
55 75 const menus = await getAsyncMenus();
56   -
57 76 const allParentPath = await getAllParentPath(menus, currentPath);
58   -
59 77 return allParentPath?.[0];
60 78 }
61 79  
62 80 // Get the level 1 menu, delete children
63 81 export async function getShallowMenus(): Promise<Menu[]> {
64 82 const menus = await getAsyncMenus();
65   - const routes = router.getRoutes();
66 83 const shallowMenuList = menus.map((item) => ({ ...item, children: undefined }));
67   - return !isBackMode() ? shallowMenuList.filter(basicFilter(routes)) : shallowMenuList;
  84 + if (isRoleMode()) {
  85 + const routes = router.getRoutes();
  86 + return shallowMenuList.filter(basicFilter(routes));
  87 + }
  88 + return shallowMenuList;
68 89 }
69 90  
70 91 // Get the children of the menu
71 92 export async function getChildrenMenus(parentPath: string) {
72 93 const menus = await getMenus();
73 94 const parent = menus.find((item) => item.path === parentPath);
74   - if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) return [] as Menu[];
75   - const routes = router.getRoutes();
76   -
77   - return !isBackMode() ? filter(parent.children, basicFilter(routes)) : parent.children;
  95 + if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) {
  96 + return [] as Menu[];
  97 + }
  98 + if (isRoleMode()) {
  99 + const routes = router.getRoutes();
  100 + return filter(parent.children, basicFilter(routes));
  101 + }
  102 + return parent.children;
78 103 }
79 104  
80 105 function basicFilter(routes: RouteRecordNormalized[]) {
... ...
src/router/menus/modules/about.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const about: MenuModule = {
5   - orderNo: 100000,
6   - menu: {
7   - path: '/about/index',
8   - name: t('routes.dashboard.about'),
9   - },
10   -};
11   -export default about;
src/router/menus/modules/dashboard.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 10,
6   - menu: {
7   - name: t('routes.dashboard.dashboard'),
8   - path: '/dashboard',
9   -
10   - children: [
11   - {
12   - path: 'analysis',
13   - name: t('routes.dashboard.analysis'),
14   - },
15   - {
16   - path: 'workbench',
17   - name: t('routes.dashboard.workbench'),
18   - },
19   - ],
20   - },
21   -};
22   -export default menu;
src/router/menus/modules/demo/charts.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 500,
6   - menu: {
7   - name: t('routes.demo.charts.charts'),
8   - path: '/charts',
9   -
10   - children: [
11   - {
12   - path: 'aMap',
13   - name: t('routes.demo.charts.aMap'),
14   - },
15   -
16   - {
17   - path: 'baiduMap',
18   - name: t('routes.demo.charts.baiduMap'),
19   - },
20   - {
21   - path: 'googleMap',
22   - name: t('routes.demo.charts.googleMap'),
23   - },
24   - {
25   - path: 'echarts',
26   - name: 'Echarts',
27   - children: [
28   - {
29   - path: 'map',
30   - name: t('routes.demo.charts.map'),
31   - },
32   - {
33   - path: 'line',
34   - name: t('routes.demo.charts.line'),
35   - },
36   - {
37   - path: 'pie',
38   - name: t('routes.demo.charts.pie'),
39   - },
40   - ],
41   - },
42   - ],
43   - },
44   -};
45   -export default menu;
src/router/menus/modules/demo/comp.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 30,
6   - menu: {
7   - name: t('routes.demo.comp.comp'),
8   - path: '/comp',
9   - tag: { dot: true },
10   - children: [
11   - {
12   - path: 'basic',
13   - name: t('routes.demo.comp.basic'),
14   - },
15   - {
16   - path: 'form',
17   - name: t('routes.demo.form.form'),
18   -
19   - children: [
20   - {
21   - path: 'basic',
22   - name: t('routes.demo.form.basic'),
23   - },
24   - {
25   - path: 'useForm',
26   - name: t('routes.demo.form.useForm'),
27   - },
28   - {
29   - path: 'refForm',
30   - name: t('routes.demo.form.refForm'),
31   - },
32   - {
33   - path: 'advancedForm',
34   - name: t('routes.demo.form.advancedForm'),
35   - },
36   - {
37   - path: 'ruleForm',
38   - name: t('routes.demo.form.ruleForm'),
39   - },
40   - {
41   - path: 'dynamicForm',
42   - name: t('routes.demo.form.dynamicForm'),
43   - },
44   - {
45   - path: 'customerForm',
46   - name: t('routes.demo.form.customerForm'),
47   - },
48   - {
49   - path: 'appendForm',
50   - name: t('routes.demo.form.appendForm'),
51   - },
52   - ],
53   - },
54   - {
55   - path: 'table',
56   - name: t('routes.demo.table.table'),
57   -
58   - children: [
59   - {
60   - path: 'basic',
61   - name: t('routes.demo.table.basic'),
62   - },
63   - {
64   - path: 'treeTable',
65   - name: t('routes.demo.table.treeTable'),
66   - },
67   - {
68   - path: 'fetchTable',
69   - name: t('routes.demo.table.fetchTable'),
70   - },
71   - {
72   - path: 'fixedColumn',
73   - name: t('routes.demo.table.fixedColumn'),
74   - },
75   - {
76   - path: 'customerCell',
77   - name: t('routes.demo.table.customerCell'),
78   - },
79   - {
80   - path: 'formTable',
81   - name: t('routes.demo.table.formTable'),
82   - },
83   - {
84   - path: 'useTable',
85   - name: t('routes.demo.table.useTable'),
86   - },
87   - {
88   - path: 'refTable',
89   - name: t('routes.demo.table.refTable'),
90   - },
91   - {
92   - path: 'multipleHeader',
93   - name: t('routes.demo.table.multipleHeader'),
94   - },
95   - {
96   - path: 'mergeHeader',
97   - name: t('routes.demo.table.mergeHeader'),
98   - },
99   - {
100   - path: 'expandTable',
101   - name: t('routes.demo.table.expandTable'),
102   - },
103   - {
104   - path: 'fixedHeight',
105   - name: t('routes.demo.table.fixedHeight'),
106   - },
107   - {
108   - path: 'footerTable',
109   - name: t('routes.demo.table.footerTable'),
110   - },
111   - {
112   - path: 'editCellTable',
113   - name: t('routes.demo.table.editCellTable'),
114   - },
115   - {
116   - path: 'editRowTable',
117   - name: t('routes.demo.table.editRowTable'),
118   - },
119   - {
120   - path: 'authColumn',
121   - name: t('routes.demo.table.authColumn'),
122   - },
123   - ],
124   - },
125   - {
126   - path: 'cropper',
127   - name: t('routes.demo.comp.cropperImage'),
128   - tag: {
129   - content: 'new',
130   - },
131   - },
132   - {
133   - path: 'countTo',
134   - name: t('routes.demo.comp.countTo'),
135   - },
136   - {
137   - path: 'timestamp',
138   - name: t('routes.demo.comp.time'),
139   - },
140   - {
141   - path: 'transition',
142   - name: t('routes.demo.comp.transition'),
143   - },
144   -
145   - {
146   - path: 'modal',
147   - name: t('routes.demo.comp.modal'),
148   - },
149   - {
150   - path: 'drawer',
151   - name: t('routes.demo.comp.drawer'),
152   - },
153   - {
154   - path: 'desc',
155   - name: t('routes.demo.comp.desc'),
156   - },
157   - {
158   - path: 'qrcode',
159   - name: t('routes.demo.comp.qrcode'),
160   - },
161   - {
162   - path: 'strength-meter',
163   - name: t('routes.demo.comp.strength'),
164   - },
165   - {
166   - path: 'upload',
167   - name: t('routes.demo.comp.upload'),
168   - },
169   - {
170   - path: 'loading',
171   - name: t('routes.demo.comp.loading'),
172   - },
173   - {
174   - path: 'tree',
175   - name: t('routes.demo.comp.tree'),
176   -
177   - children: [
178   - {
179   - path: 'basic',
180   - name: t('routes.demo.comp.treeBasic'),
181   - },
182   - {
183   - path: 'editTree',
184   - name: t('routes.demo.comp.editTree'),
185   - },
186   - {
187   - path: 'actionTree',
188   - name: t('routes.demo.comp.actionTree'),
189   - },
190   - ],
191   - },
192   - {
193   - name: t('routes.demo.editor.editor'),
194   - path: 'editor',
195   - children: [
196   - {
197   - path: 'json',
198   - name: t('routes.demo.editor.jsonEditor'),
199   - },
200   - {
201   - path: 'markdown',
202   - name: t('routes.demo.editor.markdown'),
203   - children: [
204   - {
205   - path: 'index',
206   - name: t('routes.demo.editor.tinymceBasic'),
207   - },
208   - {
209   - path: 'editor',
210   - name: t('routes.demo.editor.tinymceForm'),
211   - },
212   - ],
213   - },
214   - {
215   - path: 'tinymce',
216   - name: t('routes.demo.editor.tinymce'),
217   - children: [
218   - {
219   - path: 'index',
220   - name: t('routes.demo.editor.tinymceBasic'),
221   - },
222   - {
223   - path: 'editor',
224   - name: t('routes.demo.editor.tinymceForm'),
225   - },
226   - ],
227   - },
228   - ],
229   - },
230   - {
231   - path: 'scroll',
232   - name: t('routes.demo.comp.scroll'),
233   - children: [
234   - {
235   - path: 'basic',
236   - name: t('routes.demo.comp.scrollBasic'),
237   - },
238   - {
239   - path: 'action',
240   - name: t('routes.demo.comp.scrollAction'),
241   - },
242   - {
243   - path: 'virtualScroll',
244   - name: t('routes.demo.comp.virtualScroll'),
245   - },
246   - ],
247   - },
248   - {
249   - path: 'lazy',
250   - name: t('routes.demo.comp.lazy'),
251   - children: [
252   - {
253   - path: 'basic',
254   - name: t('routes.demo.comp.lazyBasic'),
255   - },
256   - {
257   - path: 'transition',
258   - name: t('routes.demo.comp.lazyTransition'),
259   - },
260   - ],
261   - },
262   - {
263   - path: 'verify',
264   - name: t('routes.demo.comp.verify'),
265   - children: [
266   - {
267   - path: 'drag',
268   - name: t('routes.demo.comp.verifyDrag'),
269   - },
270   - {
271   - path: 'rotate',
272   - name: t('routes.demo.comp.verifyRotate'),
273   - },
274   - ],
275   - },
276   - ],
277   - },
278   -};
279   -export default menu;
src/router/menus/modules/demo/excel.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 500,
6   - menu: {
7   - name: t('routes.demo.excel.excel'),
8   - path: '/excel',
9   - children: [
10   - {
11   - path: 'customExport',
12   - name: t('routes.demo.excel.customExport'),
13   - },
14   - {
15   - path: 'jsonExport',
16   - name: t('routes.demo.excel.jsonExport'),
17   - },
18   - {
19   - path: 'arrayExport',
20   - name: t('routes.demo.excel.arrayExport'),
21   - },
22   - {
23   - path: 'importExcel',
24   - name: t('routes.demo.excel.importExcel'),
25   - },
26   - ],
27   - },
28   -};
29   -export default menu;
src/router/menus/modules/demo/feat.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 19,
6   - menu: {
7   - name: t('routes.demo.feat.feat'),
8   - path: '/feat',
9   - children: [
10   - {
11   - path: 'icon',
12   - name: t('routes.demo.feat.icon'),
13   - },
14   - {
15   - path: 'ws',
16   - name: t('routes.demo.feat.ws'),
17   - },
18   - {
19   - name: t('routes.demo.feat.sessionTimeout'),
20   - path: 'session-timeout',
21   - },
22   - {
23   - path: 'tabs',
24   - name: t('routes.demo.feat.tabs'),
25   - },
26   -
27   - {
28   - path: 'context-menu',
29   - name: t('routes.demo.feat.contextMenu'),
30   - },
31   - {
32   - path: 'download',
33   - name: t('routes.demo.feat.download'),
34   - },
35   - {
36   - path: 'print',
37   - name: t('routes.demo.feat.print'),
38   - },
39   - {
40   - path: 'click-out-side',
41   - name: t('routes.demo.feat.clickOutSide'),
42   - },
43   - {
44   - path: 'img-preview',
45   - name: t('routes.demo.feat.imgPreview'),
46   - },
47   - {
48   - path: 'copy',
49   - name: t('routes.demo.feat.copy'),
50   - },
51   - {
52   - path: 'msg',
53   - name: t('routes.demo.feat.msg'),
54   - },
55   - {
56   - path: 'watermark',
57   - name: t('routes.demo.feat.watermark'),
58   - },
59   - {
60   - path: 'ripple',
61   - name: t('routes.demo.feat.ripple'),
62   - },
63   - {
64   - path: 'full-screen',
65   - name: t('routes.demo.feat.fullScreen'),
66   - },
67   - {
68   - path: 'error-log',
69   - name: t('routes.demo.feat.errorLog'),
70   - },
71   -
72   - {
73   - name: t('routes.demo.excel.excel'),
74   - path: 'excel',
75   - children: [
76   - {
77   - path: 'customExport',
78   - name: t('routes.demo.excel.customExport'),
79   - },
80   - {
81   - path: 'jsonExport',
82   - name: t('routes.demo.excel.jsonExport'),
83   - },
84   - {
85   - path: 'arrayExport',
86   - name: t('routes.demo.excel.arrayExport'),
87   - },
88   - {
89   - path: 'importExcel',
90   - name: t('routes.demo.excel.importExcel'),
91   - },
92   - ],
93   - },
94   - {
95   - name: t('routes.demo.feat.breadcrumb'),
96   - path: 'breadcrumb',
97   -
98   - children: [
99   - // {
100   - // path: 'flat',
101   - // name: t('routes.demo.feat.breadcrumbFlat'),
102   - // },
103   - // {
104   - // path: 'flatDetail',
105   - // name: t('routes.demo.feat.breadcrumbFlatDetail'),
106   - // },
107   - {
108   - path: 'children',
109   - name: t('routes.demo.feat.breadcrumbChildren'),
110   - },
111   - ],
112   - },
113   - {
114   - path: 'testTab',
115   - name: t('routes.demo.feat.tab'),
116   - children: [
117   - {
118   - path: 'id1',
119   - name: t('routes.demo.feat.tab1'),
120   - },
121   - {
122   - path: 'id2',
123   - name: t('routes.demo.feat.tab2'),
124   - },
125   - ],
126   - },
127   - ],
128   - },
129   -};
130   -export default menu;
src/router/menus/modules/demo/flow.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 5000,
6   - menu: {
7   - name: t('routes.demo.flow.name'),
8   - path: '/flow',
9   - children: [
10   - {
11   - path: 'flowChart',
12   - name: t('routes.demo.flow.flowChart'),
13   - },
14   - ],
15   - },
16   -};
17   -export default menu;
src/router/menus/modules/demo/iframe.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 1000,
6   - menu: {
7   - name: t('routes.demo.iframe.frame'),
8   - path: '/frame',
9   - children: [
10   - {
11   - path: 'doc',
12   - name: t('routes.demo.iframe.doc'),
13   - },
14   - {
15   - path: 'antv',
16   - name: t('routes.demo.iframe.antv'),
17   - },
18   - {
19   - path: 'https://vvbin.cn/doc-next/',
20   - name: t('routes.demo.iframe.docExternal'),
21   - },
22   - ],
23   - },
24   -};
25   -export default menu;
src/router/menus/modules/demo/level.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 2000,
6   - menu: {
7   - name: t('routes.demo.level.level'),
8   - path: '/level',
9   - children: [
10   - {
11   - path: 'menu1',
12   - name: 'Menu1',
13   - children: [
14   - {
15   - path: 'menu1-1',
16   - name: 'Menu1-1',
17   - children: [
18   - {
19   - path: 'menu1-1-1',
20   - name: 'Menu1-1-1',
21   - },
22   - ],
23   - },
24   - {
25   - path: 'menu1-2',
26   - name: 'Menu1-2',
27   - },
28   - ],
29   - },
30   - {
31   - path: 'menu2',
32   - name: 'Menu2',
33   - },
34   - ],
35   - },
36   -};
37   -export default menu;
src/router/menus/modules/demo/page.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 20,
6   - menu: {
7   - name: t('routes.demo.page.page'),
8   - path: '/page-demo',
9   -
10   - children: [
11   - {
12   - path: 'form',
13   - name: t('routes.demo.page.form'),
14   -
15   - children: [
16   - {
17   - path: 'basic',
18   - name: t('routes.demo.page.formBasic'),
19   - },
20   - {
21   - path: 'step',
22   - name: t('routes.demo.page.formStep'),
23   - },
24   - {
25   - path: 'high',
26   - name: t('routes.demo.page.formHigh'),
27   - },
28   - ],
29   - },
30   - {
31   - path: 'desc',
32   - name: t('routes.demo.page.desc'),
33   -
34   - children: [
35   - {
36   - path: 'basic',
37   - name: t('routes.demo.page.descBasic'),
38   - },
39   - {
40   - path: 'high',
41   - name: t('routes.demo.page.descHigh'),
42   - },
43   - ],
44   - },
45   - {
46   - path: 'result',
47   - name: t('routes.demo.page.result'),
48   -
49   - children: [
50   - {
51   - path: 'success',
52   - name: t('routes.demo.page.resultSuccess'),
53   - },
54   - {
55   - path: 'fail',
56   - name: t('routes.demo.page.resultFail'),
57   - },
58   - ],
59   - },
60   - {
61   - path: 'exception',
62   - name: t('routes.demo.page.exception'),
63   - children: [
64   - {
65   - path: '403',
66   - name: t('403'),
67   - },
68   - {
69   - path: '404',
70   - name: t('404'),
71   - },
72   - {
73   - path: '500',
74   - name: t('500'),
75   - },
76   - {
77   - path: 'net-work-error',
78   - name: t('routes.demo.page.netWorkError'),
79   - },
80   - {
81   - path: 'not-data',
82   - name: t('routes.demo.page.notData'),
83   - },
84   - ],
85   - },
86   - {
87   - path: 'account',
88   - name: t('routes.demo.page.account'),
89   - children: [
90   - {
91   - path: 'center',
92   - name: t('routes.demo.page.accountCenter'),
93   - },
94   - {
95   - path: 'setting',
96   - name: t('routes.demo.page.accountSetting'),
97   - },
98   - ],
99   - },
100   - {
101   - path: 'list',
102   - name: t('routes.demo.page.list'),
103   - children: [
104   - {
105   - path: 'basic',
106   - name: t('routes.demo.page.listBasic'),
107   - },
108   - {
109   - path: 'card',
110   - name: t('routes.demo.page.listCard'),
111   - },
112   - {
113   - path: 'search',
114   - name: t('routes.demo.page.listSearch'),
115   - },
116   - ],
117   - },
118   - ],
119   - },
120   -};
121   -export default menu;
src/router/menus/modules/demo/permission.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 15,
6   - menu: {
7   - name: t('routes.demo.permission.permission'),
8   - path: '/permission',
9   - children: [
10   - {
11   - path: 'front',
12   - name: t('routes.demo.permission.front'),
13   - children: [
14   - {
15   - path: 'page',
16   - name: t('routes.demo.permission.frontPage'),
17   - },
18   - {
19   - path: 'btn',
20   - name: t('routes.demo.permission.frontBtn'),
21   - },
22   - {
23   - path: 'auth-pageA',
24   - name: t('routes.demo.permission.frontTestA'),
25   - },
26   - {
27   - path: 'auth-pageB',
28   - name: t('routes.demo.permission.frontTestB'),
29   - },
30   - ],
31   - },
32   - {
33   - path: 'back',
34   - name: t('routes.demo.permission.back'),
35   - children: [
36   - {
37   - path: 'page',
38   - name: t('routes.demo.permission.backPage'),
39   - },
40   - {
41   - path: 'btn',
42   - name: t('routes.demo.permission.backBtn'),
43   - },
44   - ],
45   - },
46   - ],
47   - },
48   -};
49   -export default menu;
src/router/menus/modules/demo/setup.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const setup: MenuModule = {
5   - orderNo: 90000,
6   - menu: {
7   - path: '/setup/index',
8   - name: t('routes.demo.setup.page'),
9   - tag: {
10   - content: 'new',
11   - },
12   - },
13   -};
14   -export default setup;
src/router/menus/modules/demo/system.ts deleted 100644 → 0
1   -import type { MenuModule } from '/@/router/types';
2   -import { t } from '/@/hooks/web/useI18n';
3   -
4   -const menu: MenuModule = {
5   - orderNo: 2000,
6   - menu: {
7   - name: t('routes.demo.system.moduleName'),
8   - path: '/system',
9   - children: [
10   - {
11   - path: 'account',
12   - name: t('routes.demo.system.account'),
13   - },
14   - {
15   - path: 'role',
16   - name: t('routes.demo.system.role'),
17   - },
18   - {
19   - path: 'menu',
20   - name: t('routes.demo.system.menu'),
21   - },
22   - {
23   - path: 'dept',
24   - name: t('routes.demo.system.dept'),
25   - },
26   -
27   - {
28   - path: 'changePassword',
29   - name: t('routes.demo.system.password'),
30   - },
31   - ],
32   - },
33   -};
34   -export default menu;
src/router/routes/basic.ts
... ... @@ -10,6 +10,7 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
10 10 meta: {
11 11 title: 'ErrorPage',
12 12 hideBreadcrumb: true,
  13 + hideMenu: true,
13 14 },
14 15 children: [
15 16 {
... ... @@ -31,6 +32,7 @@ export const REDIRECT_ROUTE: AppRouteRecordRaw = {
31 32 meta: {
32 33 title: REDIRECT_NAME,
33 34 hideBreadcrumb: true,
  35 + hideMenu: true,
34 36 },
35 37 children: [
36 38 {
... ...
src/router/routes/modules/about.ts
... ... @@ -9,8 +9,10 @@ const dashboard: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/about/index',
11 11 meta: {
  12 + hideChildrenInMenu: true,
12 13 icon: 'simple-icons:about-dot-me',
13 14 title: t('routes.dashboard.about'),
  15 + orderNo: 100000,
14 16 },
15 17 children: [
16 18 {
... ...
src/router/routes/modules/dashboard.ts
... ... @@ -9,6 +9,7 @@ const dashboard: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/dashboard/analysis',
11 11 meta: {
  12 + orderNo: 10,
12 13 icon: 'ion:grid-outline',
13 14 title: t('routes.dashboard.dashboard'),
14 15 },
... ...
src/router/routes/modules/demo/charts.ts
... ... @@ -9,6 +9,7 @@ const charts: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/charts/echarts/map',
11 11 meta: {
  12 + orderNo: 500,
12 13 icon: 'ion:bar-chart-outline',
13 14 title: t('routes.demo.charts.charts'),
14 15 },
... ...
src/router/routes/modules/demo/comp.ts
... ... @@ -9,6 +9,7 @@ const comp: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/comp/basic',
11 11 meta: {
  12 + orderNo: 30,
12 13 icon: 'ion:layers-outline',
13 14 title: t('routes.demo.comp.comp'),
14 15 },
... ...
src/router/routes/modules/demo/feat.ts
... ... @@ -9,6 +9,7 @@ const feat: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/feat/icon',
11 11 meta: {
  12 + orderNo: 19,
12 13 icon: 'ion:git-compare-outline',
13 14 title: t('routes.demo.feat.feat'),
14 15 },
... ...
src/router/routes/modules/demo/flow.ts
... ... @@ -9,6 +9,7 @@ const charts: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/flow/flowChart',
11 11 meta: {
  12 + orderNo: 5000,
12 13 icon: 'tabler:chart-dots',
13 14 title: t('routes.demo.flow.name'),
14 15 },
... ...
src/router/routes/modules/demo/iframe.ts
... ... @@ -10,6 +10,7 @@ const iframe: AppRouteModule = {
10 10 component: LAYOUT,
11 11 redirect: '/frame/doc',
12 12 meta: {
  13 + orderNo: 1000,
13 14 icon: 'ion:tv-outline',
14 15 title: t('routes.demo.iframe.frame'),
15 16 },
... ...
src/router/routes/modules/demo/level.ts
... ... @@ -9,6 +9,7 @@ const permission: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/level/menu1/menu1-1/menu1-1-1',
11 11 meta: {
  12 + orderNo: 2000,
12 13 icon: 'ion:menu-outline',
13 14 title: t('routes.demo.level.level'),
14 15 },
... ...
src/router/routes/modules/demo/page.ts
... ... @@ -12,6 +12,7 @@ const page: AppRouteModule = {
12 12 component: LAYOUT,
13 13 redirect: '/page-demo/form/basic',
14 14 meta: {
  15 + orderNo: 20,
15 16 icon: 'ion:aperture-outline',
16 17 title: t('routes.demo.page.page'),
17 18 },
... ...
src/router/routes/modules/demo/permission.ts
... ... @@ -10,6 +10,7 @@ const permission: AppRouteModule = {
10 10 component: LAYOUT,
11 11 redirect: '/permission/front/page',
12 12 meta: {
  13 + orderNo: 15,
13 14 icon: 'ion:key-outline',
14 15 title: t('routes.demo.permission.permission'),
15 16 },
... ...
src/router/routes/modules/demo/setup.ts
... ... @@ -9,6 +9,8 @@ const setup: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/setup/index',
11 11 meta: {
  12 + orderNo: 90000,
  13 + hideChildrenInMenu: true,
12 14 icon: 'simple-icons:about-dot-me',
13 15 title: t('routes.demo.setup.page'),
14 16 },
... ...
src/router/routes/modules/demo/system.ts
... ... @@ -9,6 +9,7 @@ const system: AppRouteModule = {
9 9 component: LAYOUT,
10 10 redirect: '/system/account',
11 11 meta: {
  12 + orderNo: 2000,
12 13 icon: 'ion:settings-outline',
13 14 title: t('routes.demo.system.moduleName'),
14 15 },
... ... @@ -26,6 +27,7 @@ const system: AppRouteModule = {
26 27 path: 'account_detail/:id',
27 28 name: 'AccountDetail',
28 29 meta: {
  30 + hideMenu: true,
29 31 title: t('routes.demo.system.account_detail'),
30 32 ignoreKeepAlive: true,
31 33 showMenu: false,
... ...
src/settings/projectSetting.ts
... ... @@ -24,7 +24,7 @@ const setting: ProjectConfig = {
24 24 settingButtonPosition: SettingButtonPositionEnum.AUTO,
25 25  
26 26 // Permission mode
27   - permissionMode: PermissionModeEnum.ROLE,
  27 + permissionMode: PermissionModeEnum.ROUTE_MAPPING,
28 28  
29 29 // Permission-related cache is stored in sessionStorage or localStorage
30 30 permissionCacheType: CacheTypeEnum.LOCAL,
... ...
src/store/modules/app.ts
... ... @@ -103,6 +103,6 @@ export const useAppStore = defineStore({
103 103 });
104 104  
105 105 // Need to be used outside the setup
106   -export function useAppStoreWidthOut() {
  106 +export function useAppStoreWithOut() {
107 107 return useAppStore(store);
108 108 }
... ...
src/store/modules/permission.ts
... ... @@ -4,7 +4,7 @@ import { defineStore } from &#39;pinia&#39;;
4 4 import { store } from '/@/store';
5 5 import { useI18n } from '/@/hooks/web/useI18n';
6 6 import { useUserStore } from './user';
7   -import { useAppStoreWidthOut } from './app';
  7 +import { useAppStoreWithOut } from './app';
8 8 import { toRaw } from 'vue';
9 9 import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
10 10 import { transformRouteToMenu } from '/@/router/helper/menuHelper';
... ... @@ -32,6 +32,7 @@ interface PermissionState {
32 32 lastBuildMenuTime: number;
33 33 // Backstage menu list
34 34 backMenuList: Menu[];
  35 + frontMenuList: Menu[];
35 36 }
36 37 export const usePermissionStore = defineStore({
37 38 id: 'app-permission',
... ... @@ -43,6 +44,8 @@ export const usePermissionStore = defineStore({
43 44 lastBuildMenuTime: 0,
44 45 // Backstage menu list
45 46 backMenuList: [],
  47 + // menu List
  48 + frontMenuList: [],
46 49 }),
47 50 getters: {
48 51 getPermCodeList(): string[] | number[] {
... ... @@ -51,6 +54,9 @@ export const usePermissionStore = defineStore({
51 54 getBackMenuList(): Menu[] {
52 55 return this.backMenuList;
53 56 },
  57 + getFrontMenuList(): Menu[] {
  58 + return this.frontMenuList;
  59 + },
54 60 getLastBuildMenuTime(): number {
55 61 return this.lastBuildMenuTime;
56 62 },
... ... @@ -68,6 +74,10 @@ export const usePermissionStore = defineStore({
68 74 list?.length > 0 && this.setLastBuildMenuTime();
69 75 },
70 76  
  77 + setFrontMenuList(list: Menu[]) {
  78 + this.frontMenuList = list;
  79 + },
  80 +
71 81 setLastBuildMenuTime() {
72 82 this.lastBuildMenuTime = new Date().getTime();
73 83 },
... ... @@ -88,52 +98,70 @@ export const usePermissionStore = defineStore({
88 98 async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
89 99 const { t } = useI18n();
90 100 const userStore = useUserStore();
91   - const appStore = useAppStoreWidthOut();
  101 + const appStore = useAppStoreWithOut();
92 102  
93 103 let routes: AppRouteRecordRaw[] = [];
94 104 const roleList = toRaw(userStore.getRoleList) || [];
95 105 const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
96   - // role permissions
97   - if (permissionMode === PermissionModeEnum.ROLE) {
98   - const routeFilter = (route: AppRouteRecordRaw) => {
99   - const { meta } = route;
100   - const { roles } = meta || {};
101   - if (!roles) return true;
102   - return roleList.some((role) => roles.includes(role));
103   - };
104   - routes = filter(asyncRoutes, routeFilter);
105   - routes = routes.filter(routeFilter);
106   - // Convert multi-level routing to level 2 routing
107   - routes = flatMultiLevelRoutes(routes);
  106 +
  107 + const routeFilter = (route: AppRouteRecordRaw) => {
  108 + const { meta } = route;
  109 + const { roles } = meta || {};
  110 + if (!roles) return true;
  111 + return roleList.some((role) => roles.includes(role));
  112 + };
  113 +
  114 + switch (permissionMode) {
  115 + case PermissionModeEnum.ROLE:
  116 + routes = filter(asyncRoutes, routeFilter);
  117 + routes = routes.filter(routeFilter);
  118 + // Convert multi-level routing to level 2 routing
  119 + routes = flatMultiLevelRoutes(routes);
  120 + break;
  121 +
  122 + case PermissionModeEnum.ROUTE_MAPPING:
  123 + routes = filter(asyncRoutes, routeFilter);
  124 + routes = routes.filter(routeFilter);
  125 + const menuList = transformRouteToMenu(asyncRoutes);
  126 + menuList.sort((a, b) => {
  127 + return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
  128 + });
  129 + this.setFrontMenuList(menuList);
  130 + // Convert multi-level routing to level 2 routing
  131 + routes = flatMultiLevelRoutes(routes);
  132 + break;
  133 +
108 134 // If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
109   - } else if (permissionMode === PermissionModeEnum.BACK) {
110   - const { createMessage } = useMessage();
111   -
112   - createMessage.loading({
113   - content: t('sys.app.menuLoading'),
114   - duration: 1,
115   - });
116   -
117   - // !Simulate to obtain permission codes from the background,
118   - // this function may only need to be executed once, and the actual project can be put at the right time by itself
119   - let routeList: AppRouteRecordRaw[] = [];
120   - try {
121   - this.changePermissionCode();
122   - routeList = (await getMenuList()) as AppRouteRecordRaw[];
123   - } catch (error) {
124   - console.error(error);
125   - }
126   -
127   - // Dynamically introduce components
128   - routeList = transformObjToRoute(routeList);
129   -
130   - // Background routing to menu structure
131   - const backMenuList = transformRouteToMenu(routeList);
132   - this.setBackMenuList(backMenuList);
133   -
134   - routeList = flatMultiLevelRoutes(routeList);
135   - routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
  135 + case PermissionModeEnum.BACK:
  136 + const { createMessage } = useMessage();
  137 +
  138 + createMessage.loading({
  139 + content: t('sys.app.menuLoading'),
  140 + duration: 1,
  141 + });
  142 +
  143 + // !Simulate to obtain permission codes from the background,
  144 + // this function may only need to be executed once, and the actual project can be put at the right time by itself
  145 + let routeList: AppRouteRecordRaw[] = [];
  146 + try {
  147 + this.changePermissionCode();
  148 + routeList = (await getMenuList()) as AppRouteRecordRaw[];
  149 + } catch (error) {
  150 + console.error(error);
  151 + }
  152 +
  153 + // Dynamically introduce components
  154 + routeList = transformObjToRoute(routeList);
  155 +
  156 + // Background routing to menu structure
  157 + const backMenuList = transformRouteToMenu(routeList);
  158 + this.setBackMenuList(backMenuList);
  159 +
  160 + routeList = flatMultiLevelRoutes(routeList);
  161 + routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
  162 + break;
136 163 }
  164 +
137 165 routes.push(ERROR_LOG_ROUTE);
138 166 return routes;
139 167 },
... ... @@ -141,6 +169,6 @@ export const usePermissionStore = defineStore({
141 169 });
142 170  
143 171 // Need to be used outside the setup
144   -export function usePermissionStoreWidthOut() {
  172 +export function usePermissionStoreWithOut() {
145 173 return usePermissionStore(store);
146 174 }
... ...
src/store/modules/user.ts
... ... @@ -128,6 +128,6 @@ export const useUserStore = defineStore({
128 128 });
129 129  
130 130 // Need to be used outside the setup
131   -export function useUserStoreWidthOut() {
  131 +export function useUserStoreWithOut() {
132 132 return useUserStore(store);
133 133 }
... ...
src/utils/http/axios/checkStatus.ts
... ... @@ -3,7 +3,7 @@ import { useMessage } from &#39;/@/hooks/web/useMessage&#39;;
3 3 import { useI18n } from '/@/hooks/web/useI18n';
4 4 // import router from '/@/router';
5 5 // import { PageEnum } from '/@/enums/pageEnum';
6   -import { useUserStoreWidthOut } from '/@/store/modules/user';
  6 +import { useUserStoreWithOut } from '/@/store/modules/user';
7 7 import projectSetting from '/@/settings/projectSetting';
8 8 import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum';
9 9  
... ... @@ -17,7 +17,7 @@ export function checkStatus(
17 17 errorMessageMode: ErrorMessageMode = 'message'
18 18 ): void {
19 19 const { t } = useI18n();
20   - const userStore = useUserStoreWidthOut();
  20 + const userStore = useUserStoreWithOut();
21 21 let errMessage = '';
22 22  
23 23 switch (status) {
... ...
types/vue-router.d.ts
... ... @@ -2,6 +2,7 @@ export {};
2 2  
3 3 declare module 'vue-router' {
4 4 interface RouteMeta extends Record<string | number | symbol, unknown> {
  5 + orderNo?: number;
5 6 // title
6 7 title: string;
7 8 // Whether to ignore permissions
... ...