default-layout.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <a-layout class="layout" :class="{ mobile: appStore.hideMenu }">
  3. <div v-if="navbar" class="layout-navbar">
  4. <NavBar />
  5. </div>
  6. <a-layout class="layout-main">
  7. <a-layout-sider
  8. v-if="renderMenu"
  9. v-show="!hideMenu"
  10. class="layout-sider"
  11. breakpoint="xl"
  12. :collapsed="collapsed"
  13. :collapsible="true"
  14. :width="menuWidth"
  15. :style="{ paddingTop: navbar ? '60px' : '' }"
  16. :hide-trigger="true"
  17. @collapse="setCollapsed"
  18. >
  19. <div class="menu-wrapper">
  20. <Menu />
  21. </div>
  22. </a-layout-sider>
  23. <a-drawer
  24. v-if="hideMenu"
  25. :visible="drawerVisible"
  26. placement="left"
  27. :footer="false"
  28. mask-closable
  29. :closable="false"
  30. @cancel="drawerCancel"
  31. >
  32. <Menu />
  33. </a-drawer>
  34. <a-layout class="layout-content" :style="paddingStyle">
  35. <TabBar v-if="appStore.tabBar" />
  36. <a-layout-content>
  37. <PageLayout />
  38. </a-layout-content>
  39. <Footer v-if="footer" />
  40. </a-layout>
  41. </a-layout>
  42. </a-layout>
  43. </template>
  44. <script lang="ts" setup>
  45. import { ref, computed, watch, provide, onMounted } from 'vue';
  46. import { useRouter, useRoute } from 'vue-router';
  47. import { useAppStore, useUserStore } from '@/store';
  48. import NavBar from '@/components/navbar/index.vue';
  49. import Menu from '@/components/menu/index.vue';
  50. import Footer from '@/components/footer/index.vue';
  51. import TabBar from '@/components/tab-bar/index.vue';
  52. import usePermission from '@/hooks/permission';
  53. import useResponsive from '@/hooks/responsive';
  54. import PageLayout from './page-layout.vue';
  55. const isInit = ref(false);
  56. const appStore = useAppStore();
  57. const userStore = useUserStore();
  58. const router = useRouter();
  59. const route = useRoute();
  60. const permission = usePermission();
  61. useResponsive(true);
  62. const navbarHeight = `60px`;
  63. const navbar = computed(() => appStore.navbar);
  64. const renderMenu = computed(() => appStore.menu && !appStore.topMenu);
  65. const hideMenu = computed(() => appStore.hideMenu);
  66. const footer = computed(() => appStore.footer);
  67. const menuWidth = computed(() => {
  68. return appStore.menuCollapse ? 48 : appStore.menuWidth;
  69. });
  70. const collapsed = computed(() => {
  71. return appStore.menuCollapse;
  72. });
  73. const paddingStyle = computed(() => {
  74. const paddingLeft =
  75. renderMenu.value && !hideMenu.value
  76. ? { paddingLeft: `${menuWidth.value}px` }
  77. : {};
  78. const paddingTop = navbar.value ? { paddingTop: navbarHeight } : {};
  79. return { ...paddingLeft, ...paddingTop };
  80. });
  81. const setCollapsed = (val: boolean) => {
  82. if (!isInit.value) return; // for page initialization menu state problem
  83. appStore.updateSettings({ menuCollapse: val });
  84. };
  85. watch(
  86. () => userStore.role,
  87. (roleValue) => {
  88. if (roleValue && !permission.accessRouter(route))
  89. router.push({ name: 'notFound' });
  90. }
  91. );
  92. const drawerVisible = ref(false);
  93. const drawerCancel = () => {
  94. drawerVisible.value = false;
  95. };
  96. provide('toggleDrawerMenu', () => {
  97. drawerVisible.value = !drawerVisible.value;
  98. });
  99. onMounted(() => {
  100. isInit.value = true;
  101. });
  102. </script>
  103. <style scoped lang="scss">
  104. $nav-size-height: 60px;
  105. $layout-max-width: 1100px;
  106. .layout,
  107. .layout-main {
  108. width: 100%;
  109. height: 100%;
  110. }
  111. .layout-navbar {
  112. position: fixed;
  113. top: 0;
  114. left: 0;
  115. z-index: 100;
  116. width: 100%;
  117. height: $nav-size-height;
  118. }
  119. .layout-sider {
  120. position: fixed;
  121. top: 0;
  122. left: 0;
  123. z-index: 99;
  124. height: 100%;
  125. transition: all 0.2s cubic-bezier(0.34, 0.69, 0.1, 1);
  126. &::after {
  127. position: absolute;
  128. top: 0;
  129. right: -1px;
  130. display: block;
  131. width: 1px;
  132. height: 100%;
  133. background-color: var(--color-border);
  134. content: '';
  135. }
  136. > :deep(.arco-layout-sider-children) {
  137. overflow-y: hidden;
  138. }
  139. }
  140. .menu-wrapper {
  141. height: 100%;
  142. overflow: auto;
  143. overflow-x: hidden;
  144. :deep(.arco-menu) {
  145. ::-webkit-scrollbar {
  146. width: 12px;
  147. height: 4px;
  148. }
  149. ::-webkit-scrollbar-thumb {
  150. border: 4px solid transparent;
  151. background-clip: padding-box;
  152. border-radius: 7px;
  153. background-color: var(--color-text-4);
  154. }
  155. ::-webkit-scrollbar-thumb:hover {
  156. background-color: var(--color-text-3);
  157. }
  158. }
  159. }
  160. .layout-content {
  161. height: 100vh;
  162. overflow-y: auto;
  163. overflow-x: hidden;
  164. background-color: var(--color-fill-2);
  165. transition: padding 0.2s cubic-bezier(0.34, 0.69, 0.1, 1);
  166. > .arco-layout-content {
  167. height: 100%;
  168. }
  169. }
  170. </style>