MenuView.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <script setup lang="ts">
  2. import { useRoute, useRouter } from 'vue-router'
  3. import { useUserStore } from '@/stores/modules/user'
  4. const route = useRoute()
  5. const router = useRouter()
  6. const userStore = useUserStore()
  7. const isCollapse = defineModel<boolean>()
  8. // [
  9. // {
  10. // index: '1',
  11. // label: 'Dashboard',
  12. // icon: 'icon_data_fill_b',
  13. // path: '/dashboard'
  14. // },
  15. // {
  16. // index: '3',
  17. // label: 'Booking',
  18. // icon: 'icon_booking__fill_b',
  19. // path: '/booking'
  20. // },
  21. // {
  22. // index: '4',
  23. // label: 'Tracking',
  24. // icon: 'icon_tracking__fill_b',
  25. // path: '/tracking'
  26. // },
  27. // {
  28. // index: '6',
  29. // label: 'System Management',
  30. // icon: 'icon_system__management_fill_b',
  31. // type: 'list',
  32. // children: [
  33. // {
  34. // index: '5-4',
  35. // label: 'Operation Log',
  36. // path: '/Operationlog'
  37. // }
  38. // ]
  39. // }
  40. // ]
  41. const menuList = ref()
  42. watch(
  43. () => userStore.username,
  44. () => {
  45. getMenuList()
  46. }
  47. )
  48. const getMenuList = () => {
  49. $api.getMenuList().then((res) => {
  50. if (res.code === 200) {
  51. menuList.value = res.data
  52. }
  53. })
  54. }
  55. getMenuList()
  56. //监听窗口大小
  57. const handler = () => {
  58. return (() => {
  59. let screenWidth = document.body.clientWidth
  60. if (screenWidth < 1400) {
  61. isCollapse.value = true
  62. } else {
  63. isCollapse.value = false
  64. }
  65. })()
  66. }
  67. const listeningWindow = () => {
  68. window.addEventListener('resize', handler)
  69. }
  70. const unListeningWindow = () => {
  71. window.removeEventListener('resize', handler)
  72. }
  73. watchEffect(() => {
  74. listeningWindow()
  75. })
  76. onUnmounted(() => {
  77. unListeningWindow()
  78. })
  79. const activeMenu = ref()
  80. activeMenu.value = (route.meta?.activeMenu as string) || route.path
  81. // 未登录白名单
  82. const whiteList = ['/login', '/public-tracking', '/public-tracking/detail', '/reset-password']
  83. // 判断是否允许跳转
  84. const isAllowJump = (path: any) => {
  85. // 判断是否登录
  86. if (!whiteList.includes(path) && !localStorage.getItem('username')) {
  87. ElMessage.warning({
  88. message: 'Please log in to use this feature.',
  89. grouping: true
  90. })
  91. activeMenu.value = route.path // 保持选中状态不变
  92. return false
  93. }
  94. return true
  95. }
  96. // 路由后置守卫
  97. router.afterEach(() => {
  98. activeMenu.value = (route.meta?.activeMenu as string) || route.path
  99. })
  100. const isVisible = ref(false)
  101. const emits = defineEmits(['changeVisible'])
  102. // 路由跳转函数
  103. const changeRouter = (path: any) => {
  104. if (sessionStorage.getItem('searchTableQeury') == '{}') {
  105. sessionStorage.removeItem('searchTableQeury')
  106. }
  107. if (sessionStorage.getItem('searchTableQeuryTracking') == '{}') {
  108. sessionStorage.removeItem('searchTableQeuryTracking')
  109. }
  110. isVisible.value = false
  111. emits('changeVisible', isVisible.value)
  112. isVisible.value = false
  113. let toPath = path
  114. if (path === '/tracking' && !localStorage.getItem('username')) {
  115. toPath = '/public-tracking'
  116. }
  117. // 如果允许跳转,执行跳转
  118. if (isAllowJump(toPath)) {
  119. router.push(toPath)
  120. } else {
  121. // 如果不允许跳转,保持当前 activeMenu 不变
  122. nextTick(() => {
  123. activeMenu.value = (route.meta?.activeMenu as string) || route.path // 确保菜单栏选中状态为当前路径
  124. })
  125. }
  126. }
  127. const handleCollapseClick = () => {
  128. isCollapse.value = !isCollapse.value
  129. }
  130. const menuRef = ref()
  131. </script>
  132. <template>
  133. <el-menu
  134. ref="menuRef"
  135. class="layout-menu"
  136. @select="changeRouter"
  137. :default-active="activeMenu"
  138. :collapse="isCollapse"
  139. >
  140. <template v-for="item in menuList" :key="item.index">
  141. <el-menu-item
  142. :class="{
  143. 'clear-active-style': route.path === '/login' || route.path === '/reset-password'
  144. }"
  145. v-if="item.type !== 'list'"
  146. :index="item.path"
  147. >
  148. <span class="font_family" :class="[`icon-${item.icon}`]"></span>
  149. <template #title>{{ item.label }}</template>
  150. </el-menu-item>
  151. <el-sub-menu v-else :index="item.path">
  152. <template #title>
  153. <div class="font_family" style="font-size: 16px" :class="[`icon-${item.icon}`]"></div>
  154. <span>{{ item.label }}</span>
  155. </template>
  156. <template v-for="childrenItem in item.children" :key="childrenItem.index">
  157. <el-menu-item :index="childrenItem.path">{{ childrenItem.label }}</el-menu-item>
  158. </template>
  159. </el-sub-menu>
  160. </template>
  161. </el-menu>
  162. <div class="collapse-icon">
  163. <div @click="handleCollapseClick">
  164. <span
  165. :style="{ transform: isCollapse ? 'rotate(0deg)' : 'rotate(180deg)' }"
  166. class="font_family icon-icon_menu_collapse_b"
  167. ></span>
  168. </div>
  169. </div>
  170. </template>
  171. <style lang="scss" scoped>
  172. .layout-menu {
  173. height: calc(100% - 120px);
  174. border-bottom: 1px solid var(--color-border);
  175. border-right: none;
  176. .font_family {
  177. margin-left: 4px;
  178. margin-right: 8px;
  179. }
  180. }
  181. .collapse-icon {
  182. display: flex;
  183. justify-content: flex-end;
  184. align-items: center;
  185. height: 56px;
  186. padding-right: 10px;
  187. div {
  188. display: flex;
  189. justify-content: center;
  190. align-items: center;
  191. width: 42px;
  192. height: 100%;
  193. cursor: pointer;
  194. }
  195. }
  196. .el-menu-item.is-active {
  197. background-color: var(--color-mune-active-bg);
  198. color: var(--color-theme);
  199. font-weight: 700;
  200. & > span {
  201. color: var(--color-theme);
  202. }
  203. }
  204. .el-menu-item {
  205. height: 40px;
  206. margin: 0 12px 2px;
  207. padding-left: 8px !important;
  208. border-radius: 6px;
  209. &:hover {
  210. background-color: var(--color-mune-active-bg);
  211. }
  212. :deep(.el-menu-tooltip__trigger) {
  213. padding-left: 8px;
  214. }
  215. }
  216. li.clear-active-style {
  217. background-color: transparent !important;
  218. color: var(--color-neutral-1) !important;
  219. font-weight: normal !important;
  220. & > span {
  221. color: var(--color-neutral-1) !important;
  222. }
  223. }
  224. :deep(.el-sub-menu__title) {
  225. height: 40px;
  226. margin: 0 12px;
  227. padding-left: 8px !important;
  228. line-height: 40px;
  229. &:hover {
  230. background-color: var(--color-mune-active-bg);
  231. }
  232. }
  233. .el-sub-menu {
  234. margin-bottom: 2px;
  235. .el-menu-item {
  236. padding-left: 36px !important;
  237. }
  238. }
  239. </style>