feat: UI redesign with uv-ui color system and landscape imagery
- Replace all colors with uv-ui design tokens (primary #3c9cff, warning #f9ae3d, etc.) - Hero section: Wugong Mountain landscape photo with dark overlay - Super Player card: photo background, large typography, warning-color price/CTA, value comparison (¥198 vs ¥3800+) - Spots section: landscape thumbnails instead of CSS gradients, warning-color prices - Profile page: landscape hero header, CSS menu icons, floating card layout - Card list page: landscape hero header, filter pills, empty state design - TabBar: rename '入园码' to '旅游卡', Lucide-style PNG icons (home/card/profile) - Typography: corrected font weights (semibold for prices, medium for labels) - Remove broken font-loader (lxgw-wen-kai CDN 404) - Skip wx.getPrivacySetting in devtools to avoid framework timeout - Replace all inline SVG with CSS-only icons for mini-program compatibility - Add design system files (styles/, components/, animations) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+497
-232
@@ -1,92 +1,98 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- 头部区域:背景图 + 渐变遮罩 + 标题 + 搜索栏 -->
|
||||
<view class="hero">
|
||||
<!-- Hero: mountain landscape photo -->
|
||||
<view class="hero animate-fade-in-up">
|
||||
<image
|
||||
class="hero-bg"
|
||||
src="https://images.pexels.com/photos/28594448/pexels-photo-28594448.jpeg?auto=compress&cs=tinysrgb&w=750"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="hero-overlay" />
|
||||
<view class="hero-content">
|
||||
<view class="hero-inner">
|
||||
<text class="hero-title">爱上萍乡</text>
|
||||
<text class="hero-subtitle">赣湘之间 · 发现旅途美好</text>
|
||||
<view class="search-bar" @click="goSearch">
|
||||
<view class="search-icon-wrap">
|
||||
<view class="search-icon-circle" />
|
||||
</view>
|
||||
<text class="search-placeholder">搜索景区、活动...</text>
|
||||
</view>
|
||||
<text class="hero-sub">赣湘之间 · 发现旅途美好</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="scroll-content">
|
||||
<scroll-view scroll-y class="main-scroll">
|
||||
<!-- 公告栏 -->
|
||||
<view class="notice-bar" v-if="announcements.length">
|
||||
<view class="notice-label">
|
||||
<view class="notice-dot" />
|
||||
<text class="notice-text">公告</text>
|
||||
<view v-if="announcements.length" class="notice animate-fade-in-up stagger-1">
|
||||
<view class="notice-tag">
|
||||
<view class="notice-pip animate-pulse" />
|
||||
<text class="notice-label">公告</text>
|
||||
</view>
|
||||
<swiper class="notice-swiper" vertical autoplay circular :interval="3000" :duration="500">
|
||||
<swiper-item v-for="item in announcements" :key="item.id">
|
||||
<text class="notice-content">{{ item.content }}</text>
|
||||
<text class="notice-text">{{ item.content }}</text>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<!-- 卡片销售宣传 -->
|
||||
<view class="card-section">
|
||||
<view class="promo-card promo-card-gx" @click="goCardDetail('gx')">
|
||||
<view class="promo-card-badge">工会会员专属</view>
|
||||
<text class="promo-card-name">赣湘全域旅游年卡</text>
|
||||
<view class="promo-card-price-row">
|
||||
<text class="promo-card-currency">¥</text>
|
||||
<text class="promo-card-price">300</text>
|
||||
<text class="promo-card-unit">/套卡(2张)</text>
|
||||
</view>
|
||||
<view class="promo-card-features">
|
||||
<view class="promo-card-feature"><view class="feature-dot" /><text>22家景区免门票</text></view>
|
||||
<view class="promo-card-feature"><view class="feature-dot" /><text>武功山·方特·君澜温泉</text></view>
|
||||
<view class="promo-card-feature"><view class="feature-dot" /><text>覆盖萍乡/长沙/株洲/湘潭</text></view>
|
||||
</view>
|
||||
<view class="promo-card-btn">
|
||||
<text class="promo-card-btn-text">立即抢购</text>
|
||||
<view class="btn-arrow" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="promo-card promo-card-super" @click="goCardDetail('super')">
|
||||
<view class="promo-card-badge">大学生·市民专属</view>
|
||||
<text class="promo-card-name">超级玩家卡</text>
|
||||
<view class="promo-card-price-row">
|
||||
<text class="promo-card-currency">¥</text>
|
||||
<text class="promo-card-price">198</text>
|
||||
</view>
|
||||
<view class="promo-card-features">
|
||||
<view class="promo-card-feature"><view class="feature-dot" /><text>40家景区免门票</text></view>
|
||||
<view class="promo-card-feature"><view class="feature-dot" /><text>武功山·方特·韶山·滴水洞</text></view>
|
||||
<view class="promo-card-feature"><view class="feature-dot" /><text>含外骨骼登山·青年旅社等</text></view>
|
||||
</view>
|
||||
<view class="promo-card-btn">
|
||||
<text class="promo-card-btn-text">立即抢购</text>
|
||||
<view class="btn-arrow" />
|
||||
<!-- 旅游卡 — 大字报风格 -->
|
||||
<view class="promo-wrap animate-fade-in-up stagger-2">
|
||||
<view class="promo" @click="goCardDetail()">
|
||||
<image
|
||||
class="promo-bg"
|
||||
src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=750&h=400&fit=crop"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="promo-overlay" />
|
||||
<view class="promo-content">
|
||||
<view class="promo-badge">大学生·市民专属</view>
|
||||
<text class="promo-name">超级玩家卡</text>
|
||||
<view class="promo-price-row">
|
||||
<view class="promo-price-block">
|
||||
<text class="promo-currency">¥</text>
|
||||
<text class="promo-price">198</text>
|
||||
</view>
|
||||
<view class="promo-value-block">
|
||||
<text class="promo-value-label">景区总价值</text>
|
||||
<text class="promo-value">¥3800+</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="promo-desc">40家景区免门票 · 武功山·方特·韶山·滴水洞</text>
|
||||
<view class="promo-cta">
|
||||
<text class="cta-label">立即抢购</text>
|
||||
<view class="cta-arrow" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 热门景点列表 -->
|
||||
<!-- 热门景点 -->
|
||||
<view class="spots-section">
|
||||
<view class="spots-header">
|
||||
<view class="spots-head animate-fade-in-up stagger-3">
|
||||
<text class="spots-title">热门景点</text>
|
||||
<view class="spots-more" @click="goMore">
|
||||
<text>查看全部</text>
|
||||
<view class="chevron-right" />
|
||||
<text class="spots-more-text">查看全部</text>
|
||||
<view class="chevron" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="spot-card" v-for="spot in scenicSpots" :key="spot.id" @click="goSpot(spot)">
|
||||
<view class="spot-image" :style="{ background: getGradient(spot.region) }">
|
||||
<view class="spot-region-tag">{{ spot.region }}</view>
|
||||
</view>
|
||||
<view class="spot-info">
|
||||
<text class="spot-name">{{ spot.name }}</text>
|
||||
<view class="spot-meta">
|
||||
<text class="spot-price">¥{{ spot.price }}</text>
|
||||
<view class="spot-free-tag">持卡免门票</view>
|
||||
|
||||
<view class="spots-grid">
|
||||
<view
|
||||
v-for="(spot, idx) in scenicSpots.slice(0, 6)"
|
||||
:key="spot.id"
|
||||
class="spot animate-fade-in-up"
|
||||
:class="`stagger-${Math.min(idx + 4, 10)}`"
|
||||
@click="goSpot(spot)"
|
||||
>
|
||||
<view class="spot-cover">
|
||||
<image class="spot-img" :src="getSpotImage(spot.id)" mode="aspectFill" />
|
||||
<view class="spot-region">
|
||||
<view class="pin-dot" />
|
||||
<text>{{ spot.region }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="spot-body">
|
||||
<text class="spot-name">{{ spot.name }}</text>
|
||||
<view class="spot-meta">
|
||||
<text class="spot-price">¥{{ spot.price }}</text>
|
||||
<view class="spot-free">
|
||||
<view class="free-dot" />
|
||||
<text>免门票</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -107,202 +113,461 @@ const announcements = ref([
|
||||
{ id: 3, content: '武功山金顶景区已开放,持卡可免费入园1次。' },
|
||||
])
|
||||
|
||||
/** 区域对应的渐变色(景点图片占位) */
|
||||
const regionGradients: Record<string, string> = {
|
||||
'萍乡': 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
||||
'长沙': 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)',
|
||||
'株洲': 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)',
|
||||
'湘潭': 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',
|
||||
/** 景点山水风景图 */
|
||||
const spotImages: Record<number, string> = {
|
||||
1: 'https://images.unsplash.com/photo-1513415564515-763d91423bdd?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||
2: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||
3: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||
4: 'https://images.unsplash.com/photo-1433086966358-54859d0ed716?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||
5: 'https://images.unsplash.com/photo-1441974231531-c6227db76b6e?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||
6: 'https://images.unsplash.com/photo-1501854140801-50d01698950b?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||
}
|
||||
|
||||
function getGradient(region: string): string {
|
||||
return regionGradients[region] || regionGradients['萍乡']
|
||||
function getSpotImage(id: number): string {
|
||||
return spotImages[id] || `https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=400&h=250&fit=crop`
|
||||
}
|
||||
|
||||
/** 跳转搜索(暂不实现) */
|
||||
function goSearch() {
|
||||
uni.showToast({ title: '搜索功能开发中', icon: 'none' })
|
||||
}
|
||||
|
||||
/** 跳转卡片详情 */
|
||||
function goCardDetail(type: 'gx' | 'super') {
|
||||
function goCardDetail() {
|
||||
uni.navigateTo({ url: '/packages/user/pages/card/list' })
|
||||
}
|
||||
|
||||
/** 跳转景点详情 */
|
||||
function goSpot(spot: ScenicSpotItem) {
|
||||
uni.showToast({ title: `${spot.name} 详情开发中`, icon: 'none' })
|
||||
}
|
||||
|
||||
/** 查看全部景点 */
|
||||
function goMore() {
|
||||
uni.showToast({ title: '景点列表开发中', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page { display: flex; flex-direction: column; min-height: 100vh; background: #f5f5f5; }
|
||||
<style lang="scss" scoped>
|
||||
/* ============================================
|
||||
Page
|
||||
============================================ */
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
background: $color-background;
|
||||
}
|
||||
|
||||
/* === 头部区域 === */
|
||||
.hero { position: relative; height: 360rpx; overflow: hidden; }
|
||||
.hero-overlay {
|
||||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: linear-gradient(180deg, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0.6) 100%);
|
||||
z-index: 1;
|
||||
}
|
||||
.hero::before {
|
||||
content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: linear-gradient(135deg, #1a237e 0%, #4a148c 50%, #e65100 100%);
|
||||
}
|
||||
.hero-content {
|
||||
position: relative; z-index: 2;
|
||||
padding: 80rpx 30rpx 30rpx;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
.hero-title { font-size: 42rpx; font-weight: bold; color: #fff; margin-bottom: 8rpx; }
|
||||
.hero-subtitle { font-size: 24rpx; color: rgba(255,255,255,0.8); margin-bottom: 24rpx; }
|
||||
|
||||
/* 搜索栏 */
|
||||
.search-bar {
|
||||
display: flex; align-items: center;
|
||||
background: rgba(255,255,255,0.95); border-radius: 40rpx;
|
||||
padding: 18rpx 24rpx;
|
||||
min-height: 88rpx;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.search-bar:active { opacity: 0.7; }
|
||||
.search-icon-wrap {
|
||||
width: 36rpx; height: 36rpx; margin-right: 12rpx;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.search-icon-circle {
|
||||
width: 24rpx; height: 24rpx;
|
||||
border: 3rpx solid #999; border-radius: 50%;
|
||||
/* ============================================
|
||||
Hero — mountain landscape photo
|
||||
============================================ */
|
||||
.hero {
|
||||
position: relative;
|
||||
}
|
||||
.search-icon-circle::after {
|
||||
content: ''; position: absolute;
|
||||
width: 3rpx; height: 10rpx;
|
||||
background: #999; border-radius: 2rpx;
|
||||
bottom: -10rpx; right: -4rpx;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.search-placeholder { font-size: 26rpx; color: #999; }
|
||||
|
||||
/* === 公告栏 === */
|
||||
.notice-bar {
|
||||
display: flex; align-items: center;
|
||||
background: #fff; padding: 20rpx 24rpx; margin: 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
.notice-label { display: flex; align-items: center; margin-right: 16rpx; flex-shrink: 0; }
|
||||
.notice-dot {
|
||||
width: 14rpx; height: 14rpx; border-radius: 50%;
|
||||
background: #E74C3C; margin-right: 8rpx;
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.4; }
|
||||
}
|
||||
.notice-text { font-size: 24rpx; color: #E74C3C; font-weight: 500; }
|
||||
.notice-swiper { flex: 1; height: 40rpx; }
|
||||
.notice-content { font-size: 24rpx; color: #666; line-height: 40rpx; }
|
||||
|
||||
/* === 卡片销售宣传 === */
|
||||
.card-section { padding: 24rpx; display: flex; flex-direction: column; gap: 24rpx; }
|
||||
|
||||
.promo-card {
|
||||
position: relative; border-radius: 24rpx; padding: 40rpx 32rpx;
|
||||
height: 340rpx;
|
||||
overflow: hidden;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
.promo-card:active { transform: scale(0.98); }
|
||||
.promo-card-gx {
|
||||
background: linear-gradient(135deg, #1a237e 0%, #283593 40%, #ffd54f 100%);
|
||||
|
||||
.hero-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.promo-card-super {
|
||||
background: linear-gradient(135deg, #e65100 0%, #bf360c 40%, #7b1fa2 100%);
|
||||
|
||||
.hero-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0.45) 0%,
|
||||
rgba(0, 0, 0, 0.3) 40%,
|
||||
rgba(0, 0, 0, 0.65) 100%
|
||||
);
|
||||
}
|
||||
.promo-card-badge {
|
||||
|
||||
.hero-inner {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: $spacing-16 $spacing-4 $spacing-4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-family: $font-family-display;
|
||||
font-size: $font-size-3xl;
|
||||
font-weight: $font-weight-bold;
|
||||
color: #fff;
|
||||
line-height: $line-height-tight;
|
||||
margin-bottom: $spacing-1;
|
||||
text-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.hero-sub {
|
||||
font-size: $font-size-sm;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
letter-spacing: 4rpx;
|
||||
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
CSS-only icons
|
||||
============================================ */
|
||||
.notice-pip {
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
background: $color-accent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chevron {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-top: 2rpx solid $color-muted-foreground;
|
||||
border-right: 2rpx solid $color-muted-foreground;
|
||||
transform: rotate(45deg);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pin-dot {
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.free-dot {
|
||||
width: 8rpx;
|
||||
height: 8rpx;
|
||||
border-radius: 50%;
|
||||
background: $color-accent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Notice bar
|
||||
============================================ */
|
||||
.notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: $color-card;
|
||||
padding: $spacing-2 $spacing-3;
|
||||
border-bottom: $border-width solid $color-border;
|
||||
}
|
||||
|
||||
.notice-tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: $spacing-2;
|
||||
flex-shrink: 0;
|
||||
gap: $spacing-1;
|
||||
}
|
||||
|
||||
.notice-label {
|
||||
font-size: $font-size-xs;
|
||||
color: $color-accent;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
.notice-swiper {
|
||||
flex: 1;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.notice-text {
|
||||
font-size: $font-size-sm;
|
||||
color: $color-muted-foreground;
|
||||
line-height: 40rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Promo card — landscape photo hero card
|
||||
============================================ */
|
||||
.promo-wrap {
|
||||
padding: $spacing-3;
|
||||
}
|
||||
|
||||
.promo {
|
||||
position: relative;
|
||||
border-radius: $radius-xl;
|
||||
overflow: hidden;
|
||||
min-height: 400rpx;
|
||||
transition: transform $transition-fast;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
}
|
||||
|
||||
.promo-bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.promo-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
160deg,
|
||||
rgba($color-foreground, 0.88) 0%,
|
||||
rgba($color-foreground, 0.6) 55%,
|
||||
rgba($color-foreground, 0.3) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.promo-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: $spacing-5 $spacing-4;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.promo-badge {
|
||||
display: inline-block;
|
||||
background: rgba(255,255,255,0.2); border-radius: 20rpx;
|
||||
padding: 6rpx 16rpx; margin-bottom: 16rpx;
|
||||
font-size: 22rpx; color: rgba(255,255,255,0.9);
|
||||
}
|
||||
.promo-card-name { font-size: 34rpx; font-weight: bold; color: #fff; display: block; margin-bottom: 12rpx; }
|
||||
.promo-card-price-row { display: flex; align-items: baseline; margin-bottom: 20rpx; }
|
||||
.promo-card-currency { font-size: 32rpx; color: #fff; font-weight: bold; }
|
||||
.promo-card-price { font-size: 64rpx; color: #fff; font-weight: bold; line-height: 1; }
|
||||
.promo-card-unit { font-size: 24rpx; color: rgba(255,255,255,0.8); margin-left: 8rpx; }
|
||||
.promo-card-features { display: flex; flex-direction: column; gap: 10rpx; margin-bottom: 24rpx; }
|
||||
.promo-card-feature {
|
||||
display: flex; align-items: center; gap: 10rpx;
|
||||
font-size: 24rpx; color: rgba(255,255,255,0.9);
|
||||
}
|
||||
.feature-dot {
|
||||
width: 8rpx; height: 8rpx; border-radius: 50%;
|
||||
background: rgba(255,255,255,0.7); flex-shrink: 0;
|
||||
}
|
||||
.promo-card-btn {
|
||||
display: flex; align-items: center; justify-content: center; gap: 8rpx;
|
||||
background: #fff; border-radius: 44rpx;
|
||||
padding: 22rpx 0;
|
||||
min-height: 88rpx;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.promo-card-btn:active { opacity: 0.8; }
|
||||
.promo-card-btn-text { font-size: 28rpx; font-weight: bold; color: #333; }
|
||||
.btn-arrow {
|
||||
width: 12rpx; height: 12rpx;
|
||||
border-top: 3rpx solid #333;
|
||||
border-right: 3rpx solid #333;
|
||||
transform: rotate(45deg);
|
||||
align-self: flex-start;
|
||||
background: rgba($color-accent, 0.2);
|
||||
border: $border-width solid rgba($color-accent, 0.4);
|
||||
border-radius: $radius-full;
|
||||
padding: 6rpx $spacing-3;
|
||||
font-size: $font-size-sm;
|
||||
color: rgba(255, 255, 255, 0.95);
|
||||
font-weight: $font-weight-semibold;
|
||||
margin-bottom: $spacing-3;
|
||||
}
|
||||
|
||||
/* === 热门景点列表 === */
|
||||
.spots-section { padding: 24rpx; }
|
||||
.spots-header {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
.promo-name {
|
||||
font-family: $font-family-display;
|
||||
font-size: 56rpx;
|
||||
font-weight: $font-weight-bold;
|
||||
color: #fff;
|
||||
display: block;
|
||||
margin-bottom: $spacing-3;
|
||||
text-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.4);
|
||||
letter-spacing: 2rpx;
|
||||
}
|
||||
.spots-title { font-size: 34rpx; font-weight: bold; color: #333; }
|
||||
|
||||
.promo-price-row {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: $spacing-4;
|
||||
margin-bottom: $spacing-3;
|
||||
}
|
||||
|
||||
.promo-price-block {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.promo-currency {
|
||||
font-size: $font-size-2xl;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $uv-warning;
|
||||
}
|
||||
|
||||
.promo-price {
|
||||
font-size: 96rpx;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $uv-warning;
|
||||
line-height: 0.85;
|
||||
letter-spacing: -4rpx;
|
||||
}
|
||||
|
||||
.promo-value-block {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: $spacing-2;
|
||||
}
|
||||
|
||||
.promo-value-label {
|
||||
font-size: $font-size-xs;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.promo-value {
|
||||
font-size: $font-size-xl;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
text-decoration: line-through;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
.promo-desc {
|
||||
font-size: $font-size-base;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
display: block;
|
||||
margin-bottom: $spacing-4;
|
||||
line-height: $line-height-relaxed;
|
||||
}
|
||||
|
||||
.promo-cta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: $spacing-2;
|
||||
align-self: flex-start;
|
||||
padding: $spacing-2 $spacing-8;
|
||||
border-radius: $radius-full;
|
||||
background: $uv-warning;
|
||||
transition: transform $transition-fast;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.cta-label {
|
||||
font-size: $font-size-base;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $uv-main-color;
|
||||
}
|
||||
|
||||
.cta-arrow {
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-top: 3rpx solid $uv-main-color;
|
||||
border-right: 3rpx solid $uv-main-color;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Spots section
|
||||
============================================ */
|
||||
.spots-section {
|
||||
padding: $spacing-3;
|
||||
}
|
||||
|
||||
.spots-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: $spacing-3;
|
||||
}
|
||||
|
||||
.spots-title {
|
||||
font-family: $font-family-display;
|
||||
font-size: $font-size-xl;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $color-foreground;
|
||||
}
|
||||
|
||||
.spots-more {
|
||||
display: flex; align-items: center; gap: 4rpx;
|
||||
font-size: 24rpx; color: #999;
|
||||
}
|
||||
.chevron-right {
|
||||
width: 10rpx; height: 10rpx;
|
||||
border-top: 2rpx solid #999;
|
||||
border-right: 2rpx solid #999;
|
||||
transform: rotate(45deg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $spacing-1;
|
||||
}
|
||||
|
||||
.spot-card {
|
||||
background: #fff; border-radius: 20rpx; overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
.spot-card:active { transform: scale(0.98); }
|
||||
.spot-image {
|
||||
width: 100%; height: 320rpx; position: relative;
|
||||
}
|
||||
.spot-region-tag {
|
||||
position: absolute; top: 16rpx; left: 16rpx;
|
||||
background: rgba(0,0,0,0.5); border-radius: 16rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
font-size: 22rpx; color: #fff;
|
||||
}
|
||||
.spot-info { padding: 20rpx 24rpx; }
|
||||
.spot-name { font-size: 30rpx; font-weight: 600; color: #333; margin-bottom: 12rpx; display: block; }
|
||||
.spot-meta { display: flex; justify-content: space-between; align-items: center; }
|
||||
.spot-price { font-size: 32rpx; color: #E74C3C; font-weight: bold; }
|
||||
.spot-free-tag {
|
||||
background: #E8F5E9; border-radius: 16rpx;
|
||||
padding: 6rpx 16rpx;
|
||||
font-size: 22rpx; color: #2E7D32; font-weight: 500;
|
||||
.spots-more-text {
|
||||
font-size: $font-size-sm;
|
||||
color: $color-muted-foreground;
|
||||
}
|
||||
|
||||
/* === 滚动区域 === */
|
||||
.scroll-content { flex: 1; }
|
||||
/* Spots grid — 2 column */
|
||||
.spots-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: $spacing-2;
|
||||
}
|
||||
|
||||
.spot {
|
||||
width: calc(50% - #{$spacing-1});
|
||||
background: $color-card;
|
||||
border-radius: $radius-lg;
|
||||
overflow: hidden;
|
||||
box-shadow: $shadow-sm;
|
||||
transition: transform $transition-fast, box-shadow $transition-base;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.97);
|
||||
box-shadow: $shadow-base;
|
||||
}
|
||||
}
|
||||
|
||||
.spot-cover {
|
||||
width: 100%;
|
||||
height: 220rpx;
|
||||
position: relative;
|
||||
background: $color-muted;
|
||||
}
|
||||
|
||||
.spot-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.spot-region {
|
||||
position: absolute;
|
||||
top: $spacing-2;
|
||||
left: $spacing-2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
backdrop-filter: blur(8rpx);
|
||||
border-radius: $radius-sm;
|
||||
padding: 4rpx $spacing-2;
|
||||
|
||||
text {
|
||||
font-size: $font-size-xs;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.spot-body {
|
||||
padding: $spacing-2;
|
||||
}
|
||||
|
||||
.spot-name {
|
||||
font-size: $font-size-sm;
|
||||
font-weight: $font-weight-semibold;
|
||||
color: $color-foreground;
|
||||
display: block;
|
||||
margin-bottom: $spacing-1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.spot-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.spot-price {
|
||||
font-size: $font-size-base;
|
||||
color: $uv-warning;
|
||||
font-weight: $font-weight-semibold;
|
||||
}
|
||||
|
||||
.spot-free {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
background: rgba($color-accent, 0.08);
|
||||
border-radius: $radius-sm;
|
||||
padding: 4rpx $spacing-1;
|
||||
|
||||
text {
|
||||
font-size: $font-size-xs;
|
||||
color: $color-accent;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Scroll area
|
||||
============================================ */
|
||||
.main-scroll {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user