layout.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <script lang="ts" setup>
  2. import { computed } from 'vue';
  3. import { PreferencesWidget } from '@vben/common-ui';
  4. import { $t } from '@vben/locales';
  5. import { VbenAdminLayout } from '@vben-core/layout-ui';
  6. import {
  7. preferences,
  8. updatePreferences,
  9. usePreferences,
  10. } from '@vben-core/preferences';
  11. import { VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
  12. import { mapTree } from '@vben-core/toolkit';
  13. import { MenuRecordRaw } from '@vben-core/typings';
  14. import { LayoutContent } from './content';
  15. import { LayoutFooter } from './footer';
  16. import { LayoutHeader } from './header';
  17. import {
  18. LayoutExtraMenu,
  19. LayoutMenu,
  20. LayoutMixedMenu,
  21. useExtraMenu,
  22. useMixedMenu,
  23. } from './menu';
  24. import { LayoutTabbar, LayoutTabbarTools } from './tabbar';
  25. import { Breadcrumb } from './widgets';
  26. defineOptions({ name: 'BasicLayout' });
  27. const { isDark, isHeaderNav, isMixedNav, isSideMixedNav, layout } =
  28. usePreferences();
  29. const headerMenuTheme = computed(() => {
  30. return isDark.value ? 'dark' : 'light';
  31. });
  32. const theme = computed(() => {
  33. const dark = isDark.value || preferences.app.semiDarkMenu;
  34. return dark ? 'dark' : 'light';
  35. });
  36. const logoClass = computed(() => {
  37. const { collapsed, collapsedShowTitle } = preferences.sidebar;
  38. return collapsedShowTitle && collapsed && !isMixedNav.value ? 'mx-auto' : '';
  39. });
  40. const isMenuRounded = computed(() => {
  41. return preferences.navigation.styleType === 'rounded';
  42. });
  43. const logoCollapse = computed(() => {
  44. if (isHeaderNav.value || isMixedNav.value) {
  45. return false;
  46. }
  47. const { isMobile } = preferences.app;
  48. const { collapsed } = preferences.sidebar;
  49. if (!collapsed && isMobile) {
  50. return false;
  51. }
  52. return collapsed || isSideMixedNav.value;
  53. });
  54. const showHeaderNav = computed(() => {
  55. return isHeaderNav.value || isMixedNav.value;
  56. });
  57. const {
  58. extraActiveMenu,
  59. extraMenus,
  60. handleDefaultSelect,
  61. handleMenuMouseEnter,
  62. handleMixedMenuSelect,
  63. handleSideMouseLeave,
  64. sidebarExtraVisible,
  65. } = useExtraMenu();
  66. const {
  67. handleMenuSelect,
  68. headerActive,
  69. headerMenus,
  70. sideActive,
  71. sideMenus,
  72. sideVisible,
  73. } = useMixedMenu();
  74. function wrapperMenus(menus: MenuRecordRaw[]) {
  75. return mapTree(menus, (item) => {
  76. return { ...item, name: $t(item.name) };
  77. });
  78. }
  79. function toggleSidebar() {
  80. updatePreferences({
  81. sidebar: {
  82. hidden: !preferences.sidebar.hidden,
  83. },
  84. });
  85. }
  86. </script>
  87. <template>
  88. <VbenAdminLayout
  89. v-model:sidebar-extra-visible="sidebarExtraVisible"
  90. :content-compact="preferences.app.contentCompact"
  91. :footer-enable="preferences.footer.enable"
  92. :footer-fixed="preferences.footer.fixed"
  93. :header-hidden="preferences.header.hidden"
  94. :header-mode="preferences.header.mode"
  95. :header-visible="preferences.header.enable"
  96. :is-mobile="preferences.app.isMobile"
  97. :layout="layout"
  98. :sidebar-collapse="preferences.sidebar.collapsed"
  99. :sidebar-collapse-show-title="preferences.sidebar.collapsedShowTitle"
  100. :sidebar-enable="sideVisible"
  101. :sidebar-expand-on-hover="preferences.sidebar.expandOnHover"
  102. :sidebar-extra-collapse="preferences.sidebar.extraCollapse"
  103. :sidebar-hidden="preferences.sidebar.hidden"
  104. :sidebar-semi-dark="preferences.app.semiDarkMenu"
  105. :sidebar-theme="theme"
  106. :sidebar-width="preferences.sidebar.width"
  107. :tabbar-enable="preferences.tabbar.enable"
  108. @side-mouse-leave="handleSideMouseLeave"
  109. @toggle-sidebar="toggleSidebar"
  110. @update:sidebar-collapse="
  111. (value: boolean) => updatePreferences({ sidebar: { collapsed: value } })
  112. "
  113. @update:sidebar-enable="
  114. (value: boolean) => updatePreferences({ sidebar: { enable: value } })
  115. "
  116. @update:sidebar-expand-on-hover="
  117. (value: boolean) =>
  118. updatePreferences({ sidebar: { expandOnHover: value } })
  119. "
  120. @update:sidebar-extra-collapse="
  121. (value: boolean) =>
  122. updatePreferences({ sidebar: { extraCollapse: value } })
  123. "
  124. >
  125. <template v-if="preferences.app.showPreference" #preferences>
  126. <PreferencesWidget />
  127. </template>
  128. <template #floating-groups>
  129. <VbenBackTop />
  130. <!-- <VbenFloatingButtonGroup /> -->
  131. </template>
  132. <!-- logo -->
  133. <template #logo>
  134. <VbenLogo
  135. :alt="preferences.app.name"
  136. :class="logoClass"
  137. :collapse="logoCollapse"
  138. :src="preferences.logo.source"
  139. :text="preferences.app.name"
  140. :theme="showHeaderNav ? headerMenuTheme : theme"
  141. />
  142. </template>
  143. <!-- 头部区域 -->
  144. <template #header>
  145. <LayoutHeader :theme="theme">
  146. <template
  147. v-if="!showHeaderNav && preferences.breadcrumb.enable"
  148. #breadcrumb
  149. >
  150. <Breadcrumb
  151. :hide-when-only-one="preferences.breadcrumb.hideOnlyOne"
  152. :show-home="preferences.breadcrumb.showHome"
  153. :show-icon="preferences.breadcrumb.showIcon"
  154. :type="preferences.breadcrumb.styleType"
  155. />
  156. </template>
  157. <template v-if="showHeaderNav" #menu>
  158. <LayoutMenu
  159. :default-active="headerActive"
  160. :menus="wrapperMenus(headerMenus)"
  161. :rounded="isMenuRounded"
  162. :theme="headerMenuTheme"
  163. class="w-full"
  164. mode="horizontal"
  165. @select="handleMenuSelect"
  166. />
  167. </template>
  168. <template #user-dropdown>
  169. <slot name="user-dropdown"></slot>
  170. </template>
  171. <template #notification>
  172. <slot name="notification"></slot>
  173. </template>
  174. </LayoutHeader>
  175. </template>
  176. <!-- 侧边菜单区域 -->
  177. <template #menu>
  178. <LayoutMenu
  179. :accordion="preferences.navigation.accordion"
  180. :collapse="preferences.sidebar.collapsed"
  181. :collapse-show-title="preferences.sidebar.collapsedShowTitle"
  182. :default-active="sideActive"
  183. :menus="wrapperMenus(sideMenus)"
  184. :rounded="isMenuRounded"
  185. :theme="theme"
  186. mode="vertical"
  187. @select="handleMenuSelect"
  188. />
  189. </template>
  190. <template #mixed-menu>
  191. <LayoutMixedMenu
  192. :active-path="extraActiveMenu"
  193. :collapse="!preferences.sidebar.collapsedShowTitle"
  194. :menus="wrapperMenus(headerMenus)"
  195. :rounded="isMenuRounded"
  196. :theme="theme"
  197. @default-select="handleDefaultSelect"
  198. @enter="handleMenuMouseEnter"
  199. @select="handleMixedMenuSelect"
  200. />
  201. </template>
  202. <!-- 侧边额外区域 -->
  203. <template #side-extra>
  204. <LayoutExtraMenu
  205. :accordion="preferences.navigation.accordion"
  206. :collapse="preferences.sidebar.extraCollapse"
  207. :menus="wrapperMenus(extraMenus)"
  208. :rounded="isMenuRounded"
  209. :theme="theme"
  210. />
  211. </template>
  212. <template #side-extra-title>
  213. <VbenLogo
  214. v-if="preferences.logo.enable"
  215. :alt="preferences.app.name"
  216. :text="preferences.app.name"
  217. :theme="theme"
  218. />
  219. </template>
  220. <template #tabbar>
  221. <LayoutTabbar
  222. v-if="preferences.tabbar.enable"
  223. :show-icon="preferences.tabbar.showIcon"
  224. />
  225. </template>
  226. <template #tabbar-tools>
  227. <LayoutTabbarTools v-if="preferences.tabbar.enable" />
  228. </template>
  229. <!-- 主体内容 -->
  230. <template #content>
  231. <LayoutContent />
  232. </template>
  233. <!-- 页脚 -->
  234. <template v-if="preferences.footer.enable" #footer>
  235. <LayoutFooter v-if="preferences.app.copyright">
  236. {{ preferences.app.copyright }}
  237. </LayoutFooter>
  238. </template>
  239. </VbenAdminLayout>
  240. </template>