feat: 首页Hero改造Banner轮播 + 公告栏优化
- Hero: 替换为运营Banner图, swiper轮播结构, 移除文字遮罩, 点击跳转卡列表 - 公告栏: 卡片化圆角阴影, 分类标签(重要/景区/福利), 按类型变色脉冲圆点, 触摸暂停轮播, 右侧更多按钮, 修复橙色圆点被拉伸bug(.promo类名冲突) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+94
-60
@@ -1,31 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page">
|
<view class="page">
|
||||||
<!-- Hero: mountain landscape photo -->
|
<!-- Hero: 运营Banner轮播 -->
|
||||||
<view class="hero animate-fade-in-up">
|
<view class="hero animate-fade-in-up" @click="goCardDetail()">
|
||||||
|
<swiper class="hero-swiper" autoplay circular :interval="5000">
|
||||||
|
<swiper-item>
|
||||||
<image
|
<image
|
||||||
class="hero-bg"
|
class="hero-bg"
|
||||||
src="https://images.pexels.com/photos/28594448/pexels-photo-28594448.jpeg?auto=compress&cs=tinysrgb&w=750"
|
src="https://aliyunoss.hntgov.net/image/2026/04/14/d2bf03167e484ba59f7c2d62879ad07f.jpg"
|
||||||
mode="aspectFill"
|
mode="aspectFill"
|
||||||
/>
|
/>
|
||||||
<view class="hero-overlay" />
|
</swiper-item>
|
||||||
<view class="hero-inner">
|
</swiper>
|
||||||
<text class="hero-title">爱上萍乡</text>
|
|
||||||
<text class="hero-sub">赣湘之间 · 发现旅途美好</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<scroll-view scroll-y class="main-scroll">
|
<scroll-view scroll-y class="main-scroll">
|
||||||
<!-- 公告栏 -->
|
<!-- 公告栏 -->
|
||||||
<view v-if="announcements.length" class="notice animate-fade-in-up stagger-1">
|
<view v-if="announcements.length" class="notice animate-fade-in-up stagger-1">
|
||||||
<view class="notice-tag">
|
<view class="notice-tag">
|
||||||
<view class="notice-pip animate-pulse" />
|
<view class="notice-pip animate-pulse" :class="`type-${currentNoticeType}`" />
|
||||||
<text class="notice-label">公告</text>
|
<text class="notice-label">公告</text>
|
||||||
</view>
|
</view>
|
||||||
<swiper class="notice-swiper" vertical autoplay circular :interval="3000" :duration="500">
|
<swiper
|
||||||
|
class="notice-swiper"
|
||||||
|
vertical
|
||||||
|
:autoplay="swiperAutoplay"
|
||||||
|
circular
|
||||||
|
:interval="3000"
|
||||||
|
:duration="500"
|
||||||
|
@change="onNoticeChange"
|
||||||
|
@touchstart="onNoticeTouchStart"
|
||||||
|
@touchend="onNoticeTouchEnd"
|
||||||
|
>
|
||||||
<swiper-item v-for="item in announcements" :key="item.id">
|
<swiper-item v-for="item in announcements" :key="item.id">
|
||||||
|
<view class="notice-item">
|
||||||
|
<text class="notice-type-tag" :class="`type-${item.type}`">{{ item.typeLabel }}</text>
|
||||||
<text class="notice-text">{{ item.content }}</text>
|
<text class="notice-text">{{ item.content }}</text>
|
||||||
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
|
<view class="notice-more" @click="goMoreNotice">
|
||||||
|
<text class="notice-more-text">更多</text>
|
||||||
|
<view class="chevron" />
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 旅游卡 — 大字报风格 -->
|
<!-- 旅游卡 — 大字报风格 -->
|
||||||
@@ -102,17 +118,27 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { scenicSpots } from '../../data/scenic-spots'
|
import { scenicSpots } from '../../data/scenic-spots'
|
||||||
import type { ScenicSpotItem } from '../../data/scenic-spots'
|
import type { ScenicSpotItem } from '../../data/scenic-spots'
|
||||||
|
|
||||||
/** 公告数据(mock,后续接 API) */
|
/** 公告数据(mock,后续接 API) */
|
||||||
const announcements = ref([
|
const announcements = ref([
|
||||||
{ id: 1, content: '赣湘全域旅游年卡限时优惠,工会会员专享¥300/套卡!' },
|
{ id: 1, type: 'important', typeLabel: '重要', content: '赣湘全域旅游年卡限时优惠,工会会员专享¥300/套卡!' },
|
||||||
{ id: 2, content: '超级玩家卡全新上线,40家景区免门票,仅¥198!' },
|
{ id: 2, type: 'scenic', typeLabel: '景区', content: '武功山金顶景区已开放,持卡可免费入园1次。' },
|
||||||
{ id: 3, content: '武功山金顶景区已开放,持卡可免费入园1次。' },
|
{ id: 3, type: 'promo', typeLabel: '福利', content: '超级玩家卡全新上线,40家景区免门票,仅¥198!' },
|
||||||
])
|
])
|
||||||
|
|
||||||
|
/** 公告轮播状态 */
|
||||||
|
const swiperAutoplay = ref(true)
|
||||||
|
const currentNoticeIndex = ref(0)
|
||||||
|
const currentNoticeType = computed(() => announcements.value[currentNoticeIndex.value]?.type || 'scenic')
|
||||||
|
|
||||||
|
function onNoticeChange(e: any) { currentNoticeIndex.value = e.detail.current }
|
||||||
|
function onNoticeTouchStart() { swiperAutoplay.value = false }
|
||||||
|
function onNoticeTouchEnd() { swiperAutoplay.value = true }
|
||||||
|
function goMoreNotice() { uni.showToast({ title: '全部公告开发中', icon: 'none' }) }
|
||||||
|
|
||||||
/** 景点山水风景图 */
|
/** 景点山水风景图 */
|
||||||
const spotImages: Record<number, string> = {
|
const spotImages: Record<number, string> = {
|
||||||
1: 'https://images.unsplash.com/photo-1513415564515-763d91423bdd?fm=jpg&q=80&w=400&h=250&fit=crop',
|
1: 'https://images.unsplash.com/photo-1513415564515-763d91423bdd?fm=jpg&q=80&w=400&h=250&fit=crop',
|
||||||
@@ -152,7 +178,7 @@ function goMore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
Hero — mountain landscape photo
|
Hero — 运营Banner轮播
|
||||||
============================================ */
|
============================================ */
|
||||||
.hero {
|
.hero {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -160,51 +186,14 @@ function goMore() {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hero-swiper {
|
||||||
|
width: 100%;
|
||||||
|
height: 340rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.hero-bg {
|
.hero-bg {
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 340rpx;
|
||||||
}
|
|
||||||
|
|
||||||
.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%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
@@ -213,9 +202,15 @@ function goMore() {
|
|||||||
.notice-pip {
|
.notice-pip {
|
||||||
width: 12rpx;
|
width: 12rpx;
|
||||||
height: 12rpx;
|
height: 12rpx;
|
||||||
|
min-height: 12rpx;
|
||||||
|
max-height: 12rpx;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: $color-accent;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
background: $color-accent;
|
||||||
|
|
||||||
|
&.type-important { background: #EF4444; }
|
||||||
|
&.type-scenic { background: #0052FF; }
|
||||||
|
&.type-promo { background: #F59E0B; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.chevron {
|
.chevron {
|
||||||
@@ -251,7 +246,9 @@ function goMore() {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
background: $color-card;
|
background: $color-card;
|
||||||
padding: $spacing-2 $spacing-3;
|
padding: $spacing-2 $spacing-3;
|
||||||
border-bottom: $border-width solid $color-border;
|
margin: $spacing-2 $spacing-3 0;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-tag {
|
.notice-tag {
|
||||||
@@ -260,6 +257,7 @@ function goMore() {
|
|||||||
margin-right: $spacing-2;
|
margin-right: $spacing-2;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
gap: $spacing-1;
|
gap: $spacing-1;
|
||||||
|
height: 40rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notice-label {
|
.notice-label {
|
||||||
@@ -273,6 +271,28 @@ function goMore() {
|
|||||||
height: 40rpx;
|
height: 40rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notice-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $spacing-1;
|
||||||
|
height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-type-tag {
|
||||||
|
font-size: 20rpx;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
padding: 0 10rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&.type-important { color: #EF4444; background: rgba(239, 68, 68, 0.08); }
|
||||||
|
&.type-scenic { color: #0052FF; background: rgba(0, 82, 255, 0.08); }
|
||||||
|
&.type-promo { color: #F59E0B; background: rgba(245, 158, 11, 0.08); }
|
||||||
|
}
|
||||||
|
|
||||||
.notice-text {
|
.notice-text {
|
||||||
font-size: $font-size-sm;
|
font-size: $font-size-sm;
|
||||||
color: $color-muted-foreground;
|
color: $color-muted-foreground;
|
||||||
@@ -281,6 +301,20 @@ function goMore() {
|
|||||||
-webkit-line-clamp: 1;
|
-webkit-line-clamp: 1;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-more {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $spacing-1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice-more-text {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: $color-muted-foreground;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================
|
/* ============================================
|
||||||
|
|||||||
Reference in New Issue
Block a user