- 后台全面引入 Naive UI 组件库,统一 UI 规范 - 前台 usePublicApi 切换到 API 调用(GET /api/content/[key]) - 前后台数据源统一(site_content 表) - 产品线统一管理(tour/camp/course 三套编辑器) - 产品数据归一化(itinerary/faq/pricing 格式统一) - 表单提交 API 改写入 submissions 表 - 新增 submissions 标记已读 API - site-content PUT 支持 upsert - 修复前台 bug(stories 路由冲突、占位符警告、selector breadcrumb) - 消除 PageHero 类型警告(useSEO reactive 修复) - 25 个前台页面全部 HTTP 200,展示效果不变 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
173 行
5.2 KiB
Vue
173 行
5.2 KiB
Vue
<template>
|
||
<div class="page-winter">
|
||
<LayoutPageHero
|
||
:title="seo.h1"
|
||
subtitle="独立成团不拼团 · 一单一车 · 随走随停 · 不错过每处风景"
|
||
:breadcrumbs="[{ text: '产品线', to: '/products' }, { text: '嗨冰雪' }]"
|
||
background-image="/images/seasons/winter-hero.jpg"
|
||
/>
|
||
|
||
<!-- TL;DR -->
|
||
<section class="page-tldr" aria-label="冬季产品摘要">
|
||
<div class="container">
|
||
<div class="page-tldr-inner">
|
||
<p>嗨冰雪V3系列:呼伦贝尔冬季定制游,5-7天南北两线可选。独立成团不拼团,一单一车随走随停。冰雪越野、雪地策马、冬季那达慕。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 品牌理念 -->
|
||
<ProductsProductOverview v-if="winterData" :narrative="winterData.narrative" class="reveal" />
|
||
|
||
<!-- 产品卡片 -->
|
||
<section v-if="winterData" class="section reveal">
|
||
<div class="container">
|
||
<CommonSectionTitle title="嗨冰雪V3系列" subtitle="5-7天南北两线,专属私家团" />
|
||
<div class="products-grid">
|
||
<WinterProductCard v-for="p in winterData.versions" :key="p.id" :product="p" />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 选行程指南 -->
|
||
<CommonSectionCTA
|
||
title="不确定选南线还是北线?"
|
||
description="告诉定制师您的假期和偏好,一分钟帮您选对行程"
|
||
:links="[{ to: '/contact', text: '联系定制师选行程' }]"
|
||
/>
|
||
|
||
<!-- 共同亮点 -->
|
||
<section v-if="winterData" class="section reveal">
|
||
<div class="container">
|
||
<CommonSectionTitle title="冬季行程亮点" subtitle="每一条线路都会体验到" />
|
||
<div class="highlights-grid">
|
||
<div v-for="(h, i) in winterData.highlights" :key="i" class="highlight-card">
|
||
<h3 class="highlight-title">{{ h.title }}</h3>
|
||
<p class="highlight-desc">{{ h.description }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 南线特色 -->
|
||
<section v-if="winterData" class="section section--warm reveal">
|
||
<div class="container">
|
||
<CommonSectionTitle title="南线特色 · 呼伦贝尔+阿尔山" subtitle="大雪原与童话小城的碰撞" />
|
||
<div class="highlights-grid">
|
||
<div v-for="(h, i) in winterData.southHighlights" :key="i" class="highlight-card">
|
||
<h3 class="highlight-title">{{ h.title }}</h3>
|
||
<p class="highlight-desc">{{ h.description }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 北线特色 -->
|
||
<section v-if="winterData" class="section reveal">
|
||
<div class="container">
|
||
<CommonSectionTitle title="北线特色 · 呼伦贝尔+大兴安岭" subtitle="边境风情与驯鹿部落的秘境" />
|
||
<div class="highlights-grid">
|
||
<div v-for="(h, i) in winterData.northHighlights" :key="i" class="highlight-card">
|
||
<h3 class="highlight-title">{{ h.title }}</h3>
|
||
<p class="highlight-desc">{{ h.description }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 内链 -->
|
||
<CommonSectionCTA
|
||
title="听听冬季旅行的家庭怎么说"
|
||
description="看看真实客户的冬季旅行评价"
|
||
:links="[{ to: '/reviews', text: '查看客户评价' }, { to: '/contact', text: '咨询冬季行程' }]"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { useBreadcrumbSchema } from '~/composables/useJsonLd'
|
||
|
||
const { data: winterData } = await usePublicApi('winter-products')
|
||
|
||
const seo = useSEO('products-winter', {
|
||
title: '嗨冰雪 - 呼伦贝尔冬季定制游 · 南北两线5-7天 - 呼籁旅行',
|
||
description: '呼籁旅行冬季定制游产品「嗨冰雪V3」,南线呼伦贝尔+阿尔山5-6天,北线呼伦贝尔+大兴安岭7天。冰雪那达慕、雪地狼群、白狼峰日出、呼伦湖蓝冰、驯鹿部落。一单一车专属私家团。',
|
||
h1: '嗨冰雪 · 呼伦贝尔冬季定制游',
|
||
})
|
||
useScrollReveal()
|
||
useBreadcrumbSchema([
|
||
{ text: '首页', to: '/' },
|
||
{ text: '产品线', to: '/products' },
|
||
{ text: '嗨冰雪' },
|
||
])
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
.products-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-xl;
|
||
|
||
.respond-md({
|
||
grid-template-columns: repeat(2, 1fr);
|
||
});
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
|
||
> * {
|
||
display: flex;
|
||
}
|
||
}
|
||
|
||
.highlights-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-lg;
|
||
|
||
.respond-md({
|
||
grid-template-columns: repeat(2, 1fr);
|
||
});
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
}
|
||
|
||
.highlight-card {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
transition: box-shadow @transition-base, transform @transition-base;
|
||
|
||
&:hover {
|
||
box-shadow: @shadow-md;
|
||
transform: translateY(-2px);
|
||
}
|
||
}
|
||
|
||
.highlight-title {
|
||
font-size: @font-size-lg;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin-bottom: @space-sm;
|
||
|
||
&::before {
|
||
content: '❄ ';
|
||
color: #3B82F6;
|
||
}
|
||
}
|
||
|
||
.highlight-desc {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-base;
|
||
}
|
||
|
||
.section--warm {
|
||
background: @color-bg-warm;
|
||
}
|
||
</style>
|