- 后台全面引入 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>
161 行
3.4 KiB
Vue
161 行
3.4 KiB
Vue
<template>
|
|
<section class="section-cta" :class="`section-cta--${bg}`">
|
|
<div class="section-cta-bg" />
|
|
<div class="container text-center section-cta-inner">
|
|
<h2 class="section-cta-title">{{ title }}</h2>
|
|
<p class="section-cta-desc">{{ description }}</p>
|
|
<div class="section-cta-links">
|
|
<NuxtLink
|
|
v-for="(link, index) in links"
|
|
:key="link.to"
|
|
:to="link.to"
|
|
class="cta-btn"
|
|
:class="index === 0 ? 'cta-btn--primary' : 'cta-btn--outline'"
|
|
>
|
|
{{ link.text }}
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<script setup>
|
|
defineProps({
|
|
title: { type: String, required: true },
|
|
description: { type: String, required: true },
|
|
links: { type: Array, required: true },
|
|
bg: { type: String, default: 'green' },
|
|
})
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.section-cta {
|
|
position: relative;
|
|
overflow: hidden;
|
|
.section-padding();
|
|
}
|
|
|
|
.section-cta--green {
|
|
background: linear-gradient(135deg, @color-primary-dark 0%, @color-primary 50%, @color-primary-light 100%);
|
|
}
|
|
|
|
.section-cta--warm {
|
|
background: linear-gradient(135deg, @color-bg-warm 0%, @color-accent-bg 100%);
|
|
}
|
|
|
|
.section-cta-bg {
|
|
position: absolute;
|
|
inset: 0;
|
|
background: radial-gradient(ellipse at 20% 50%, rgba(255, 255, 255, 0.08) 0%, transparent 60%),
|
|
radial-gradient(ellipse at 80% 50%, rgba(255, 255, 255, 0.05) 0%, transparent 60%);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.section-cta-inner {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.section-cta-title {
|
|
.section-cta--green & {
|
|
color: #fff;
|
|
}
|
|
|
|
&::after {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.section-cta-desc {
|
|
margin-top: @space-md;
|
|
margin-bottom: @space-xl;
|
|
font-size: @font-size-md;
|
|
line-height: @line-height-relaxed;
|
|
max-width: 560px;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
|
|
.section-cta--green & {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
.section-cta--warm & {
|
|
color: @color-text-secondary;
|
|
}
|
|
}
|
|
|
|
.section-cta-links {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: @space-md;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.cta-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 14px @space-xl;
|
|
border-radius: @border-radius-md;
|
|
font-size: @font-size-base;
|
|
font-weight: @font-weight-medium;
|
|
text-decoration: none;
|
|
transition: all @transition-base;
|
|
|
|
.respond-md({
|
|
padding: 16px 36px;
|
|
font-size: @font-size-md;
|
|
});
|
|
|
|
&--primary {
|
|
.section-cta--green & {
|
|
background: #fff;
|
|
color: @color-primary;
|
|
border: 1px solid #fff;
|
|
|
|
&:hover {
|
|
background: rgba(255, 255, 255, 0.9);
|
|
color: @color-primary-dark;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
|
}
|
|
}
|
|
|
|
.section-cta--warm & {
|
|
background: @color-primary;
|
|
color: #fff;
|
|
border: 1px solid @color-primary;
|
|
|
|
&:hover {
|
|
background: @color-primary-light;
|
|
border-color: @color-primary-light;
|
|
color: #fff;
|
|
}
|
|
}
|
|
}
|
|
|
|
&--outline {
|
|
.section-cta--green & {
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
color: #fff;
|
|
|
|
&:hover {
|
|
background: rgba(255, 255, 255, 0.15);
|
|
border-color: rgba(255, 255, 255, 0.8);
|
|
color: #fff;
|
|
}
|
|
}
|
|
|
|
.section-cta--warm & {
|
|
background: transparent;
|
|
color: @color-primary;
|
|
border: 1px solid @color-primary;
|
|
|
|
&:hover {
|
|
background: @color-primary;
|
|
color: #fff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|