Files
hjc-web/app/templates/template-03/pages/Home.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

155 lines
5.5 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>
<HeroSection />
<FeatureSection />
<!-- 关于我们 -->
<AboutSection
title-color="text-gray-900"
accent-color="#8b6f47"
summary-color="text-gray-600"
link-color="text-[#8b6f47]"
container-class="container mx-auto px-4 sm:px-6 lg:px-8 grid lg:grid-cols-2 gap-12 items-center"
image-bg-color="bg-gray-100"
image-object-fit="object-cover"
/>
<!-- 最新动态 -->
<section v-if="latestArticles.length > 0" class="py-16 lg:py-20 bg-[#f5efe6]">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="text-center mb-12">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 mb-4" data-reveal>最新动态</h2>
<p class="text-gray-600 max-w-2xl mx-auto" data-reveal data-reveal-delay="100">了解企业最新资讯与行业动态</p>
</div>
<div class="grid md:grid-cols-3 gap-6">
<article
v-for="(item, index) in latestArticles"
:key="item.id || item.articleId"
class="bg-white rounded-xl overflow-hidden shadow-sm hover:shadow-md transition-shadow"
data-reveal
:data-reveal-delay="index * 100"
>
<NuxtLink :to="`/article/${item.id || item.articleId}`">
<div class="aspect-video bg-gray-100 flex items-center justify-center overflow-hidden">
<img
:src="articleImage(item)"
:alt="item.title"
class="w-full h-full object-cover"
loading="lazy"
@error="onArticleImgError($event)"
>
</div>
</NuxtLink>
<div class="p-5">
<div class="text-xs text-gray-500 mb-2">
{{ formatDate(item.publishTime || item.createTime) }}
<span v-if="item.categoryName" class="ml-2 text-[#8b6f47]">{{ item.categoryName }}</span>
</div>
<h3 class="text-lg font-semibold text-gray-900 mb-2 line-clamp-2 hover:text-[#8b6f47] transition-colors">
<NuxtLink :to="`/article/${item.id || item.articleId}`">{{ item.title }}</NuxtLink>
</h3>
<p class="text-sm text-gray-600 line-clamp-2">{{ stripHtml(item.summary) }}</p>
</div>
</article>
</div>
<div v-if="newsNav" class="text-center mt-10">
<NuxtLink
:to="newsNav.path || '/article'"
class="inline-flex items-center text-[#8b6f47] font-semibold hover:text-[#6f5638] transition-colors"
>
查看更多
<svg class="w-4 h-4 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
</NuxtLink>
</div>
</div>
</section>
<!-- 联系我们 -->
<section class="py-16 lg:py-20 bg-white">
<div class="container mx-auto px-4 sm:px-6 lg:px-8 text-center">
<h2 class="text-2xl sm:text-3xl font-bold text-gray-900 mb-4" data-reveal>
准备好开始了吗
</h2>
<p class="text-gray-600 max-w-2xl mx-auto mb-8" data-reveal data-reveal-delay="100">
立即联系我们获取专属企业官网解决方案
</p>
<button
type="button"
class="inline-flex items-center justify-center px-8 py-3 bg-[#8b6f47] text-white font-semibold rounded-lg hover:bg-[#6f5638] transition-colors"
@click="openConsult()"
>
立即咨询
</button>
</div>
</section>
</div>
</template>
<script setup lang="ts">
/**
* 模板 3 - 首页(暖米轻商风)
* 使用 getSiteInfo 站点信息 + cms-article 文章数据
*/
import dayjs from 'dayjs'
import HeroSection from '../components/HeroSection.vue'
import FeatureSection from '../components/FeatureSection.vue'
import type { CmsNavigation, Article, PageResult, ApiEnvelope } from '~/types'
const { siteInfo, siteName, navigations, fetchSiteInfo } = useSite()
const { fileUrl } = useFileUrl()
const { openConsult } = useConsult()
// 获取站点信息(含导航)
await fetchSiteInfo()
/** 从导航中找到"新闻/动态"相关的导航项 */
const newsNav = computed<CmsNavigation | undefined>(() => {
const navs = navigations.value || []
return navs.find((n) => n.model === 'article')
})
/** 获取最新文章(取新闻导航下的文章) */
const latestArticles = ref<Article[]>([])
if (newsNav.value) {
try {
const res = await $fetch<ApiEnvelope<PageResult<Article>> | PageResult<Article>>(
'/api/article/list',
{
query: {
navigationId: newsNav.value.navigationId,
page: 1,
limit: 3
}
}
)
const envelope = res as ApiEnvelope<PageResult<Article>>
latestArticles.value = envelope?.data?.list || (res as PageResult<Article>)?.list || []
} catch {
latestArticles.value = []
}
}
function formatDate(date?: string) {
if (!date) return ''
return dayjs(date).format('YYYY-MM-DD')
}
/** 文章封面图:后端字段 > 本地兜底 */
const FALLBACK_NEWS_IMAGE = '/images/template-03/news-default.jpg'
function articleImage(item: Article) {
const raw = item.image || item.cover || item.photo || ''
if (!raw) return FALLBACK_NEWS_IMAGE
return fileUrl(raw)
}
/** 文章封面图加载失败 → 回退到本地图 */
function onArticleImgError(e: Event) {
const el = e.target as HTMLImageElement
if (el && el.src !== FALLBACK_NEWS_IMAGE) {
el.src = FALLBACK_NEWS_IMAGE
}
}
</script>