SideBar.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <script setup lang="ts">
  2. import Logo from '@/components/Logo/Logo.vue'
  3. import {routes} from '@/routes'
  4. import {useRoute} from 'vue-router'
  5. import {computed, ComputedRef, ref, watch} from 'vue'
  6. import EnvIndicator from '@/components/EnvIndicator/EnvIndicator.vue'
  7. const route = useRoute()
  8. let openKeys = [openSub()]
  9. const selectedKey = ref([route.name])
  10. function openSub() {
  11. let path = route.path
  12. let lastSepIndex = path.lastIndexOf('/')
  13. return path.substring(1, lastSepIndex)
  14. }
  15. watch(route, () => {
  16. selectedKey.value = [route.name]
  17. const sub = openSub()
  18. const p = openKeys.indexOf(sub)
  19. if (p === -1) openKeys.push(sub)
  20. })
  21. const sidebars = computed(() => {
  22. return routes[0]['children']
  23. })
  24. interface meta {
  25. icon: any
  26. hiddenInSidebar: boolean
  27. hideChildren: boolean
  28. }
  29. interface sidebar {
  30. path: string
  31. name: Function
  32. meta: meta,
  33. children: sidebar[]
  34. }
  35. const visible: ComputedRef<sidebar[]> = computed(() => {
  36. const res: sidebar[] = [];
  37. (sidebars.value || []).forEach((s) => {
  38. if (s.meta && s.meta.hiddenInSidebar) {
  39. return
  40. }
  41. const t: sidebar = {
  42. path: s.path,
  43. name: s.name,
  44. meta: s.meta as meta,
  45. children: []
  46. };
  47. (s.children || []).forEach((c: any) => {
  48. if (c.meta && c.meta.hiddenInSidebar) {
  49. return
  50. }
  51. t.children.push((c as sidebar))
  52. })
  53. res.push(t)
  54. })
  55. return res
  56. })
  57. </script>
  58. <template>
  59. <div class="sidebar">
  60. <logo/>
  61. <a-menu
  62. :openKeys="openKeys"
  63. mode="inline"
  64. v-model:openKeys="openKeys"
  65. v-model:selectedKeys="selectedKey"
  66. >
  67. <env-indicator/>
  68. <template v-for="sidebar in visible">
  69. <a-menu-item v-if="sidebar.children.length===0 || sidebar.meta.hideChildren"
  70. :key="sidebar.name"
  71. @click="$router.push('/'+sidebar.path).catch(() => {})">
  72. <component :is="sidebar.meta.icon"/>
  73. <span>{{ sidebar.name() }}</span>
  74. </a-menu-item>
  75. <a-sub-menu v-else :key="sidebar.path">
  76. <template #title>
  77. <component :is="sidebar.meta.icon"/>
  78. <span>{{ sidebar.name() }}</span>
  79. </template>
  80. <a-menu-item v-for="child in sidebar.children" :key="child.name">
  81. <router-link :to="'/'+sidebar.path+'/'+child.path">
  82. {{ child.name() }}
  83. </router-link>
  84. </a-menu-item>
  85. </a-sub-menu>
  86. </template>
  87. </a-menu>
  88. </div>
  89. </template>
  90. <style lang="less">
  91. .sidebar {
  92. position: sticky;
  93. top: 0;
  94. .logo {
  95. display: inline-flex;
  96. justify-content: center;
  97. align-items: center;
  98. img {
  99. margin-left: -18px;
  100. }
  101. }
  102. }
  103. .ant-layout-sider-collapsed .logo {
  104. overflow: hidden;
  105. }
  106. .ant-menu-inline, .ant-menu-vertical, .ant-menu-vertical-left {
  107. border-right: unset;
  108. }
  109. .ant-layout-sider-collapsed {
  110. .logo {
  111. img {
  112. margin-left: 0;
  113. }
  114. .text {
  115. display: none;
  116. }
  117. }
  118. }
  119. </style>