auto-generate breadcrumb navigation for tool pages

This commit is contained in:
jingrow 2025-12-21 21:55:35 +08:00
parent 0a23ee2587
commit 66036da8e9
2 changed files with 91 additions and 2 deletions

View File

@ -79,9 +79,75 @@ const appName = computed(() => localStorage.getItem('appName') || 'Jingrow')
const isSystemUser = computed(() => authStore.user?.user_type === 'System User')
//
function pathSegmentToLabel(segment: string): string {
// kebab-case snake_case
return segment
.split(/[-_]/)
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.join(' ')
}
//
function generateBreadcrumbFromPath(path: string): Array<{ label: string; href?: string }> {
const items: Array<{ label: string; href?: string }> = []
const segments = path.split('/').filter(Boolean)
// href
let currentPath = ''
segments.forEach((segment, index) => {
currentPath += `/${segment}`
const isLast = index === segments.length - 1
// tools
if (segment === 'tools') {
items.push({
label: t('Tools'),
href: isLast ? undefined : currentPath
})
} else {
//
items.push({
label: pathSegmentToLabel(segment),
href: isLast ? undefined : currentPath
})
}
})
return items
}
const breadcrumbItems = computed(() => {
const items: Array<{ label: string; href?: string }> = []
// meta toolName
if (route.meta?.toolName) {
// Tools /
// Tools
let toolsPath = '/app/tools' //
try {
const resolved = router.resolve({ name: 'Tools' })
if (resolved.matched.length > 0) {
toolsPath = resolved.path
}
} catch {
// 使
}
items.push({
label: t('Tools'),
href: toolsPath
})
// 使 meta.toolName
const toolLabel = route.meta.toolName as string
if (toolLabel) {
items.push({
label: toolLabel
})
}
return items
}
//
if (route.name === 'PageTypeList') {
const entity = route.params.entity as string
@ -105,8 +171,15 @@ const breadcrumbItems = computed(() => {
label: id === 'new' ? t('Create') : id
})
}
} else if (route.name === 'WorkspacePage') {
const name = route.params.name as string
if (name) {
items.push({
label: pathSegmentToLabel(name)
})
}
} else {
//
//
const map: Record<string, string> = {
Dashboard: t('Dashboard'),
AgentList: t('Agents'),
@ -123,8 +196,24 @@ const breadcrumbItems = computed(() => {
SearchResults: t('Search Results')
}
const title = map[route.name as string]
if (title) {
items.push({ label: title })
} else {
//
//
if (route.path !== '/' && !route.path.startsWith('/app/') && !route.path.startsWith('/page/')) {
const pathItems = generateBreadcrumbFromPath(route.path)
if (pathItems.length > 0) {
items.push(...pathItems)
} else {
// 使
const routeName = route.name as string
if (routeName) {
items.push({ label: pathSegmentToLabel(routeName) })
}
}
}
}
}

View File

@ -256,7 +256,7 @@ router.beforeEach(async (to, _from, next) => {
return
} else {
// 路由不存在,重定向到工具列表页
next('/tools')
next({ name: 'Tools' })
return
}
}