Files
hjc-web/app/templates/template-07/components/Footer.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

179 lines
7.1 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>
<footer class="bg-gray-900 text-gray-300">
<div class="container mx-auto px-4 sm:px-6 lg:px-8 py-12 lg:py-16">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-12 gap-8 lg:gap-12">
<!-- 公司信息 -->
<div class="lg:col-span-3">
<SiteBrand
link-class="mb-4"
:logo="siteLogo"
:icon="siteIcon"
:name="siteName"
logo-class="h-8 w-auto max-w-[200px] object-contain"
icon-class="h-6 w-auto object-contain"
name-class="text-lg font-bold text-white"
>
<template #fallback-icon>
<div class="w-8 h-8 rounded-lg bg-blue-600 flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
</div>
</template>
</SiteBrand>
<p v-if="slogan" class="text-sm text-gray-400 mb-3">{{ slogan }}</p>
<p class="text-sm text-gray-400 leading-relaxed">
{{ siteInfo?.comments || siteInfo?.content || '专注企业数字化官网建设,助力品牌增长。' }}
</p>
</div>
<!-- 导航分组支持二级父级标题 + 子级链接 -->
<div class="lg:col-span-4">
<div class="grid grid-cols-2 gap-x-6 gap-y-8">
<div v-for="group in footerGroups" :key="group.key">
<h4 class="text-white font-semibold mb-4">
<span
v-if="group.parentLink"
:to="group.parentLink"
:target="group.target === '_blank' ? '_blank' : undefined"
class="text-white"
>
{{ group.title }}
</span>
<template v-else>{{ group.title }}</template>
</h4>
<ul v-if="group.hasChildren" class="space-y-2">
<li v-for="link in group.links" :key="link.key">
<NuxtLink
:to="getNavLink(link)"
:target="link.target === '_blank' ? '_blank' : undefined"
class="text-sm text-gray-400 hover:text-white transition-colors"
>
{{ link.title }}
</NuxtLink>
</li>
</ul>
</div>
</div>
</div>
<!-- 联系方式 -->
<div class="lg:col-span-3">
<h4 class="text-white font-semibold mb-4">联系我们</h4>
<ul class="space-y-2 text-sm text-gray-400">
<li v-if="phone">
<span class="text-gray-500">电话</span>{{ phone }}
</li>
<li v-if="email">
<span class="text-gray-500">邮箱</span>{{ email }}
</li>
<li v-if="officialWebsite">
<span class="text-gray-500">官网</span>
<a :href="officialWebsiteUrl" target="_blank" rel="nofollow" class="hover:text-white transition-colors">{{ officialWebsite }}</a>
</li>
<li v-if="address" class="leading-relaxed">
<span class="text-gray-500">地址</span>{{ address }}
</li>
</ul>
</div>
<!-- 微信二维码 + 社交链接 -->
<div v-if="wxQrcode || socialLinks.length" class="lg:col-span-2">
<h4 class="text-white font-semibold mb-4">关注我们</h4>
<div v-if="wxQrcode" class="bg-white rounded-lg p-3 inline-block">
<img :src="wxQrcode" alt="微信二维码" class="w-28 h-28 object-contain">
</div>
<p v-if="wxQrcode" class="text-xs text-gray-500 mt-2">{{ siteConfig?.wxQrcodeText || '扫码关注' }}</p>
<div v-if="socialLinks.length" class="mt-3 flex flex-col gap-1">
<a
v-for="link in socialLinks"
:key="link.url"
:href="link.url"
target="_blank"
rel="nofollow"
class="text-sm text-gray-400 hover:text-white transition-colors"
>
{{ link.name || link.type }}
</a>
</div>
</div>
</div>
<div class="border-t border-gray-800 mt-12 pt-8 flex flex-col sm:flex-row items-center justify-between gap-4">
<p class="text-sm text-gray-500">
{{ copyright || ${new Date().getFullYear()} ${siteName || '企业官网'} 版权所有` }}
</p>
<div class="flex items-center gap-4">
<p v-if="icpNo" class="text-sm text-gray-500">
{{ icpNo }}
</p>
<p v-if="siteInfo?.policeNo" class="text-sm text-gray-500">
{{ siteInfo.policeNo }}
</p>
<div class="flex items-center gap-2 text-xs">
<span class="text-gray-500">Powered by</span>
<a
rel="nofollow"
href="https://site.websoft.top"
target="_blank"
class="text-gray-500 hover:text-gray-200 transition-colors"
>·企业官网</a>
</div>
</div>
</div>
</div>
</footer>
</template>
<script setup lang="ts">
/**
* 模板 7 - Footer 组件
* 使用 useSite 的 bottomNavigationstop!==1 的页脚链接)渲染导航。
* 支持二级导航:每个顶级栏目作为分组标题,其 children 作为子链接渲染在标题下方;
* 若栏目无子级,则该栏目自身作为单独链接展示(无二级时不退化、不报错)。
*/
import type { CmsNavigation } from '~/types'
const {
siteInfo, siteName, siteLogo, siteIcon, siteConfig,
bottomNavigations, phone, email, address, icpNo, copyright,
wxQrcode, slogan, officialWebsite, officialWebsiteUrl, socialLinks
} = useSite()
interface FooterGroup {
key: string | number
title: string
/** 父级可点击链接(父级自身有 path/url 时存在;无子级时即为该栏目链接) */
parentLink: string | null
/** 是否渲染子级列表 */
hasChildren: boolean
/** 子级链接(无子级时为 [父级自身]) */
links: CmsNavigation[]
/** 父级打开方式 */
target?: string
}
function navKey(nav: CmsNavigation): string | number {
return nav.navigationId ?? nav.path ?? nav.pagePath ?? nav.title ?? Math.random()
}
/** 页脚导航分组:将 bottomNavigations 整理为「父级标题 + 子级链接」结构 */
const footerGroups = computed<FooterGroup[]>(() => {
const navs = bottomNavigations.value || []
return navs
.filter((nav) => nav.model !== 'index')
.map((nav) => {
const children = nav.children && nav.children.length ? nav.children : null
const hasOwnLink = !!(nav.path || nav.url || nav.pagePath)
return {
key: navKey(nav),
title: nav.title || '',
parentLink: hasOwnLink ? getNavLink(nav) : null,
hasChildren: !!children,
links: children || [nav],
target: nav.target
}
})
})
</script>