提交 | 用户 | 时间
820397 1 <script lang="tsx">
H 2 import { ElBreadcrumb, ElBreadcrumbItem } from 'element-plus'
3 import { ref, watch, computed, unref, defineComponent, TransitionGroup } from 'vue'
4 import { useRouter } from 'vue-router'
5 import { usePermissionStore } from '@/store/modules/permission'
6 import { filterBreadcrumb } from './helper'
7 import { filter, treeToList } from '@/utils/tree'
8 import type { RouteLocationNormalizedLoaded, RouteMeta } from 'vue-router'
9
10 import { Icon } from '@/components/Icon'
11 import { useAppStore } from '@/store/modules/app'
12 import { useDesign } from '@/hooks/web/useDesign'
13
14 const { getPrefixCls } = useDesign()
15
16 const prefixCls = getPrefixCls('breadcrumb')
17
18 const appStore = useAppStore()
19
20 // 面包屑图标
21 const breadcrumbIcon = computed(() => appStore.getBreadcrumbIcon)
22
23 export default defineComponent({
24   name: 'Breadcrumb',
25   setup() {
26     const { currentRoute } = useRouter()
27
28     const { t } = useI18n()
29
30     const levelList = ref<AppRouteRecordRaw[]>([])
31
32     const permissionStore = usePermissionStore()
33
34     const menuRouters = computed(() => {
35       const routers = permissionStore.getRouters
36       return filterBreadcrumb(routers)
37     })
38
39     const getBreadcrumb = () => {
40       const currentPath = currentRoute.value.matched.slice(-1)[0].path
41
42       levelList.value = filter<AppRouteRecordRaw>(unref(menuRouters), (node: AppRouteRecordRaw) => {
43         return node.path === currentPath
44       })
45     }
46
47     const renderBreadcrumb = () => {
48       const breadcrumbList = treeToList<AppRouteRecordRaw[]>(unref(levelList))
49       return breadcrumbList.map((v) => {
50         const disabled = !v.redirect || v.redirect === 'noredirect'
51         const meta = v.meta as RouteMeta
52         return (
53           <ElBreadcrumbItem to={{ path: disabled ? '' : v.path }} key={v.name}>
54             {meta?.icon && breadcrumbIcon.value ? (
55               <div class="flex items-center">
56                 <Icon icon={meta.icon} class="mr-[2px]" svgClass="inline-block"></Icon>
57                 {t(v?.meta?.title)}
58               </div>
59             ) : (
60               t(v?.meta?.title)
61             )}
62           </ElBreadcrumbItem>
63         )
64       })
65     }
66
67     watch(
68       () => currentRoute.value,
69       (route: RouteLocationNormalizedLoaded) => {
70         if (route.path.startsWith('/redirect/')) {
71           return
72         }
73         getBreadcrumb()
74       },
75       {
76         immediate: true
77       }
78     )
79
80     return () => (
81       <ElBreadcrumb separator="/" class={`${prefixCls} flex items-center h-full ml-[10px]`}>
82         <TransitionGroup appear enter-active-class="animate__animated animate__fadeInRight">
83           {renderBreadcrumb()}
84         </TransitionGroup>
85       </ElBreadcrumb>
86     )
87   }
88 })
89 </script>
90
91 <style lang="scss" scoped>
92 $prefix-cls: #{$elNamespace}-breadcrumb;
93
94 .#{$prefix-cls} {
3e359e 95   :deep(.#{$prefix-cls}__item) {
820397 96     display: flex;
H 97     .#{$prefix-cls}__inner {
98       display: flex;
99       align-items: center;
100       color: var(--top-header-text-color);
101
102       &:hover {
103         color: var(--el-color-primary);
104       }
105     }
106   }
107
3e359e 108   :deep(.#{$prefix-cls}__item):not(:last-child) {
820397 109     .#{$prefix-cls}__inner {
H 110       color: var(--top-header-text-color);
111
112       &:hover {
113         color: var(--el-color-primary);
114       }
115     }
116   }
117
3e359e 118   :deep(.#{$prefix-cls}__item):last-child {
820397 119     .#{$prefix-cls}__inner {
H 120       display: flex;
121       align-items: center;
122       color: var(--el-text-color-placeholder);
123
124       &:hover {
125         color: var(--el-text-color-placeholder);
126       }
127     }
128   }
129 }
130 </style>