mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-12-24 21:40:22 +08:00
105 lines
3.0 KiB
Vue
105 lines
3.0 KiB
Vue
<template>
|
|
<div class="flex h-full bg-white dark:bg-[#18181c]" @mouseleave="handleMouseLeaveMenu">
|
|
<div
|
|
class="flex-col-stretch flex-1 h-full transition-width duration-300 ease-in-out"
|
|
:class="[app.menu.collapsed ? 'mix-menu_collapsed-width' : 'mix-menu_width']"
|
|
>
|
|
<global-logo :show-title="false" />
|
|
<div class="flex-1-hidden">
|
|
<n-scrollbar>
|
|
<mix-menu
|
|
v-for="item in firstDegreeMenus"
|
|
:key="item.routeName"
|
|
:route-name="item.routeName"
|
|
:label="item.label"
|
|
:icon="item.icon"
|
|
:active-route-name="activeParentRouteName"
|
|
:is-mini="app.menu.collapsed"
|
|
@click="handleMixMenu(item.routeName, item.isSingle)"
|
|
/>
|
|
</n-scrollbar>
|
|
</div>
|
|
<mix-menu-collapse />
|
|
</div>
|
|
<div
|
|
class="relative h-full transition-width duration-300 ease-in-out"
|
|
:style="{ width: app.menu.fixedMix ? theme.menuStyle.width + 'px' : '0px' }"
|
|
>
|
|
<mix-menu-drawer :visible="drawerVisible" :active-route-name="activeParentRouteName" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed } from 'vue';
|
|
import type { VNodeChild } from 'vue';
|
|
import { NScrollbar } from 'naive-ui';
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
import { useAppStore, useThemeStore } from '@/store';
|
|
import { menus } from '@/router';
|
|
import { routeNameWatcher } from '@/composables';
|
|
import { useBoolean } from '@/hooks';
|
|
import { MixMenu, MixMenuCollapse, MixMenuDrawer } from './components';
|
|
import GlobalLogo from '../GlobalLogo/index.vue';
|
|
|
|
const theme = useThemeStore();
|
|
const app = useAppStore();
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const { bool: drawerVisible, setTrue: openDrawer, setFalse: hideDrawer } = useBoolean();
|
|
|
|
const mixMenuWidth = computed(() => `${theme.menuStyle.mixWidth}px`);
|
|
const mixMenuCollapsedWidth = computed(() => `${theme.menuStyle.mixCollapsedWidth}px`);
|
|
|
|
const firstDegreeMenus = menus.map(item => {
|
|
const { routeName } = item;
|
|
const label = item.label as string;
|
|
const icon = item.icon! as () => VNodeChild;
|
|
const isSingle = !(item.children && item.children.length);
|
|
|
|
return {
|
|
routeName,
|
|
label,
|
|
icon,
|
|
isSingle
|
|
};
|
|
});
|
|
|
|
const activeParentRouteName = ref(getActiveRouteName());
|
|
|
|
function getActiveRouteName() {
|
|
let name = '';
|
|
const menuMatched = route.matched.filter(item => !item.meta.isNotMenu);
|
|
if (menuMatched.length) {
|
|
name = menuMatched[0].name as string;
|
|
}
|
|
return name;
|
|
}
|
|
|
|
function handleMixMenu(routeName: string, isSingle: boolean) {
|
|
activeParentRouteName.value = routeName;
|
|
if (isSingle) {
|
|
router.push({ name: routeName });
|
|
} else {
|
|
openDrawer();
|
|
}
|
|
}
|
|
|
|
function handleMouseLeaveMenu() {
|
|
activeParentRouteName.value = getActiveRouteName();
|
|
hideDrawer();
|
|
}
|
|
|
|
routeNameWatcher(() => {
|
|
activeParentRouteName.value = getActiveRouteName();
|
|
});
|
|
</script>
|
|
<style scoped>
|
|
.mix-menu_width {
|
|
width: v-bind(mixMenuWidth);
|
|
}
|
|
.mix-menu_collapsed-width {
|
|
width: v-bind(mixMenuCollapsedWidth);
|
|
}
|
|
</style>
|