vue-vben-admin/src/layouts/default/menu/LayoutMenu.tsx

246 lines
6.8 KiB
TypeScript
Raw Normal View History

2020-09-28 20:19:10 +08:00
import type { PropType } from 'vue';
import type { Menu } from '/@/router/types';
import { computed, defineComponent, unref, ref, onMounted, watch } from 'vue';
import { BasicMenu } from '/@/components/Menu/index';
2020-11-10 23:50:47 +08:00
import Logo from '/@/layouts/logo/index.vue';
2020-09-28 20:19:10 +08:00
import { MenuModeEnum, MenuSplitTyeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
// store
import { appStore } from '/@/store/modules/app';
import { menuStore } from '/@/store/modules/menu';
import {
getMenus,
getFlatMenus,
getShallowMenus,
getChildrenMenus,
getFlatChildrenMenus,
getCurrentParentPath,
} from '/@/router/menus/index';
import { useRouter } from 'vue-router';
import { useThrottle } from '/@/hooks/core/useThrottle';
import { permissionStore } from '/@/store/modules/permission';
2020-11-10 23:50:47 +08:00
import './index.less';
2020-09-28 20:19:10 +08:00
export default defineComponent({
name: 'DefaultLayoutMenu',
props: {
theme: {
type: String as PropType<string>,
default: '',
},
splitType: {
type: Number as PropType<MenuSplitTyeEnum>,
default: MenuSplitTyeEnum.NONE,
},
parentMenuPath: {
type: String as PropType<string>,
default: '',
},
showSearch: {
type: Boolean as PropType<boolean>,
default: true,
},
2020-10-31 19:51:24 +08:00
isTop: {
type: Boolean as PropType<boolean>,
default: false,
},
2020-09-28 20:19:10 +08:00
menuMode: {
type: [String] as PropType<MenuModeEnum | null>,
default: '',
},
},
setup(props) {
2020-11-10 22:45:39 +08:00
// Menu array
2020-09-28 20:19:10 +08:00
const menusRef = ref<Menu[]>([]);
2020-11-10 22:45:39 +08:00
// flat menu array
2020-09-28 20:19:10 +08:00
const flatMenusRef = ref<Menu[]>([]);
const { currentRoute, push } = useRouter();
2020-09-28 20:19:10 +08:00
2020-11-10 22:45:39 +08:00
// get app config
2020-09-28 20:19:10 +08:00
const getProjectConfigRef = computed(() => {
return appStore.getProjectConfig;
});
2020-11-10 22:45:39 +08:00
// get is Horizontal
2020-09-28 20:19:10 +08:00
const getIsHorizontalRef = computed(() => {
return unref(getProjectConfigRef).menuSetting.mode === MenuModeEnum.HORIZONTAL;
});
const [throttleHandleSplitLeftMenu] = useThrottle(handleSplitLeftMenu, 50);
2020-11-10 22:45:39 +08:00
// Route change split menu
2020-09-28 20:19:10 +08:00
watch(
[() => unref(currentRoute).path, () => props.splitType],
async ([path, splitType]: [string, MenuSplitTyeEnum]) => {
if (splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
const parentPath = await getCurrentParentPath(path);
parentPath && throttleHandleSplitLeftMenu(parentPath);
},
{
immediate: true,
}
);
2020-11-06 22:41:00 +08:00
2020-11-10 22:45:39 +08:00
// Menu changes
2020-09-28 20:19:10 +08:00
watch(
2020-11-10 22:45:39 +08:00
[() => permissionStore.getLastBuildMenuTimeState, () => permissionStore.getBackMenuListState],
2020-09-28 20:19:10 +08:00
() => {
genMenus();
}
);
2020-11-10 22:45:39 +08:00
// split Menu changes
2020-09-28 20:19:10 +08:00
watch([() => appStore.getProjectConfig.menuSetting.split], () => {
if (props.splitType !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontalRef)) return;
genMenus();
});
2020-11-10 22:45:39 +08:00
// Handle left menu split
2020-09-28 20:19:10 +08:00
async function handleSplitLeftMenu(parentPath: string) {
const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
if (!isSplitMenu) return;
const { splitType } = props;
2020-11-10 22:45:39 +08:00
// spilt mode left
2020-09-28 20:19:10 +08:00
if (splitType === MenuSplitTyeEnum.LEFT) {
const children = await getChildrenMenus(parentPath);
2020-11-02 23:04:25 +08:00
if (!children) {
appStore.commitProjectConfigState({
menuSetting: {
2020-11-06 22:41:00 +08:00
hidden: false,
2020-11-02 23:04:25 +08:00
},
});
flatMenusRef.value = [];
menusRef.value = [];
return;
}
2020-09-28 20:19:10 +08:00
const flatChildren = await getFlatChildrenMenus(children);
2020-11-02 23:04:25 +08:00
appStore.commitProjectConfigState({
menuSetting: {
2020-11-06 22:41:00 +08:00
hidden: true,
2020-11-02 23:04:25 +08:00
},
});
2020-09-28 20:19:10 +08:00
flatMenusRef.value = flatChildren;
menusRef.value = children;
}
}
2020-11-10 22:45:39 +08:00
// get menus
2020-09-28 20:19:10 +08:00
async function genMenus() {
const isSplitMenu = unref(getProjectConfigRef).menuSetting.split;
2020-11-10 22:45:39 +08:00
// normal mode
2020-09-28 20:19:10 +08:00
const { splitType } = props;
if (splitType === MenuSplitTyeEnum.NONE || !isSplitMenu) {
flatMenusRef.value = await getFlatMenus();
menusRef.value = await getMenus();
return;
}
2020-11-10 22:45:39 +08:00
// split-top
2020-09-28 20:19:10 +08:00
if (splitType === MenuSplitTyeEnum.TOP) {
const parentPath = await getCurrentParentPath(unref(currentRoute).path);
menuStore.commitCurrentTopSplitMenuPathState(parentPath);
const shallowMenus = await getShallowMenus();
flatMenusRef.value = shallowMenus;
menusRef.value = shallowMenus;
return;
}
}
function handleMenuClick(menu: Menu) {
const { path } = menu;
if (path) {
const { splitType } = props;
2020-11-10 22:45:39 +08:00
// split mode top
2020-09-28 20:19:10 +08:00
if (splitType === MenuSplitTyeEnum.TOP) {
menuStore.commitCurrentTopSplitMenuPathState(path);
}
push(path);
2020-09-28 20:19:10 +08:00
}
}
async function beforeMenuClickFn(menu: Menu) {
const { meta: { externalLink } = {} } = menu;
if (externalLink) {
window.open(externalLink, '_blank');
return false;
}
return true;
}
function handleClickSearchInput() {
if (menuStore.getCollapsedState) {
menuStore.commitCollapsedState(false);
}
}
const showSearchRef = computed(() => {
const { showSearch, type, mode } = unref(getProjectConfigRef).menuSetting;
return (
showSearch &&
props.showSearch &&
!(type === MenuTypeEnum.MIX && mode === MenuModeEnum.HORIZONTAL)
);
});
2020-11-06 22:41:00 +08:00
onMounted(() => {
genMenus();
});
2020-09-28 20:19:10 +08:00
return () => {
const {
showLogo,
2020-11-03 21:00:14 +08:00
menuSetting: {
type: menuType,
mode,
theme,
collapsed,
collapsedShowTitle,
collapsedShowSearch,
2020-11-10 22:45:39 +08:00
accordion,
2020-11-03 21:00:14 +08:00
},
2020-09-28 20:19:10 +08:00
} = unref(getProjectConfigRef);
const isSidebarType = menuType === MenuTypeEnum.SIDEBAR;
const isShowLogo = showLogo && isSidebarType;
const themeData = props.theme || theme;
return (
<BasicMenu
beforeClickFn={beforeMenuClickFn}
onMenuClick={handleMenuClick}
type={menuType}
mode={props.menuMode || mode}
class="layout-menu"
2020-10-19 22:47:44 +08:00
collapsedShowTitle={collapsedShowTitle}
2020-09-28 20:19:10 +08:00
theme={themeData}
showLogo={isShowLogo}
2020-11-03 21:00:14 +08:00
search={unref(showSearchRef) && (collapsedShowSearch ? true : !collapsed)}
2020-09-28 20:19:10 +08:00
items={unref(menusRef)}
flatItems={unref(flatMenusRef)}
onClickSearchInput={handleClickSearchInput}
appendClass={props.splitType === MenuSplitTyeEnum.TOP}
2020-10-31 19:51:24 +08:00
isTop={props.isTop}
2020-11-10 22:45:39 +08:00
accordion={accordion}
2020-09-28 20:19:10 +08:00
>
{{
header: () =>
isShowLogo && (
2020-11-06 22:41:00 +08:00
<Logo
showTitle={!collapsed}
class={[`layout-menu__logo`, themeData]}
theme={themeData}
/>
2020-09-28 20:19:10 +08:00
),
}}
</BasicMenu>
);
};
},
});