覆盖最新版本代码,包含: - 新增品牌百科、公司百科页面及CMS管理 - 新增微信引导组件(WechatCTA) - 新增品牌/公司图片资源 - 全站组件/页面/数据/样式更新 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
246 行
6.0 KiB
Vue
246 行
6.0 KiB
Vue
<template>
|
||
<main class="product-detail" v-if="product">
|
||
<section class="product-hero">
|
||
<div class="container">
|
||
<nav class="breadcrumb" aria-label="面包屑导航">
|
||
<NuxtLink to="/">首页</NuxtLink> / <NuxtLink to="/products">产品线</NuxtLink> / <span>{{ product.name }}</span>
|
||
</nav>
|
||
<div class="hero-content">
|
||
<span class="product-tag">{{ product.tag }}</span>
|
||
<h1>{{ seo.h1 || product.name }}</h1>
|
||
<p class="hero-audience">适合:{{ product.audience }}</p>
|
||
<p class="hero-duration">{{ product.days }}天{{ product.nights }}晚 · 专车专属·独立成团</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="product-description">
|
||
<div class="container">
|
||
<p>{{ product.description }}</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="product-highlights" v-if="product.highlights?.length">
|
||
<div class="container">
|
||
<h2>行程亮点</h2>
|
||
<ul>
|
||
<li v-for="(h, i) in product.highlights" :key="i">{{ h }}</li>
|
||
</ul>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="product-faq" v-if="relatedFaq.length">
|
||
<div class="container">
|
||
<h2>常见问题</h2>
|
||
<div class="faq-list">
|
||
<details v-for="q in relatedFaq" :key="q.id" class="faq-item">
|
||
<summary>{{ q.question }}</summary>
|
||
<p>{{ q.answer }}</p>
|
||
</details>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="product-cta">
|
||
<div class="container">
|
||
<h2>开始定制您的行程</h2>
|
||
<p>微信添加 hulai1814,定制师一对一为您规划</p>
|
||
<NuxtLink to="/contact" class="cta-button">联系定制师</NuxtLink>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
</template>
|
||
|
||
<script setup>
|
||
import useSEO from '~/composables/useSEO'
|
||
import { useTouristTripSchema, useFAQPageSchema, useBreadcrumbSchema } from '~/composables/useJsonLd'
|
||
|
||
const route = useRoute()
|
||
const productId = route.params.id
|
||
|
||
const { data: productsData } = await usePublicApi('products')
|
||
const { data: faqData } = await usePublicApi('faq')
|
||
|
||
const product = computed(() => productsData.value?.versions?.find(v => v.id === productId))
|
||
|
||
if (!product.value) {
|
||
throw createError({ statusCode: 404, statusMessage: '产品不存在' })
|
||
}
|
||
|
||
// SEO - 每个产品独立的 meta
|
||
const seoOverrides = {
|
||
title: `${product.value.name} - 呼伦贝尔${product.value.days}天${product.value.nights}晚定制游 - 呼籁旅行`,
|
||
description: product.value.description?.substring(0, 160),
|
||
h1: product.value.name,
|
||
}
|
||
const seo = useSEO('products', seoOverrides)
|
||
|
||
// 产品页专属 keywords
|
||
useHead({
|
||
meta: [
|
||
{ name: 'keywords', content: `${product.value.name},呼伦贝尔${product.value.days}天${product.value.nights}晚,呼伦贝尔定制游,呼伦贝尔亲子游,${product.value.tag}` },
|
||
],
|
||
})
|
||
|
||
// JSON-LD: 单个产品的 TouristTrip
|
||
useTouristTripSchema([product.value])
|
||
|
||
// 面包屑
|
||
useBreadcrumbSchema([
|
||
{ text: '首页', to: '/' },
|
||
{ text: '产品线', to: '/products' },
|
||
{ text: product.value.name },
|
||
])
|
||
|
||
// 相关 FAQ - 从 FAQ 数据中匹配与天数/产品相关的问题
|
||
const allQuestions = computed(() => faqData.value?.categories?.flatMap(cat => cat.questions) || [])
|
||
const relatedFaq = computed(() => allQuestions.value.filter(q =>
|
||
q.question.includes(String(product.value?.days)) ||
|
||
q.question.includes('几天') ||
|
||
q.question.includes('亲子') ||
|
||
q.question.includes('区别') ||
|
||
q.question.includes('多少钱')
|
||
).slice(0, 5))
|
||
|
||
// 产品页也注入 FAQ schema(SEO精选摘要加分项)
|
||
if (relatedFaq.value.length) {
|
||
useFAQPageSchema([{ questions: relatedFaq.value }])
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.container {
|
||
max-width: 800px;
|
||
margin: 0 auto;
|
||
padding: 0 20px;
|
||
}
|
||
.product-hero {
|
||
background: linear-gradient(135deg, #f0f5f1, #e8ede9);
|
||
padding: 40px 0 48px;
|
||
}
|
||
.breadcrumb {
|
||
font-size: 14px;
|
||
color: #7a857c;
|
||
margin-bottom: 24px;
|
||
}
|
||
.breadcrumb a {
|
||
color: #3a7d44;
|
||
text-decoration: none;
|
||
}
|
||
.product-tag {
|
||
display: inline-block;
|
||
background: #3a7d44;
|
||
color: #fff;
|
||
padding: 4px 12px;
|
||
border-radius: 4px;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
margin-bottom: 12px;
|
||
}
|
||
h1 {
|
||
font-size: 32px;
|
||
font-weight: 800;
|
||
color: #1a1f1c;
|
||
line-height: 1.3;
|
||
margin-bottom: 12px;
|
||
}
|
||
.hero-audience, .hero-duration {
|
||
font-size: 16px;
|
||
color: #4a5e4d;
|
||
margin-bottom: 4px;
|
||
}
|
||
.product-description {
|
||
padding: 40px 0;
|
||
}
|
||
.product-description p {
|
||
font-size: 17px;
|
||
line-height: 1.8;
|
||
color: #3d4a40;
|
||
}
|
||
.product-highlights {
|
||
padding: 40px 0;
|
||
background: #fafbfa;
|
||
}
|
||
.product-highlights h2 {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
margin-bottom: 20px;
|
||
color: #1a1f1c;
|
||
}
|
||
.product-highlights ul {
|
||
list-style: none;
|
||
padding: 0;
|
||
}
|
||
.product-highlights li {
|
||
padding: 14px 0;
|
||
border-bottom: 1px solid #eef0ef;
|
||
font-size: 16px;
|
||
line-height: 1.6;
|
||
color: #3d4a40;
|
||
padding-left: 24px;
|
||
position: relative;
|
||
}
|
||
.product-highlights li::before {
|
||
content: '✓';
|
||
position: absolute;
|
||
left: 0;
|
||
color: #3a7d44;
|
||
font-weight: 700;
|
||
}
|
||
.product-faq {
|
||
padding: 40px 0;
|
||
}
|
||
.product-faq h2 {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
margin-bottom: 20px;
|
||
color: #1a1f1c;
|
||
}
|
||
.faq-item {
|
||
border-bottom: 1px solid #eef0ef;
|
||
padding: 16px 0;
|
||
}
|
||
.faq-item summary {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #1a1f1c;
|
||
cursor: pointer;
|
||
list-style: none;
|
||
}
|
||
.faq-item summary::marker { display: none; }
|
||
.faq-item summary::-webkit-details-marker { display: none; }
|
||
.faq-item p {
|
||
margin-top: 12px;
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
color: #4a5e4d;
|
||
}
|
||
.product-cta {
|
||
padding: 48px 0;
|
||
text-align: center;
|
||
background: linear-gradient(135deg, #f0f5f1, #e8ede9);
|
||
}
|
||
.product-cta h2 {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
margin-bottom: 8px;
|
||
}
|
||
.product-cta p {
|
||
color: #4a5e4d;
|
||
margin-bottom: 20px;
|
||
}
|
||
.cta-button {
|
||
display: inline-block;
|
||
background: #3a7d44;
|
||
color: #fff;
|
||
padding: 12px 32px;
|
||
border-radius: 8px;
|
||
text-decoration: none;
|
||
font-weight: 600;
|
||
font-size: 16px;
|
||
}
|
||
.cta-button:hover {
|
||
background: #2e6435;
|
||
}
|
||
</style>
|