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,159 @@
|
||||
<template>
|
||||
<footer class="bg-[var(--t10-footer-bg)] text-[var(--t10-footer-text)]">
|
||||
<div class="t10-container py-12 lg:py-16">
|
||||
<!-- 上排:Logo 联系信息 + 链接列 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-10 lg:gap-8">
|
||||
<!-- 公司信息 -->
|
||||
<div class="lg:col-span-2">
|
||||
<SiteBrand
|
||||
link-class="inline-flex items-center gap-2 mb-5"
|
||||
:logo="siteLogo"
|
||||
:icon="siteIcon"
|
||||
:name="siteName"
|
||||
logo-class="h-[44px] w-auto max-w-[220px] object-contain brightness-0 invert"
|
||||
icon-class="h-8 w-auto object-contain brightness-0 invert"
|
||||
name-class="text-xl font-bold text-white truncate max-w-[220px]"
|
||||
>
|
||||
<template #fallback-icon>
|
||||
<span class="text-xl font-bold text-white">C-MVP</span>
|
||||
</template>
|
||||
</SiteBrand>
|
||||
<ul class="space-y-3 text-sm">
|
||||
<li v-if="phone" class="flex items-start gap-3">
|
||||
<svg class="w-4 h-4 mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
|
||||
</svg>
|
||||
<a :href="`tel:${phone}`" class="hover:text-white transition-colors">{{ phone }}</a>
|
||||
</li>
|
||||
<li v-if="email" class="flex items-start gap-3">
|
||||
<svg class="w-4 h-4 mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<a :href="`mailto:${email}`" class="hover:text-white transition-colors break-all">{{ email }}</a>
|
||||
</li>
|
||||
<li v-if="siteUrl" class="flex items-start gap-3">
|
||||
<svg class="w-4 h-4 mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
||||
</svg>
|
||||
<a :href="siteUrl" target="_blank" rel="noopener" class="hover:text-white transition-colors break-all">{{ siteUrl }}</a>
|
||||
</li>
|
||||
<li v-if="address" class="flex items-start gap-3">
|
||||
<svg class="w-4 h-4 mt-0.5 flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
<span>{{ address }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 链接列 -->
|
||||
<div v-for="col in linkColumns" :key="col.title">
|
||||
<h3 class="text-white font-semibold mb-5">{{ col.title }}</h3>
|
||||
<ul class="space-y-2.5 text-sm">
|
||||
<li v-for="link in col.links" :key="link.navigationId || link.path">
|
||||
<NuxtLink
|
||||
:to="getNavLink(link)"
|
||||
:target="link.target === '_blank' ? '_blank' : undefined"
|
||||
class="hover:text-white transition-colors"
|
||||
>
|
||||
{{ link.title }}
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="mt-12 pt-8 border-t border-white/15">
|
||||
<div class="flex flex-col md:flex-row items-center justify-between gap-4 text-xs text-center md:text-left">
|
||||
<span>{{ copyright || `Copyright © ${new Date().getFullYear()} ${siteName || ''} 版权所有` }}</span>
|
||||
<div class="flex flex-wrap items-center justify-center gap-x-4 gap-y-2">
|
||||
<a
|
||||
v-if="icpNo"
|
||||
href="https://beian.miit.gov.cn"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
class="hover:text-white transition-colors"
|
||||
>{{ icpNo }}</a>
|
||||
<a
|
||||
v-if="siteInfo?.policeNo"
|
||||
:href="policeUrl"
|
||||
target="_blank"
|
||||
rel="nofollow"
|
||||
class="hover:text-white transition-colors"
|
||||
>{{ siteInfo.policeNo }}</a>
|
||||
<a
|
||||
rel="nofollow"
|
||||
href="https://site.websoft.top"
|
||||
target="_blank"
|
||||
class="hover:text-white transition-colors"
|
||||
>Powered by 云·企业官网</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 模板 10 - Footer 组件(创芯存储科技蓝风格)
|
||||
* 科技蓝底 + 公司信息 + 四列链接 + 备案版权
|
||||
*/
|
||||
import type { CmsNavigation } from '~/types'
|
||||
|
||||
const {
|
||||
siteInfo, siteName, siteLogo, siteIcon,
|
||||
phone, email, address, copyright, icpNo,
|
||||
navigations, allNavigations, fetchSiteInfo
|
||||
} = useSite()
|
||||
|
||||
await fetchSiteInfo()
|
||||
|
||||
const siteUrl = computed(() => {
|
||||
const url = siteInfo.value?.domain || ''
|
||||
if (!url) return ''
|
||||
return url.startsWith('http') ? url : `https://${url}`
|
||||
})
|
||||
|
||||
const policeUrl = computed(() => {
|
||||
const no = String(siteInfo.value?.policeNo || '')
|
||||
const code = no.replace(/\D/g, '')
|
||||
return code
|
||||
? `https://beian.mps.gov.cn/#/query/webSearch?code=${code}`
|
||||
: 'https://beian.mps.gov.cn/'
|
||||
})
|
||||
|
||||
/** 按模型或标题智能分组链接 */
|
||||
const linkColumns = computed(() => {
|
||||
const navs = navigations.value || []
|
||||
const all = allNavigations.value || []
|
||||
const cols: { title: string, links: CmsNavigation[] }[] = []
|
||||
|
||||
const findByModel = (model: string) => all.filter((n) => n.model === model && (n.parentId || 0) === 0).slice(0, 6)
|
||||
const findByKeyword = (...keywords: string[]) => {
|
||||
return navs.filter((n) => keywords.some((k) => n.title.includes(k))).slice(0, 6)
|
||||
}
|
||||
|
||||
const products = findByModel('product')
|
||||
if (products.length) cols.push({ title: products[0]?.title || '产品中心', links: products[0]?.children?.slice(0, 6) || [products[0]].filter(Boolean) })
|
||||
|
||||
const cases = findByModel('case')
|
||||
if (cases.length) cols.push({ title: cases[0]?.title || '行业解决方案', links: cases[0]?.children?.slice(0, 6) || [cases[0]].filter(Boolean) })
|
||||
|
||||
const aboutLinks = findByKeyword('关于', '资讯', '联系', '加入')
|
||||
if (aboutLinks.length) cols.push({ title: '关于我们', links: aboutLinks })
|
||||
|
||||
const partnerLinks = findByKeyword('合作', '伙伴', '服务')
|
||||
if (partnerLinks.length) cols.push({ title: '合作伙伴', links: partnerLinks })
|
||||
|
||||
// 兜底:用底部导航补足列数
|
||||
if (cols.length < 3) {
|
||||
const bottom = (navs || []).filter((n) => n.model !== 'index').slice(0, 6)
|
||||
if (bottom.length) cols.push({ title: '快速链接', links: bottom })
|
||||
}
|
||||
|
||||
return cols
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user