ruoyi-plus-vben5/packages/effects/layouts/src/basic/layout.vue

334 lines
9.1 KiB
Vue
Raw Normal View History

2024-05-19 21:20:42 +08:00
<script lang="ts" setup>
import type { MenuRecordRaw } from '@vben/types';
import { computed, useSlots, watch } from 'vue';
2024-06-08 19:49:06 +08:00
import { useWatermark } from '@vben/hooks';
import { $t } from '@vben/locales';
2024-06-01 23:15:29 +08:00
import {
preferences,
updatePreferences,
usePreferences,
} from '@vben/preferences';
2024-07-30 21:10:28 +08:00
import { useLockStore, useUserStore } from '@vben/stores';
import { mapTree } from '@vben/utils';
import { VbenAdminLayout } from '@vben-core/layout-ui';
import { Toaster, VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
2024-05-19 21:20:42 +08:00
import { Breadcrumb, CheckUpdates, Preferences } from '../widgets';
import { LayoutContent, LayoutContentSpinner } from './content';
import { Copyright } from './copyright';
2024-05-19 21:20:42 +08:00
import { LayoutFooter } from './footer';
import { LayoutHeader } from './header';
import {
LayoutExtraMenu,
LayoutMenu,
LayoutMixedMenu,
useExtraMenu,
useMixedMenu,
} from './menu';
import { LayoutTabbar } from './tabbar';
2024-05-19 21:20:42 +08:00
defineOptions({ name: 'BasicLayout' });
const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
const {
isDark,
isHeaderNav,
isMixedNav,
isMobile,
isSideMixedNav,
layout,
preferencesButtonPosition,
sidebarCollapsed,
2024-08-14 20:37:21 +08:00
theme,
} = usePreferences();
2024-07-30 21:10:28 +08:00
const userStore = useUserStore();
const { updateWatermark } = useWatermark();
2024-07-30 21:10:28 +08:00
const lockStore = useLockStore();
2024-05-19 21:20:42 +08:00
2024-08-14 20:37:21 +08:00
const sidebarTheme = computed(() => {
const dark = isDark.value || preferences.theme.semiDarkSidebar;
2024-05-19 21:20:42 +08:00
return dark ? 'dark' : 'light';
});
const headerTheme = computed(() => {
const dark = isDark.value || preferences.theme.semiDarkHeader;
return dark ? 'dark' : 'light';
});
2024-05-19 21:20:42 +08:00
const logoClass = computed(() => {
const { collapsedShowTitle } = preferences.sidebar;
const classes: string[] = [];
if (collapsedShowTitle && sidebarCollapsed.value && !isMixedNav.value) {
classes.push('mx-auto');
2024-06-30 22:58:57 +08:00
}
2024-06-30 22:58:57 +08:00
if (isSideMixedNav.value) {
classes.push('flex-center');
2024-06-30 22:58:57 +08:00
}
return classes.join(' ');
2024-05-19 21:20:42 +08:00
});
const isMenuRounded = computed(() => {
2024-06-01 23:15:29 +08:00
return preferences.navigation.styleType === 'rounded';
2024-05-19 21:20:42 +08:00
});
const logoCollapsed = computed(() => {
if (isMobile.value) {
return true;
2024-05-19 21:20:42 +08:00
}
if (isHeaderNav.value || isMixedNav.value) {
2024-05-19 21:20:42 +08:00
return false;
}
return sidebarCollapsed.value || isSideMixedNav.value;
2024-05-19 21:20:42 +08:00
});
const showHeaderNav = computed(() => {
return !isMobile.value && (isHeaderNav.value || isMixedNav.value);
2024-05-19 21:20:42 +08:00
});
// 侧边多列菜单
2024-05-19 21:20:42 +08:00
const {
extraActiveMenu,
extraMenus,
handleDefaultSelect,
handleMenuMouseEnter,
handleMixedMenuSelect,
handleSideMouseLeave,
2024-06-09 15:39:11 +08:00
sidebarExtraVisible,
2024-05-19 21:20:42 +08:00
} = useExtraMenu();
const {
handleMenuSelect,
headerActive,
headerMenus,
sidebarActive,
sidebarMenus,
sidebarVisible,
2024-05-19 21:20:42 +08:00
} = useMixedMenu();
function wrapperMenus(menus: MenuRecordRaw[]) {
return mapTree(menus, (item) => {
2024-06-09 15:39:11 +08:00
return { ...item, name: $t(item.name) };
});
}
function toggleSidebar() {
updatePreferences({
sidebar: {
hidden: !preferences.sidebar.hidden,
},
});
}
function clearPreferencesAndLogout() {
emit('clearPreferencesAndLogout');
}
watch(
() => preferences.app.watermark,
async (val) => {
if (val) {
await updateWatermark({
content: `${userStore.userInfo?.username}`,
});
}
},
{
immediate: true,
},
);
const slots = useSlots();
const headerSlots = computed(() => {
return Object.keys(slots).filter((key) => key.startsWith('header-'));
});
2024-05-19 21:20:42 +08:00
</script>
<template>
<VbenAdminLayout
2024-06-09 15:39:11 +08:00
v-model:sidebar-extra-visible="sidebarExtraVisible"
2024-06-01 23:15:29 +08:00
:content-compact="preferences.app.contentCompact"
2024-06-09 13:31:43 +08:00
:footer-enable="preferences.footer.enable"
:footer-fixed="preferences.footer.fixed"
:header-hidden="preferences.header.hidden"
:header-mode="preferences.header.mode"
:header-theme="headerTheme"
:header-toggle-sidebar-button="preferences.widget.sidebarToggle"
2024-06-09 13:31:43 +08:00
:header-visible="preferences.header.enable"
2024-06-01 23:15:29 +08:00
:is-mobile="preferences.app.isMobile"
2024-05-19 21:20:42 +08:00
:layout="layout"
2024-06-09 15:39:11 +08:00
:sidebar-collapse="preferences.sidebar.collapsed"
:sidebar-collapse-show-title="preferences.sidebar.collapsedShowTitle"
:sidebar-enable="sidebarVisible"
2024-06-09 15:39:11 +08:00
:sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
:sidebar-extra-collapse="preferences.sidebar.extraCollapse"
:sidebar-hidden="preferences.sidebar.hidden"
2024-08-14 20:37:21 +08:00
:sidebar-theme="sidebarTheme"
2024-06-09 15:39:11 +08:00
:sidebar-width="preferences.sidebar.width"
:tabbar-enable="preferences.tabbar.enable"
2024-07-18 21:31:34 +08:00
:tabbar-height="preferences.tabbar.height"
2024-06-09 13:31:43 +08:00
@side-mouse-leave="handleSideMouseLeave"
2024-06-09 15:39:11 +08:00
@toggle-sidebar="toggleSidebar"
@update:sidebar-collapse="
(value: boolean) => updatePreferences({ sidebar: { collapsed: value } })
2024-06-09 12:53:38 +08:00
"
2024-06-09 15:39:11 +08:00
@update:sidebar-enable="
(value: boolean) => updatePreferences({ sidebar: { enable: value } })
"
@update:sidebar-expand-on-hover="
2024-06-09 12:53:38 +08:00
(value: boolean) =>
2024-06-09 13:31:43 +08:00
updatePreferences({ sidebar: { expandOnHover: value } })
2024-06-09 12:53:38 +08:00
"
2024-06-09 15:39:11 +08:00
@update:sidebar-extra-collapse="
2024-06-09 12:53:38 +08:00
(value: boolean) =>
2024-06-09 13:31:43 +08:00
updatePreferences({ sidebar: { extraCollapse: value } })
2024-06-09 12:53:38 +08:00
"
2024-05-19 21:20:42 +08:00
>
<!-- logo -->
<template #logo>
<VbenLogo
v-if="preferences.logo.enable"
2024-06-09 13:31:43 +08:00
:class="logoClass"
:collapsed="logoCollapsed"
2024-06-01 23:15:29 +08:00
:src="preferences.logo.source"
:text="preferences.app.name"
:theme="showHeaderNav ? headerTheme : theme"
2024-05-19 21:20:42 +08:00
/>
</template>
<!-- 头部区域 -->
<template #header>
<LayoutHeader :theme="theme">
<template
2024-06-01 23:15:29 +08:00
v-if="!showHeaderNav && preferences.breadcrumb.enable"
2024-05-19 21:20:42 +08:00
#breadcrumb
>
<Breadcrumb
2024-06-01 23:15:29 +08:00
:hide-when-only-one="preferences.breadcrumb.hideOnlyOne"
:show-home="preferences.breadcrumb.showHome"
2024-06-09 13:31:43 +08:00
:show-icon="preferences.breadcrumb.showIcon"
:type="preferences.breadcrumb.styleType"
2024-05-19 21:20:42 +08:00
/>
</template>
<template v-if="showHeaderNav" #menu>
<LayoutMenu
2024-06-09 13:31:43 +08:00
:default-active="headerActive"
:menus="wrapperMenus(headerMenus)"
2024-05-19 21:20:42 +08:00
:rounded="isMenuRounded"
:theme="headerTheme"
2024-06-09 13:31:43 +08:00
class="w-full"
mode="horizontal"
2024-05-19 21:20:42 +08:00
@select="handleMenuSelect"
/>
</template>
<template #user-dropdown>
<slot name="user-dropdown"></slot>
</template>
<template #notification>
<slot name="notification"></slot>
</template>
<template v-for="item in headerSlots" #[item]>
<slot :name="item"></slot>
</template>
2024-05-19 21:20:42 +08:00
</LayoutHeader>
</template>
<!-- 侧边菜单区域 -->
<template #menu>
<LayoutMenu
2024-06-01 23:15:29 +08:00
:accordion="preferences.navigation.accordion"
2024-06-09 15:39:11 +08:00
:collapse="preferences.sidebar.collapsed"
:collapse-show-title="preferences.sidebar.collapsedShowTitle"
:default-active="sidebarActive"
:menus="wrapperMenus(sidebarMenus)"
2024-06-09 13:31:43 +08:00
:rounded="isMenuRounded"
2024-08-14 20:37:21 +08:00
:theme="sidebarTheme"
2024-06-09 13:31:43 +08:00
mode="vertical"
2024-05-19 21:20:42 +08:00
@select="handleMenuSelect"
/>
</template>
<template #mixed-menu>
<!-- :collapse="!preferences.sidebar.collapsedShowTitle" -->
2024-05-19 21:20:42 +08:00
<LayoutMixedMenu
:active-path="extraActiveMenu"
2024-06-09 15:39:11 +08:00
:menus="wrapperMenus(headerMenus)"
2024-06-09 13:31:43 +08:00
:rounded="isMenuRounded"
2024-08-14 20:37:21 +08:00
:theme="sidebarTheme"
2024-05-19 21:20:42 +08:00
@default-select="handleDefaultSelect"
@enter="handleMenuMouseEnter"
2024-06-09 13:31:43 +08:00
@select="handleMixedMenuSelect"
2024-05-19 21:20:42 +08:00
/>
</template>
<!-- 侧边额外区域 -->
<template #side-extra>
<LayoutExtraMenu
2024-06-01 23:15:29 +08:00
:accordion="preferences.navigation.accordion"
:collapse="preferences.sidebar.extraCollapse"
2024-06-09 13:31:43 +08:00
:menus="wrapperMenus(extraMenus)"
:rounded="isMenuRounded"
2024-08-14 20:37:21 +08:00
:theme="sidebarTheme"
2024-05-19 21:20:42 +08:00
/>
</template>
<template #side-extra-title>
<VbenLogo
2024-06-01 23:15:29 +08:00
v-if="preferences.logo.enable"
:text="preferences.app.name"
2024-05-19 21:20:42 +08:00
:theme="theme"
/>
</template>
2024-06-09 15:39:11 +08:00
<template #tabbar>
<LayoutTabbar
2024-06-01 23:15:29 +08:00
v-if="preferences.tabbar.enable"
:show-icon="preferences.tabbar.showIcon"
2024-07-16 23:13:03 +08:00
:theme="theme"
2024-05-19 21:20:42 +08:00
/>
</template>
<!-- 主体内容 -->
<template #content>
<LayoutContent />
</template>
<template
v-if="preferences.transition.loading"
#content-overlay="{ overlayStyle }"
>
<LayoutContentSpinner :overlay-style="overlayStyle" />
</template>
2024-05-19 21:20:42 +08:00
<!-- 页脚 -->
2024-06-01 23:15:29 +08:00
<template v-if="preferences.footer.enable" #footer>
<LayoutFooter>
<Copyright
v-if="preferences.copyright.enable"
v-bind="preferences.copyright"
/>
2024-05-19 21:20:42 +08:00
</LayoutFooter>
</template>
<template #extra>
<slot name="extra"></slot>
<Toaster />
<CheckUpdates
v-if="preferences.app.enableCheckUpdates"
2024-07-29 23:56:59 +08:00
:check-updates-interval="preferences.app.checkUpdatesInterval"
/>
<Transition v-if="preferences.widget.lockScreen" name="slide-up">
2024-07-30 21:10:28 +08:00
<slot v-if="lockStore.isLockScreen" name="lock-screen"></slot>
</Transition>
2024-08-14 20:37:21 +08:00
<template v-if="preferencesButtonPosition.fixed">
2024-08-14 20:37:21 +08:00
<Preferences
class="z-100 fixed bottom-20 right-0"
2024-08-14 20:37:21 +08:00
@clear-preferences-and-logout="clearPreferencesAndLogout"
/>
</template>
<VbenBackTop />
</template>
2024-05-19 21:20:42 +08:00
</VbenAdminLayout>
</template>