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,92 @@
|
||||
<template>
|
||||
<div>
|
||||
<Component :is="templatePage" v-if="templatePage" />
|
||||
<SiteLoading v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* CMS 页面路由
|
||||
* /page/:id → 既支持旧的导航节点 ID(数字),也支持新版「单页管理」的 path(slug)
|
||||
* 数字 id → 按 navigationId 取 cms_navigation + cms_design 内容
|
||||
* 非数字 slug → 按 path 取 cms_page 已发布单页(website-admin「单页管理」模块)
|
||||
*/
|
||||
const route = useRoute()
|
||||
const id = route.params.id as string
|
||||
const isNumeric = /^\d+$/.test(id)
|
||||
const slug = isNumeric ? undefined : id
|
||||
|
||||
// 规范路由收敛:单页的规范地址是顶层 /about、/contact(独立富组件),
|
||||
// /page/about、/page/contact 仅作兼容入口,统一 301 到规范地址,避免重复页与 SEO 分散。
|
||||
const CANONICAL_PAGE_ROUTE: Record<string, string> = { about: '/about', contact: '/contact' }
|
||||
if (slug && CANONICAL_PAGE_ROUTE[slug]) {
|
||||
// 规范地址收敛:用 Nuxt 标准的 navigateTo 301 重定向(createError 仅渲染错误页,不会真正跳转)
|
||||
throw navigateTo(CANONICAL_PAGE_ROUTE[slug], { redirectCode: 301 })
|
||||
}
|
||||
|
||||
const { loadTemplate } = useTemplate()
|
||||
const { siteInfo, navigations, fetchSiteInfo } = useSite()
|
||||
|
||||
await fetchSiteInfo()
|
||||
|
||||
const templatePage = shallowRef<Component | null>(null)
|
||||
const components = await loadTemplate()
|
||||
// 语义化 slug 优先映射到独立页面组件(about→关于我们、contact→联系我们),
|
||||
// 避免有专属组件的 slug 落入通用单页 Page 逻辑——CMS 未录入正文时会显示空状态。
|
||||
// (这些页面已有结构化组件,内容更丰富,无需依赖 CMS 单页正文。)
|
||||
const standaloneComp =
|
||||
slug === 'about' ? components?.About
|
||||
: slug === 'contact' ? components?.Contact
|
||||
: null
|
||||
templatePage.value = standaloneComp || components?.Page || null
|
||||
|
||||
// 从导航中查找当前页面信息(仅数字 id 时有效)
|
||||
const currentNav = computed(() => {
|
||||
if (isNumeric) {
|
||||
const navs = navigations.value || []
|
||||
const findNav = (items: any[]): any => {
|
||||
for (const item of items) {
|
||||
if (String(item.navigationId) === id) return item
|
||||
if (item.children?.length) {
|
||||
const found = findNav(item.children)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
return findNav(navs)
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
||||
// 非数字 slug:拉取单页 SEO 信息(标题/关键词/描述/头图)
|
||||
let seoData = ref<{
|
||||
title?: string
|
||||
keywords?: string
|
||||
description?: string
|
||||
photo?: string | null
|
||||
} | null>(null)
|
||||
if (!isNumeric && slug) {
|
||||
const { data } = await useFetch<{
|
||||
title?: string
|
||||
keywords?: string
|
||||
description?: string
|
||||
photo?: string | null
|
||||
}>('/api/page/detail', {
|
||||
query: { path: slug }
|
||||
})
|
||||
seoData = data
|
||||
}
|
||||
|
||||
usePageSeo(
|
||||
{
|
||||
title: seoData.value?.title || currentNav.value?.title || (slug === 'about' ? '关于我们' : slug === 'contact' ? '联系我们' : '页面'),
|
||||
path: route.fullPath,
|
||||
keywords: seoData.value?.keywords,
|
||||
description: seoData.value?.description,
|
||||
image: seoData.value?.photo || undefined
|
||||
},
|
||||
siteInfo.value
|
||||
)
|
||||
</script>
|
||||
Reference in New Issue
Block a user