index.vue 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <script setup lang="ts">
  2. import { useNav } from "@/layout/hooks/useNav";
  3. import LaySearch from "../lay-search/index.vue";
  4. import LayNotice from "../lay-notice/index.vue";
  5. import LayNavMix from "../lay-sidebar/NavMix.vue";
  6. import { useTranslationLang } from "@/layout/hooks/useTranslationLang";
  7. import LaySidebarFullScreen from "../lay-sidebar/components/SidebarFullScreen.vue";
  8. import LaySidebarBreadCrumb from "../lay-sidebar/components/SidebarBreadCrumb.vue";
  9. import GlobalizationIcon from "@/assets/svg/globalization.svg?component";
  10. import AccountSettingsIcon from "~icons/ri/user-settings-line";
  11. import LogoutCircleRLine from "~icons/ri/logout-circle-r-line";
  12. import Setting from "~icons/ri/settings-3-line";
  13. import Check from "~icons/ep/check";
  14. import Location from "~icons/ri/map-pin-line";
  15. import { getStationList } from "@/api/station";
  16. import { reactive, computed, onMounted } from "vue";
  17. const {
  18. layout,
  19. device,
  20. logout,
  21. onPanel,
  22. username,
  23. userAvatar,
  24. avatarsStyle,
  25. toAccountSettings,
  26. getDropdownItemStyle,
  27. getDropdownItemClass
  28. } = useNav();
  29. const { t, locale, translationCh, translationEn } = useTranslationLang();
  30. // Session 工具
  31. const Session = {
  32. get: (key: string) => {
  33. const value = sessionStorage.getItem(key);
  34. return value ? JSON.parse(value) : null;
  35. },
  36. set: (key: string, value: any) => {
  37. sessionStorage.setItem(key, JSON.stringify(value));
  38. }
  39. };
  40. const state = reactive({
  41. stationList: [] as any[],
  42. currentStationId: null as string | null,
  43. currentStationName: '' as string
  44. });
  45. // 加载站点列表
  46. const loadStationList = () => {
  47. getStationList({ pageNum: 1, pageSize: 1024 }).then((res: any) => {
  48. const list = res?.data?.list || res?.list || res?.data || res || [];
  49. state.stationList = list;
  50. // 获取当前选中的站点
  51. const savedStationId = Session.get("currentStationId");
  52. if (savedStationId && list.length > 0) {
  53. const currentStation = list.find((s: any) => s.stationId === savedStationId);
  54. if (currentStation) {
  55. state.currentStationId = currentStation.stationId;
  56. state.currentStationName = currentStation.stationName;
  57. } else {
  58. // 如果保存的站点不在列表中,选择第一个
  59. state.currentStationId = list[0]?.stationId;
  60. state.currentStationName = list[0]?.stationName;
  61. }
  62. } else if (list.length > 0) {
  63. // 默认选择第一个站点
  64. state.currentStationId = list[0]?.stationId;
  65. state.currentStationName = list[0]?.stationName;
  66. }
  67. }).catch(() => {
  68. console.warn('站点列表加载失败');
  69. });
  70. };
  71. // 切换站点
  72. const handleStationChange = (station: any) => {
  73. state.currentStationId = station.stationId;
  74. state.currentStationName = station.stationName;
  75. Session.set("currentStationId", station.stationId);
  76. // 刷新页面以加载新站点数据
  77. setTimeout(() => {
  78. window.location.reload();
  79. }, 300);
  80. };
  81. onMounted(() => {
  82. loadStationList();
  83. });
  84. </script>
  85. <template>
  86. <div class="navbar bg-[#fff] shadow-xs shadow-[rgba(0,21,41,0.08)]">
  87. <LaySidebarBreadCrumb
  88. v-if="layout !== 'mix' && device !== 'mobile'"
  89. class="breadcrumb-container"
  90. />
  91. <LayNavMix v-if="layout === 'mix'" />
  92. <div v-if="layout === 'vertical'" class="vertical-header-right">
  93. <!-- 站点切换 -->
  94. <el-dropdown id="header-station" trigger="click" @command="handleStationChange">
  95. <div class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-hidden flex items-center">
  96. <IconifyIconOffline :icon="Location" style="margin-right: 5px;" />
  97. <span class="dark:text-white truncate max-w-[150px]">{{ state.currentStationName || '选择站点' }}</span>
  98. </div>
  99. <template #dropdown>
  100. <el-dropdown-menu>
  101. <el-dropdown-item
  102. v-for="station in state.stationList"
  103. :key="station.stationId"
  104. :command="station"
  105. :disabled="state.currentStationId === station.stationId"
  106. >
  107. {{ station.stationName }}
  108. </el-dropdown-item>
  109. </el-dropdown-menu>
  110. </template>
  111. </el-dropdown>
  112. <!-- 菜单搜索 -->
  113. <LaySearch id="header-search" />
  114. <!-- 国际化 -->
  115. <el-dropdown id="header-translation" trigger="click">
  116. <GlobalizationIcon
  117. class="navbar-bg-hover w-[40px] h-[48px] p-[11px] cursor-pointer outline-hidden"
  118. />
  119. <template #dropdown>
  120. <el-dropdown-menu class="translation">
  121. <el-dropdown-item
  122. :style="getDropdownItemStyle(locale, 'zh')"
  123. :class="['dark:text-white!', getDropdownItemClass(locale, 'zh')]"
  124. @click="translationCh"
  125. >
  126. <IconifyIconOffline
  127. v-show="locale === 'zh'"
  128. class="check-zh"
  129. :icon="Check"
  130. />
  131. 简体中文
  132. </el-dropdown-item>
  133. <el-dropdown-item
  134. :style="getDropdownItemStyle(locale, 'en')"
  135. :class="['dark:text-white!', getDropdownItemClass(locale, 'en')]"
  136. @click="translationEn"
  137. >
  138. <span v-show="locale === 'en'" class="check-en">
  139. <IconifyIconOffline :icon="Check" />
  140. </span>
  141. English
  142. </el-dropdown-item>
  143. </el-dropdown-menu>
  144. </template>
  145. </el-dropdown>
  146. <!-- 全屏 -->
  147. <LaySidebarFullScreen id="full-screen" />
  148. <!-- 消息通知 -->
  149. <LayNotice id="header-notice" />
  150. <!-- 退出登录 -->
  151. <el-dropdown trigger="click">
  152. <span class="el-dropdown-link navbar-bg-hover select-none">
  153. <img :src="userAvatar" :style="avatarsStyle" />
  154. <p v-if="username" class="dark:text-white">{{ username }}</p>
  155. </span>
  156. <template #dropdown>
  157. <el-dropdown-menu class="logout">
  158. <el-dropdown-item @click="toAccountSettings">
  159. <IconifyIconOffline
  160. :icon="AccountSettingsIcon"
  161. style="margin: 5px"
  162. />
  163. {{ t("buttons.pureAccountSettings") }}
  164. </el-dropdown-item>
  165. <el-dropdown-item @click="logout">
  166. <IconifyIconOffline
  167. :icon="LogoutCircleRLine"
  168. style="margin: 5px"
  169. />
  170. {{ t("buttons.pureLoginOut") }}
  171. </el-dropdown-item>
  172. </el-dropdown-menu>
  173. </template>
  174. </el-dropdown>
  175. <span
  176. class="set-icon navbar-bg-hover"
  177. :title="t('buttons.pureOpenSystemSet')"
  178. @click="onPanel"
  179. >
  180. <IconifyIconOffline :icon="Setting" />
  181. </span>
  182. </div>
  183. </div>
  184. </template>
  185. <style lang="scss" scoped>
  186. .navbar {
  187. width: 100%;
  188. height: 48px;
  189. overflow: hidden;
  190. .hamburger-container {
  191. float: left;
  192. height: 100%;
  193. line-height: 48px;
  194. cursor: pointer;
  195. }
  196. .vertical-header-right {
  197. display: flex;
  198. align-items: center;
  199. justify-content: flex-end;
  200. min-width: 280px;
  201. height: 48px;
  202. color: #000000d9;
  203. .el-dropdown-link {
  204. display: flex;
  205. align-items: center;
  206. justify-content: space-around;
  207. height: 48px;
  208. padding: 10px;
  209. color: #000000d9;
  210. cursor: pointer;
  211. p {
  212. font-size: 14px;
  213. }
  214. img {
  215. width: 22px;
  216. height: 22px;
  217. border-radius: 50%;
  218. }
  219. }
  220. }
  221. .breadcrumb-container {
  222. float: left;
  223. margin-left: 16px;
  224. }
  225. }
  226. .translation {
  227. ::v-deep(.el-dropdown-menu__item) {
  228. padding: 5px 40px;
  229. }
  230. .check-zh {
  231. position: absolute;
  232. left: 20px;
  233. }
  234. .check-en {
  235. position: absolute;
  236. left: 20px;
  237. }
  238. }
  239. .logout {
  240. width: 120px;
  241. ::v-deep(.el-dropdown-menu__item) {
  242. display: inline-flex;
  243. flex-wrap: wrap;
  244. min-width: 100%;
  245. }
  246. }
  247. </style>