You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
2.8 KiB

  1. <script setup lang="ts">
  2. import { isEqual } from "@pureadmin/utils";
  3. import { transformI18n } from "@/plugins/i18n";
  4. import { useRoute, useRouter } from "vue-router";
  5. import { ref, watch, onMounted, toRaw } from "vue";
  6. import { getParentPaths, findRouteByPath } from "@/router/utils";
  7. import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
  8. const route = useRoute();
  9. const levelList = ref([]);
  10. const router = useRouter();
  11. const routes: any = router.options.routes;
  12. const multiTags: any = useMultiTagsStoreHook().multiTags;
  13. const getBreadcrumb = (): void => {
  14. // 当前路由信息
  15. let currentRoute;
  16. if (Object.keys(route.query).length > 0) {
  17. multiTags.forEach(item => {
  18. if (isEqual(route.query, item?.query)) {
  19. currentRoute = toRaw(item);
  20. }
  21. });
  22. } else if (Object.keys(route.params).length > 0) {
  23. multiTags.forEach(item => {
  24. if (isEqual(route.params, item?.params)) {
  25. currentRoute = toRaw(item);
  26. }
  27. });
  28. } else {
  29. currentRoute = findRouteByPath(router.currentRoute.value.path, routes);
  30. }
  31. // 当前路由的父级路径组成的数组
  32. const parentRoutes = getParentPaths(
  33. router.currentRoute.value.name as string,
  34. routes,
  35. "name"
  36. );
  37. // 存放组成面包屑的数组
  38. const matched = [];
  39. // 获取每个父级路径对应的路由信息
  40. parentRoutes.forEach(path => {
  41. if (path !== "/") matched.push(findRouteByPath(path, routes));
  42. });
  43. matched.push(currentRoute);
  44. matched.forEach((item, index) => {
  45. if (currentRoute?.query || currentRoute?.params) return;
  46. if (item?.children) {
  47. item.children.forEach(v => {
  48. if (v?.meta?.title === item?.meta?.title) {
  49. matched.splice(index, 1);
  50. }
  51. });
  52. }
  53. });
  54. levelList.value = matched.filter(
  55. item => item?.meta && item?.meta.title !== false
  56. );
  57. };
  58. const handleLink = item => {
  59. const { redirect, name, path } = item;
  60. if (redirect) {
  61. router.push(redirect as any);
  62. } else {
  63. if (name) {
  64. if (item.query) {
  65. router.push({
  66. name,
  67. query: item.query
  68. });
  69. } else if (item.params) {
  70. router.push({
  71. name,
  72. params: item.params
  73. });
  74. } else {
  75. router.push({ name });
  76. }
  77. } else {
  78. router.push({ path });
  79. }
  80. }
  81. };
  82. onMounted(() => {
  83. getBreadcrumb();
  84. });
  85. watch(
  86. () => route.path,
  87. () => {
  88. getBreadcrumb();
  89. },
  90. {
  91. deep: true
  92. }
  93. );
  94. </script>
  95. <template>
  96. <el-breadcrumb class="!leading-[50px] select-none" separator="/">
  97. <transition-group name="breadcrumb">
  98. <el-breadcrumb-item
  99. v-for="item in levelList"
  100. :key="item.path"
  101. class="!inline !items-stretch"
  102. >
  103. <a @click.prevent="handleLink(item)">
  104. {{ transformI18n(item.meta.title) }}
  105. </a>
  106. </el-breadcrumb-item>
  107. </transition-group>
  108. </el-breadcrumb>
  109. </template>