- 后台全面引入 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>
517 行
13 KiB
Vue
517 行
13 KiB
Vue
<template>
|
||
<div class="page-partners">
|
||
<LayoutPageHero
|
||
:title="seo.h1"
|
||
subtitle="行业认证 · 平台背书 · 景区合作 · 高校联合"
|
||
:breadcrumbs="[{ text: '关于我们', to: '/about' }, { text: '合作伙伴' }]"
|
||
background-image="/images/team/campsite-team.jpg"
|
||
/>
|
||
|
||
<!-- TL;DR -->
|
||
<section class="page-tldr" aria-label="合作伙伴摘要">
|
||
<div class="container">
|
||
<div class="page-tldr-inner">
|
||
<p>呼籁旅行合作伙伴:涵盖平台认证(携程、飞猪、马蜂窝)、景区合作、高校联合、异业合作等多个维度,展示品牌信任背书。</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 平台认证(已验证,排在最前) -->
|
||
<section v-if="partners" class="section section-platforms">
|
||
<div class="container">
|
||
<CommonSectionTitle
|
||
title="平台认证与荣誉"
|
||
subtitle="官方认证账号,平台公开可查"
|
||
/>
|
||
<div class="platforms-grid reveal">
|
||
<div
|
||
v-for="platform in verifiedPlatforms"
|
||
:key="platform.platform"
|
||
class="platform-card platform-card--verified"
|
||
>
|
||
<div class="platform-card__status">✓ {{ platform.status }}</div>
|
||
<h3 class="platform-card__name">{{ platform.platform }}</h3>
|
||
<p class="platform-card__detail">{{ platform.detail }}</p>
|
||
<p v-if="platform.followers" class="platform-card__followers">粉丝 {{ platform.followers }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 政府与行业认证 -->
|
||
<section v-if="partners" class="section section-gov section-alt">
|
||
<div class="container">
|
||
<CommonSectionTitle
|
||
title="政府资质与行业背书"
|
||
subtitle="来自官方机构的认可与合作"
|
||
/>
|
||
<div class="partners-list reveal">
|
||
<div class="partners-list__group">
|
||
<h3 class="partners-list__group-title">官方资质认定</h3>
|
||
<div class="partners-items">
|
||
<div v-for="item in partners.associations.slice(0, 1)" :key="item.name" class="partner-item partner-item--official">
|
||
<div class="partner-item__icon">🏛️</div>
|
||
<div class="partner-item__content">
|
||
<h4 class="partner-item__name">{{ item.name }}</h4>
|
||
<p class="partner-item__relation">{{ item.relationship }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="partners-list__group">
|
||
<h3 class="partners-list__group-title">行业协会
|
||
<span class="group-title-note">⚠️ 以下信息需确认</span>
|
||
</h3>
|
||
<div class="partners-items">
|
||
<div
|
||
v-for="item in partners.associations.slice(1)"
|
||
:key="item.name"
|
||
class="partner-item"
|
||
:class="{ 'partner-item--unverified': !item.verified }"
|
||
>
|
||
<div class="partner-item__icon">🤝</div>
|
||
<div class="partner-item__content">
|
||
<h4 class="partner-item__name">{{ item.name }}</h4>
|
||
<p class="partner-item__relation">{{ item.memberType }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 高校合作 -->
|
||
<section v-if="partners" class="section section-academic">
|
||
<div class="container">
|
||
<CommonSectionTitle
|
||
title="校企合作"
|
||
subtitle="联合高校,培养本地旅游人才"
|
||
/>
|
||
<div class="academic-grid reveal">
|
||
<div
|
||
v-for="coop in partners.academicCoops"
|
||
:key="coop.name"
|
||
class="academic-card"
|
||
>
|
||
<div class="academic-card__icon">🎓</div>
|
||
<div class="academic-card__content">
|
||
<h3 class="academic-card__name">{{ coop.name }}</h3>
|
||
<span class="academic-card__type">{{ coop.relationship }}</span>
|
||
<p class="academic-card__desc">{{ coop.description }}</p>
|
||
<span v-if="coop.since" class="academic-card__since">合作始于 {{ coop.since }} 年</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 景区合作 -->
|
||
<section v-if="partners" class="section section-scenic section-alt">
|
||
<div class="container">
|
||
<CommonSectionTitle
|
||
title="景区合作"
|
||
subtitle="与呼伦贝尔核心景区深度合作,确保专属体验"
|
||
/>
|
||
<div class="scenic-grid reveal">
|
||
<div
|
||
v-for="scenic in verifiedScenicPartners"
|
||
:key="scenic.name"
|
||
class="scenic-card"
|
||
>
|
||
<h3 class="scenic-card__name">{{ scenic.name }}</h3>
|
||
<p class="scenic-card__desc">{{ scenic.description }}</p>
|
||
</div>
|
||
</div>
|
||
<p v-if="unverifiedScenicCount > 0" class="section-placeholder-note">
|
||
⚠️ 还有 {{ unverifiedScenicCount }} 个合作景区待确认,请补充完整
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 媒体报道 -->
|
||
<section v-if="partners" class="section section-media">
|
||
<div class="container">
|
||
<div class="section-header-with-note reveal">
|
||
<CommonSectionTitle
|
||
title="媒体报道"
|
||
subtitle="第三方媒体对呼籁旅行的报道与采访"
|
||
/>
|
||
<div class="placeholder-banner">
|
||
⚠️ 本栏目所有内容均为占位框架,需补充真实媒体报道链接后方可正式上线
|
||
</div>
|
||
</div>
|
||
<div class="media-grid reveal">
|
||
<div
|
||
v-for="(report, index) in partners.mediaReports"
|
||
:key="index"
|
||
class="media-card media-card--placeholder"
|
||
>
|
||
<div class="media-card__outlet">{{ report.outlet }}</div>
|
||
<h3 class="media-card__title">{{ report.title }}</h3>
|
||
<p class="media-card__summary">{{ report.summary }}</p>
|
||
<div class="media-card__footer">
|
||
<span class="media-card__date">{{ report.date }}</span>
|
||
<span class="media-card__link-placeholder">⚠️ 链接待补充</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 内链 -->
|
||
<CommonSectionCTA
|
||
title="选择有资质的旅行品牌"
|
||
description="查看呼籁的完整资质证明,或直接联系定制师"
|
||
:links="[
|
||
{ to: '/qualifications', text: '查看完整资质证书' },
|
||
{ to: '/reviews', text: '查看真实客户评价' },
|
||
]"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { useOrganizationSchema, useBreadcrumbSchema } from '~/composables/useJsonLd'
|
||
|
||
const { data: partners } = await usePublicApi('partners')
|
||
const { data: brand } = await usePublicApi('brand')
|
||
const { data: contact } = await usePublicApi('contact')
|
||
|
||
const seo = useSEO('partners')
|
||
useScrollReveal()
|
||
useOrganizationSchema(brand.value, contact.value)
|
||
useBreadcrumbSchema([
|
||
{ text: '首页', to: '/' },
|
||
{ text: '关于我们', to: '/about' },
|
||
{ text: '合作伙伴与媒体' },
|
||
])
|
||
|
||
const verifiedPlatforms = computed(() =>
|
||
(partners.value?.platformEndorsements || []).filter(p => p.verified)
|
||
)
|
||
|
||
const verifiedScenicPartners = computed(() =>
|
||
(partners.value?.scenicPartners || []).filter(p => p.verified)
|
||
)
|
||
|
||
const unverifiedScenicCount = computed(() =>
|
||
(partners.value?.scenicPartners || []).filter(p => !p.verified).length
|
||
)
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
// 平台认证
|
||
.platforms-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-lg;
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
}
|
||
|
||
.platform-card {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
|
||
&--verified {
|
||
border-color: @color-primary;
|
||
background: @color-primary-bg;
|
||
}
|
||
|
||
&__status {
|
||
font-size: @font-size-xs;
|
||
color: @color-primary;
|
||
font-weight: @font-weight-bold;
|
||
margin-bottom: @space-sm;
|
||
}
|
||
|
||
&__name {
|
||
font-size: @font-size-lg;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0 0 @space-sm;
|
||
}
|
||
|
||
&__detail {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
margin: 0 0 @space-sm;
|
||
line-height: @line-height-base;
|
||
}
|
||
|
||
&__followers {
|
||
font-size: @font-size-sm;
|
||
color: @color-primary;
|
||
font-weight: @font-weight-medium;
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
// 政府合作
|
||
.section-gov {
|
||
background: @color-bg-gray;
|
||
}
|
||
|
||
.partners-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: @space-xl;
|
||
|
||
&__group {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
}
|
||
|
||
&__group-title {
|
||
font-size: @font-size-md;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0 0 @space-lg;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: @space-md;
|
||
}
|
||
}
|
||
|
||
.group-title-note {
|
||
font-size: @font-size-xs;
|
||
font-weight: normal;
|
||
color: #e67e22;
|
||
background: #fef9e7;
|
||
padding: 2px @space-sm;
|
||
border-radius: @border-radius-sm;
|
||
}
|
||
|
||
.partners-items {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: @space-md;
|
||
}
|
||
|
||
.partner-item {
|
||
display: flex;
|
||
gap: @space-md;
|
||
align-items: flex-start;
|
||
padding: @space-md;
|
||
border-radius: @border-radius-md;
|
||
background: @color-bg-gray;
|
||
|
||
&--official {
|
||
background: @color-primary-bg;
|
||
}
|
||
|
||
&--unverified {
|
||
opacity: 0.7;
|
||
}
|
||
|
||
&__icon {
|
||
font-size: 24px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
&__content {
|
||
flex: 1;
|
||
}
|
||
|
||
&__name {
|
||
font-size: @font-size-sm;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0 0 @space-xs;
|
||
}
|
||
|
||
&__relation {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
margin: 0;
|
||
}
|
||
}
|
||
|
||
// 高校合作
|
||
.academic-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-lg;
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(2, 1fr);
|
||
});
|
||
}
|
||
|
||
.academic-card {
|
||
display: flex;
|
||
gap: @space-lg;
|
||
align-items: flex-start;
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
|
||
&__icon {
|
||
font-size: 36px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
&__content {
|
||
flex: 1;
|
||
}
|
||
|
||
&__name {
|
||
font-size: @font-size-md;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0 0 @space-xs;
|
||
}
|
||
|
||
&__type {
|
||
display: inline-block;
|
||
font-size: @font-size-xs;
|
||
padding: 2px @space-sm;
|
||
background: @color-primary;
|
||
color: #fff;
|
||
border-radius: @border-radius-full;
|
||
margin-bottom: @space-sm;
|
||
}
|
||
|
||
&__desc {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
margin: 0 0 @space-sm;
|
||
line-height: @line-height-base;
|
||
}
|
||
|
||
&__since {
|
||
font-size: @font-size-xs;
|
||
color: @color-text-muted;
|
||
}
|
||
}
|
||
|
||
// 景区合作
|
||
.section-scenic {
|
||
background: @color-bg-gray;
|
||
}
|
||
|
||
.scenic-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: @space-md;
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
}
|
||
|
||
.scenic-card {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-md;
|
||
padding: @space-lg;
|
||
|
||
&__name {
|
||
font-size: @font-size-sm;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0 0 @space-sm;
|
||
}
|
||
|
||
&__desc {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
margin: 0;
|
||
line-height: @line-height-base;
|
||
}
|
||
}
|
||
|
||
.section-placeholder-note {
|
||
margin-top: @space-lg;
|
||
text-align: center;
|
||
font-size: @font-size-sm;
|
||
color: #e67e22;
|
||
}
|
||
|
||
// 媒体报道
|
||
.section-header-with-note {
|
||
margin-bottom: @space-xl;
|
||
}
|
||
|
||
.placeholder-banner {
|
||
background: #fef9e7;
|
||
border: 1px solid #f39c12;
|
||
border-radius: @border-radius-md;
|
||
padding: @space-md @space-lg;
|
||
font-size: @font-size-sm;
|
||
color: #7d6608;
|
||
margin-top: @space-lg;
|
||
}
|
||
|
||
.media-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: @space-lg;
|
||
|
||
.respond-lg({
|
||
grid-template-columns: repeat(3, 1fr);
|
||
});
|
||
}
|
||
|
||
.media-card {
|
||
background: @color-bg-white;
|
||
border: 1px solid @color-border;
|
||
border-radius: @border-radius-lg;
|
||
padding: @space-xl;
|
||
|
||
&--placeholder {
|
||
border-style: dashed;
|
||
opacity: 0.7;
|
||
}
|
||
|
||
&__outlet {
|
||
font-size: @font-size-xs;
|
||
color: @color-primary;
|
||
font-weight: @font-weight-bold;
|
||
margin-bottom: @space-sm;
|
||
}
|
||
|
||
&__title {
|
||
font-size: @font-size-base;
|
||
font-weight: @font-weight-bold;
|
||
color: @color-text-primary;
|
||
margin: 0 0 @space-sm;
|
||
line-height: @line-height-tight;
|
||
}
|
||
|
||
&__summary {
|
||
font-size: @font-size-sm;
|
||
color: @color-text-secondary;
|
||
margin: 0 0 @space-lg;
|
||
line-height: @line-height-base;
|
||
flex: 1;
|
||
}
|
||
|
||
&__footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding-top: @space-sm;
|
||
border-top: 1px solid @color-border;
|
||
}
|
||
|
||
&__date {
|
||
font-size: @font-size-xs;
|
||
color: @color-text-muted;
|
||
}
|
||
|
||
&__link-placeholder {
|
||
font-size: @font-size-xs;
|
||
color: #e67e22;
|
||
}
|
||
}
|
||
</style>
|