feat(other): The menu supports jumping to external links and fixing some known problems

This commit is contained in:
vben
2024-05-21 21:45:48 +08:00
parent 399334ac57
commit c31d21be50
43 changed files with 505 additions and 243 deletions

View File

@@ -1,8 +1,11 @@
<script lang="ts" setup>
import { VbenAdminLayout } from '@vben-core/layout-ui';
import { VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
import { mapTree } from '@vben-core/toolkit';
import { MenuRecordRaw } from '@vben-core/typings';
import { PreferenceWidget } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { preference, updatePreference, usePreference } from '@vben/preference';
import { computed } from 'vue';
@@ -80,6 +83,15 @@ const {
sideMenus,
sideVisible,
} = useMixedMenu();
function wrapperMenus(menus: MenuRecordRaw[]) {
return mapTree(menus, (item) => {
return {
...item,
name: $t(item.name),
};
});
}
</script>
<template>
@@ -154,7 +166,7 @@ const {
:rounded="isMenuRounded"
mode="horizontal"
:theme="headerMenuTheme"
:menus="headerMenus"
:menus="wrapperMenus(headerMenus)"
:default-active="headerActive"
@select="handleMenuSelect"
/>
@@ -175,7 +187,7 @@ const {
:collapse-show-title="preference.sideCollapseShowTitle"
:collapse="preference.sideCollapse"
:theme="theme"
:menus="sideMenus"
:menus="wrapperMenus(sideMenus)"
:default-active="sideActive"
@select="handleMenuSelect"
/>
@@ -195,7 +207,7 @@ const {
<template #side-extra>
<LayoutExtraMenu
:rounded="isMenuRounded"
:menus="extraMenus"
:menus="wrapperMenus(extraMenus)"
:collapse="preference.sideExtraCollapse"
:theme="theme"
/>

View File

@@ -3,7 +3,9 @@ import type { MenuRecordRaw } from '@vben-core/typings';
import { Menu, MenuProps } from '@vben-core/menu-ui';
import { useRoute, useRouter } from 'vue-router';
import { useRoute } from 'vue-router';
import { useNavigation } from './use-navigation';
interface Props extends MenuProps {
collspae?: boolean;
@@ -13,10 +15,10 @@ interface Props extends MenuProps {
defineProps<Props>();
const route = useRoute();
const router = useRouter();
const { navigation } = useNavigation();
function handleSelect(key: string) {
router.push(key);
async function handleSelect(key: string) {
await navigation(key);
}
</script>

View File

@@ -3,17 +3,18 @@ import type { MenuRecordRaw } from '@vben-core/typings';
import { preference } from '@vben/preference';
import { useAccessStore } from '@vben/stores';
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useRoute } from 'vue-router';
import { findRootMenuByPath } from './helper';
import { useNavigation } from './use-navigation';
function useExtraMenu() {
const accessStore = useAccessStore();
const { navigation } = useNavigation();
const menus = computed(() => accessStore.getAccessMenus);
const route = useRoute();
const router = useRouter();
const extraMenus = ref<MenuRecordRaw[]>([]);
const extraVisible = ref<boolean>(false);
const extraActiveMenu = ref('');
@@ -22,14 +23,14 @@ function useExtraMenu() {
* 选择混合菜单事件
* @param menu
*/
const handleMixedMenuSelect = (menu: MenuRecordRaw) => {
const handleMixedMenuSelect = async (menu: MenuRecordRaw) => {
extraMenus.value = menu?.children ?? [];
extraActiveMenu.value = menu.parents?.[0] ?? menu.path;
const hasChildren = extraMenus.value.length > 0;
extraVisible.value = hasChildren;
if (!hasChildren) {
router.push(menu.path);
await navigation(menu.path);
}
};

View File

@@ -3,15 +3,15 @@ import type { MenuRecordRaw } from '@vben-core/typings';
import { preference, usePreference } from '@vben/preference';
import { useAccessStore } from '@vben/stores';
import { computed, onBeforeMount, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useRoute } from 'vue-router';
import { findRootMenuByPath } from './helper';
import { useNavigation } from './use-navigation';
function useMixedMenu() {
const accessStore = useAccessStore();
const { navigation } = useNavigation();
const route = useRoute();
const router = useRouter();
const splitSideMenus = ref<MenuRecordRaw[]>([]);
const rootMenuPath = ref<string>('');
@@ -75,7 +75,7 @@ function useMixedMenu() {
*/
const handleMenuSelect = (key: string, mode?: string) => {
if (!isMixedNav.value || mode === 'vertical') {
router.push(key);
navigation(key);
return;
}
@@ -83,7 +83,7 @@ function useMixedMenu() {
rootMenuPath.value = rootMenu?.path ?? '';
splitSideMenus.value = rootMenu?.children ?? [];
if (splitSideMenus.value.length === 0) {
router.push(key);
navigation(key);
}
};

View File

@@ -0,0 +1,19 @@
import { isHttpUrl, openWindow } from '@vben-core/toolkit';
import { useRouter } from 'vue-router';
function useNavigation() {
const router = useRouter();
const navigation = async (path: string) => {
if (isHttpUrl(path)) {
openWindow(path, { target: '_blank' });
} else {
await router.push(path);
}
};
return { navigation };
}
export { useNavigation };

View File

@@ -12,7 +12,12 @@ import {
MdiPinOff,
} from '@vben-core/iconify';
import { filterTree } from '@vben-core/toolkit';
import type {
RouteLocationNormalized,
RouteRecordNormalized,
} from 'vue-router';
import { $t } from '@vben/locales';
import { storeToRefs, useAccessStore, useTabsStore } from '@vben/stores';
import { computed, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
@@ -39,6 +44,9 @@ function useTabs() {
const affixTabs = filterTree(router.getRoutes(), (route) => {
return !!route.meta?.affixTab;
});
affixTabs.forEach((tab) => {
Object.assign(tab, wrapperTabLocale(tab));
});
tabsStore.setAffixTabs(affixTabs);
};
@@ -52,6 +60,18 @@ function useTabs() {
await tabsStore.closeTabByKey(key, router);
};
function wrapperTabLocale(
tab: RouteLocationNormalized | RouteRecordNormalized,
) {
return {
...tab,
meta: {
...tab.meta,
title: $t(tab.meta.title as string),
},
};
}
watch(
() => accessMenus.value,
() => {
@@ -63,7 +83,7 @@ function useTabs() {
watch(
() => route.path,
() => {
tabsStore.addTab(route);
tabsStore.addTab(wrapperTabLocale(route) as RouteLocationNormalized);
},
{ immediate: true },
);

View File

@@ -4,6 +4,7 @@ import type { IBreadcrumb } from '@vben-core/shadcn-ui';
import { VbenBackgroundBreadcrumb, VbenBreadcrumb } from '@vben-core/shadcn-ui';
import { BreadcrumbStyle } from '@vben-core/typings';
import { $t } from '@vben/locales';
import { computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
@@ -43,7 +44,7 @@ const breadcrumbs = computed((): IBreadcrumb[] => {
resultBreadcrumb.push({
icon: icon as string,
path: path || route.path,
title: (title || name) as string,
title: $t((title || name) as string),
// items: children.map((child) => {
// return {
// icon: child?.meta?.icon as string,