This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div :class="sideNavCls">
|
||||
<t-menu
|
||||
:class="menuCls"
|
||||
:theme="theme"
|
||||
:value="active"
|
||||
:collapsed="collapsed"
|
||||
:expanded="expanded"
|
||||
:expand-mutex="menuAutoCollapsed"
|
||||
@expand="onExpanded"
|
||||
>
|
||||
<template #logo>
|
||||
<span v-if="showLogo" :class="`${prefix}-side-nav-logo-wrapper brand-logo`" @click="goHome">
|
||||
<span class="brand-name" :class="{ 'brand-name--compact': collapsed }">财务系统</span>
|
||||
</span>
|
||||
</template>
|
||||
<menu-content :nav-data="menu" />
|
||||
<template #operations>
|
||||
<t-button
|
||||
variant="text"
|
||||
shape="square"
|
||||
:aria-label="collapsed ? '展开侧栏' : '收起侧栏'"
|
||||
:title="collapsed ? '展开侧栏' : '收起侧栏'"
|
||||
@click="changeCollapsed"
|
||||
>
|
||||
<template #icon><t-icon name="view-list" /></template>
|
||||
</t-button>
|
||||
<span v-show="!isCompact" :class="versionCls">
|
||||
{{ !collapsed ? t('common.appName') : '' }} {{ pgk.version }}
|
||||
</span>
|
||||
</template>
|
||||
</t-menu>
|
||||
<div :class="`${prefix}-side-nav-placeholder${collapsed ? '-hidden' : ''}`"></div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import difference from 'lodash/difference';
|
||||
import remove from 'lodash/remove';
|
||||
import union from 'lodash/union';
|
||||
import type { MenuValue } from 'tdesign-vue-next';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { prefix } from '@/config/global';
|
||||
import { t } from '@/locales';
|
||||
import { getActive } from '@/router';
|
||||
import { useSettingStore } from '@/store';
|
||||
import type { MenuRoute, ModeType } from '@/types/interface';
|
||||
|
||||
import pgk from '../../../package.json';
|
||||
import MenuContent from './MenuContent.vue';
|
||||
|
||||
const { menu, showLogo, isFixed, layout, theme, isCompact } = defineProps({
|
||||
menu: {
|
||||
type: Array as PropType<MenuRoute[]>,
|
||||
default: () => [],
|
||||
},
|
||||
showLogo: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
isFixed: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
layout: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
headerHeight: {
|
||||
type: String as PropType<string>,
|
||||
default: '64px',
|
||||
},
|
||||
theme: {
|
||||
type: String as PropType<ModeType>,
|
||||
default: 'light',
|
||||
},
|
||||
isCompact: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const MIN_POINT = 992 - 1;
|
||||
|
||||
const collapsed = computed(() => useSettingStore().isSidebarCompact);
|
||||
const menuAutoCollapsed = computed(() => useSettingStore().menuAutoCollapsed);
|
||||
|
||||
const active = computed(() => getActive());
|
||||
|
||||
const expanded = ref<MenuValue[]>([]);
|
||||
|
||||
const getExpanded = () => {
|
||||
const path = getActive();
|
||||
const parts = path.split('/').slice(1);
|
||||
const result = parts.map((_, index) => `/${parts.slice(0, index + 1).join('/')}`);
|
||||
|
||||
const allRoutes = router.getRoutes();
|
||||
const allRoutesExpanded = allRoutes.filter((item) => item.meta?.expanded).map((item) => item.path);
|
||||
|
||||
expanded.value = menuAutoCollapsed.value
|
||||
? union(result, allRoutesExpanded)
|
||||
: union(result, expanded.value, allRoutesExpanded);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => active.value,
|
||||
() => {
|
||||
getExpanded();
|
||||
},
|
||||
);
|
||||
|
||||
const onExpanded = (value: MenuValue[]) => {
|
||||
const currentOperationMenu = difference(expanded.value, value);
|
||||
const allExpanded = union(value, expanded.value);
|
||||
remove(allExpanded, (item) => currentOperationMenu.includes(item));
|
||||
expanded.value = allExpanded;
|
||||
};
|
||||
|
||||
const changeCollapsed = () => {
|
||||
settingStore.updateConfig({
|
||||
isSidebarCompact: !settingStore.isSidebarCompact,
|
||||
});
|
||||
};
|
||||
const sideMode = computed(() => {
|
||||
return theme === 'dark';
|
||||
});
|
||||
const versionCls = computed(() => {
|
||||
return [
|
||||
`version-container`,
|
||||
{
|
||||
[`${prefix}-side-nav-dark`]: sideMode.value,
|
||||
},
|
||||
];
|
||||
});
|
||||
const sideNavCls = computed(() => {
|
||||
return [
|
||||
`${prefix}-sidebar-layout`,
|
||||
{
|
||||
[`${prefix}-sidebar-compact`]: isCompact,
|
||||
},
|
||||
];
|
||||
});
|
||||
const menuCls = computed(() => {
|
||||
return [
|
||||
`${prefix}-side-nav`,
|
||||
{
|
||||
[`${prefix}-side-nav-no-logo`]: !showLogo,
|
||||
[`${prefix}-side-nav-no-fixed`]: !isFixed,
|
||||
[`${prefix}-side-nav-mix-fixed`]: layout === 'mix' && isFixed,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
const autoCollapsed = () => {
|
||||
const isCompact = window.innerWidth <= MIN_POINT;
|
||||
settingStore.updateConfig({
|
||||
isSidebarCompact: isCompact,
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getExpanded();
|
||||
autoCollapsed();
|
||||
|
||||
window.addEventListener('resize', autoCollapsed);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', autoCollapsed);
|
||||
});
|
||||
|
||||
const goHome = () => {
|
||||
router.push('/role-select');
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.brand-logo {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
.brand-name {
|
||||
color: var(--td-text-color-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand-name--compact {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user