NavHorizontal.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <script setup lang="ts">
  2. import { emitter } from "@/utils/mitt";
  3. import { useNav } from "@/layout/hooks/useNav";
  4. import LaySearch from "../lay-search/index.vue";
  5. import LayNotice from "../lay-notice/index.vue";
  6. import { responsiveStorageNameSpace } from "@/config";
  7. import { ref, nextTick, computed, onMounted, onBeforeUnmount } from "vue";
  8. import { storageLocal, isAllEmpty } from "@pureadmin/utils";
  9. import { useTranslationLang } from "../../hooks/useTranslationLang";
  10. import { usePermissionStoreHook } from "@/store/modules/permission";
  11. import LaySidebarItem from "../lay-sidebar/components/SidebarItem.vue";
  12. import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue";
  13. import GlobalizationIcon from "@/assets/svg/globalization.svg?component";
  14. import LogoutCircleRLine from "~icons/ri/logout-circle-r-line";
  15. import Setting from "~icons/ri/settings-3-line";
  16. import Check from "~icons/ep/check";
  17. const menuRef = ref();
  18. const menuKey = ref(0);
  19. const showLogo = ref(
  20. storageLocal().getItem<StorageConfigs>(
  21. `${responsiveStorageNameSpace()}configure`
  22. )?.showLogo ?? true
  23. );
  24. const { t, route, locale, translationCh, translationEn } =
  25. useTranslationLang(menuRef);
  26. const {
  27. title,
  28. logout,
  29. onPanel,
  30. getLogo,
  31. username,
  32. userAvatar,
  33. backTopMenu,
  34. avatarsStyle,
  35. getDropdownItemStyle,
  36. getDropdownItemClass
  37. } = useNav();
  38. const defaultActive = computed(() =>
  39. !isAllEmpty(route.meta?.activePath) ? route.meta.activePath : route.path
  40. );
  41. nextTick(() => {
  42. menuRef.value?.handleResize();
  43. });
  44. onMounted(() => {
  45. emitter.on("logoChange", key => {
  46. showLogo.value = key;
  47. });
  48. emitter.on("menuRefresh", () => {
  49. menuKey.value++;
  50. });
  51. });
  52. onBeforeUnmount(() => {
  53. emitter.off("logoChange");
  54. emitter.off("menuRefresh");
  55. });
  56. </script>
  57. <template>
  58. <div
  59. v-loading="usePermissionStoreHook().wholeMenus.length === 0"
  60. class="horizontal-header"
  61. >
  62. <div v-if="showLogo" class="horizontal-header-left" @click="backTopMenu">
  63. <img :src="getLogo()" alt="logo" />
  64. <span>{{ title }}</span>
  65. </div>
  66. <el-menu
  67. ref="menuRef"
  68. :key="menuKey"
  69. mode="horizontal"
  70. popper-class="pure-scrollbar"
  71. class="horizontal-header-menu"
  72. :default-active="defaultActive"
  73. >
  74. <LaySidebarItem
  75. v-for="route in usePermissionStoreHook().wholeMenus"
  76. :key="route.path"
  77. :item="route"
  78. :base-path="route.path"
  79. />
  80. </el-menu>
  81. <div class="horizontal-header-right">
  82. <!-- 菜单搜索 -->
  83. <LaySearch id="header-search" />
  84. <!-- 国际化 -->
  85. <el-dropdown id="header-translation" trigger="click">
  86. <GlobalizationIcon
  87. class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-hidden"
  88. />
  89. <template #dropdown>
  90. <el-dropdown-menu class="translation">
  91. <el-dropdown-item
  92. :style="getDropdownItemStyle(locale, 'zh')"
  93. :class="['dark:text-white!', getDropdownItemClass(locale, 'zh')]"
  94. @click="translationCh"
  95. >
  96. <span v-show="locale === 'zh'" class="check-zh">
  97. <IconifyIconOffline :icon="Check" />
  98. </span>
  99. 简体中文
  100. </el-dropdown-item>
  101. <el-dropdown-item
  102. :style="getDropdownItemStyle(locale, 'en')"
  103. :class="['dark:text-white!', getDropdownItemClass(locale, 'en')]"
  104. @click="translationEn"
  105. >
  106. <span v-show="locale === 'en'" class="check-en">
  107. <IconifyIconOffline :icon="Check" />
  108. </span>
  109. English
  110. </el-dropdown-item>
  111. </el-dropdown-menu>
  112. </template>
  113. </el-dropdown>
  114. <!-- 全屏 -->
  115. <LaySidebarFullScreen id="full-screen" />
  116. <!-- 消息通知 -->
  117. <LayNotice id="header-notice" />
  118. <!-- 退出登录 -->
  119. <el-dropdown trigger="click">
  120. <span class="el-dropdown-link navbar-bg-hover">
  121. <img :src="userAvatar" :style="avatarsStyle" />
  122. <p v-if="username" class="dark:text-white">{{ username }}</p>
  123. </span>
  124. <template #dropdown>
  125. <el-dropdown-menu class="logout">
  126. <el-dropdown-item @click="logout">
  127. <IconifyIconOffline
  128. :icon="LogoutCircleRLine"
  129. style="margin: 5px"
  130. />
  131. {{ t("buttons.pureLoginOut") }}
  132. </el-dropdown-item>
  133. </el-dropdown-menu>
  134. </template>
  135. </el-dropdown>
  136. <span
  137. class="set-icon navbar-bg-hover"
  138. :title="t('buttons.pureOpenSystemSet')"
  139. @click="onPanel"
  140. >
  141. <IconifyIconOffline :icon="Setting" />
  142. </span>
  143. </div>
  144. </div>
  145. </template>
  146. <style lang="scss" scoped>
  147. :deep(.el-loading-mask) {
  148. opacity: 0.45;
  149. }
  150. .translation {
  151. ::v-deep(.el-dropdown-menu__item) {
  152. padding: 5px 40px;
  153. }
  154. .check-zh {
  155. position: absolute;
  156. left: 20px;
  157. }
  158. .check-en {
  159. position: absolute;
  160. left: 20px;
  161. }
  162. }
  163. .logout {
  164. width: 120px;
  165. ::v-deep(.el-dropdown-menu__item) {
  166. display: inline-flex;
  167. flex-wrap: wrap;
  168. min-width: 100%;
  169. }
  170. }
  171. </style>