layout.vue 7.1 KB

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