default-layout.vue 4.8 KB

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