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
+7
View File
@@ -55,6 +55,13 @@ test('source contract: keeps route context and user identity in the compact head
assert.doesNotMatch(routerSource, /showPageHeading|showTenantName/)
})
test('source contract: renders the complete route breadcrumb before page content', () => {
assert.match(layoutSource, /import \{ getFirstAccessiblePath, getRouteBreadcrumbs \} from '@\/navigation\/clientNavigation'/)
assert.match(layoutSource, /const breadcrumbs = computed\(\(\) => getRouteBreadcrumbs\(route\.path, String\(pageTitle\.value\)\)\)/)
assert.match(layoutSource, /<nav class="client-breadcrumb" aria-label="页面路径">[\s\S]*?v-for="\(item, index\) in breadcrumbs"[\s\S]*?<RouterLink v-if="item\.path" :to="item\.path">[\s\S]*?<strong v-else aria-current="page">/)
assert.match(shellStyles, /\.client-breadcrumb \{[^}]*margin: 0 0 14px;/)
})
test('source contract: aligns the light top bar beside the prototype-inspired dark sidebar and bounds the mobile header', () => {
assert.match(shellStyles, /\.top-header \{[^}]*inset: 0 0 auto 250px;[^}]*max-width: calc\(100vw - 250px\);[^}]*padding: 0 24px;/)
assert.match(shellStyles, /\.top-header \{[^}]*background: rgba\(255, 255, 255, \.96\)/)
+9 -1
View File
@@ -8,7 +8,7 @@ import ClientSidebarMenu from '@/components/ClientSidebarMenu.vue'
import WorkspaceTabs from '@/components/WorkspaceTabs.vue'
import { useAuthStore } from '@/modules/auth/public'
import { useNotificationsStore } from '@/modules/notifications/public'
import { getFirstAccessiblePath } from '@/navigation/clientNavigation'
import { getFirstAccessiblePath, getRouteBreadcrumbs } from '@/navigation/clientNavigation'
import { useUnsavedWorkStore } from '@/navigation/workspace-tabs/unsavedWork'
import {
MAX_CACHED_WORKSPACE_VIEWS,
@@ -25,6 +25,7 @@ const workspace = useWorkspaceTabsStore()
const unsaved = useUnsavedWorkStore()
const pageTitle = computed(() => route.meta.title || '业务总览')
const pageDescription = computed(() => route.meta.description || '')
const breadcrumbs = computed(() => getRouteBreadcrumbs(route.path, String(pageTitle.value)))
const mobileMenuOpen = ref(false)
const desktopViewport = ref(true)
const menuButtonRef = ref<HTMLButtonElement>()
@@ -259,6 +260,13 @@ async function handleLogout() {
:inert="mobileMenuOpen"
:aria-hidden="mobileMenuOpen ? 'true' : undefined"
>
<nav class="client-breadcrumb" aria-label="页面路径">
<template v-for="(item, index) in breadcrumbs" :key="`${item.title}-${index}`">
<span v-if="index" aria-hidden="true">/</span>
<RouterLink v-if="item.path" :to="item.path">{{ item.title }}</RouterLink>
<strong v-else aria-current="page">{{ item.title }}</strong>
</template>
</nav>
<RouterView v-slot="{ Component, route: viewRoute }">
<KeepAlive :max="MAX_CACHED_WORKSPACE_VIEWS">
<component