SiderBar.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <template>
  2. <el-aside class="siderbar_container" :width="isCollapse ? '72px' : '150px'">
  3. <div @click="toggleCollapse" class="collapse_box">
  4. <img v-if="isCollapse" src="@/assets/icon/open.svg" alt="">
  5. <img v-else src="@/assets/icon/close.svg" alt="">
  6. </div>
  7. <el-menu :collapse="isCollapse" router :default-active="activeMenuRoute">
  8. <el-menu-item v-for="item in menuItems" :key="item.route" :index="item.route">
  9. <template #default>
  10. <i class="iconfont" :class="item.icon"></i>
  11. <span v-if="!isCollapse">{{ item.title }}</span>
  12. </template>
  13. <template #title>
  14. <span v-if="isCollapse">{{ item.title }}</span>
  15. </template>
  16. </el-menu-item>
  17. </el-menu>
  18. </el-aside>
  19. </template>
  20. <script lang="ts">
  21. export default {
  22. name: 'SiderBar'
  23. }
  24. </script>
  25. <script lang="ts" setup>
  26. import { ref, watch, onMounted, computed } from 'vue';
  27. import { useRoute } from 'vue-router'
  28. import router from '@/router';
  29. const route = useRoute()
  30. const activeRoute = ref(route.path)
  31. watch(() => route.path, (newVal) => {
  32. activeRoute.value = newVal
  33. })
  34. // 当前应选中的菜单项:精确匹配优先,否则匹配路由前缀(处理详情页等子页面高亮父级菜单)
  35. const activeMenuRoute = computed(() => {
  36. if (!menuItems.value) return activeRoute.value
  37. const exact = menuItems.value.find(item => item.route === activeRoute.value)
  38. if (exact) return exact.route
  39. const prefix = menuItems.value.find(item => item.route && activeRoute.value.startsWith(item.route))
  40. return prefix?.route || activeRoute.value
  41. })
  42. const isCollapse = ref(false)
  43. interface menuItem {
  44. label: string;
  45. title: string;
  46. icon: string;
  47. route: string;
  48. }
  49. const menuItems = ref<menuItem[]>()
  50. onMounted(() => {
  51. const menuListStr = localStorage.getItem('menuList')
  52. const userInfoStr = localStorage.getItem('userInfo')
  53. if (menuListStr) {
  54. menuItems.value = JSON.parse(menuListStr)
  55. // 运维人员只显示学校管理和用户查询,不显示日志监控和业务监控
  56. // 先过滤掉后端可能返回的日志监控和业务监控
  57. menuItems.value = menuItems.value?.filter(menu =>
  58. menu.route !== '/main/logMonitor' && menu.route !== '/main/performanceMonitor'
  59. )
  60. // 通过 userInfo 判断是否为运维人员
  61. // 如果是运维账号(没有管理员相关菜单或特定字段),则不添加日志监控和业务监控
  62. const userInfo = userInfoStr ? JSON.parse(userInfoStr) : {}
  63. const isOpsUser = userInfo?.userType === 'ops' || userInfo?.roleType === 'ops'
  64. // 判断是否为管理员账号(有运维管理或联考管理菜单)
  65. const hasAdminMenu = menuItems.value?.some(menu =>
  66. menu.route === '/main/manager' || menu.route === '/main/examination'
  67. )
  68. console.log('isOpsUser:', isOpsUser, 'hasAdminMenu:', hasAdminMenu)
  69. if (!isOpsUser && hasAdminMenu) {
  70. // 非运维人员且有管理员菜单,添加日志监控和业务监控
  71. const additionalMenuList = [
  72. {
  73. icon: "icon_xuexiaoguanli",
  74. route: "/main/logMonitor",
  75. title: "日志监控",
  76. label:'',
  77. },
  78. {
  79. icon: "icon_xuexiaoguanli",
  80. route: "/main/performanceMonitor",
  81. title: "业务监控",
  82. label:'',
  83. },
  84. ]
  85. additionalMenuList.forEach(item => {
  86. const exists = menuItems.value?.some(menu => menu.route === item.route)
  87. if (!exists) {
  88. menuItems.value?.push(item)
  89. }
  90. })
  91. }
  92. }
  93. });
  94. const toggleCollapse = () => {
  95. isCollapse.value = !isCollapse.value
  96. }
  97. </script>
  98. <style lang="scss" scoped>
  99. .siderbar_container {
  100. background: #fff;
  101. padding: 16px;
  102. }
  103. .el-menu {
  104. width: 100%;
  105. border: none;
  106. }
  107. .el-menu-item {
  108. padding: 0;
  109. }
  110. .iconfont {
  111. margin-right: 5px;
  112. display: inline-block;
  113. color: #666666;
  114. font-size: 20px;
  115. }
  116. .collapse_box {
  117. padding-left: 10px;
  118. // text-align: center;
  119. }
  120. .el-menu.el-menu--vertical :deep(.el-menu-item) {
  121. height: 40px;
  122. margin: 10px 0;
  123. padding: 0 10px;
  124. border-radius: 4px;
  125. .iconfont {
  126. margin-right: 8px;
  127. text-align: center;
  128. }
  129. }
  130. .el-menu--collapse .el-menu-item span {
  131. display: none;
  132. }
  133. .el-menu-item :deep(.el-menu-tooltip__trigger) {
  134. padding: 0 10px;
  135. }
  136. .el-menu-item {
  137. &.is-active,
  138. &.is-active:hover {
  139. background: #2E64FA;
  140. color: #fff;
  141. .iconfont {
  142. color: #fff;
  143. }
  144. }
  145. &:not(.is-active):hover {
  146. background: inherit;
  147. color: #2E64FA;
  148. .iconfont {
  149. color: #2E64FA;
  150. }
  151. }
  152. }
  153. </style>