123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <template>
- <div :class="[prefixCls, `${prefixCls}--${theme}`]">
- <a-breadcrumb :routes="routes">
- <template #itemRender="{ route, routes, paths }">
- <Icon :icon="route.meta.icon" v-if="getShowBreadCrumbIcon && route.meta.icon" />
- <span v-if="!hasRedirect(routes, route)">
- {{ t(route.meta.title) }}
- </span>
- <router-link v-else to="" @click="handleClick(route, paths, $event)">
- {{ t(route.meta.title) }}
- </router-link>
- </template>
- </a-breadcrumb>
- </div>
- </template>
- <script lang="ts">
- import type { RouteLocationMatched } from 'vue-router';
- import { defineComponent, ref, toRaw, watchEffect } from 'vue';
- import { Breadcrumb } from 'ant-design-vue';
- import { useI18n } from 'vue-i18n';
- import { useRouter } from 'vue-router';
- import { filter } from '/@/utils/helper/treeHelper';
- import { REDIRECT_NAME } from '/@/router/constant';
- import Icon from '/@/components/Icon';
- import { HomeOutlined } from '@ant-design/icons-vue';
- import { PageEnum } from '/@/enums/pageEnum';
- import { useDesign } from '/@/hooks/web/useDesign';
- import { useRootSetting } from '/@/hooks/setting/useRootSetting';
- import { propTypes } from '/@/utils/propTypes';
- import { useGo } from '/@/hooks/web/usePage';
- import { isString } from '/@/utils/is';
- export default defineComponent({
- name: 'LayoutBreadcrumb',
- components: { HomeOutlined, Icon, [Breadcrumb.name]: Breadcrumb },
- props: {
- theme: propTypes.oneOf(['dark', 'light']),
- },
- setup() {
- const routes = ref<RouteLocationMatched[]>([]);
- const { currentRoute } = useRouter();
- const { prefixCls } = useDesign('layout-breadcrumb');
- const { getShowBreadCrumbIcon } = useRootSetting();
- const { t } = useI18n();
- watchEffect(() => {
- if (currentRoute.value.name === REDIRECT_NAME) return;
- const matched = currentRoute.value?.matched;
- if (!matched || matched.length === 0) return;
- let breadcrumbList = filterItem(toRaw(matched));
- const filterBreadcrumbList = breadcrumbList.filter(
- (item) => item.path !== PageEnum.BASE_HOME
- );
- if (filterBreadcrumbList.length === breadcrumbList.length) {
- filterBreadcrumbList.unshift(({
- path: PageEnum.BASE_HOME,
- meta: {
- title: t('layout.header.home'),
- isLink: true,
- },
- } as unknown) as RouteLocationMatched);
- }
- if (currentRoute.value.meta?.currentActiveMenu) {
- filterBreadcrumbList.push((currentRoute.value as unknown) as RouteLocationMatched);
- }
- // routes.value = filterBreadcrumbList.length === 1 ? [] : filterBreadcrumbList;
- routes.value = filterBreadcrumbList;
- });
- function filterItem(list: RouteLocationMatched[]) {
- let resultList = filter(list, (item) => {
- const { meta } = item;
- if (!meta) {
- return false;
- }
- const { title, hideBreadcrumb, hideMenu } = meta;
- if (!title || hideBreadcrumb || hideMenu) {
- return false;
- }
- return true;
- }).filter((item) => !item.meta?.hideBreadcrumb || !item.meta?.hideMenu);
- resultList = resultList.filter((item) => item.path !== PageEnum.BASE_HOME);
- return resultList;
- }
- function handleClick(route: RouteLocationMatched, paths: string[], e: Event) {
- e?.preventDefault();
- const {
- children,
- redirect,
- meta,
- // components
- } = route;
- // const isParent =
- // components?.default?.name === 'DefaultLayout' || (components?.default as any)?.parentView;
- if (
- children?.length &&
- !redirect
- // && !isParent
- ) {
- e?.stopPropagation();
- return;
- }
- if (meta?.carryParam) {
- return;
- }
- const go = useGo();
- if (redirect && isString(redirect)) {
- go(redirect);
- } else {
- const ps = paths.slice(1);
- const lastPath = ps.pop() || '';
- const parentPath = ps.pop() || '';
- let path = `${parentPath}/${lastPath}`;
- path = /^\//.test(path) ? path : `/${path}`;
- go(path);
- }
- }
- function hasRedirect(routes: RouteLocationMatched[], route: RouteLocationMatched) {
- if (route?.meta?.isLink) {
- return true;
- }
- if (routes.indexOf(route) === routes.length - 1) {
- return false;
- }
- return true;
- }
- return { routes, t, prefixCls, getShowBreadCrumbIcon, handleClick, hasRedirect };
- },
- });
- </script>
- <style lang="less">
- @prefix-cls: ~'@{namespace}-layout-breadcrumb';
- .@{prefix-cls} {
- display: flex;
- padding: 0 8px;
- align-items: center;
- .ant-breadcrumb-link {
- .anticon {
- margin-right: 4px;
- margin-bottom: 2px;
- }
- }
- &--light {
- .ant-breadcrumb-link {
- color: @breadcrumb-item-normal-color;
- a {
- color: rgba(0, 0, 0, 0.65);
- &:hover {
- color: @primary-color;
- }
- }
- }
- .ant-breadcrumb-separator {
- color: @breadcrumb-item-normal-color;
- }
- }
- &--dark {
- .ant-breadcrumb-link {
- color: rgba(255, 255, 255, 0.6);
- a {
- color: rgba(255, 255, 255, 0.8);
- &:hover {
- color: @white;
- }
- }
- }
- .ant-breadcrumb-separator,
- .anticon {
- color: rgba(255, 255, 255, 0.8);
- }
- }
- }
- </style>
|