124 lines
4.7 KiB
TypeScript
124 lines
4.7 KiB
TypeScript
/*
|
|
* @Author: ZhaoYing
|
|
* @Date: 2026-02-02 16:24:49
|
|
* @Last Modified by: ZhaoYing
|
|
* @Last Modified time: 2026-02-02 16:24:49
|
|
*/
|
|
/**
|
|
* useNavigationBreadcrumbs Hook
|
|
*
|
|
* Automatically updates breadcrumbs based on current route:
|
|
* - Matches current path against menu structure
|
|
* - Supports dynamic routes with parameters
|
|
* - Handles nested menu hierarchies
|
|
* - Updates breadcrumbs on route changes
|
|
*
|
|
* @hook
|
|
*/
|
|
|
|
import { useEffect } from 'react';
|
|
import { useLocation } from 'react-router-dom';
|
|
import { useMenu } from '@/store/menu';
|
|
|
|
/**
|
|
* Hook to automatically update breadcrumbs based on navigation.
|
|
*
|
|
* @param source - Menu source type ('space' or 'manage')
|
|
*/
|
|
export const useNavigationBreadcrumbs = (source: 'space' | 'manage' = 'manage') => {
|
|
const location = useLocation();
|
|
const { allMenus, updateBreadcrumbs } = useMenu();
|
|
|
|
useEffect(() => {
|
|
const currentPath = location.pathname;
|
|
const menus = allMenus[source] || [];
|
|
|
|
/** Find matching menu item and build key path */
|
|
const findMenuKeyPath = (menuList: any[], parentKeys: string[] = []): string[] | null => {
|
|
let bestMatch: { path: string; parentId?: string; score: number } | null = null;
|
|
|
|
for (const menu of menuList) {
|
|
/** Check submenus */
|
|
if (menu.subs && menu.subs.length > 0) {
|
|
const menuPath = menu.path ? (menu.path[0] !== '/' ? '/' + menu.path : menu.path) : '';
|
|
for (const sub of menu.subs) {
|
|
if (sub.path) {
|
|
const subPath = sub.path[0] !== '/' ? '/' + sub.path : sub.path;
|
|
|
|
/** Exact match has priority */
|
|
if (subPath === currentPath) {
|
|
return [sub.path, `${menu.id}`];
|
|
}
|
|
console.log('menuPath', menuPath)
|
|
/** Dynamic route matching */
|
|
if (subPath.includes(':')) {
|
|
/** Check if under parent menu */
|
|
if (menuPath && currentPath.startsWith(menuPath + '/')) {
|
|
const relativePath = currentPath.replace(menuPath, '');
|
|
const pathSegments = subPath.split('/');
|
|
const relativeSegments = relativePath.split('/');
|
|
if (pathSegments.length === relativeSegments.length) {
|
|
const pathPattern = subPath.replace(/:[\w-]+/g, '[^/]+').replace(/\[[\w-]+\]/g, '[^/]+');
|
|
const regex = new RegExp(`^${pathPattern}$`);
|
|
if (regex.test(relativePath)) {
|
|
return [sub.path, `${menu.id}`];
|
|
}
|
|
}
|
|
}
|
|
/** Direct match submenu path */
|
|
const pathSegments = subPath.split('/');
|
|
const currentSegments = currentPath.split('/');
|
|
if (pathSegments.length === currentSegments.length) {
|
|
const pathPattern = subPath.replace(/:[\w-]+/g, '[^/]+').replace(/\[[\w-]+\]/g, '[^/]+');
|
|
const regex = new RegExp(`^${pathPattern}$`);
|
|
if (regex.test(currentPath)) {
|
|
return [sub.path, `${menu.id}`];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Check main menu */
|
|
if (menu.path) {
|
|
const menuPath = menu.path[0] !== '/' ? '/' + menu.path : menu.path;
|
|
/** Exact match has priority */
|
|
if (menuPath === currentPath) {
|
|
return [menu.path, ...parentKeys].reverse();
|
|
}
|
|
/** Dynamic route matching */
|
|
if (menuPath.includes(':')) {
|
|
const pathSegments = menuPath.split('/');
|
|
const currentSegments = currentPath.split('/');
|
|
if (pathSegments.length === currentSegments.length) {
|
|
const pathPattern = menuPath.replace(/:[\w-]+/g, '[^/]+').replace(/\[[\w-]+\]/g, '[^/]+');
|
|
const regex = new RegExp(`^${pathPattern}$`);
|
|
if (regex.test(currentPath)) {
|
|
const score = menuPath.split('/').length;
|
|
if (!bestMatch || score > bestMatch.score) {
|
|
bestMatch = { path: menu.path, score };
|
|
}
|
|
}
|
|
}
|
|
} else if (currentPath.startsWith(menuPath + '/')) {
|
|
const score = menuPath.split('/').length;
|
|
if (!bestMatch || score > bestMatch.score) {
|
|
bestMatch = { path: menu.path, score };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bestMatch) {
|
|
return bestMatch.parentId ? [bestMatch.path, bestMatch.parentId] : [bestMatch.path];
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const keyPath = findMenuKeyPath(menus);
|
|
if (keyPath) {
|
|
updateBreadcrumbs(keyPath, source);
|
|
}
|
|
}, [location.pathname, allMenus, source, updateBreadcrumbs]);
|
|
}; |