Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(param-menu): feature: menu with params #845

Merged
merged 1 commit into from
Jul 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/locales/lang/en/routes/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export default {
tab: 'Tab with parameters',
tab1: 'Tab with parameter 1',
tab2: 'Tab with parameter 2',
menu: 'Menu with parameters',
menu1: 'Menu with parameters 1',
menu2: 'Menu with parameters 2',

ws: 'Websocket test',

Expand Down
3 changes: 3 additions & 0 deletions src/locales/lang/zh_CN/routes/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ export default {
tab: 'Tab带参',
tab1: 'Tab带参1',
tab2: 'Tab带参2',
menu: 'Menu带参',
menu1: 'Menu带参1',
menu2: 'Menu带参2',
ws: 'websocket测试',
breadcrumb: '面包屑导航',
breadcrumbFlat: '平级模式',
Expand Down
2 changes: 2 additions & 0 deletions src/router/guard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createPermissionGuard } from './permissionGuard';
import { createStateGuard } from './stateGuard';
import nProgress from 'nprogress';
import projectSetting from '/@/settings/projectSetting';
import { createParamMenuGuard } from './paramMenuGuard';

// Don't change the order of creation
export function setupRouterGuard(router: Router) {
Expand All @@ -21,6 +22,7 @@ export function setupRouterGuard(router: Router) {
createMessageGuard(router);
createProgressGuard(router);
createPermissionGuard(router);
createParamMenuGuard(router); // must after createPermissionGuard (menu has been built.)
createStateGuard(router);
}

Expand Down
47 changes: 47 additions & 0 deletions src/router/guard/paramMenuGuard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import type { Router } from 'vue-router';
import { configureDynamicParamsMenu } from '../helper/menuHelper';
import { Menu } from '../types';
import { PermissionModeEnum } from '/@/enums/appEnum';
import { useAppStoreWithOut } from '/@/store/modules/app';

import { usePermissionStoreWithOut } from '/@/store/modules/permission';

export function createParamMenuGuard(router: Router) {
const permissionStore = usePermissionStoreWithOut();
router.beforeEach(async (to, _, next) => {
// filter no name route
if (!to.name) {
next();
return;
}

// menu has been built.
if (!permissionStore.getIsDynamicAddedRoute) {
next();
return;
}

let menus: Menu[] = [];
if (isBackMode()) {
menus = permissionStore.getBackMenuList;
} else if (isRouteMappingMode()) {
menus = permissionStore.getFrontMenuList;
}
menus.forEach((item) => configureDynamicParamsMenu(item, to.params));

next();
});
}

const getPermissionMode = () => {
const appStore = useAppStoreWithOut();
return appStore.getProjectConfig.permissionMode;
};

const isBackMode = () => {
return getPermissionMode() === PermissionModeEnum.BACK;
};

const isRouteMappingMode = () => {
return getPermissionMode() === PermissionModeEnum.ROUTE_MAPPING;
};
24 changes: 24 additions & 0 deletions src/router/helper/menuHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
import { findPath, treeMap } from '/@/utils/helper/treeHelper';
import { cloneDeep } from 'lodash-es';
import { isUrl } from '/@/utils/is';
import { RouteParams } from 'vue-router';
import { toRaw } from 'vue';

export function getAllParentPath<T = Recordable>(treeData: T[], path: string) {
const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
Expand Down Expand Up @@ -66,3 +68,25 @@ export function transformRouteToMenu(routeModList: AppRouteModule[], routerMappi
joinParentPath(list);
return cloneDeep(list);
}

/**
* config menu with given params
*/
const menuParamRegex = /(?<=:)([\s\S]+?)((?=\/)|$)/g;
export function configureDynamicParamsMenu(menu: Menu, params: RouteParams) {
const { path, paramPath } = toRaw(menu);
let realPath = paramPath ? paramPath : path;
const matchArr = realPath.match(menuParamRegex);
matchArr?.forEach((it) => {
if (params[it]) {
realPath = realPath.replace(`:${it}`, params[it] as string);
}
});
// save original param path.
if (!paramPath && matchArr && matchArr.length > 0) {
menu.paramPath = path;
}
menu.path = realPath;
// children
menu.children?.forEach((item) => configureDynamicParamsMenu(item, params));
}
29 changes: 29 additions & 0 deletions src/router/routes/modules/demo/feat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,35 @@ const feat: AppRouteModule = {
carryParam: true,
},
},
{
path: 'testParam/:id',
name: 'TestParam',
component: getParentLayout('TestParam'),
meta: {
title: t('routes.demo.feat.menu'),
ignoreKeepAlive: true,
},
children: [
{
path: 'sub1',
name: 'TestParam_1',
component: () => import('/@/views/demo/feat/menu-params/index.vue'),
meta: {
title: t('routes.demo.feat.menu1'),
ignoreKeepAlive: true,
},
},
{
path: 'sub2',
name: 'TestParam_2',
component: () => import('/@/views/demo/feat/menu-params/index.vue'),
meta: {
title: t('routes.demo.feat.menu2'),
ignoreKeepAlive: true,
},
},
],
},
],
};

Expand Down
3 changes: 3 additions & 0 deletions src/router/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export interface Menu {

path: string;

// path contains param, auto assignment.
paramPath?: string;

disabled?: boolean;

children?: Menu[];
Expand Down
42 changes: 42 additions & 0 deletions src/views/demo/feat/menu-params/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<template>
<PageWrapper title="带参数菜单(路由)" content="支持多级参数">
当前参数:{{ params }}
<br />
输入参数切换路由:
<Input v-model:value="value" placeholder="建议为url标准字符,输入后点击切换" />
<a-button type="primary" @click="handleClickGo">切换路由</a-button>
<br />
切换路由后
<ul>
<li>可刷新页面测试路由参数情况是否正常。</li>
<li>可于左侧菜单中展开子菜单,点击测试参数是否携带正常。</li>
</ul>
</PageWrapper>
</template>
<script lang="ts">
import { Input } from 'ant-design-vue';
import { computed, defineComponent, ref, unref } from 'vue';
import { useRouter } from 'vue-router';
import { PageWrapper } from '/@/components/Page';

export default defineComponent({
name: 'TestMenu',
components: { PageWrapper, Input },
setup() {
const { currentRoute, replace } = useRouter();
const value = ref<string>('');

const handleClickGo = () => {
const { name } = unref(currentRoute);
replace({ name: name!, params: { id: unref(value) } });
};
return {
value,
handleClickGo,
params: computed(() => {
return unref(currentRoute).params;
}),
};
},
});
</script>