Files
hjc-web/app/templates/template-10/components/Header.vue
T
gxwebsoft 2b69686795 feat(app): 添加多模板关于我们页面及相关路由和404页面
- 新增404页面,优化未找到页面体验,避免被搜索引擎索引
- 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理
- 实现/article、/case、/product及/page动态路由兼容列表与详情展示
- 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置
- 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持
- 模板增强支持CMS单页内容加载及SEO信息动态设置
- 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
2026-09-08 12:13:44 +08:00

148 lines
6.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<header class="sticky top-0 z-50 bg-white shadow-sm">
<div class="t10-container flex items-center h-[72px]">
<!-- Logo -->
<SiteBrand
link-class="flex-shrink-0 mr-8 lg:mr-12"
:logo="siteLogo"
:icon="siteIcon"
:name="siteName"
logo-class="h-[44px] w-auto max-w-[220px] object-contain"
icon-class="h-8 w-auto object-contain"
name-class="text-xl font-bold text-[var(--t10-primary)] truncate max-w-[220px]"
>
<template #fallback-icon>
<span class="text-xl font-bold text-[var(--t10-primary)]">C-MVP</span>
</template>
</SiteBrand>
<!-- 桌面端导航 -->
<nav class="hidden lg:flex items-center h-full flex-1 min-w-0">
<template v-for="item in navItems" :key="item.navigationId || item.path">
<!-- 有子菜单 -->
<div v-if="item.children && item.children.length > 0" class="relative group h-full flex items-center">
<button
class="h-full px-4 text-[15px] text-[var(--t10-text)] hover:text-[var(--t10-primary)] transition-colors flex items-center gap-1 whitespace-nowrap"
>
{{ item.title }}
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div class="absolute left-0 top-full opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all">
<div class="bg-white shadow-lg border border-[var(--t10-border)] py-2 min-w-[164px]">
<NuxtLink
v-for="child in item.children"
:key="child.navigationId"
:to="getChildPath(child)"
class="block px-4 py-2 text-[15px] text-[var(--t10-text-secondary)] hover:text-[var(--t10-primary)] hover:bg-[var(--t10-primary-soft)] transition-colors whitespace-nowrap"
>
{{ child.title }}
</NuxtLink>
</div>
</div>
</div>
<!-- 无子菜单 -->
<NuxtLink
v-else
:to="getNavLink(item)"
:target="item.target === '_blank' ? '_blank' : undefined"
class="h-full px-4 flex items-center text-[15px] text-[var(--t10-text)] hover:text-[var(--t10-primary)] transition-colors whitespace-nowrap relative"
active-class="!text-[var(--t10-primary)] after:absolute after:left-4 after:right-4 after:bottom-0 after:h-[2px] after:bg-[var(--t10-primary)]"
>
{{ item.title }}
</NuxtLink>
</template>
</nav>
<!-- 右侧语言 + 搜索 -->
<div class="hidden lg:flex items-center gap-4 flex-shrink-0 ml-4">
<button class="text-sm text-[var(--t10-text-secondary)] hover:text-[var(--t10-primary)] transition-colors border border-[var(--t10-border)] rounded-full px-3 py-1">
CN
</button>
<SiteSearchBox
v-if="showHeaderSearch"
variant="light"
accent="var(--t10-primary)"
placeholder="搜索"
class="flex items-center"
/>
</div>
<!-- 移动端菜单按钮 -->
<button
class="lg:hidden ml-auto p-2 text-[var(--t10-text)]"
aria-label="菜单"
@click="mobileMenuOpen = !mobileMenuOpen"
>
<svg v-if="!mobileMenuOpen" class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg v-else class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- 移动端菜单 -->
<div v-if="mobileMenuOpen" class="lg:hidden bg-white border-t border-[var(--t10-border)]">
<div class="t10-container py-4 space-y-1">
<SiteSearchBox
v-if="showHeaderSearch"
variant="light"
accent="var(--t10-primary)"
placeholder="搜索"
class="mb-3"
/>
<template v-for="item in navItems" :key="item.navigationId || item.path">
<div v-if="item.children && item.children.length > 0">
<div class="px-4 py-3 text-base font-semibold text-[var(--t10-primary)]">
{{ item.title }}
</div>
<NuxtLink
v-for="child in item.children"
:key="child.navigationId"
:to="getChildPath(child)"
class="block px-8 py-2 text-sm text-[var(--t10-text-secondary)] hover:text-[var(--t10-primary)] hover:bg-[var(--t10-primary-soft)] transition-colors"
@click="mobileMenuOpen = false"
>
{{ child.title }}
</NuxtLink>
</div>
<NuxtLink
v-else
:to="getNavLink(item)"
:target="item.target === '_blank' ? '_blank' : undefined"
class="block px-4 py-3 text-base text-[var(--t10-text)] hover:text-[var(--t10-primary)] hover:bg-[var(--t10-primary-soft)] transition-colors"
active-class="text-[var(--t10-primary)] bg-[var(--t10-primary-soft)]"
@click="mobileMenuOpen = false"
>
{{ item.title }}
</NuxtLink>
</template>
</div>
</div>
</header>
</template>
<script setup lang="ts">
/**
* 模板 10 - Header 组件(创芯存储科技蓝风格)
* 白底 72px,左 Logo + 水平菜单 + 右侧语言切换与搜索
*/
import type { CmsNavigation } from '~/types'
const { siteName, siteLogo, siteIcon, navigations, showHeaderSearch, fetchSiteInfo } = useSite()
const mobileMenuOpen = ref(false)
function getChildPath(child: CmsNavigation): string {
return getNavLink(child)
}
await fetchSiteInfo()
const navItems = computed<CmsNavigation[]>(() => {
return navigations.value || []
})
</script>