wip: use kingdee style header
This commit is contained in:
parent
0ed5dd9d06
commit
11908d5812
@ -1,3 +1,4 @@
|
|||||||
import BasicMenu from './src/BasicMenu.vue'
|
import BasicMenu from './src/BasicMenu.vue'
|
||||||
|
import KingdeeBaseMenu from './src/KingdeeBasicMenu.vue'
|
||||||
|
|
||||||
export { BasicMenu }
|
export { BasicMenu, KingdeeBaseMenu }
|
||||||
|
147
src/components/Menu/src/KingdeeBasicMenu.vue
Normal file
147
src/components/Menu/src/KingdeeBasicMenu.vue
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, reactive, ref, toRefs, unref, watch } from 'vue'
|
||||||
|
import type { MenuProps } from 'ant-design-vue'
|
||||||
|
import { Menu } from 'ant-design-vue'
|
||||||
|
import type { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import type { MenuState } from './types'
|
||||||
|
import KingdeeBasicSubMenuItem from './components/KingdeeBasicSubMenuItem.vue'
|
||||||
|
import { useOpenKeys } from './useOpenKeys'
|
||||||
|
import { basicProps } from './props'
|
||||||
|
import { MenuModeEnum, MenuTypeEnum } from '@/enums/menuEnum'
|
||||||
|
import { isFunction } from '@/utils/is'
|
||||||
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting'
|
||||||
|
import { REDIRECT_NAME } from '@/router/constant'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { getCurrentParentPath } from '@/router/menus'
|
||||||
|
import { listenerRouteChange } from '@/logics/mitt/routeChange'
|
||||||
|
import { getAllParentPath } from '@/router/helper/menuHelper'
|
||||||
|
|
||||||
|
defineOptions({ name: 'BasicMenu' })
|
||||||
|
|
||||||
|
const props = defineProps(basicProps)
|
||||||
|
const emit = defineEmits(['menuClick'])
|
||||||
|
|
||||||
|
const isClickGo = ref(false)
|
||||||
|
const currentActiveMenu = ref('')
|
||||||
|
|
||||||
|
const menuState = reactive<MenuState>({
|
||||||
|
defaultSelectedKeys: [],
|
||||||
|
openKeys: [],
|
||||||
|
selectedKeys: [],
|
||||||
|
collapsedOpenKeys: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('basic-menu')
|
||||||
|
const { items, mode, accordion } = toRefs(props)
|
||||||
|
|
||||||
|
const { getCollapsed, getTopMenuAlign, getSplit } = useMenuSetting()
|
||||||
|
|
||||||
|
const { currentRoute } = useRouter()
|
||||||
|
|
||||||
|
const { handleOpenChange, setOpenKeys, getOpenKeys } = useOpenKeys(menuState, items, mode as any, accordion)
|
||||||
|
|
||||||
|
const getIsTopMenu = computed(() => {
|
||||||
|
const { type, mode } = props
|
||||||
|
|
||||||
|
return (type === MenuTypeEnum.TOP_MENU && mode === MenuModeEnum.HORIZONTAL) || (props.isHorizontal && unref(getSplit))
|
||||||
|
})
|
||||||
|
|
||||||
|
const getMenuClass = computed(() => {
|
||||||
|
const align = props.isHorizontal && unref(getSplit) ? 'start' : unref(getTopMenuAlign)
|
||||||
|
return [
|
||||||
|
prefixCls,
|
||||||
|
`justify-${align}`,
|
||||||
|
{
|
||||||
|
[`${prefixCls}__second`]: !props.isHorizontal && unref(getSplit),
|
||||||
|
[`${prefixCls}__sidebar-hor`]: unref(getIsTopMenu),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const getInlineCollapseOptions = computed(() => {
|
||||||
|
const isInline = props.mode === MenuModeEnum.INLINE
|
||||||
|
|
||||||
|
const inlineCollapseOptions: { inlineCollapsed?: boolean } = {}
|
||||||
|
if (isInline)
|
||||||
|
inlineCollapseOptions.inlineCollapsed = props.mixSider ? false : unref(getCollapsed)
|
||||||
|
|
||||||
|
return inlineCollapseOptions
|
||||||
|
})
|
||||||
|
|
||||||
|
listenerRouteChange((route) => {
|
||||||
|
if (route.name === REDIRECT_NAME)
|
||||||
|
return
|
||||||
|
handleMenuChange(route)
|
||||||
|
currentActiveMenu.value = route.meta?.currentActiveMenu as string
|
||||||
|
|
||||||
|
if (unref(currentActiveMenu)) {
|
||||||
|
menuState.selectedKeys = [unref(currentActiveMenu)]
|
||||||
|
setOpenKeys(unref(currentActiveMenu))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
!props.mixSider
|
||||||
|
&& watch(
|
||||||
|
() => props.items,
|
||||||
|
() => {
|
||||||
|
handleMenuChange()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleMenuClick: MenuProps['onClick'] = async ({ key }) => {
|
||||||
|
const { beforeClickFn } = props
|
||||||
|
if (beforeClickFn && isFunction(beforeClickFn)) {
|
||||||
|
const flag = await beforeClickFn(key)
|
||||||
|
if (!flag)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
emit('menuClick', key)
|
||||||
|
|
||||||
|
isClickGo.value = true
|
||||||
|
menuState.selectedKeys = [key]
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {
|
||||||
|
if (unref(isClickGo)) {
|
||||||
|
isClickGo.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const path = (route || unref(currentRoute)).meta?.currentActiveMenu || (route || unref(currentRoute)).path
|
||||||
|
setOpenKeys(path)
|
||||||
|
if (unref(currentActiveMenu))
|
||||||
|
return
|
||||||
|
if (props.isHorizontal && unref(getSplit)) {
|
||||||
|
const parentPath = await getCurrentParentPath(path)
|
||||||
|
menuState.selectedKeys = [parentPath]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const parentPaths = await getAllParentPath(props.items, path)
|
||||||
|
menuState.selectedKeys = parentPaths
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Menu
|
||||||
|
:selected-keys="menuState.selectedKeys"
|
||||||
|
:default-selected-keys="menuState.defaultSelectedKeys"
|
||||||
|
:mode="mode"
|
||||||
|
:open-keys="getOpenKeys"
|
||||||
|
:inline-indent="inlineIndent"
|
||||||
|
:theme="theme"
|
||||||
|
:class="getMenuClass"
|
||||||
|
:sub-menu-open-delay="0.2"
|
||||||
|
v-bind="getInlineCollapseOptions"
|
||||||
|
@open-change="handleOpenChange"
|
||||||
|
@click="handleMenuClick"
|
||||||
|
>
|
||||||
|
<template v-for="item in items" :key="item.path">
|
||||||
|
<KingdeeBasicSubMenuItem :item="item" :theme="theme" :is-horizontal="isHorizontal" />
|
||||||
|
</template>
|
||||||
|
</Menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import './index.less';
|
||||||
|
</style>
|
@ -0,0 +1,56 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { Menu } from 'ant-design-vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { itemProps } from '../props'
|
||||||
|
import BasicMenuItem from './BasicMenuItem.vue'
|
||||||
|
import MenuItemContent from './MenuItemContent.vue'
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import type { Menu as MenuType } from '@/router/types'
|
||||||
|
|
||||||
|
defineOptions({ name: 'BasicSubMenuItem' })
|
||||||
|
|
||||||
|
const props = defineProps(itemProps)
|
||||||
|
|
||||||
|
const SubMenu = Menu.SubMenu
|
||||||
|
|
||||||
|
const { prefixCls } = useDesign('basic-menu-item')
|
||||||
|
|
||||||
|
const getShowMenu = computed(() => !props.item.meta?.hideMenu)
|
||||||
|
function menuHasChildren(menuTreeItem: MenuType): boolean {
|
||||||
|
return (
|
||||||
|
!menuTreeItem.meta?.hideChildrenInMenu
|
||||||
|
&& Reflect.has(menuTreeItem, 'children')
|
||||||
|
&& !!menuTreeItem.children
|
||||||
|
&& menuTreeItem.children.length > 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
function handleSwitchCloud(item: MenuType) {
|
||||||
|
router.push(getFirstPathOfLastChild(item))
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirstPathOfLastChild(item: MenuType): string {
|
||||||
|
// 如果当前菜单没有子菜单,直接返回当前菜单的 path
|
||||||
|
if (!item.children || item.children.length === 0)
|
||||||
|
return item.path
|
||||||
|
|
||||||
|
// 递归找到最后一个子菜单的第一个 path
|
||||||
|
return getFirstPathOfLastChild(item.children[0])
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<BasicMenuItem v-if="!menuHasChildren(item) && getShowMenu" v-bind="$props" :class="prefixCls" />
|
||||||
|
<SubMenu v-if="menuHasChildren(item) && getShowMenu" :key="`submenu-${item.path}`" :class="[theme]" popup-class-name="app-top-menu-popup">
|
||||||
|
<template #title>
|
||||||
|
<MenuItemContent v-bind="$props" :item="item" @click="handleSwitchCloud(item)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- <template v-for="childrenItem in item.children || []" :key="childrenItem.path"> -->
|
||||||
|
<!-- <BasicSubMenuItem v-bind="$props" :item="childrenItem" /> -->
|
||||||
|
<!-- </template> -->
|
||||||
|
</SubMenu>
|
||||||
|
</template>
|
@ -16,6 +16,10 @@ import { useMultipleTabStore } from '@/store/modules/multipleTab'
|
|||||||
|
|
||||||
defineOptions({ name: 'LayoutMultipleHeader' })
|
defineOptions({ name: 'LayoutMultipleHeader' })
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
scoped: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const HEADER_HEIGHT = 48
|
const HEADER_HEIGHT = 48
|
||||||
|
|
||||||
const TABS_HEIGHT = 32
|
const TABS_HEIGHT = 32
|
||||||
@ -90,7 +94,7 @@ const getClass = computed(() => {
|
|||||||
/>
|
/>
|
||||||
<div :style="getWrapStyle" :class="getClass">
|
<div :style="getWrapStyle" :class="getClass">
|
||||||
<LayoutHeader v-if="getShowInsetHeaderRef" />
|
<LayoutHeader v-if="getShowInsetHeaderRef" />
|
||||||
<MultipleTabs v-if="getShowTabs" :key="tabStore.getLastDragEndIndex" />
|
<MultipleTabs v-if="getShowTabs" :key="tabStore.getLastDragEndIndex" :scoped="scoped" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
import { computed, unref } from 'vue'
|
import { computed, unref } from 'vue'
|
||||||
|
|
||||||
import { Layout } from 'ant-design-vue'
|
import { Layout } from 'ant-design-vue'
|
||||||
import { ErrorAction, FullScreen, LayoutBreadcrumb, Notify, UserDropDown } from '../../components'
|
import { ErrorAction, FullScreen, Notify, UserDropDown } from '../../components'
|
||||||
import LayoutTrigger from '../../../trigger/index.vue'
|
import LayoutTrigger from '../../../trigger/index.vue'
|
||||||
|
import KingdeeTopMenu from './KingdeeTopMenu.vue'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
// import { AppLocalePicker, AppLogo, AppSearch, AppSizePicker } from '@/components/Application'
|
// import { AppLocalePicker, AppLogo, AppSearch, AppSizePicker } from '@/components/Application'
|
||||||
@ -19,7 +20,7 @@ import { useHeaderSetting } from '@/hooks/setting/useHeaderSetting'
|
|||||||
import { useMenuSetting } from '@/hooks/setting/useMenuSetting'
|
import { useMenuSetting } from '@/hooks/setting/useMenuSetting'
|
||||||
import { useRootSetting } from '@/hooks/setting/useRootSetting'
|
import { useRootSetting } from '@/hooks/setting/useRootSetting'
|
||||||
|
|
||||||
// import { MenuModeEnum, MenuSplitTyeEnum } from '@/enums/menuEnum'
|
import { MenuModeEnum, MenuSplitTyeEnum } from '@/enums/menuEnum'
|
||||||
import { SettingButtonPositionEnum } from '@/enums/appEnum'
|
import { SettingButtonPositionEnum } from '@/enums/appEnum'
|
||||||
|
|
||||||
import { useAppInject } from '@/hooks/web/useAppInject'
|
import { useAppInject } from '@/hooks/web/useAppInject'
|
||||||
@ -41,7 +42,7 @@ const { getShowHeaderTrigger, getSplit, getIsMixMode, getMenuWidth, getIsMixSide
|
|||||||
// const { getIsMixMode, getMenuWidth } = useMenuSetting()
|
// const { getIsMixMode, getMenuWidth } = useMenuSetting()
|
||||||
const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting()
|
const { getUseErrorHandle, getShowSettingButton, getSettingButtonPosition } = useRootSetting()
|
||||||
|
|
||||||
const { getHeaderTheme, getShowFullScreen, getShowNotice, getShowContent, getShowBread, getShowHeaderLogo, getShowHeader, getShowSearch }
|
const { getHeaderTheme, getShowFullScreen, getShowNotice, getShowContent, getShowHeaderLogo, getShowHeader, getShowSearch }
|
||||||
= useHeaderSetting()
|
= useHeaderSetting()
|
||||||
|
|
||||||
const { getShowLocalePicker } = useLocale()
|
const { getShowLocalePicker } = useLocale()
|
||||||
@ -80,10 +81,10 @@ const getLogoWidth = computed(() => {
|
|||||||
return { width: `${width}px` }
|
return { width: `${width}px` }
|
||||||
})
|
})
|
||||||
|
|
||||||
// const getSplitType = computed(() => {
|
const getSplitType = computed(() => {
|
||||||
// return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE
|
return unref(getSplit) ? MenuSplitTyeEnum.TOP : MenuSplitTyeEnum.NONE
|
||||||
// })
|
})
|
||||||
//
|
|
||||||
// const getMenuMode = computed(() => {
|
// const getMenuMode = computed(() => {
|
||||||
// return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null
|
// return unref(getSplit) ? MenuModeEnum.HORIZONTAL : null
|
||||||
// })
|
// })
|
||||||
@ -107,14 +108,14 @@ const getLogoWidth = computed(() => {
|
|||||||
v-if="(getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile"
|
v-if="(getShowContent && getShowHeaderTrigger && !getSplit && !getIsMixSidebar) || getIsMobile"
|
||||||
:theme="getHeaderTheme" :sider="false"
|
:theme="getHeaderTheme" :sider="false"
|
||||||
/>
|
/>
|
||||||
<LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
|
<!-- <LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" /> -->
|
||||||
</div>
|
</div>
|
||||||
<!-- left end -->
|
<!-- left end -->
|
||||||
|
|
||||||
<!-- menu start -->
|
<!-- menu start -->
|
||||||
<!-- <div v-if="getShowTopMenu && !getIsMobile" :class="`${prefixCls}-menu`"> -->
|
<div v-if="!getIsMobile" :class="`${prefixCls}-menu`">
|
||||||
<!-- <LayoutMenu :is-horizontal="true" :theme="getHeaderTheme" :split-type="getSplitType" :menu-mode="getMenuMode" /> -->
|
<KingdeeTopMenu :is-horizontal="true" :theme="getHeaderTheme" :split-type="getSplitType" :menu-mode="MenuModeEnum.HORIZONTAL" />
|
||||||
<!-- </div> -->
|
</div>
|
||||||
<!-- menu-end -->
|
<!-- menu-end -->
|
||||||
|
|
||||||
<!-- action -->
|
<!-- action -->
|
||||||
|
248
src/layouts/default/header/kingdee/new/KingdeeTopMenu.vue
Normal file
248
src/layouts/default/header/kingdee/new/KingdeeTopMenu.vue
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
<script lang="tsx">
|
||||||
|
import type { CSSProperties } from 'vue'
|
||||||
|
|
||||||
|
import { computed, defineComponent, toRef, unref } from 'vue'
|
||||||
|
import { useSplitMenu } from '@/layouts/default/menu/useLayoutMenu'
|
||||||
|
import { KingdeeBaseMenu } 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'
|
||||||
|
import type { Menu } from '@/router/types'
|
||||||
|
import { useMultipleTabStore } from '@/store/modules/multipleTab'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'KingdeeTopMenu',
|
||||||
|
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: '',
|
||||||
|
},
|
||||||
|
isScoped: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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 tabStore = useMultipleTabStore()
|
||||||
|
const getTabsState = computed(() => {
|
||||||
|
return tabStore.getTabList.filter(item => !item.meta?.hideTab)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只显示已经打开的一级菜单
|
||||||
|
* @param menus
|
||||||
|
* @param openedFullPath
|
||||||
|
*/
|
||||||
|
function filterMenus(menus: Menu[], openedFullPath: string[]): Menu[] {
|
||||||
|
return menus
|
||||||
|
.map((menu) => {
|
||||||
|
// 如果当前菜单的路径在 openedFullPath 中,直接保留
|
||||||
|
if (openedFullPath.includes(menu.path))
|
||||||
|
return menu
|
||||||
|
|
||||||
|
// 如果当前菜单有子菜单,递归过滤子菜单
|
||||||
|
if (menu.children && menu.children.length > 0) {
|
||||||
|
const filteredChildren = filterMenus(menu.children, openedFullPath)
|
||||||
|
|
||||||
|
// 如果过滤后的子菜单不为空,保留当前菜单并更新子菜单
|
||||||
|
if (filteredChildren.length > 0) {
|
||||||
|
return {
|
||||||
|
...menu,
|
||||||
|
children: filteredChildren,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前菜单的路径不在 openedFullPath 中,且没有子菜单,则过滤掉
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
.filter(menu => menu !== null) as Menu[]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFirstPathSegment(path: string): string {
|
||||||
|
const trimmedPath = path.replace(/^\/+/, '/')
|
||||||
|
|
||||||
|
const segments = trimmedPath.split('/')
|
||||||
|
|
||||||
|
const firstSegment = segments.find(segment => segment !== '')
|
||||||
|
|
||||||
|
return firstSegment ? `/${firstSegment}` : '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCommonProps = computed(() => {
|
||||||
|
const openedPath: string[] = []
|
||||||
|
const openedFullPath: string[] = []
|
||||||
|
const tabs = unref(getTabsState)
|
||||||
|
for (let i = 0; i < tabs.length; i++) {
|
||||||
|
openedPath.push(getFirstPathSegment(tabs[i].path))
|
||||||
|
openedFullPath.push(tabs[i].path)
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterMenu = filterMenus(unref(menusRef), openedFullPath)
|
||||||
|
const menus = unref(menusRef)
|
||||||
|
return {
|
||||||
|
menus: filterMenu,
|
||||||
|
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} />
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<KingdeeBaseMenu
|
||||||
|
{...(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}-kd-layout-menu';
|
||||||
|
@logo-prefix-cls: ~'@{namespace}-kd-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>
|
@ -52,7 +52,7 @@ const layoutClass = computed(() => {
|
|||||||
<Layout :class="[layoutClass, `${prefixCls}-out`]">
|
<Layout :class="[layoutClass, `${prefixCls}-out`]">
|
||||||
<LayoutSideBar v-if="(getShowSidebar || getIsMobile)" />
|
<LayoutSideBar v-if="(getShowSidebar || getIsMobile)" />
|
||||||
<Layout :class="`${prefixCls}-main`">
|
<Layout :class="`${prefixCls}-main`">
|
||||||
<LayoutMultipleHeader />
|
<LayoutMultipleHeader :scoped="true" />
|
||||||
<LayoutContent />
|
<LayoutContent />
|
||||||
<LayoutFooter />
|
<LayoutFooter />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
@ -123,8 +123,9 @@ export default defineComponent({
|
|||||||
const getCommonProps = computed(() => {
|
const getCommonProps = computed(() => {
|
||||||
const current = getFirstPathSegment(currentPath.path)
|
const current = getFirstPathSegment(currentPath.path)
|
||||||
const menus = findChildrenByFirstPathSegment(unref(menusRef), current)
|
const menus = findChildrenByFirstPathSegment(unref(menusRef), current)
|
||||||
|
const scoped = props.isScoped
|
||||||
return {
|
return {
|
||||||
menus,
|
menus: scoped ? menus : unref(menusRef),
|
||||||
beforeClickFn: beforeMenuClickFn,
|
beforeClickFn: beforeMenuClickFn,
|
||||||
items: menus,
|
items: menus,
|
||||||
theme: unref(getComputedMenuTheme),
|
theme: unref(getComputedMenuTheme),
|
||||||
|
@ -6,7 +6,7 @@ import { useMouse } from '@vueuse/core'
|
|||||||
import { computed, ref, unref } from 'vue'
|
import { computed, ref, unref } from 'vue'
|
||||||
|
|
||||||
import { Tabs } from 'ant-design-vue'
|
import { Tabs } from 'ant-design-vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import TabContent from './components/TabContent.vue'
|
import TabContent from './components/TabContent.vue'
|
||||||
import FoldButton from './components/FoldButton.vue'
|
import FoldButton from './components/FoldButton.vue'
|
||||||
import TabRedo from './components/TabRedo.vue'
|
import TabRedo from './components/TabRedo.vue'
|
||||||
@ -26,6 +26,10 @@ import { listenerRouteChange } from '@/logics/mitt/routeChange'
|
|||||||
|
|
||||||
defineOptions({ name: 'MultipleTabs' })
|
defineOptions({ name: 'MultipleTabs' })
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
scoped: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
const affixTextList = initAffixTabs()
|
const affixTextList = initAffixTabs()
|
||||||
const activeKeyRef = ref('')
|
const activeKeyRef = ref('')
|
||||||
|
|
||||||
@ -33,13 +37,32 @@ useTabsDrag(affixTextList)
|
|||||||
const tabStore = useMultipleTabStore()
|
const tabStore = useMultipleTabStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
const { prefixCls } = useDesign('multiple-tabs')
|
const { prefixCls } = useDesign('multiple-tabs')
|
||||||
const go = useGo()
|
const go = useGo()
|
||||||
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting()
|
const { getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting()
|
||||||
|
|
||||||
|
function getFirstPathSegment(path: string): string {
|
||||||
|
if (!path || typeof path !== 'string')
|
||||||
|
return '/'
|
||||||
|
|
||||||
|
const segments = path.split('/').filter(Boolean) // 移除空字符串
|
||||||
|
return segments.length > 0 ? `/${segments[0]}` : '/'
|
||||||
|
}
|
||||||
|
|
||||||
const getTabsState = computed(() => {
|
const getTabsState = computed(() => {
|
||||||
return tabStore.getTabList.filter(item => !item.meta?.hideTab)
|
const currentPath = route.path
|
||||||
|
|
||||||
|
const currentCloud = getFirstPathSegment(currentPath)
|
||||||
|
|
||||||
|
if (props.scoped) {
|
||||||
|
return tabStore.getTabList.filter(item => !item.meta?.hideTab).filter((item) => {
|
||||||
|
const firstPath = getFirstPathSegment(item.path)
|
||||||
|
return firstPath === currentCloud
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else { return tabStore.getTabList.filter(item => !item.meta?.hideTab) }
|
||||||
})
|
})
|
||||||
|
|
||||||
const unClose = computed(() => unref(getTabsState).length === 1)
|
const unClose = computed(() => unref(getTabsState).length === 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user