vertical.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <script setup lang="ts">
  2. import Logo from "./logo.vue";
  3. import { useRoute } from "vue-router";
  4. import { emitter } from "@/utils/mitt";
  5. import SidebarItem from "./sidebarItem.vue";
  6. import LeftCollapse from "./leftCollapse.vue";
  7. import { useNav } from "@/layout/hooks/useNav";
  8. import CenterCollapse from "./centerCollapse.vue";
  9. import { responsiveStorageNameSpace } from "@/config";
  10. import { storageLocal, isAllEmpty } from "@pureadmin/utils";
  11. import { findRouteByPath, getParentPaths } from "@/router/utils";
  12. import { usePermissionStoreHook } from "@/store/modules/permission";
  13. import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue";
  14. const route = useRoute();
  15. const isShow = ref(false);
  16. const showLogo = ref(
  17. storageLocal().getItem<StorageConfigs>(
  18. `${responsiveStorageNameSpace()}configure`
  19. )?.showLogo ?? true
  20. );
  21. const {
  22. device,
  23. pureApp,
  24. isCollapse,
  25. tooltipEffect,
  26. menuSelect,
  27. toggleSideBar
  28. } = useNav();
  29. const subMenuData = ref([]);
  30. const menuData = computed(() => {
  31. return pureApp.layout === "mix" && device.value !== "mobile"
  32. ? subMenuData.value
  33. : usePermissionStoreHook().wholeMenus;
  34. });
  35. const loading = computed(() =>
  36. pureApp.layout === "mix" ? false : menuData.value.length === 0 ? true : false
  37. );
  38. const defaultActive = computed(() =>
  39. !isAllEmpty(route.meta?.activePath) ? route.meta.activePath : route.path
  40. );
  41. function getSubMenuData() {
  42. let path = "";
  43. path = defaultActive.value;
  44. subMenuData.value = [];
  45. // path的上级路由组成的数组
  46. const parentPathArr = getParentPaths(
  47. path,
  48. usePermissionStoreHook().wholeMenus
  49. );
  50. // 当前路由的父级路由信息
  51. const parenetRoute = findRouteByPath(
  52. parentPathArr[0] || path,
  53. usePermissionStoreHook().wholeMenus
  54. );
  55. if (!parenetRoute?.children) return;
  56. subMenuData.value = parenetRoute?.children;
  57. }
  58. watch(
  59. () => [route.path, usePermissionStoreHook().wholeMenus],
  60. () => {
  61. if (route.path.includes("/redirect")) return;
  62. getSubMenuData();
  63. menuSelect(route.path);
  64. }
  65. );
  66. onMounted(() => {
  67. getSubMenuData();
  68. emitter.on("logoChange", key => {
  69. showLogo.value = key;
  70. });
  71. });
  72. onBeforeUnmount(() => {
  73. // 解绑`logoChange`公共事件,防止多次触发
  74. emitter.off("logoChange");
  75. });
  76. </script>
  77. <template>
  78. <div
  79. v-loading="loading"
  80. :class="['sidebar-container', showLogo ? 'has-logo' : 'no-logo']"
  81. @mouseenter.prevent="isShow = true"
  82. @mouseleave.prevent="isShow = false"
  83. >
  84. <Logo v-if="showLogo" :collapse="isCollapse" />
  85. <el-scrollbar
  86. wrap-class="scrollbar-wrapper"
  87. :class="[device === 'mobile' ? 'mobile' : 'pc']"
  88. >
  89. <el-menu
  90. router
  91. unique-opened
  92. mode="vertical"
  93. popper-class="pure-scrollbar"
  94. class="outer-most select-none"
  95. :collapse="isCollapse"
  96. :collapse-transition="false"
  97. :popper-effect="tooltipEffect"
  98. :default-active="defaultActive"
  99. >
  100. <sidebar-item
  101. v-for="routes in menuData"
  102. :key="routes.path"
  103. :item="routes"
  104. :base-path="routes.path"
  105. class="outer-most select-none"
  106. />
  107. </el-menu>
  108. </el-scrollbar>
  109. <CenterCollapse
  110. v-if="device !== 'mobile' && (isShow || isCollapse)"
  111. :is-active="pureApp.sidebar.opened"
  112. @toggleClick="toggleSideBar"
  113. />
  114. <LeftCollapse
  115. v-if="device !== 'mobile'"
  116. :is-active="pureApp.sidebar.opened"
  117. @toggleClick="toggleSideBar"
  118. />
  119. </div>
  120. </template>
  121. <style scoped>
  122. :deep(.el-loading-mask) {
  123. opacity: 0.45;
  124. }
  125. </style>