feat: 官网代码全量更新 (2026-04-18)
这个提交包含在:
@@ -21,17 +21,54 @@
|
||||
<ul class="card-highlights">
|
||||
<li v-for="(h, i) in product.highlights" :key="i">
|
||||
<span class="check" aria-hidden="true">✓</span>
|
||||
{{ h }}
|
||||
{{ itineraryText(h) }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 行程概览 -->
|
||||
<details v-if="product.itinerary && product.itinerary.length" class="card-itinerary">
|
||||
<summary class="itinerary-toggle">查看每日行程 ▾</summary>
|
||||
<ol class="itinerary-list">
|
||||
<li v-for="(day, i) in product.itinerary" :key="i">{{ day }}</li>
|
||||
</ol>
|
||||
<!-- 价格区间 -->
|
||||
<div v-if="priceRange" class="card-price">
|
||||
<div class="price-main">
|
||||
<span class="price-label">成人价</span>
|
||||
<span class="price-value">¥{{ priceRange.min }}</span>
|
||||
<span v-if="priceRange.max > priceRange.min" class="price-range">
|
||||
起 · 旺季 ¥{{ priceRange.max }}
|
||||
</span>
|
||||
<span v-else class="price-range"> 起</span>
|
||||
</div>
|
||||
<div v-if="priceRange.childMin" class="price-sub">
|
||||
儿童 ¥{{ priceRange.childMin }} 起
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 行程 + 报价展开 -->
|
||||
<details v-if="hasItinerary || hasPricing" class="card-itinerary">
|
||||
<summary class="itinerary-toggle">
|
||||
<span v-if="hasItinerary && hasPricing">查看每日行程 + 分日期报价 ▾</span>
|
||||
<span v-else-if="hasItinerary">查看每日行程 ▾</span>
|
||||
<span v-else>查看分日期报价 ▾</span>
|
||||
</summary>
|
||||
<div v-if="hasItinerary" class="itinerary-section">
|
||||
<div class="section-head">每日行程</div>
|
||||
<ol class="itinerary-list">
|
||||
<li v-for="(day, i) in product.itinerary" :key="i">{{ itineraryText(day) }}</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div v-if="hasPricing" class="pricing-section">
|
||||
<div class="section-head">分日期报价</div>
|
||||
<div class="pricing-table">
|
||||
<div class="pricing-row pricing-head">
|
||||
<span class="col-date">出行日期</span>
|
||||
<span class="col-price">成人价</span>
|
||||
<span class="col-price">儿童价</span>
|
||||
</div>
|
||||
<div v-for="(row, i) in product.pricing" :key="i" class="pricing-row">
|
||||
<span class="col-date">{{ row.date }}</span>
|
||||
<span class="col-price">¥{{ row.adult }}</span>
|
||||
<span class="col-price">¥{{ row.child }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- 底部 CTA -->
|
||||
@@ -49,6 +86,27 @@ const isPopular = computed(() => props.product.id === 'autumn-south-5d4n')
|
||||
const shortName = computed(() => {
|
||||
return props.product.name.replace(/^游牧的森林V3·/, '')
|
||||
})
|
||||
|
||||
const hasItinerary = computed(() => Array.isArray(props.product.itinerary) && props.product.itinerary.length > 0)
|
||||
const hasPricing = computed(() => Array.isArray(props.product.pricing) && props.product.pricing.length > 0)
|
||||
|
||||
const priceRange = computed(() => {
|
||||
if (!hasPricing.value) return null
|
||||
const adults = props.product.pricing.map(p => Number(p.adult)).filter(n => n > 0)
|
||||
const children = props.product.pricing.map(p => Number(p.child)).filter(n => n > 0)
|
||||
if (!adults.length) return null
|
||||
return {
|
||||
min: Math.min(...adults),
|
||||
max: Math.max(...adults),
|
||||
childMin: children.length ? Math.min(...children) : null,
|
||||
}
|
||||
})
|
||||
|
||||
function itineraryText(item) {
|
||||
if (typeof item === 'string') return item
|
||||
if (item && typeof item === 'object') return item.title || ''
|
||||
return ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -196,7 +254,47 @@ const shortName = computed(() => {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
// 行程概览
|
||||
// 价格区间
|
||||
.card-price {
|
||||
padding: @space-md @space-lg;
|
||||
background: linear-gradient(135deg, #FFF7ED 0%, #FEF3C7 100%);
|
||||
border-top: 1px solid rgba(217, 119, 6, 0.15);
|
||||
border-bottom: 1px solid rgba(217, 119, 6, 0.15);
|
||||
}
|
||||
|
||||
.price-main {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.price-label {
|
||||
font-size: @font-size-xs;
|
||||
color: #92400E;
|
||||
margin-right: @space-xs;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: @font-size-2xl;
|
||||
font-weight: @font-weight-bold;
|
||||
color: #B45309;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.price-range {
|
||||
font-size: @font-size-xs;
|
||||
color: #92400E;
|
||||
}
|
||||
|
||||
.price-sub {
|
||||
margin-top: 4px;
|
||||
font-size: @font-size-xs;
|
||||
color: #92400E;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
// 行程概览 + 分日期报价
|
||||
.card-itinerary {
|
||||
border-top: 1px solid @color-border;
|
||||
}
|
||||
@@ -209,6 +307,9 @@ const shortName = computed(() => {
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
transition: background @transition-fast;
|
||||
list-style: none;
|
||||
|
||||
&::-webkit-details-marker { display: none; }
|
||||
|
||||
&:hover {
|
||||
background: @color-bg-gray;
|
||||
@@ -216,6 +317,20 @@ const shortName = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.section-head {
|
||||
padding: 0 @space-lg @space-xs;
|
||||
font-size: @font-size-xs;
|
||||
font-weight: @font-weight-medium;
|
||||
color: #D97706;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.itinerary-section + .pricing-section {
|
||||
margin-top: @space-md;
|
||||
padding-top: @space-md;
|
||||
border-top: 1px dashed @color-border;
|
||||
}
|
||||
|
||||
.itinerary-list {
|
||||
padding: 0 @space-lg @space-md;
|
||||
display: flex;
|
||||
@@ -230,6 +345,35 @@ const shortName = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.pricing-table {
|
||||
padding: 0 @space-lg @space-md;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: @font-size-xs;
|
||||
}
|
||||
|
||||
.pricing-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1.6fr 1fr 1fr;
|
||||
gap: @space-sm;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px dashed rgba(0, 0, 0, 0.06);
|
||||
color: @color-text-secondary;
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
|
||||
.col-date { color: @color-text-primary; }
|
||||
.col-price { text-align: right; color: #B45309; font-weight: @font-weight-medium; font-variant-numeric: tabular-nums; }
|
||||
}
|
||||
|
||||
.pricing-head {
|
||||
font-weight: @font-weight-medium;
|
||||
color: @color-text-muted;
|
||||
border-bottom: 1px solid @color-border;
|
||||
|
||||
.col-date, .col-price { color: @color-text-muted; font-weight: @font-weight-medium; }
|
||||
}
|
||||
|
||||
// 底部 CTA
|
||||
.card-cta {
|
||||
display: block;
|
||||
|
||||
在新工单中引用
屏蔽一个用户