覆盖最新版本代码,包含: - 新增品牌百科、公司百科页面及CMS管理 - 新增微信引导组件(WechatCTA) - 新增品牌/公司图片资源 - 全站组件/页面/数据/样式更新 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
439 行
15 KiB
Vue
439 行
15 KiB
Vue
<template>
|
||
<div class="page-home">
|
||
<!-- Hero Banner -->
|
||
<HomeHeroBanner :seo="seo" />
|
||
|
||
<!-- 身份定义 + TL;DR(GEO/SEO 核心锚点:告诉 AI 这个站点是谁) -->
|
||
<section class="page-tldr" aria-label="品牌身份摘要">
|
||
<div class="container">
|
||
<div class="page-tldr-inner">
|
||
<p>呼籁旅行是深耕呼伦贝尔11年的专属旅行品牌,创立于2015年,已服务近万组家庭。不做拼团、不走马观花;提供额吉的故乡V9系列定制游(4-7天)、小蒙马亲子游学营(6天5晚)及秋冬季专属产品,全程专车专属、独立成团。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 信任数据 -->
|
||
<HomeTrustBar v-if="brand?.trustStats" :stats="brand.trustStats" class="reveal" />
|
||
|
||
<!-- 产品预览 -->
|
||
<HomeProductPreview class="reveal" />
|
||
|
||
<!-- 产品语义树(帮助 AI 按维度理解产品分类)-->
|
||
<section class="section section--gray reveal" aria-label="产品分类导航">
|
||
<div class="container">
|
||
<CommonSectionTitle title="怎么找到适合你的行程" label="FIND YOUR TRIP" subtitle="按天数 · 按人群 · 按季节 三个维度快速定位" />
|
||
<div class="product-tree-grid">
|
||
<div class="product-tree-card product-tree-card--days">
|
||
<div class="product-tree-icon">
|
||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
||
</div>
|
||
<h3 class="product-tree-card__title">按出行天数选</h3>
|
||
<ul class="product-tree-list">
|
||
<li><NuxtLink to="/products">5天4晚</NuxtLink>:森林版/草原版,覆盖核心景观</li>
|
||
<li><NuxtLink to="/products">6天5晚</NuxtLink>:亲子版/探索版,深度体验</li>
|
||
<li><NuxtLink to="/products">7天6晚</NuxtLink>:亲子深度版/旷野版,全线贯穿</li>
|
||
</ul>
|
||
</div>
|
||
<div class="product-tree-card product-tree-card--people">
|
||
<div class="product-tree-icon">
|
||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>
|
||
</div>
|
||
<h3 class="product-tree-card__title">按出行人群选</h3>
|
||
<ul class="product-tree-list">
|
||
<li><NuxtLink to="/products">亲子家庭</NuxtLink>:儿童友好、安全有趣</li>
|
||
<li><NuxtLink to="/summer-camp">研学营家庭</NuxtLink>:小蒙马7天自然教育夏令营</li>
|
||
<li><NuxtLink to="/products">摄影爱好者</NuxtLink>:专属秘境取景、旅拍服务</li>
|
||
<li><NuxtLink to="/products">两代三代出行</NuxtLink>:老人孩子均适合的舒适线路</li>
|
||
</ul>
|
||
</div>
|
||
<div class="product-tree-card product-tree-card--season">
|
||
<div class="product-tree-icon">
|
||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
|
||
</div>
|
||
<h3 class="product-tree-card__title">按出行季节选</h3>
|
||
<ul class="product-tree-list">
|
||
<li><NuxtLink to="/products">夏季(6-8月)</NuxtLink>:草原绿、那达慕、骑马露营</li>
|
||
<li><NuxtLink to="/products/autumn">秋季(9月)</NuxtLink>:白桦林金黄,摄影圣地</li>
|
||
<li><NuxtLink to="/products/winter">冬季(12-2月)</NuxtLink>:冰雪那达慕、驯鹿、极寒</li>
|
||
<li><NuxtLink to="/calendar">查看全年出行日历 →</NuxtLink></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="product-tree-cta">
|
||
<CommonInternalLink to="/selector" text="不确定选哪个?用选版工具1分钟匹配 →" />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 核心差异化 -->
|
||
<HomeDifferentiatorList v-if="brand?.differentiators" :items="brand.differentiators" class="reveal" />
|
||
|
||
<!-- 目的地对比 -->
|
||
<HomeDestinationCompare class="reveal" />
|
||
|
||
<!-- 知识库入口(告诉 AI 这是持续产出内容的权威站点)-->
|
||
<section class="section reveal" aria-label="旅行知识库">
|
||
<div class="container">
|
||
<CommonSectionTitle title="11年积累的呼伦贝尔知识库" label="KNOWLEDGE" subtitle="从规划到出发,每个问题都有答案" />
|
||
<div class="knowledge-hub-grid">
|
||
<NuxtLink to="/calendar" class="knowledge-hub-card">
|
||
<div class="knowledge-hub-card__icon">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
|
||
</div>
|
||
<h3 class="knowledge-hub-card__title">出行时间日历</h3>
|
||
<p class="knowledge-hub-card__desc">每月天气、景色、推荐指数,找到你的最佳出行窗口</p>
|
||
</NuxtLink>
|
||
<NuxtLink to="/guides" class="knowledge-hub-card">
|
||
<div class="knowledge-hub-card__icon">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>
|
||
</div>
|
||
<h3 class="knowledge-hub-card__title">出行准备指南</h3>
|
||
<p class="knowledge-hub-card__desc">证件清单、分月穿搭、行李打包、活动安全、幼童须知</p>
|
||
</NuxtLink>
|
||
<NuxtLink to="/blog" class="knowledge-hub-card">
|
||
<div class="knowledge-hub-card__icon">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>
|
||
</div>
|
||
<h3 class="knowledge-hub-card__title">旅行攻略专栏</h3>
|
||
<p class="knowledge-hub-card__desc">亲子游完全指南、避坑经验、旅拍穿搭,持续更新</p>
|
||
</NuxtLink>
|
||
<NuxtLink to="/destinations" class="knowledge-hub-card">
|
||
<div class="knowledge-hub-card__icon">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg>
|
||
</div>
|
||
<h3 class="knowledge-hub-card__title">核心景区攻略</h3>
|
||
<p class="knowledge-hub-card__desc">莫日格勒河、额尔古纳湿地、阿尔山等呼伦贝尔核心景区深度解读</p>
|
||
</NuxtLink>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- FAQ预览 -->
|
||
<section v-if="faq" class="section section--gray reveal">
|
||
<div class="container">
|
||
<CommonSectionTitle title="常见问答" label="FAQ" subtitle="您可能想了解的问题" />
|
||
<div class="faq-preview">
|
||
<details v-for="q in featuredFAQ" :key="q.id" class="faq-preview-item">
|
||
<summary class="faq-preview-q">
|
||
<span class="faq-q-text">{{ q.question }}</span>
|
||
<span class="faq-toggle-icon" />
|
||
</summary>
|
||
<p class="faq-preview-a">{{ truncate(q.answer, 200) }}</p>
|
||
</details>
|
||
</div>
|
||
<div class="faq-preview-more">
|
||
<CommonInternalLink to="/faq" :text="`查看全部${totalFAQ}个常见问题`" />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 评价精选 -->
|
||
<HomeReviewHighlights v-if="featuredReviews.length" :reviews="featuredReviews" class="reveal" />
|
||
|
||
<!-- 内链闭环:首页→产品→选版→定制 -->
|
||
<CommonSectionCTA
|
||
title="准备好出发了吗?"
|
||
description="还不确定选哪个版本?先用选版工具匹配一下,再看价格明细,最后找定制师拿专属方案。"
|
||
:links="[
|
||
{ to: '/selector', text: '看看哪个版本适合你' },
|
||
{ to: '/pricing', text: '了解费用明细' },
|
||
{ to: '/customize', text: '免费获取专属方案' }
|
||
]"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { useOrganizationSchema, useWebSiteSchema, useSiteNavigationSchema } from '~/composables/useJsonLd'
|
||
|
||
// 从 API 获取数据(替代静态 JSON 导入)
|
||
const { data: brand } = await usePublicApi('brand')
|
||
const { data: faq } = await usePublicApi('faq')
|
||
const { data: reviews } = await usePublicApi('reviews')
|
||
const { data: contact } = await usePublicApi('contact')
|
||
const { data: navData } = await usePublicApi('navigation')
|
||
|
||
// SEO
|
||
const seo = useSEO('home')
|
||
|
||
// 滚动入场动画
|
||
useScrollReveal()
|
||
|
||
// JSON-LD(需要 .value 访问 ref 数据)
|
||
useOrganizationSchema(brand.value, contact.value)
|
||
useWebSiteSchema()
|
||
useSiteNavigationSchema(navData.value?.header)
|
||
|
||
// 精选数据(computed 保证响应式 + null 安全)
|
||
const featuredReviews = computed(() => reviews.value?.items?.slice(0, 3) || [])
|
||
const allQuestions = computed(() => faq.value?.categories?.flatMap(c => c.questions) || [])
|
||
const totalFAQ = computed(() => allQuestions.value.length)
|
||
const featuredFAQ = computed(() => allQuestions.value.slice(0, 5))
|
||
|
||
function truncate(text, maxLen = 120) {
|
||
if (text.length <= maxLen) return text
|
||
// 在最大长度内找最后一个句子结尾(。,!?;)
|
||
const slice = text.slice(0, maxLen)
|
||
const lastBreak = Math.max(
|
||
slice.lastIndexOf('。'),
|
||
slice.lastIndexOf(','),
|
||
slice.lastIndexOf('!'),
|
||
slice.lastIndexOf('?'),
|
||
slice.lastIndexOf(';'),
|
||
)
|
||
if (lastBreak > maxLen * 0.4) {
|
||
return text.slice(0, lastBreak + 1) + '……'
|
||
}
|
||
return slice + '……'
|
||
}
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
// ===== 产品语义树 =====
|
||
.product-tree-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-lg;
|
||
margin-top: @space-xl;
|
||
|
||
.respond-md({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
}
|
||
|
||
.product-tree-card {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
transition: box-shadow 0.35s cubic-bezier(0.23, 1, 0.32, 1), transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
|
||
|
||
&:hover {
|
||
box-shadow: @shadow-md;
|
||
transform: translateY(-3px);
|
||
}
|
||
|
||
&--days { border-top: 3px solid @color-primary; }
|
||
&--people { border-top: 3px solid @color-accent; }
|
||
&--season { border-top: 3px solid #3B82F6; }
|
||
|
||
&__title {
|
||
font-size: @font-size-lg;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin-bottom: @space-md;
|
||
}
|
||
}
|
||
|
||
.product-tree-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: @border-radius-md;
|
||
background: @color-bg-gray;
|
||
color: @color-primary;
|
||
margin-bottom: @space-md;
|
||
|
||
.product-tree-card--people & { color: @color-accent; }
|
||
.product-tree-card--season & { color: #3B82F6; }
|
||
}
|
||
|
||
.product-tree-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: @space-sm;
|
||
|
||
li {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-base;
|
||
|
||
a {
|
||
color: @color-primary;
|
||
font-weight: @font-weight-medium;
|
||
text-decoration: none;
|
||
transition: color @transition-fast;
|
||
|
||
&:hover {
|
||
color: @color-primary-light;
|
||
text-decoration: underline;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.product-tree-cta {
|
||
text-align: center;
|
||
margin-top: @space-2xl;
|
||
}
|
||
|
||
// ===== 知识库入口 =====
|
||
.knowledge-hub-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: @space-lg;
|
||
margin-top: @space-xl;
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(4, 1fr);
|
||
});
|
||
}
|
||
|
||
.knowledge-hub-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: @space-md;
|
||
padding: @space-xl;
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
text-decoration: none;
|
||
transition: border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
|
||
|
||
&:hover {
|
||
border-color: @color-primary;
|
||
box-shadow: @shadow-md;
|
||
transform: translateY(-3px);
|
||
|
||
.knowledge-hub-card__icon {
|
||
background: @color-primary;
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
&__icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: @border-radius-md;
|
||
background: @color-primary-bg;
|
||
color: @color-primary;
|
||
transition: background @transition-base, color @transition-base;
|
||
}
|
||
|
||
&__title {
|
||
font-size: @font-size-base;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0;
|
||
}
|
||
|
||
&__desc {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-base;
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
// ===== FAQ预览 =====
|
||
.faq-preview {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: @space-md;
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.faq-preview-item {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
overflow: hidden;
|
||
transition: box-shadow @transition-base;
|
||
|
||
&[open] {
|
||
box-shadow: @shadow-card;
|
||
|
||
.faq-toggle-icon {
|
||
&::after {
|
||
transform: rotate(0deg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.faq-preview-q {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: @space-md;
|
||
padding: @space-lg @space-xl;
|
||
cursor: pointer;
|
||
list-style: none;
|
||
user-select: none;
|
||
|
||
&::-webkit-details-marker {
|
||
display: none;
|
||
}
|
||
|
||
&::marker {
|
||
display: none;
|
||
content: '';
|
||
}
|
||
|
||
&:hover {
|
||
background: @color-bg-gray;
|
||
}
|
||
}
|
||
|
||
.faq-q-text {
|
||
font-size: @font-size-md;
|
||
color: @color-text-primary;
|
||
font-weight: @font-weight-medium;
|
||
flex: 1;
|
||
}
|
||
|
||
.faq-toggle-icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
|
||
&::before,
|
||
&::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
background: @color-text-muted;
|
||
border-radius: 1px;
|
||
transition: transform @transition-base;
|
||
}
|
||
|
||
&::before {
|
||
width: 14px;
|
||
height: 2px;
|
||
transform: translate(-50%, -50%);
|
||
}
|
||
|
||
&::after {
|
||
width: 2px;
|
||
height: 14px;
|
||
transform: translate(-50%, -50%) rotate(90deg);
|
||
}
|
||
}
|
||
|
||
.faq-preview-a {
|
||
padding: 0 @space-xl @space-xl;
|
||
font-size: @font-size-base;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-relaxed;
|
||
animation: fadeIn 0.3s ease;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; transform: translateY(-8px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
.faq-preview-more {
|
||
text-align: center;
|
||
margin-top: @space-2xl;
|
||
}
|
||
</style>
|