NavMix.vue 6.0 KB

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