mirror of
https://github.com/vbenjs/gf-vben-admin.git
synced 2025-01-23 11:50:20 +08:00
feat(menu): the route is automatically mapped to the menu
This commit is contained in:
parent
327d71b8fb
commit
913c22c84f
@ -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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
if (isRoleMode()) {
|
||||
const routes = router.getRoutes();
|
||||
|
||||
return !isBackMode() ? filter(menus, basicFilter(routes)) : menus;
|
||||
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[];
|
||||
if (!parent || !parent.children || !!parent?.meta?.hideChildrenInMenu) {
|
||||
return [] as Menu[];
|
||||
}
|
||||
if (isRoleMode()) {
|
||||
const routes = router.getRoutes();
|
||||
|
||||
return !isBackMode() ? filter(parent.children, basicFilter(routes)) : parent.children;
|
||||
return filter(parent.children, basicFilter(routes));
|
||||
}
|
||||
return parent.children;
|
||||
}
|
||||
|
||||
function basicFilter(routes: RouteRecordNormalized[]) {
|
||||
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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,25 +98,41 @@ 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));
|
||||
};
|
||||
|
||||
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) {
|
||||
case PermissionModeEnum.BACK:
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
createMessage.loading({
|
||||
@ -133,7 +159,9 @@ export const usePermissionStore = defineStore({
|
||||
|
||||
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) {
|
||||
|
1
types/vue-router.d.ts
vendored
1
types/vue-router.d.ts
vendored
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user