code 提交
This commit is contained in:
parent
d7e3a153dc
commit
87b8bd47dc
@ -1,19 +1,24 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-navbars-breadcrumb-index" :class="setBreadcrumbStyle">
|
<div class="layout-navbars-breadcrumb-index" :class="setBreadcrumbStyle">
|
||||||
<Logo v-if="setIsShowLogo" />
|
<div class="left-section">
|
||||||
<Breadcrumb />
|
<Logo v-if="setIsShowLogo" />
|
||||||
<Horizontal :menuList="state.menuList" v-if="isLayoutTransverse" />
|
<Breadcrumb />
|
||||||
<User />
|
</div>
|
||||||
|
<div class="right-section">
|
||||||
|
<ModuleSwitch :menuList="state.menuList" />
|
||||||
|
<User />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="layoutBreadcrumbIndex">
|
<script setup lang="ts" name="layoutBreadcrumbIndex">
|
||||||
import { defineAsyncComponent, computed, reactive, onMounted, onUnmounted } from 'vue'
|
import { defineAsyncComponent, computed, reactive, onMounted, onUnmounted, onBeforeMount } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useRoutesList } from '/@/stores/routesList'
|
import { useRoutesList } from '/@/stores/routesList'
|
||||||
import { useThemeConfig } from '/@/stores/themeConfig'
|
import { useThemeConfig } from '/@/stores/themeConfig'
|
||||||
import mittBus from '/@/utils/mitt'
|
import mittBus from '/@/utils/mitt'
|
||||||
|
import ModuleSwitch from './module-switch.vue'
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const Breadcrumb = defineAsyncComponent(() => import('/@/layout/navBars/topBar/breadcrumb.vue'))
|
const Breadcrumb = defineAsyncComponent(() => import('/@/layout/navBars/topBar/breadcrumb.vue'))
|
||||||
@ -21,12 +26,17 @@ const User = defineAsyncComponent(() => import('/@/layout/navBars/topBar/user.vu
|
|||||||
const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'))
|
const Logo = defineAsyncComponent(() => import('/@/layout/logo/index.vue'))
|
||||||
const Horizontal = defineAsyncComponent(() => import('/@/layout/navMenu/horizontal.vue'))
|
const Horizontal = defineAsyncComponent(() => import('/@/layout/navMenu/horizontal.vue'))
|
||||||
|
|
||||||
// 定义变量内容
|
// 支持 props 传递 menuList
|
||||||
|
const props = defineProps<{
|
||||||
|
menuList?: RouteItems
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
const stores = useRoutesList()
|
const stores = useRoutesList()
|
||||||
const storesThemeConfig = useThemeConfig()
|
const storesThemeConfig = useThemeConfig()
|
||||||
const { themeConfig } = storeToRefs(storesThemeConfig)
|
|
||||||
const { routesList } = storeToRefs(stores)
|
const { routesList } = storeToRefs(stores)
|
||||||
const route = useRoute()
|
const { themeConfig } = storeToRefs(storesThemeConfig)
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
menuList: [] as RouteItems,
|
menuList: [] as RouteItems,
|
||||||
})
|
})
|
||||||
@ -89,17 +99,45 @@ const setSendClassicChildren = (path: string) => {
|
|||||||
})
|
})
|
||||||
return currentData
|
return currentData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 优先用 props.menuList,否则 fallback 到 layout.children
|
||||||
|
const topModules = computed<RouteItem[]>(() => {
|
||||||
|
if (props.menuList && props.menuList.length) {
|
||||||
|
return filterRoutesFun(props.menuList)
|
||||||
|
}
|
||||||
|
const layout = routesList.value.find((item: RouteItem) => item.path === '/')
|
||||||
|
if (!layout || !layout.children) return []
|
||||||
|
return filterRoutesFun(layout.children)
|
||||||
|
})
|
||||||
|
|
||||||
|
const onModuleChange = (path: string) => {
|
||||||
|
router.push(path)
|
||||||
|
mittBus.emit('getBreadcrumbIndexSetFilterRoutes')
|
||||||
|
if (themeConfig.value.layout === 'classic' && themeConfig.value.isClassicSplitMenu) {
|
||||||
|
mittBus.emit('setSendClassicChildren', path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 页面加载时
|
// 页面加载时
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setFilterRoutes()
|
setFilterRoutes()
|
||||||
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
mittBus.on('getBreadcrumbIndexSetFilterRoutes', () => {
|
||||||
setFilterRoutes()
|
setFilterRoutes()
|
||||||
})
|
})
|
||||||
|
if (themeConfig.value.layout === 'classic' && themeConfig.value.isClassicSplitMenu) {
|
||||||
|
mittBus.emit('setSendClassicChildren', route.path)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
// 页面卸载时
|
// 页面卸载时
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {})
|
mittBus.off('getBreadcrumbIndexSetFilterRoutes', () => {})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
if (themeConfig.value.layout === 'classic' && themeConfig.value.isClassicSplitMenu) {
|
||||||
|
mittBus.emit('setSendClassicChildren', route.path)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -107,9 +145,23 @@ onUnmounted(() => {
|
|||||||
height: 50px;
|
height: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
background: var(--next-bg-topBar);
|
background: var(--next-bg-topBar);
|
||||||
border-bottom: 1px solid var(--next-border-color-light);
|
border-bottom: 1px solid var(--next-border-color-light);
|
||||||
|
|
||||||
|
.left-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-navbars-breadcrumb-index-no-bb {
|
.layout-navbars-breadcrumb-index-no-bb {
|
||||||
border-bottom-width: 0px;
|
border-bottom-width: 0px;
|
||||||
}
|
}
|
||||||
|
180
src/layout/navBars/topBar/module-switch.vue
Normal file
180
src/layout/navBars/topBar/module-switch.vue
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<template>
|
||||||
|
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onMenuChange">
|
||||||
|
<div class="layout-navbars-breadcrumb-user-icon">
|
||||||
|
<i class="iconfont icon-diqiu" :title="$t('message.user.title1')"></i>
|
||||||
|
<span class="current-lang">{{ currentModuleName }}</span>
|
||||||
|
</div>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item v-for="item in menuLists as RouteItem[]" :key="item.path || ''" :command="item.path || ''">
|
||||||
|
<SvgIcon :name="item.meta?.icon" />
|
||||||
|
{{ $t(item.meta?.title || '未命名模块') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="navMenuHorizontal">
|
||||||
|
import { defineAsyncComponent, reactive, computed, onBeforeMount, watch } from 'vue'
|
||||||
|
import { useRoute, onBeforeRouteUpdate, RouteRecordRaw, useRouter } from 'vue-router'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { useRoutesList } from '/@/stores/routesList'
|
||||||
|
import { useThemeConfig } from '/@/stores/themeConfig'
|
||||||
|
import other from '/@/utils/other'
|
||||||
|
import mittBus from '/@/utils/mitt'
|
||||||
|
import { treeToList, listToTree, filterList } from '/@/utils/tree'
|
||||||
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 引入组件
|
||||||
|
const SubItem = defineAsyncComponent(() => import('/@/layout/navMenu/subItem.vue'))
|
||||||
|
|
||||||
|
// 定义父组件传过来的值
|
||||||
|
const props = defineProps({
|
||||||
|
// 菜单列表
|
||||||
|
menuList: {
|
||||||
|
type: Array<RouteRecordRaw>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
|
const stores = useRoutesList()
|
||||||
|
const storesThemeConfig = useThemeConfig()
|
||||||
|
const { routesList } = storeToRefs(stores)
|
||||||
|
const { themeConfig } = storeToRefs(storesThemeConfig)
|
||||||
|
const route = useRoute()
|
||||||
|
const state = reactive({
|
||||||
|
defaultActive: '' as string | undefined,
|
||||||
|
currentModuleName: '' as string,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取父级菜单数据
|
||||||
|
const menuLists = computed(() => {
|
||||||
|
return <RouteItems>props.menuList
|
||||||
|
})
|
||||||
|
|
||||||
|
const onMenuChange = (path: string) => {
|
||||||
|
console.log('path', path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由过滤递归函数
|
||||||
|
const filterRoutesFun = <T extends RouteItem>(arr: T[]): T[] => {
|
||||||
|
return arr
|
||||||
|
.filter((item: T) => !item.meta?.isHide)
|
||||||
|
.map((item: T) => {
|
||||||
|
item = Object.assign({}, item)
|
||||||
|
if (item.children) item.children = filterRoutesFun(item.children)
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得根菜单路径
|
||||||
|
const getRootPath = (path: string) => {
|
||||||
|
let rootPath = ''
|
||||||
|
let routeTree = listToTree(
|
||||||
|
filterList(treeToList(cloneDeep(routesList.value)), path, {
|
||||||
|
filterWhere: (item: any, filterword: string) => {
|
||||||
|
return item.path?.toLocaleLowerCase() === filterword
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
if (routeTree.length > 0 && routeTree[0]?.path) {
|
||||||
|
rootPath = routeTree[0].path
|
||||||
|
}
|
||||||
|
return rootPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 传送当前子级数据到菜单中
|
||||||
|
const setSendClassicChildren = (path: string) => {
|
||||||
|
let rootPath = getRootPath(path)
|
||||||
|
rootPath = rootPath || path
|
||||||
|
const currentPathSplit = rootPath.split('/')
|
||||||
|
let currentData: MittMenu = { children: [] }
|
||||||
|
filterRoutesFun(routesList.value).map((v, k) => {
|
||||||
|
if (v.path === `/${currentPathSplit[1]}`) {
|
||||||
|
v['k'] = k
|
||||||
|
currentData['item'] = { ...v }
|
||||||
|
currentData['children'] = [{ ...v }]
|
||||||
|
if (v.children) currentData['children'] = v.children
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return currentData
|
||||||
|
}
|
||||||
|
// 设置页面当前路由高亮
|
||||||
|
const setCurrentRouterHighlight = (currentRoute: RouteToFrom) => {
|
||||||
|
console.log('currentRoute', currentRoute)
|
||||||
|
const { path, meta } = currentRoute
|
||||||
|
|
||||||
|
if (themeConfig.value.layout === 'classic') {
|
||||||
|
let rootPath = getRootPath(path || '')
|
||||||
|
rootPath = rootPath || path || ''
|
||||||
|
setCurrentModuleName(`/${rootPath?.split('/')[1]}` || '')
|
||||||
|
state.defaultActive = `/${rootPath?.split('/')[1]}`
|
||||||
|
if (!state.defaultActive || state.defaultActive === '/') router.push(routesList.value[0].path)
|
||||||
|
} else {
|
||||||
|
const pathSplit = meta?.isDynamic ? meta.isDynamicPath!.split('/') : path!.split('/')
|
||||||
|
if (pathSplit.length >= 4 && meta?.isHide) state.defaultActive = pathSplit.splice(0, 3).join('/')
|
||||||
|
else state.defaultActive = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载前
|
||||||
|
onBeforeMount(() => {
|
||||||
|
setCurrentRouterHighlight(route)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 路由更新时
|
||||||
|
onBeforeRouteUpdate((to) => {
|
||||||
|
// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
|
||||||
|
setCurrentRouterHighlight(to)
|
||||||
|
// 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题
|
||||||
|
let { layout, isClassicSplitMenu } = themeConfig.value
|
||||||
|
if (layout === 'classic' && isClassicSplitMenu) {
|
||||||
|
mittBus.emit('setSendClassicChildren', setSendClassicChildren(to.path))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.el-menu-horizontal-warp {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-right: 30px;
|
||||||
|
|
||||||
|
:deep(.el-scrollbar__bar.is-vertical) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(a) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-menu.el-menu--horizontal {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-navbars-breadcrumb-user-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.module-name {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
max-width: 120px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -15,12 +15,6 @@
|
|||||||
<SvgIcon :name="val.meta.icon" />
|
<SvgIcon :name="val.meta.icon" />
|
||||||
{{ $t(val.meta.title) }}
|
{{ $t(val.meta.title) }}
|
||||||
</template>
|
</template>
|
||||||
<template #title v-else>
|
|
||||||
<a class="w100" @click.prevent="onALinkClick(val)">
|
|
||||||
<SvgIcon :name="val.meta.icon" />
|
|
||||||
{{ $t(val.meta.title) }}
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@ -113,8 +107,12 @@ const setSendClassicChildren = (path: string) => {
|
|||||||
}
|
}
|
||||||
// 设置页面当前路由高亮
|
// 设置页面当前路由高亮
|
||||||
const setCurrentRouterHighlight = (currentRoute: RouteToFrom) => {
|
const setCurrentRouterHighlight = (currentRoute: RouteToFrom) => {
|
||||||
|
console.log('currentRoute', currentRoute)
|
||||||
|
|
||||||
const { path, meta } = currentRoute
|
const { path, meta } = currentRoute
|
||||||
if (themeConfig.value.layout === 'classic') {
|
if (themeConfig.value.layout === 'classic') {
|
||||||
|
console.log('themeConfig.value.layout', themeConfig.value.layout)
|
||||||
|
|
||||||
let rootPath = getRootPath(path || '')
|
let rootPath = getRootPath(path || '')
|
||||||
rootPath = rootPath || path || ''
|
rootPath = rootPath || path || ''
|
||||||
state.defaultActive = `/${rootPath?.split('/')[1]}`
|
state.defaultActive = `/${rootPath?.split('/')[1]}`
|
||||||
@ -135,6 +133,7 @@ onBeforeMount(() => {
|
|||||||
})
|
})
|
||||||
// 路由更新时
|
// 路由更新时
|
||||||
onBeforeRouteUpdate((to) => {
|
onBeforeRouteUpdate((to) => {
|
||||||
|
console.log('to', to)
|
||||||
// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
|
// 修复:https://gitee.com/lyt-top/vue-next-admin/issues/I3YX6G
|
||||||
setCurrentRouterHighlight(to)
|
setCurrentRouterHighlight(to)
|
||||||
// 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题
|
// 修复经典布局开启切割菜单时,点击tagsView后左侧导航菜单数据不变的问题
|
||||||
|
Loading…
x
Reference in New Issue
Block a user