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.
310 lines
8.4 KiB
310 lines
8.4 KiB
<script lang="tsx">
|
|
import { PropType } from 'vue'
|
|
import { ElMenu, ElScrollbar } from 'element-plus'
|
|
import { useAppStore } from '@/store/modules/app'
|
|
import { usePermissionStore } from '@/store/modules/permission'
|
|
import { useRenderMenuItem } from './components/useRenderMenuItem'
|
|
import { isUrl } from '@/utils/is'
|
|
import { useDesign } from '@/hooks/web/useDesign'
|
|
import { LayoutType } from '@/types/layout'
|
|
|
|
const { getPrefixCls } = useDesign()
|
|
|
|
const prefixCls = getPrefixCls('menu')
|
|
|
|
export default defineComponent({
|
|
// eslint-disable-next-line vue/no-reserved-component-names
|
|
name: 'Menu',
|
|
props: {
|
|
menuSelect: {
|
|
type: Function as PropType<(index: string) => void>,
|
|
default: undefined
|
|
}
|
|
},
|
|
setup(props) {
|
|
const appStore = useAppStore()
|
|
|
|
const layout = computed(() => appStore.getLayout)
|
|
|
|
const { push, currentRoute } = useRouter()
|
|
|
|
const permissionStore = usePermissionStore()
|
|
|
|
const menuMode = computed((): 'vertical' | 'horizontal' => {
|
|
// 竖
|
|
const vertical: LayoutType[] = ['classic', 'topLeft', 'cutMenu']
|
|
|
|
if (vertical.includes(unref(layout))) {
|
|
return 'vertical'
|
|
} else {
|
|
return 'horizontal'
|
|
}
|
|
})
|
|
|
|
const routers = computed(() =>
|
|
unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
|
|
)
|
|
|
|
const categoryRoutes = computed(() => {
|
|
const allRoutes = unref(layout) === 'cutMenu' ? permissionStore.getMenuTabRouters : permissionStore.getRouters
|
|
const categoryPath = appStore.getCategoryRoutePath
|
|
let findRoutes = allRoutes.find(item=>!item.meta.hidden&&item.path === categoryPath)
|
|
if(findRoutes){
|
|
findRoutes = JSON.parse(JSON.stringify(findRoutes))
|
|
findRoutes?.children?.forEach(item => {
|
|
item.path = findRoutes?.path+'/'+item.path
|
|
});
|
|
}
|
|
let homeRoute = allRoutes.find(item=>!item.meta.hidden&&item.path === '/')
|
|
if(categoryPath!=homeRoute?.path&&homeRoute){
|
|
homeRoute = JSON.parse(JSON.stringify(homeRoute))
|
|
homeRoute?.children?.forEach(item => {
|
|
item.path = homeRoute?.path+item.path
|
|
});
|
|
}
|
|
return categoryPath!=homeRoute?.path?[...homeRoute?.children||[],...findRoutes?.children||[]]:[...findRoutes?.children||[]]||homeRoute||[]
|
|
})
|
|
|
|
const collapse = computed(() => appStore.getCollapse)
|
|
|
|
const uniqueOpened = computed(() => appStore.getUniqueOpened)
|
|
|
|
const activeMenu = computed(() => {
|
|
const { meta, path } = unref(currentRoute)
|
|
// if set path, the sidebar will highlight the path you set
|
|
if (meta.activeMenu) {
|
|
return meta.activeMenu as string
|
|
}
|
|
return path
|
|
})
|
|
|
|
const menuSelect = (index: string) => {
|
|
if (props.menuSelect) {
|
|
props.menuSelect(index)
|
|
}
|
|
// 自定义事件
|
|
if (isUrl(index)) {
|
|
window.open(index)
|
|
} else {
|
|
push(index)
|
|
}
|
|
}
|
|
|
|
const renderMenuWrap = () => {
|
|
if (unref(layout) === 'top') {
|
|
return renderMenu()
|
|
} else {
|
|
return <ElScrollbar>{renderMenu()}</ElScrollbar>
|
|
}
|
|
}
|
|
|
|
const renderMenu = () => {
|
|
return (
|
|
<ElMenu
|
|
defaultActive={unref(activeMenu)}
|
|
mode={unref(menuMode)}
|
|
collapse={
|
|
unref(layout) === 'top' || unref(layout) === 'cutMenu' ? false : unref(collapse)
|
|
}
|
|
uniqueOpened={unref(layout) === 'top' ? false : unref(uniqueOpened)}
|
|
backgroundColor="var(--left-menu-bg-color)"
|
|
textColor="var(--left-menu-text-color)"
|
|
activeTextColor="var(--left-menu-text-active-color)"
|
|
onSelect={menuSelect}
|
|
>
|
|
{{
|
|
default: () => {
|
|
const { renderMenuItem } = useRenderMenuItem(unref(menuMode))
|
|
return appStore.getShowCategoryMenu?renderMenuItem(unref(categoryRoutes)):renderMenuItem(unref(routers))
|
|
}
|
|
}}
|
|
</ElMenu>
|
|
)
|
|
}
|
|
|
|
return () => (
|
|
<div
|
|
id={prefixCls}
|
|
class={[
|
|
`${prefixCls} ${prefixCls}__${unref(menuMode)}`,
|
|
'h-[100%] overflow-hidden flex-col bg-[var(--left-menu-bg-color)]',
|
|
{
|
|
'w-[var(--left-menu-min-width)]': unref(collapse) && unref(layout) !== 'cutMenu',
|
|
'w-[var(--left-menu-max-width)]': !unref(collapse) && unref(layout) !== 'cutMenu'
|
|
}
|
|
]}
|
|
>
|
|
{renderMenuWrap()}
|
|
</div>
|
|
)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
$prefix-cls: #{$namespace}-menu;
|
|
|
|
.is-active--after {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: 4px;
|
|
height: 100%;
|
|
background-color: var(--el-color-primary);
|
|
content: '';
|
|
}
|
|
|
|
.#{$prefix-cls} {
|
|
position: relative;
|
|
transition: width var(--transition-time-02);
|
|
|
|
:deep(.#{$elNamespace}-menu) {
|
|
width: 100% !important;
|
|
border-right: none;
|
|
|
|
// 设置选中时子标题的颜色
|
|
.is-active {
|
|
& > .#{$elNamespace}-sub-menu__title {
|
|
color: var(--left-menu-text-active-color) !important;
|
|
}
|
|
}
|
|
|
|
// 设置子菜单悬停的高亮和背景色
|
|
.#{$elNamespace}-sub-menu__title,
|
|
.#{$elNamespace}-menu-item {
|
|
&:hover {
|
|
color: var(--left-menu-text-active-color) !important;
|
|
background-color: var(--left-menu-bg-color) !important;
|
|
}
|
|
}
|
|
|
|
// 设置选中时的高亮背景和高亮颜色
|
|
.#{$elNamespace}-sub-menu.is-active,
|
|
.#{$elNamespace}-menu-item.is-active {
|
|
color: var(--left-menu-text-active-color) !important;
|
|
background-color: var(--left-menu-bg-active-color) !important;
|
|
|
|
&:hover {
|
|
background-color: var(--left-menu-bg-active-color) !important;
|
|
}
|
|
}
|
|
|
|
.#{$elNamespace}-menu-item.is-active {
|
|
position: relative;
|
|
|
|
&::after {
|
|
@extend .is-active--after;
|
|
}
|
|
}
|
|
|
|
// 设置子菜单的背景颜色
|
|
.#{$elNamespace}-menu {
|
|
.#{$elNamespace}-sub-menu__title,
|
|
.#{$elNamespace}-menu-item:not(.is-active) {
|
|
background-color: var(--left-menu-bg-light-color) !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 折叠时的最小宽度
|
|
:deep(.#{$elNamespace}-menu--collapse) {
|
|
width: var(--left-menu-min-width);
|
|
|
|
& > .is-active,
|
|
& > .is-active > .#{$elNamespace}-sub-menu__title {
|
|
position: relative;
|
|
background-color: var(--left-menu-collapse-bg-active-color) !important;
|
|
|
|
&::after {
|
|
@extend .is-active--after;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 折叠动画的时候,就需要把文字给隐藏掉
|
|
:deep(.horizontal-collapse-transition) {
|
|
// transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
|
|
.#{$prefix-cls}__title {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
// 水平菜单
|
|
&__horizontal {
|
|
height: calc(var(--top-tool-height)) !important;
|
|
|
|
:deep(.#{$elNamespace}-menu--horizontal) {
|
|
height: calc(var(--top-tool-height));
|
|
border-bottom: none;
|
|
// 重新设置底部高亮颜色
|
|
& > .#{$elNamespace}-sub-menu.is-active {
|
|
.#{$elNamespace}-sub-menu__title {
|
|
border-bottom-color: var(--el-color-primary) !important;
|
|
}
|
|
}
|
|
|
|
.#{$elNamespace}-menu-item.is-active {
|
|
position: relative;
|
|
|
|
&::after {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
.#{$prefix-cls}__title {
|
|
/* stylelint-disable-next-line */
|
|
max-height: calc(var(--top-tool-height) - 2px) !important;
|
|
/* stylelint-disable-next-line */
|
|
line-height: calc(var(--top-tool-height) - 2px);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<style lang="scss">
|
|
$prefix-cls: #{$namespace}-menu-popper;
|
|
|
|
.is-active--after {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: 4px;
|
|
height: 100%;
|
|
background-color: var(--el-color-primary);
|
|
content: '';
|
|
}
|
|
|
|
.#{$prefix-cls}--vertical,
|
|
.#{$prefix-cls}--horizontal {
|
|
// 设置选中时子标题的颜色
|
|
.is-active {
|
|
& > .el-sub-menu__title {
|
|
color: var(--left-menu-text-active-color) !important;
|
|
}
|
|
}
|
|
|
|
// 设置子菜单悬停的高亮和背景色
|
|
.el-sub-menu__title,
|
|
.el-menu-item {
|
|
&:hover {
|
|
color: var(--left-menu-text-active-color) !important;
|
|
background-color: var(--left-menu-bg-color) !important;
|
|
}
|
|
}
|
|
|
|
// 设置选中时的高亮背景
|
|
.el-menu-item.is-active {
|
|
position: relative;
|
|
background-color: var(--left-menu-bg-active-color) !important;
|
|
|
|
&:hover {
|
|
background-color: var(--left-menu-bg-active-color) !important;
|
|
}
|
|
|
|
&::after {
|
|
@extend .is-active--after;
|
|
}
|
|
}
|
|
}
|
|
</style>
|
|
|