提交 913c22c8 编写于 作者: V vben

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

上级 327d71b8
## Wip
### ⚡ Performance Improvements
- **Icon** 移除 Icon 组件全局注册,防止特定情况下热更新问题
### ✨ Features
- **Menu** 新增 `permissionMode=PermissionModeEnum.ROUTE_MAPPING`模式
- 项目默认改为该模式,删除原有菜单文件
- 如果之前已经写好了菜单,可以更改为`PermissionModeEnum.ROLE`模式即可
## 2.5.1(2021-06-26)
### ⚡ Performance Improvements
......
......@@ -33,6 +33,8 @@ export enum PermissionModeEnum {
ROLE = 'ROLE',
// black
BACK = 'BACK',
// route mapping
ROUTE_MAPPING = 'ROUTE_MAPPING',
}
// Route switching animation
......
......@@ -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!'
);
}
......
......@@ -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();
......
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) {
......
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) {
......
......@@ -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) {
......
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[]) {
......
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
......@@ -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: [
{
......
......@@ -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: [
{
......
......@@ -9,6 +9,7 @@ const dashboard: AppRouteModule = {
component: LAYOUT,
redirect: '/dashboard/analysis',
meta: {
orderNo: 10,
icon: 'ion:grid-outline',
title: t('routes.dashboard.dashboard'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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'),
},
......
......@@ -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,
......
......@@ -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,
......
......@@ -103,6 +103,6 @@ export const useAppStore = defineStore({
});
// Need to be used outside the setup
export function useAppStoreWidthOut() {
export function useAppStoreWithOut() {
return useAppStore(store);
}
......@@ -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);
}
......@@ -128,6 +128,6 @@ export const useUserStore = defineStore({
});
// Need to be used outside the setup
export function useUserStoreWidthOut() {
export function useUserStoreWithOut() {
return useUserStore(store);
}
......@@ -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) {
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册