This commit is contained in:
2026-09-11 16:17:24 +08:00
parent 80e83a6668
commit ec7f76fede
18 changed files with 263 additions and 31 deletions
+26
View File
@@ -17,6 +17,7 @@ import {
getFirstAccessiblePath,
getNavigationLeaves,
getNavigationParentKeys,
getRouteBreadcrumbs,
openNavigationParentKeys,
} from './clientNavigation.ts'
@@ -207,6 +208,31 @@ test('returns navigation parent keys from outermost to innermost', () => {
assert.deepEqual(getNavigationParentKeys(clientNavigation, '/not-found'), [])
})
test('builds complete breadcrumbs without repeating the current navigation page', () => {
assert.deepEqual(getRouteBreadcrumbs('/', '业务总览'), [{ title: '首页' }])
assert.deepEqual(getRouteBreadcrumbs('/orders/first-leg', '订单列表'), [
{ title: '首页', path: '/' },
{ title: '头程物流' },
{ title: '订单列表' },
])
assert.deepEqual(getRouteBreadcrumbs('/orders/first-leg/create', '创建订单'), [
{ title: '首页', path: '/' },
{ title: '头程物流' },
{ title: '订单列表', path: '/orders/first-leg' },
{ title: '创建订单' },
])
assert.deepEqual(getRouteBreadcrumbs('/notifications/NOTICE-001', '消息详情'), [
{ title: '首页', path: '/' },
{ title: '消息中心' },
{ title: '我的消息', path: '/notifications' },
{ title: '消息详情' },
])
assert.deepEqual(getRouteBreadcrumbs('/forbidden', '无权访问'), [
{ title: '首页', path: '/' },
{ title: '无权访问' },
])
})
test('opens the company parent group for a company route', () => {
const openedKeys = []
+35
View File
@@ -62,6 +62,41 @@ export function getFirstAccessiblePath(permissions: readonly string[]) {
return getNavigationLeaves(filterNavigationByPermissions(clientNavigation, permissions))[0]?.path ?? '/forbidden'
}
export interface ClientBreadcrumbItem {
title: string
path?: string
}
function findNavigationTrail(
nodes: readonly ClientNavigationNode[],
path: string,
parents: readonly ClientBreadcrumbItem[] = [],
): ClientBreadcrumbItem[] | undefined {
for (const node of nodes) {
if (isNavigationGroup(node)) {
const result = findNavigationTrail(node.children, path, [...parents, { title: node.title }])
if (result) return result
continue
}
if (node.path === path) return [...parents, { title: node.title, path: node.path }]
}
}
export function getRouteBreadcrumbs(path: string, currentTitle: string): ClientBreadcrumbItem[] {
const home: ClientBreadcrumbItem = { title: '首页', path: '/' }
if (path === '/') return [{ title: '首页' }]
const leaves = getNavigationLeaves(clientNavigation)
.filter((leaf) => leaf.path !== '/' && (path === leaf.path || path.startsWith(`${leaf.path}/`)))
.sort((left, right) => right.path.length - left.path.length)
const parentLeaf = leaves[0]
const trail = parentLeaf ? findNavigationTrail(clientNavigation, parentLeaf.path) ?? [] : []
const items = [home, ...trail]
if (items.at(-1)?.title !== currentTitle) items.push({ title: currentTitle })
if (items.length > 1) delete items.at(-1)!.path
return items
}
function findNavigationParentKeys(
nodes: readonly ClientNavigationNode[],
path: string,