You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

195 lines
5.5 KiB

2 years ago
  1. <script setup lang="ts">
  2. import extraIcon from "./extraIcon.vue";
  3. import Search from "../search/index.vue";
  4. import Notice from "../notice/index.vue";
  5. import FullScreen from "./fullScreen.vue";
  6. import { isAllEmpty } from "@pureadmin/utils";
  7. import { useNav } from "@/layout/hooks/useNav";
  8. import { transformI18n } from "@/plugins/i18n";
  9. import { ref, toRaw, watch, onMounted, nextTick } from "vue";
  10. import { useRenderIcon } from "@/components/ReIcon/src/hooks";
  11. import { getParentPaths, findRouteByPath } from "@/router/utils";
  12. import { useTranslationLang } from "../../hooks/useTranslationLang";
  13. import { usePermissionStoreHook } from "@/store/modules/permission";
  14. import globalization from "@/assets/svg/globalization.svg?component";
  15. import LogoutCircleRLine from "@iconify-icons/ri/logout-circle-r-line";
  16. import Setting from "@iconify-icons/ri/settings-3-line";
  17. import Check from "@iconify-icons/ep/check";
  18. const menuRef = ref();
  19. const defaultActive = ref(null);
  20. const { t, route, locale, translationCh, translationEn } =
  21. useTranslationLang(menuRef);
  22. const {
  23. device,
  24. logout,
  25. onPanel,
  26. resolvePath,
  27. username,
  28. userAvatar,
  29. getDivStyle,
  30. avatarsStyle,
  31. getDropdownItemStyle,
  32. getDropdownItemClass
  33. } = useNav();
  34. function getDefaultActive(routePath) {
  35. const wholeMenus = usePermissionStoreHook().wholeMenus;
  36. /** 当前路由的父级路径 */
  37. const parentRoutes = getParentPaths(routePath, wholeMenus)[0];
  38. defaultActive.value = !isAllEmpty(route.meta?.activePath)
  39. ? route.meta.activePath
  40. : findRouteByPath(parentRoutes, wholeMenus)?.children[0]?.path;
  41. }
  42. onMounted(() => {
  43. getDefaultActive(route.path);
  44. });
  45. nextTick(() => {
  46. menuRef.value?.handleResize();
  47. });
  48. watch(
  49. () => [route.path, usePermissionStoreHook().wholeMenus],
  50. () => {
  51. getDefaultActive(route.path);
  52. }
  53. );
  54. </script>
  55. <template>
  56. <div
  57. v-if="device !== 'mobile'"
  58. v-loading="usePermissionStoreHook().wholeMenus.length === 0"
  59. class="horizontal-header"
  60. >
  61. <el-menu
  62. ref="menuRef"
  63. router
  64. mode="horizontal"
  65. popper-class="pure-scrollbar"
  66. class="horizontal-header-menu"
  67. :default-active="defaultActive"
  68. >
  69. <el-menu-item
  70. v-for="route in usePermissionStoreHook().wholeMenus"
  71. :key="route.path"
  72. :index="resolvePath(route) || route.redirect"
  73. >
  74. <template #title>
  75. <div
  76. v-if="toRaw(route.meta.icon)"
  77. :class="['sub-menu-icon', route.meta.icon]"
  78. >
  79. <component
  80. :is="useRenderIcon(route.meta && toRaw(route.meta.icon))"
  81. />
  82. </div>
  83. <div :style="getDivStyle">
  84. <span class="select-none">
  85. {{ transformI18n(route.meta.title) }}
  86. </span>
  87. <extraIcon :extraIcon="route.meta.extraIcon" />
  88. </div>
  89. </template>
  90. </el-menu-item>
  91. </el-menu>
  92. <div class="horizontal-header-right">
  93. <!-- 菜单搜索 -->
  94. <Search id="header-search" />
  95. <!-- 国际化 -->
  96. <el-dropdown id="header-translation" trigger="click">
  97. <globalization
  98. class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-none"
  99. />
  100. <template #dropdown>
  101. <el-dropdown-menu class="translation">
  102. <el-dropdown-item
  103. :style="getDropdownItemStyle(locale, 'zh')"
  104. :class="['dark:!text-white', getDropdownItemClass(locale, 'zh')]"
  105. @click="translationCh"
  106. >
  107. <span v-show="locale === 'zh'" class="check-zh">
  108. <IconifyIconOffline :icon="Check" />
  109. </span>
  110. 简体中文
  111. </el-dropdown-item>
  112. <el-dropdown-item
  113. :style="getDropdownItemStyle(locale, 'en')"
  114. :class="['dark:!text-white', getDropdownItemClass(locale, 'en')]"
  115. @click="translationEn"
  116. >
  117. <span v-show="locale === 'en'" class="check-en">
  118. <IconifyIconOffline :icon="Check" />
  119. </span>
  120. English
  121. </el-dropdown-item>
  122. </el-dropdown-menu>
  123. </template>
  124. </el-dropdown>
  125. <!-- 全屏 -->
  126. <FullScreen id="full-screen" />
  127. <!-- 消息通知 -->
  128. <Notice id="header-notice" />
  129. <!-- 退出登录 -->
  130. <el-dropdown trigger="click">
  131. <span class="el-dropdown-link navbar-bg-hover select-none">
  132. <img :src="userAvatar" :style="avatarsStyle" />
  133. <p v-if="username" class="dark:text-white">{{ username }}</p>
  134. </span>
  135. <template #dropdown>
  136. <el-dropdown-menu class="logout">
  137. <el-dropdown-item @click="logout">
  138. <IconifyIconOffline
  139. :icon="LogoutCircleRLine"
  140. style="margin: 5px"
  141. />
  142. {{ t("buttons.pureLoginOut") }}
  143. </el-dropdown-item>
  144. </el-dropdown-menu>
  145. </template>
  146. </el-dropdown>
  147. <span
  148. class="set-icon navbar-bg-hover"
  149. :title="t('buttons.pureOpenSystemSet')"
  150. @click="onPanel"
  151. >
  152. <IconifyIconOffline :icon="Setting" />
  153. </span>
  154. </div>
  155. </div>
  156. </template>
  157. <style lang="scss" scoped>
  158. :deep(.el-loading-mask) {
  159. opacity: 0.45;
  160. }
  161. .translation {
  162. ::v-deep(.el-dropdown-menu__item) {
  163. padding: 5px 40px;
  164. }
  165. .check-zh {
  166. position: absolute;
  167. left: 20px;
  168. }
  169. .check-en {
  170. position: absolute;
  171. left: 20px;
  172. }
  173. }
  174. .logout {
  175. width: 120px;
  176. ::v-deep(.el-dropdown-menu__item) {
  177. display: inline-flex;
  178. flex-wrap: wrap;
  179. min-width: 100%;
  180. }
  181. }
  182. </style>