feat(app): 添加多模板关于我们页面及相关路由和404页面
- 新增404页面,优化未找到页面体验,避免被搜索引擎索引 - 增加文件代理接口,隐藏真实文件服务器地址,支持文件请求代理 - 实现/article、/case、/product及/page动态路由兼容列表与详情展示 - 添加动态CMS页面兼容入口处理旧式路径,统一路由与SEO设置 - 新增模板1、模板7、模板2、模板3关于我们页面,实现多模板支持 - 模板增强支持CMS单页内容加载及SEO信息动态设置 - 配置环境变量及Git忽略文件规则辅助开发和构建环境管理
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<header class="sticky top-0 z-50 bg-white border-b border-[var(--t9-border)]">
|
||||
<div class="t9-container flex items-center h-[80px]">
|
||||
<!-- Logo -->
|
||||
<SiteBrand
|
||||
link-class="flex-shrink-0 mr-6 lg:mr-10"
|
||||
:logo="siteLogo"
|
||||
:icon="siteIcon"
|
||||
:name="siteName"
|
||||
logo-class="h-[52px] w-auto max-w-[240px] object-contain"
|
||||
icon-class="h-8 w-auto object-contain"
|
||||
name-class="text-xl font-bold text-[var(--t9-primary)] truncate max-w-[220px]"
|
||||
/>
|
||||
|
||||
<!-- 桌面端导航(水平排列,居左紧贴 Logo) -->
|
||||
<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-base text-[var(--t9-text)] hover:text-[var(--t9-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(--t9-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(--t9-text)] hover:text-[var(--t9-primary)] hover:bg-[var(--t9-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-base text-[var(--t9-text)] hover:text-[var(--t9-primary)] transition-colors whitespace-nowrap relative"
|
||||
active-class="!text-[var(--t9-primary)] after:absolute after:left-4 after:right-4 after:bottom-0 after:h-[2px] after:bg-[var(--t9-primary)]"
|
||||
>
|
||||
{{ item.title }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</nav>
|
||||
|
||||
<!-- 搜索框(后台 setting.searchBtn 控制是否显示) -->
|
||||
<SiteSearchBox
|
||||
v-if="showHeaderSearch"
|
||||
variant="light"
|
||||
accent="var(--t9-primary)"
|
||||
placeholder="搜索"
|
||||
class="hidden lg:flex items-center flex-shrink-0 ml-4"
|
||||
/>
|
||||
|
||||
<!-- 移动端菜单按钮 -->
|
||||
<button
|
||||
class="lg:hidden ml-auto p-2 text-[var(--t9-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(--t9-border)]">
|
||||
<div class="t9-container py-4 space-y-1">
|
||||
<SiteSearchBox
|
||||
v-if="showHeaderSearch"
|
||||
variant="light"
|
||||
accent="var(--t9-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(--t9-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(--t9-text-secondary)] hover:text-[var(--t9-primary)] hover:bg-[var(--t9-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(--t9-text)] hover:text-[var(--t9-primary)] hover:bg-[var(--t9-primary-soft)] transition-colors"
|
||||
active-class="text-[var(--t9-primary)] bg-[var(--t9-primary-soft)]"
|
||||
@click="mobileMenuOpen = false"
|
||||
>
|
||||
{{ item.title }}
|
||||
</NuxtLink>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 模板 9 - Header 组件(墨绿文化出版风,对齐漓江出版社官网)
|
||||
* 单层结构:白底 80px,左 Logo + 水平菜单 + 右侧圆角搜索框
|
||||
*/
|
||||
import type { CmsNavigation } from '~/types'
|
||||
|
||||
const { siteName, siteLogo, siteIcon, navigations, showHeaderSearch, fetchSiteInfo } = useSite()
|
||||
const mobileMenuOpen = ref(false)
|
||||
|
||||
/** 子导航链接统一走 app/utils 的 getNavLink */
|
||||
function getChildPath(child: CmsNavigation): string {
|
||||
return getNavLink(child)
|
||||
}
|
||||
|
||||
// 获取站点信息(含导航数据)
|
||||
await fetchSiteInfo()
|
||||
|
||||
/** 导航项(从 useSite 的 navigations 获取,已合并 topNavs + bottomNavs 并过滤 top===1) */
|
||||
const navItems = computed<CmsNavigation[]>(() => {
|
||||
return navigations.value || []
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user