SidebarItem.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. <template>
  2. <div v-if="!item.hidden">
  3. <template v-if="hasOneShowingChild(item, item.children) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
  4. <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
  5. <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
  6. <svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
  7. <template #title>
  8. <el-badge :value="menuCounts[resolvePath(onlyOneChild.path)]" :offset="[10, 10]" :show-zero="false">
  9. <span class="menu-title" :title="hasTitle(onlyOneChild.meta.title)">{{ onlyOneChild.meta.title }}</span>
  10. </el-badge>
  11. </template>
  12. </el-menu-item>
  13. </app-link>
  14. </template>
  15. <el-sub-menu v-else ref="subMenu" :index="resolvePath(item.path)" teleported>
  16. <template v-if="item.meta" #title>
  17. <svg-icon :icon-class="item.meta ? item.meta.icon : ''" />
  18. <span class="p-rtv" :title="hasTitle(item.meta?.title)">
  19. <el-badge :value="menuCounts[resolvePath(item.path)]" :offset="[10, 10]" :show-zero="false">
  20. <span class="menu-title" :title="hasTitle(item.meta?.title)">{{ item.meta?.title }}</span>
  21. </el-badge>
  22. </span>
  23. </template>
  24. <sidebar-item v-for="(child, index) in item.children" :key="child.path + index" :is-nest="true" :item="child" :base-path="resolvePath(child.path)" class="nest-menu" />
  25. </el-sub-menu>
  26. </div>
  27. </template>
  28. <script setup lang="ts">
  29. import { isExternal } from '@/utils/validate';
  30. import AppLink from './Link.vue';
  31. import { getNormalPath } from '@/utils/ruoyi';
  32. import { RouteRecordRaw } from 'vue-router';
  33. import { useSideNumStore } from '@/store/modules/sideNum';
  34. const { menuCounts } = toRefs(useSideNumStore());
  35. const props = defineProps({
  36. item: {
  37. type: Object as PropType<RouteRecordRaw>,
  38. required: true
  39. },
  40. isNest: {
  41. type: Boolean,
  42. default: false
  43. },
  44. basePath: {
  45. type: String,
  46. default: ''
  47. }
  48. });
  49. const onlyOneChild = ref<any>({});
  50. const hasOneShowingChild = (parent: RouteRecordRaw, children?: RouteRecordRaw[]) => {
  51. if (!children) {
  52. children = [];
  53. }
  54. const showingChildren = children.filter((item) => {
  55. if (item.hidden) {
  56. return false;
  57. }
  58. onlyOneChild.value = item;
  59. return true;
  60. });
  61. // When there is only one child router, the child router is displayed by default
  62. if (showingChildren.length === 1) {
  63. return true;
  64. }
  65. // Show parent if there are no child router to display
  66. if (showingChildren.length === 0) {
  67. onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
  68. return true;
  69. }
  70. return false;
  71. };
  72. const resolvePath = (routePath: string, routeQuery?: string): any => {
  73. if (isExternal(routePath)) {
  74. return routePath;
  75. }
  76. if (isExternal(props.basePath as string)) {
  77. return props.basePath;
  78. }
  79. if (routeQuery) {
  80. let query = JSON.parse(routeQuery);
  81. return { path: getNormalPath(props.basePath + '/' + routePath), query: query };
  82. }
  83. return getNormalPath(props.basePath + '/' + routePath);
  84. };
  85. const hasTitle = (title: string | undefined): string => {
  86. if (!title || title.length <= 5) {
  87. return '';
  88. }
  89. return title;
  90. };
  91. </script>
  92. <style lang="scss" scoped>
  93. .el-menu-item.is-active {
  94. background: var(--el-color-primary) !important;
  95. color: #fff !important;
  96. }
  97. </style>