- 后台全面引入 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>
452 行
11 KiB
Vue
452 行
11 KiB
Vue
<template>
|
||
<div class="page-about">
|
||
<LayoutPageHero
|
||
:title="seo.h1 || '关于呼籁旅行'"
|
||
subtitle="一个深耕呼伦贝尔的旅行品牌"
|
||
:breadcrumbs="[{ text: '关于我们' }]"
|
||
background-image="/images/seasons/summer-hero.jpg"
|
||
/>
|
||
|
||
<!-- TL;DR -->
|
||
<section class="page-tldr" aria-label="关于我们摘要">
|
||
<div class="container">
|
||
<div class="page-tldr-inner">
|
||
<p>呼籁旅行创立于2015年,是内蒙古呼伦贝尔本地旅行品牌,11年专注呼伦贝尔一个目的地。旗下持有三重旅行社经营许可证,购买1000万旅游责任险。集团旗下涵盖旅行社、旅游客运、露营地、牧场商贸、研学教育等9家主体。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 1. 品牌故事:为什么只做呼伦贝尔 -->
|
||
<AboutBrandStory v-if="about" :story="about.story" class="reveal" />
|
||
|
||
<!-- 2. 服务旅程:跟呼籁出行是什么体验 -->
|
||
<section v-if="about" class="section section--gray reveal" aria-label="服务旅程">
|
||
<div class="container">
|
||
<CommonSectionTitle :title="about.serviceJourney.title" :subtitle="about.serviceJourney.subtitle" />
|
||
<ol class="journey-list">
|
||
<li v-for="m in about.serviceJourney.moments" :key="m.step" class="journey-item">
|
||
<span class="journey-step">{{ m.step }}</span>
|
||
<div class="journey-body">
|
||
<strong class="journey-name">{{ m.name }}</strong>
|
||
<p class="journey-detail">{{ m.detail }}</p>
|
||
</div>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 3. 团队介绍:谁在照顾你 -->
|
||
<AboutTeamIntro v-if="about" :team="about.team" class="reveal" />
|
||
|
||
<!-- 4. 小红书 -->
|
||
<AboutXiaohongshuShowcase v-if="about" :xhs="about.xiaohongshu" class="reveal" />
|
||
|
||
<!-- 6. 品牌发展历程 -->
|
||
<section v-if="about" class="section reveal" aria-label="品牌发展历程">
|
||
<div class="container">
|
||
<CommonSectionTitle :title="about.heritage.title" subtitle="2015年创立至今,一步一个脚印走在呼伦贝尔草原上" />
|
||
<div class="timeline">
|
||
<div v-for="milestone in about.heritage.milestones" :key="milestone.year" class="timeline-item">
|
||
<div class="timeline-marker">
|
||
<div class="timeline-dot" />
|
||
</div>
|
||
<div class="timeline-card">
|
||
<h4 class="timeline-year">{{ milestone.year }} 年</h4>
|
||
<p v-for="(p, i) in milestone.paragraphs" :key="i" class="timeline-text">{{ p }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 7. 集团企业 -->
|
||
<AboutSubsidiaryGrid v-if="about" :subsidiaries="about.subsidiaries" class="reveal" />
|
||
|
||
<!-- 8. 品牌资产:知识产权 + 吉祥物 -->
|
||
<AboutCopyrightList v-if="about" :copyrights="about.copyrights" :trademark="about.trademark" class="reveal" />
|
||
<AboutMascotShowcase class="reveal" />
|
||
|
||
<!-- 9. 企业文化 -->
|
||
<section v-if="about" class="section reveal" aria-label="企业文化">
|
||
<div class="container">
|
||
<!-- 核心信念 -->
|
||
<div class="culture-belief">
|
||
<p class="culture-belief__prefix">我们深知</p>
|
||
<div class="culture-belief__divider"></div>
|
||
<p class="culture-belief__quote">大部分人只来一次呼伦贝尔</p>
|
||
<p class="culture-belief__quote">而这一次便是一辈子的回忆</p>
|
||
<div class="culture-belief__divider"></div>
|
||
<p class="culture-belief__cta">所以,我们从不敢有任何的怠慢</p>
|
||
</div>
|
||
|
||
<!-- 价值观 -->
|
||
<CommonSectionTitle title="呼籁文化理念" />
|
||
<div class="culture-values">
|
||
<div v-for="value in about.culture.values" :key="value.name" class="culture-value-card">
|
||
<h4 class="culture-value-card__name">{{ value.name }}</h4>
|
||
<ul class="culture-value-card__list">
|
||
<li v-for="(point, i) in value.points" :key="i">{{ point }}</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 品牌 Slogan -->
|
||
<div v-if="about.culture.slogan" class="culture-slogan">
|
||
<div v-for="(line, i) in about.culture.slogan.lines" :key="i" class="culture-slogan__line">
|
||
<span v-if="line.label" class="culture-slogan__label">{{ line.label }}</span>
|
||
<p class="culture-slogan__text">{{ line.text }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- CTA -->
|
||
<CommonSectionCTA
|
||
title="想了解我们的产品?"
|
||
description="查看额吉的故乡V9系列和小蒙马夏令营"
|
||
:links="[
|
||
{ to: '/products', text: '查看旅行产品' },
|
||
{ to: '/contact', text: '联系定制师' },
|
||
]"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { useOrganizationSchema, useBreadcrumbSchema, usePersonSchema } from '~/composables/useJsonLd'
|
||
|
||
const { data: about } = await usePublicApi('about')
|
||
const { data: brand } = await usePublicApi('brand')
|
||
const { data: contact } = await usePublicApi('contact')
|
||
|
||
const seo = useSEO('about')
|
||
useScrollReveal()
|
||
useOrganizationSchema(brand.value, contact.value)
|
||
usePersonSchema(about.value?.founder)
|
||
useBreadcrumbSchema([
|
||
{ text: '首页', to: '/' },
|
||
{ text: '关于我们' },
|
||
])
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
// ===== 服务旅程 =====
|
||
.journey-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: @space-xl 0 0;
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-md;
|
||
|
||
.respond-md({
|
||
grid-template-columns: repeat(2, 1fr);
|
||
});
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(4, 1fr);
|
||
});
|
||
}
|
||
|
||
.journey-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
text-align: center;
|
||
padding: @space-xl @space-lg;
|
||
background: @color-bg-white;
|
||
border-radius: @border-radius-lg;
|
||
border: 1px solid @color-border;
|
||
transition: box-shadow @transition-base, transform @transition-base;
|
||
|
||
&:hover {
|
||
box-shadow: @shadow-md;
|
||
transform: translateY(-2px);
|
||
border-color: @color-primary-lighter;
|
||
|
||
.journey-step {
|
||
background: @color-primary;
|
||
color: #fff;
|
||
border-color: @color-primary;
|
||
}
|
||
}
|
||
}
|
||
|
||
.journey-step {
|
||
flex-shrink: 0;
|
||
width: 40px;
|
||
height: 40px;
|
||
background: transparent;
|
||
color: @color-primary;
|
||
border: 2px solid @color-primary;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: @font-size-sm;
|
||
font-weight: @font-weight-bold;
|
||
margin-bottom: @space-md;
|
||
transition: all @transition-base;
|
||
}
|
||
|
||
.journey-body {
|
||
flex: 1;
|
||
}
|
||
|
||
.journey-name {
|
||
display: block;
|
||
font-size: @font-size-base;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin-bottom: @space-xs;
|
||
}
|
||
|
||
.journey-detail {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-base;
|
||
margin: 0;
|
||
}
|
||
|
||
// ===== 发展历程 =====
|
||
.timeline {
|
||
position: relative;
|
||
max-width: 800px;
|
||
margin: @space-xl auto 0;
|
||
padding-left: @space-xl;
|
||
|
||
// 左侧竖线
|
||
&::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 5px;
|
||
top: 8px;
|
||
bottom: 0;
|
||
width: 2px;
|
||
background: @color-primary-lighter;
|
||
}
|
||
}
|
||
|
||
.timeline-item {
|
||
position: relative;
|
||
display: flex;
|
||
gap: @space-lg;
|
||
padding-bottom: @space-2xl;
|
||
|
||
&:last-child {
|
||
padding-bottom: 0;
|
||
|
||
// 最后一项不画线到底
|
||
&::before {
|
||
display: none;
|
||
}
|
||
}
|
||
}
|
||
|
||
.timeline-marker {
|
||
position: absolute;
|
||
left: -@space-xl + 1px;
|
||
top: 6px;
|
||
}
|
||
|
||
.timeline-dot {
|
||
width: 10px;
|
||
height: 10px;
|
||
background: @color-primary;
|
||
border-radius: 50%;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.timeline-card {
|
||
flex: 1;
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-lg @space-xl;
|
||
box-shadow: @shadow-xs;
|
||
transition: box-shadow @transition-base;
|
||
|
||
&:hover {
|
||
box-shadow: @shadow-card;
|
||
}
|
||
}
|
||
|
||
.timeline-year {
|
||
font-size: @font-size-lg;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-primary;
|
||
margin: 0 0 @space-sm;
|
||
}
|
||
|
||
.timeline-text {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-relaxed;
|
||
margin: 0 0 @space-md;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
// ===== 企业文化 =====
|
||
.culture-belief {
|
||
background: linear-gradient(135deg, @color-primary-dark 0%, @color-primary 60%, @color-primary-light 100%);
|
||
color: #fff;
|
||
border-radius: @border-radius-xl;
|
||
padding: @space-3xl @space-2xl;
|
||
margin-bottom: @space-2xl;
|
||
text-align: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
|
||
.respond-md({
|
||
padding: @space-4xl @space-3xl;
|
||
});
|
||
|
||
&__prefix {
|
||
font-size: @font-size-lg;
|
||
font-weight: @font-weight-bold;
|
||
letter-spacing: 6px;
|
||
color: #fff;
|
||
margin: 0 0 @space-lg;
|
||
|
||
.respond-md({
|
||
font-size: @font-size-xl;
|
||
letter-spacing: 8px;
|
||
});
|
||
}
|
||
|
||
&__divider {
|
||
width: 48px;
|
||
height: 2px;
|
||
background: rgba(255, 255, 255, 0.5);
|
||
margin: @space-lg auto;
|
||
}
|
||
|
||
&__quote {
|
||
font-size: @font-size-2xl;
|
||
font-weight: @font-weight-bold;
|
||
line-height: @line-height-relaxed;
|
||
margin: 0 0 @space-sm;
|
||
letter-spacing: 2px;
|
||
color: #fff;
|
||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||
|
||
.respond-md({
|
||
font-size: @font-size-3xl;
|
||
letter-spacing: 3px;
|
||
});
|
||
}
|
||
|
||
&__cta {
|
||
font-size: @font-size-md;
|
||
font-weight: @font-weight-medium;
|
||
letter-spacing: 3px;
|
||
color: rgba(255, 255, 255, 0.9);
|
||
margin: 0;
|
||
|
||
.respond-md({
|
||
font-size: @font-size-xl;
|
||
letter-spacing: 4px;
|
||
});
|
||
}
|
||
}
|
||
|
||
.culture-values {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-lg;
|
||
margin-top: @space-xl;
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
}
|
||
|
||
.culture-value-card {
|
||
background: @color-bg-gray;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
|
||
&__name {
|
||
font-size: @font-size-lg;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-primary;
|
||
margin: 0 0 @space-md;
|
||
}
|
||
|
||
&__list {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: @space-md;
|
||
|
||
li {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
line-height: @line-height-base;
|
||
padding-left: @space-lg;
|
||
position: relative;
|
||
|
||
&::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 9px;
|
||
width: 16px;
|
||
height: 2px;
|
||
background: @color-primary-lighter;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.culture-slogan {
|
||
margin-top: @space-3xl;
|
||
text-align: center;
|
||
padding: @space-2xl 0;
|
||
max-width: 640px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
|
||
&__line {
|
||
margin-bottom: @space-xl;
|
||
padding-bottom: @space-xl;
|
||
border-bottom: 1px solid @color-divider;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
padding-bottom: 0;
|
||
border-bottom: none;
|
||
}
|
||
}
|
||
|
||
&__label {
|
||
display: inline-block;
|
||
font-size: @font-size-xs;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-primary;
|
||
letter-spacing: 4px;
|
||
text-transform: uppercase;
|
||
margin-bottom: @space-sm;
|
||
}
|
||
|
||
&__text {
|
||
font-size: @font-size-xl;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
line-height: @line-height-normal;
|
||
margin: 0;
|
||
letter-spacing: 1px;
|
||
|
||
.respond-md({
|
||
font-size: @font-size-2xl;
|
||
});
|
||
}
|
||
}
|
||
</style>
|