Files
hjc-web/app/templates/template-05/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

172 lines
7.6 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>
<!-- 顶部数据条满坛记品牌数据具体数值请替换为真实数据 -->
<div class="bg-[#2E2620] text-[#E9DFD3] text-xs">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-center sm:justify-end gap-x-5 gap-y-1 py-1.5">
<span v-for="stat in topStats" :key="stat" class="flex items-center gap-1.5">
<svg class="w-3.5 h-3.5 text-[#F2A900]" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2l2.4 7.4H22l-6 4.6 2.3 7.4-6.3-4.8L5.7 21.4 8 14 2 9.4h7.6z" />
</svg>
{{ stat }}
</span>
</div>
</div>
</div>
<header class="sticky top-0 z-50 bg-[#FFF8F0]/95 backdrop-blur-sm border-b border-[#F0E2D5]">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16 lg:h-20">
<!-- Logo -->
<SiteBrand
link-class="flex-shrink-0"
:logo="siteLogo"
:icon="siteIcon"
:name="siteName"
default-name="品牌官网"
logo-class="h-12 w-auto max-w-[200px] object-contain"
icon-class="h-8 w-auto object-contain"
name-class="text-lg font-bold text-[#33291F] truncate max-w-[160px] sm:max-w-xs"
>
<template #fallback-icon>
<div class="w-9 h-9 rounded-xl bg-[#E5472E] flex items-center justify-center">
<svg class="w-5 h-5 text-white" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 2C7 2 3 6 3 11c0 5 4 9 9 9s9-4 9-9c0-5-4-9-9-9zm0 16c-3.9 0-7-3-7-7 0-2.8 1.6-5.2 4-6.4.2 1.6 1.1 3 2.5 3.8-1-.7-1.6-1.9-1.6-3.1 2.3.3 4.1 2.1 4.4 4.4.8.7 1.3 1.7 1.3 2.9 0 .6-.1 1.2-.4 1.7 1.4-.7 2.4-2.1 2.4-3.7 1.8 1.2 3 3.3 3 5.4 0 4-3.1 7-7 7z" />
</svg>
</div>
</template>
</SiteBrand>
<!-- 搜索框后台 setting.searchBtn 控制是否显示 -->
<SiteSearchBox v-if="showHeaderSearch" variant="light" accent="#E5472E" class="hidden lg:flex items-center ml-8 mr-auto" />
<!-- 桌面端导航 -->
<nav class="hidden lg:flex items-center gap-8">
<template v-for="item in navItems" :key="item.navigationId || item.path">
<div v-if="item.children && item.children.length > 0" class="relative group">
<button class="text-base font-medium text-[#33291F] hover:text-[#E5472E] transition-colors flex items-center gap-1">
{{ item.title }}
<svg class="w-4 h-4" 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-1/2 -translate-x-1/2 top-full pt-3 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all">
<div
class="bg-white rounded-2xl shadow-xl border border-[#F0E2D5] py-2"
:class="item.children.length > 4 ? 'grid grid-cols-2 gap-x-2 px-2 min-w-[340px]' : 'min-w-[170px]'"
>
<NuxtLink
v-for="child in item.children"
:key="child.navigationId"
:to="getChildPath(child)"
class="block px-4 py-2 text-[15px] text-[#33291F] hover:text-[#E5472E] hover:bg-[#FFF1E6] transition-colors whitespace-nowrap"
>
{{ child.title }}
</NuxtLink>
</div>
</div>
</div>
<NuxtLink
v-else
:to="getNavLink(item)"
:target="item.target === '_blank' ? '_blank' : undefined"
class="text-base font-medium text-[#33291F] hover:text-[#E5472E] transition-colors"
active-class="text-[#E5472E]"
>
{{ item.title }}
</NuxtLink>
</template>
</nav>
<!-- CTA -->
<div class="hidden lg:block mx-10">
<NuxtLink
to="/contact"
class="inline-flex items-center justify-center px-5 py-2 bg-[#E5472E] text-white text-base font-semibold rounded-full hover:bg-[#C53A22] transition-colors shadow-sm"
>
立即咨询
</NuxtLink>
</div>
<!-- 移动端菜单按钮 -->
<button
class="lg:hidden p-2 rounded-lg hover:bg-[#F0E2D5]"
@click="mobileMenuOpen = !mobileMenuOpen"
>
<svg v-if="!mobileMenuOpen" class="w-6 h-6 text-[#33291F]" 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 text-[#33291F]" 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>
<!-- 移动端菜单 -->
<div v-if="mobileMenuOpen" class="lg:hidden bg-[#FFF8F0] border-t border-[#F0E2D5]">
<div class="container mx-auto px-4 py-4 space-y-1">
<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-[#33291F]">
{{ 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-[#8A7B6B] hover:text-[#E5472E] hover:bg-[#FFF1E6] rounded-xl 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 font-medium text-[#33291F] hover:text-[#E5472E] hover:bg-[#FFF1E6] rounded-xl transition-colors"
active-class="text-[#E5472E] bg-[#FFF1E6]"
@click="mobileMenuOpen = false"
>
{{ item.title }}
</NuxtLink>
</template>
<NuxtLink
to="/contact"
class="block px-4 py-3 mt-2 text-center bg-[#E5472E] text-white font-semibold rounded-xl hover:bg-[#C53A22] transition-colors"
@click="mobileMenuOpen = false"
>
立即咨询
</NuxtLink>
</div>
</div>
</header>
</template>
<script setup lang="ts">
/**
* 模板 5 - Header 组件(温暖自然食品风)
* 使用 useSite 的 navigations(合并 topNavs + bottomNavs,过滤 top===1)渲染导航菜单
*/
import type { CmsNavigation } from '~/types'
const { siteInfo, siteName, siteLogo, siteIcon, navigations, showHeaderSearch, fetchSiteInfo } = useSite()
const mobileMenuOpen = ref(false)
/** 顶部数据条(满坛记品牌;可按站点实际数据替换为接口字段) */
const topStats = ['全球11大工厂', '远销近70个国家地区', '品牌价值568.72亿']
/** 子导航链接统一走 app/utils 的 getNavLink(自动避免 /page/4598?navId=4598 冗余拼接) */
function getChildPath(child: CmsNavigation): string {
return getNavLink(child)
}
// 获取站点信息(含导航数据)
await fetchSiteInfo()
/** 导航项(从 useSite 的 navigations 获取,已合并 topNavs + bottomNavs 并过滤 top===1 */
const navItems = computed<CmsNavigation[]>(() => {
return navigations.value || []
})
</script>