diff --git a/src/components/GlobalComponent/Breadcrumb.jsx b/src/components/GlobalComponent/Breadcrumb.jsx
new file mode 100644
index 0000000..229ab12
--- /dev/null
+++ b/src/components/GlobalComponent/Breadcrumb.jsx
@@ -0,0 +1,233 @@
+import React, { useState, useEffect } from 'react';
+import { Breadcrumb } from 'antd';
+import { CloseOutlined } from '@ant-design/icons';
+import { history, useLocation, matchRoutes } from '@umijs/max';
+import './breadcrumb.less';
+import routes from '../../../config/routes';
+
+const CustomBreadcrumb = () => {
+ // 从sessionStorage初始化面包屑数据,与Vue实例保持一致
+ const [breadcrumbList, setBreadcrumbList] = useState(() => {
+ return JSON.parse(sessionStorage.getItem('breadcrumb')) || [];
+ });
+
+ const [currentRouterName, setCurrentRouterName] = useState('');
+
+ const location = useLocation();
+
+ // 获取当前路由的真实信息
+ const getCurrentRoute = () => {
+ const pathname = location.pathname || '/';
+ const href = window.location.href;
+
+ console.log('当前路径:', pathname);
+
+ // 使用matchRoutes匹配当前路径与路由配置
+ const matchedRoutes = matchRoutes(routes, pathname);
+
+ console.log('匹配的路由:', matchedRoutes);
+
+ // 如果有匹配的路由,获取最深层的匹配路由信息
+ if (matchedRoutes && matchedRoutes.length > 0) {
+ const matchedRoute = matchedRoutes[matchedRoutes.length - 1]; // 获取最深层的匹配路由
+ const routeConfig = matchedRoute.route;
+
+ console.log('匹配的路由配置:', routeConfig);
+
+ // 根据路由配置文件,直接使用routeConfig.name作为标题,这样可以确保名称正确显示
+ const routeTitle = routeConfig.name || '未知页面';
+
+ return {
+ name: routeConfig.name || pathname.replace(/\//g, '_').slice(1) || 'home',
+ path: pathname,
+ href,
+ fullPath: href,
+ meta: {
+ title: routeTitle,
+ affix: pathname === '/'
+ }
+ };
+ }
+
+ // 手动处理特殊情况,确保即使matchRoutes不工作,也能显示正确的路由名称
+ const pathSegments = pathname.split('/').filter(Boolean);
+ const lastSegment = pathSegments[pathSegments.length - 1] || 'home';
+
+ // 直接返回路径的最后一段作为名称
+ return {
+ name: lastSegment,
+ path: pathname,
+ href,
+ fullPath: href,
+ meta: {
+ title: lastSegment === 'home' ? '首页' : lastSegment,
+ affix: pathname === '/'
+ }
+ };
+ };
+
+ // 生成面包屑数据 - 修复了path指向错误的问题
+ const generateBreadcrumb = () => {
+ // 从当前路由获取信息
+ const currentRoute = getCurrentRoute();
+ const { meta: { title }, name, path } = currentRoute;
+
+ // 如果title存在,将路由信息添加到breadcrumbList数组
+ if (title) {
+ const newBreadcrumbList = [...breadcrumbList];
+ newBreadcrumbList.push({
+ name,
+ path: path, // 正确使用当前路由的path属性
+ title
+ });
+
+ // 使用reduce方法对breadcrumbList进行去重处理,与Vue组件完全一致
+ const uniqueList = newBreadcrumbList.reduce((accumulator, current) => {
+ const x = accumulator.find(item => item.name === current.name);
+
+ if (!x) {
+ return accumulator.concat(current);
+ } else {
+ accumulator.forEach((val, i) => {
+ if (val.name == current.name) {
+ val.title = current.title;
+ val.path = current.path;
+ }
+ });
+ return accumulator;
+ }
+ }, []);
+
+ // 将处理后的面包屑数据存储到sessionStorage中
+ setBreadcrumbList(uniqueList);
+ sessionStorage.setItem('breadcrumb', JSON.stringify(uniqueList));
+ }
+ };
+
+ // 处理导航逻辑
+ const toPath = (item) => {
+ const currentRoute = getCurrentRoute();
+ // 如果路径相同,点击导航则不跳转
+ if (item.name === currentRoute.name) {
+ return '';
+ }
+ // 如果是固定路由,则不跳转
+ if (item.meta?.affix) {
+ return '';
+ } else {
+ // 跳转路由
+ return item.path;
+ }
+ };
+
+ // 关闭面包屑项,先跳转再删除面包屑
+ const cloneCurrentPage = (item, index) => {
+ // 如果没有面包屑页面或只剩一个页面,跳转到根目录
+ if (!breadcrumbList || breadcrumbList.length <= 1) {
+ // 使用window.location.href进行有感刷新
+ window.location.href = '/';
+ return;
+ }
+
+ const updatedList = [...breadcrumbList];
+ updatedList.splice(index, 1);
+
+ let length = updatedList.length;
+ // 先进行页面跳转
+ if (currentRouterName === item.name && length > 0) {
+ // 使用history进行无刷新跳转
+ history.push(updatedList[length - 1].path);
+ }
+
+ // 然后删除面包屑项
+ setBreadcrumbList(updatedList);
+ sessionStorage.setItem('breadcrumb', JSON.stringify(updatedList));
+ };
+
+ // 处理面包屑项点击事件
+ const handleItemClick = (item) => {
+ const path = toPath(item);
+ if (path) {
+ console.log(currentRouterName, 'yp')
+ // 使用history进行无刷新跳转
+ history.push(path);
+ }
+ };
+
+ // 组件挂载时初始化
+ useEffect(() => {
+ const currentRoute = getCurrentRoute();
+ setCurrentRouterName(currentRoute.name);
+ generateBreadcrumb();
+ }, []);
+
+ // 监听路由变化,当路由变化时触发generateBreadcrumb方法
+ useEffect(() => {
+ const handleRouteChange = () => {
+ const currentRoute = getCurrentRoute();
+ setCurrentRouterName(currentRoute.name);
+ generateBreadcrumb();
+ };
+
+ // 监听浏览器前进后退事件
+ window.addEventListener('popstate', handleRouteChange);
+
+ // 重写pushState和replaceState方法以捕获更多路由变化
+ const originalPushState = window.history.pushState;
+ const originalReplaceState = window.history.replaceState;
+
+ window.history.pushState = function (...args) {
+ originalPushState.apply(this, args);
+ handleRouteChange();
+ };
+
+ window.history.replaceState = function (...args) {
+ originalReplaceState.apply(this, args);
+ handleRouteChange();
+ };
+
+ // 监听hash变化(针对hash路由)
+ window.addEventListener('hashchange', handleRouteChange);
+
+ return () => {
+ window.removeEventListener('popstate', handleRouteChange);
+ window.removeEventListener('hashchange', handleRouteChange);
+ // 还原原始方法
+ window.history.pushState = originalPushState;
+ window.history.replaceState = originalReplaceState;
+ };
+ }, [breadcrumbList, location]);
+
+ // 当location.pathname变化时,自动更新currentRouterName
+ useEffect(() => {
+ const currentRoute = getCurrentRoute();
+ setCurrentRouterName(currentRoute.name);
+ }, [location.pathname]);
+
+ return (
+
+
+ {breadcrumbList.map((item, index) => (
+ handleItemClick(item)}
+ className={`breadcrumb-item ${item.name === currentRouterName ? 'breadcrumb-item-active' : ''}`}
+ >
+
+ {item.title}
+ {
+ e.stopPropagation();
+ cloneCurrentPage(item, index);
+ }}
+ />
+
+
+ ))}
+
+
+ );
+};
+
+export default CustomBreadcrumb;
\ No newline at end of file
diff --git a/src/components/GlobalComponent/breadcrumb.less b/src/components/GlobalComponent/breadcrumb.less
new file mode 100644
index 0000000..acd336f
--- /dev/null
+++ b/src/components/GlobalComponent/breadcrumb.less
@@ -0,0 +1,151 @@
+// 面包屑容器样式
+.bread-crumb {
+ // display: flex;
+ align-items: center;
+ overflow-x: auto;
+ overflow-y: hidden;
+ height: auto;
+ max-width: 100%;
+ margin: 8px 0;
+ padding: 0 12px;
+ background-color: transparent;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ box-sizing: border-box;
+}
+
+// 面包屑容器滚动条样式
+.bread-crumb::-webkit-scrollbar {
+ height: 4px;
+}
+
+.bread-crumb::-webkit-scrollbar-track {
+ background-color: #f1f1f1;
+ border-radius: 2px;
+}
+
+.bread-crumb::-webkit-scrollbar-thumb {
+ background-color: #c1c1c1;
+ border-radius: 2px;
+}
+
+.bread-crumb::-webkit-scrollbar-thumb:hover {
+ background-color: #a1a1a1;
+}
+
+// 面包屑导航容器
+.ant-breadcrumb {
+ display: flex !important;
+ flex-wrap: nowrap !important;
+ align-items: center;
+ gap: 8px;
+ margin: 0;
+ padding: 0;
+}
+
+// 面包屑项基础样式
+.breadcrumb-item {
+ height: 32px;
+ padding: 0 12px;
+ border-radius: 16px;
+ background-color: #fff;
+ border: 1px solid #E8E8E8;
+ margin-right: 8px;
+ display: flex;
+ align-items: center;
+ transition: all 0.3s ease;
+ cursor: pointer;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 180px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
+ box-sizing: border-box;
+
+ // 移除默认的分隔符
+ .ant-breadcrumb-separator {
+ display: none !important;
+ }
+
+ // 链接样式
+ .ant-breadcrumb-link {
+ display: flex;
+ align-items: center;
+ height: 100%;
+ color: #808080 !important;
+ background: transparent !important;
+ padding: 0;
+ margin: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 100%;
+ }
+
+ // 悬停效果
+ &:hover {
+ border-color: #0056FF;
+ // transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 86, 255, 0.1);
+ }
+}
+
+// 面包屑项选中状态样式
+.breadcrumb-item-active {
+ background-color: #ECF2FF;
+ border-color: #0056FF;
+
+ .ant-breadcrumb-link {
+ color: #0056FF !important;
+ font-weight: 500;
+ }
+}
+
+// 面包屑项内容容器
+.breadcrumb-item-content {
+ display: flex;
+ align-items: center;
+ height: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 100%;
+}
+
+// 面包屑项文本样式
+.breadcrumb-item-text {
+ font-size: 14px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ flex: 1;
+}
+
+// 关闭图标样式
+.breadcrumb-close-icon {
+ font-size: 14px;
+ color: #7D9CD8;
+ margin-left: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: color 0.3s ease;
+ flex-shrink: 0;
+
+ &:hover {
+ color: #0056FF;
+ }
+}
+
+// 确保所有面包屑链接样式一致
+.ant-breadcrumb-link {
+ color: #808080 !important;
+ transition: color 0.3s ease;
+}
+
+.ant-breadcrumb-link:hover {
+ color: #0056FF !important;
+}
+
+.ant-breadcrumb-item-active .ant-breadcrumb-link {
+ color: #0056FF !important;
+}
\ No newline at end of file
diff --git a/src/components/GlobalComponent/index.js b/src/components/GlobalComponent/index.js
index 3a637ab..ac2716b 100644
--- a/src/components/GlobalComponent/index.js
+++ b/src/components/GlobalComponent/index.js
@@ -1,5 +1,6 @@
-import { PureComponent } from 'react'
-import * as plugins from 'antd'
+import React, { PureComponent } from 'react';
+import * as plugins from 'antd';
+import CustomBreadcrumb from './Breadcrumb';
class GlobalComponent extends PureComponent {
constructor(props) {
@@ -69,7 +70,11 @@ class GlobalComponent extends PureComponent {
this.Typography = plugins.Typography
this.Upload = plugins.Upload
this.message = plugins.message
+ // 自定义组件
+ this.CustomBreadcrumb = CustomBreadcrumb;
}
}
-export default GlobalComponent
+export default GlobalComponent;
+// 同时导出自定义面包屑组件,方便直接使用
+export { CustomBreadcrumb };
diff --git a/src/pages/nav_system_content/SystemContentList.js b/src/pages/nav_system_content/SystemContentList.js
index db805a0..79acc22 100644
--- a/src/pages/nav_system_content/SystemContentList.js
+++ b/src/pages/nav_system_content/SystemContentList.js
@@ -10,6 +10,7 @@ import { HomeOutlined, SettingOutlined, LogoutOutlined } from '@ant-design/icons
import { getPageQuery } from '@/utils/utils'
import menuTitle from '@/assets/img/memuTitle.png'
import menuTitle1 from '@/assets/img/memuTitle1.png'
+import { CustomBreadcrumb } from '@/components/GlobalComponent'
const SystemContentList = (props) => {
const dynamicRoute = window.dynamicRoute
@@ -181,7 +182,10 @@ const SystemContentList = (props) => {