You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
4.7 KiB
187 lines
4.7 KiB
<script lang="tsx"> |
|
import type { CSSProperties } from 'vue' |
|
|
|
import { computed, defineComponent, toRef, unref } from 'vue' |
|
import { useSplitMenu } from './useLayoutMenu' |
|
import { BasicMenu } from '@/components/Menu' |
|
import { SimpleMenu } from '@/components/SimpleMenu' |
|
import { AppLogo } from '@/components/Application' |
|
|
|
import { MenuModeEnum, MenuSplitTyeEnum } from '@/enums/menuEnum' |
|
|
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting' |
|
import { ScrollContainer } from '@/components/Container' |
|
|
|
import { useGo } from '@/hooks/web/usePage' |
|
import { openWindow } from '@/utils' |
|
import { propTypes } from '@/utils/propTypes' |
|
import { isHttpUrl } from '@/utils/is' |
|
import { useRootSetting } from '@/hooks/setting/useRootSetting' |
|
import { useAppInject } from '@/hooks/web/useAppInject' |
|
import { useDesign } from '@/hooks/web/useDesign' |
|
|
|
export default defineComponent({ |
|
name: 'LayoutMenu', |
|
props: { |
|
theme: propTypes.oneOf(['light', 'dark']), |
|
|
|
splitType: { |
|
type: Number as PropType<MenuSplitTyeEnum>, |
|
default: MenuSplitTyeEnum.NONE, |
|
}, |
|
|
|
isHorizontal: propTypes.bool, |
|
// menu Mode |
|
menuMode: { |
|
type: [String] as PropType<Nullable<MenuModeEnum>>, |
|
default: '', |
|
}, |
|
}, |
|
setup(props) { |
|
const go = useGo() |
|
|
|
const { |
|
getMenuMode, |
|
getMenuType, |
|
getMenuTheme, |
|
getCollapsed, |
|
getCollapsedShowTitle, |
|
getAccordion, |
|
getIsHorizontal, |
|
getIsSidebarType, |
|
getSplit, |
|
} = useMenuSetting() |
|
const { getShowLogo } = useRootSetting() |
|
|
|
const { prefixCls } = useDesign('layout-menu') |
|
|
|
const { menusRef } = useSplitMenu(toRef(props, 'splitType')) |
|
|
|
const { getIsMobile } = useAppInject() |
|
|
|
const getComputedMenuMode = computed(() => (unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode))) |
|
|
|
const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme)) |
|
|
|
const getIsShowLogo = computed(() => unref(getShowLogo) && unref(getIsSidebarType)) |
|
|
|
const getUseScroll = computed(() => { |
|
return ( |
|
!unref(getIsHorizontal) |
|
&& (unref(getIsSidebarType) || props.splitType === MenuSplitTyeEnum.LEFT || props.splitType === MenuSplitTyeEnum.NONE) |
|
) |
|
}) |
|
|
|
const getWrapperStyle = computed((): CSSProperties => { |
|
return { |
|
height: `calc(100% - ${unref(getIsShowLogo) ? '48px' : '0px'})`, |
|
} |
|
}) |
|
|
|
const getLogoClass = computed(() => { |
|
return [ |
|
`${prefixCls}-logo`, |
|
unref(getComputedMenuTheme), |
|
{ |
|
[`${prefixCls}--mobile`]: unref(getIsMobile), |
|
}, |
|
] |
|
}) |
|
|
|
const getCommonProps = computed(() => { |
|
const menus = unref(menusRef) |
|
return { |
|
menus, |
|
beforeClickFn: beforeMenuClickFn, |
|
items: menus, |
|
theme: unref(getComputedMenuTheme), |
|
accordion: unref(getAccordion), |
|
collapse: unref(getCollapsed), |
|
collapsedShowTitle: unref(getCollapsedShowTitle), |
|
onMenuClick: handleMenuClick, |
|
} |
|
}) |
|
/** |
|
* click menu |
|
* @param path |
|
*/ |
|
|
|
function handleMenuClick(path: string) { |
|
go(path) |
|
} |
|
|
|
/** |
|
* before click menu |
|
* @param path |
|
*/ |
|
async function beforeMenuClickFn(path: string) { |
|
if (!isHttpUrl(path)) |
|
return true |
|
|
|
openWindow(path) |
|
return false |
|
} |
|
|
|
function renderHeader() { |
|
if (!unref(getIsShowLogo) && !unref(getIsMobile)) |
|
return null |
|
|
|
return <AppLogo showTitle={!unref(getCollapsed)} class={unref(getLogoClass)} theme={unref(getComputedMenuTheme)} /> |
|
} |
|
|
|
function renderMenu() { |
|
const { menus, ...menuProps } = unref(getCommonProps) |
|
if (!menus || !menus.length) |
|
return null |
|
return !props.isHorizontal |
|
? ( |
|
<SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} /> |
|
) |
|
: ( |
|
<BasicMenu |
|
{...(menuProps as any)} |
|
isHorizontal={props.isHorizontal} |
|
type={unref(getMenuType)} |
|
showLogo={unref(getIsShowLogo)} |
|
mode={unref(getComputedMenuMode as any)} |
|
items={menus} |
|
/> |
|
) |
|
} |
|
|
|
return () => { |
|
return ( |
|
<> |
|
{renderHeader()} |
|
{unref(getUseScroll) ? <ScrollContainer style={unref(getWrapperStyle)}>{() => renderMenu()}</ScrollContainer> : renderMenu()} |
|
</> |
|
) |
|
} |
|
}, |
|
}) |
|
</script> |
|
|
|
<style lang="less"> |
|
@prefix-cls: ~'@{namespace}-layout-menu'; |
|
@logo-prefix-cls: ~'@{namespace}-app-logo'; |
|
|
|
.@{prefix-cls} { |
|
&-logo { |
|
height: @header-height; |
|
padding: 10px 4px 10px 10px; |
|
|
|
img { |
|
width: @logo-width; |
|
height: @logo-width; |
|
} |
|
} |
|
|
|
&--mobile { |
|
.@{logo-prefix-cls} { |
|
&__title { |
|
opacity: 1; |
|
} |
|
} |
|
} |
|
} |
|
</style>
|
|
|