feat: 新增景区列表页和景区详情页
- 新增 pages/scenic-list/scenic-list.vue 全部合作景区列表页 - 动态导航栏适配胶囊按钮高度 - 搜索框支持实时模糊检索 - uni-popup 底部弹窗筛选(地区/等级),支持多条件叠加 - 单列卡片布局:封面图+等级标签、名称+挂牌价、营业状态+时间、权益标签行、温馨提示 - 42个景区完整数据内置 - 新增 pages/scenic-detail/scenic-detail.vue 景区详情页 - 首页「查看全部」跳转至景区列表页 - pages.json 注册两个新页面
This commit is contained in:
@@ -29,6 +29,20 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "个人中心"
|
"navigationBarTitleText": "个人中心"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/scenic-list/scenic-list",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/scenic-detail/scenic-detail",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ function goSpot(spot: ScenicSpotItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function goMore() {
|
function goMore() {
|
||||||
uni.showToast({ title: '景点列表开发中', icon: 'none' })
|
uni.navigateTo({ url: '/pages/scenic-list/scenic-list' })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,632 @@
|
|||||||
|
<template>
|
||||||
|
<view class="page">
|
||||||
|
<!-- 自定义导航栏 -->
|
||||||
|
<view class="nav-bar">
|
||||||
|
<view class="nav-back" @click="goBack">
|
||||||
|
<view class="back-arrow" />
|
||||||
|
</view>
|
||||||
|
<text class="nav-title">{{ scenic?.name || '景区详情' }}</text>
|
||||||
|
<view class="nav-placeholder" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 内容区 -->
|
||||||
|
<scroll-view scroll-y class="detail-scroll" v-if="scenic">
|
||||||
|
<!-- 封面图 -->
|
||||||
|
<view class="cover-section">
|
||||||
|
<image class="cover-img" :src="scenic.image" mode="aspectFill" />
|
||||||
|
<view class="region-tag">
|
||||||
|
<view class="tag-dot" />
|
||||||
|
<text>萍乡</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 信息卡片 -->
|
||||||
|
<view class="info-card">
|
||||||
|
<!-- 标题行 -->
|
||||||
|
<view class="title-row">
|
||||||
|
<text class="scenic-name">{{ scenic.name }}</text>
|
||||||
|
<view v-if="scenic.level" class="level-tag" :class="`level-${scenic.level}`">
|
||||||
|
<text>{{ scenic.level }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 营业状态 -->
|
||||||
|
<view class="info-row">
|
||||||
|
<view class="status-icon" :class="scenic.status === '正常营业' ? 'open' : 'closed'" />
|
||||||
|
<text class="status-text" :class="scenic.status === '正常营业' ? 'open' : 'closed'">
|
||||||
|
{{ scenic.status }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 营业时间 -->
|
||||||
|
<view class="info-row">
|
||||||
|
<view class="time-icon" />
|
||||||
|
<text class="time-text">{{ scenic.hours }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 价格区域 -->
|
||||||
|
<view class="price-section">
|
||||||
|
<view class="price-label">挂牌价</view>
|
||||||
|
<view class="price-group">
|
||||||
|
<text v-if="scenic.price === 0" class="price-free">免费</text>
|
||||||
|
<template v-else>
|
||||||
|
<text class="price-symbol">¥</text>
|
||||||
|
<text class="price-value">{{ scenic.price }}</text>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 权益信息 -->
|
||||||
|
<view class="benefit-section">
|
||||||
|
<view class="benefit-card">
|
||||||
|
<text class="benefit-title">持卡权益</text>
|
||||||
|
<text class="benefit-desc">
|
||||||
|
{{ scenic.freeCount > 0 ? `全年免${scenic.freeCount}次首道门票` : '免费入园' }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="benefit-card" :class="scenic.needReservation ? 'warning' : 'success'">
|
||||||
|
<text class="benefit-title">预约要求</text>
|
||||||
|
<text class="benefit-desc">{{ scenic.needReservation ? '需提前预约' : '无需预约' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 温馨提示 -->
|
||||||
|
<view v-if="scenic.tips" class="tips-section">
|
||||||
|
<view class="section-title">温馨提示</view>
|
||||||
|
<view class="tips-content">
|
||||||
|
<view class="tips-icon">!</view>
|
||||||
|
<text class="tips-text">{{ scenic.tips }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 景区类型 -->
|
||||||
|
<view class="type-section">
|
||||||
|
<view class="section-title">景区类型</view>
|
||||||
|
<view class="type-tag">
|
||||||
|
<text>{{ scenic.type }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<view class="bottom-bar">
|
||||||
|
<view class="action-btn primary" @click="onBookClick">
|
||||||
|
<text>立即预约</text>
|
||||||
|
</view>
|
||||||
|
<view class="action-btn secondary" @click="onCallClick">
|
||||||
|
<text>咨询客服</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 加载中 -->
|
||||||
|
<view v-else class="loading-state">
|
||||||
|
<view class="loading-spinner" />
|
||||||
|
<text class="loading-text">加载中...</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
interface ScenicItem {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
freeCount: number
|
||||||
|
level: '5A' | '4A' | '3A' | '2A' | 'A' | ''
|
||||||
|
status: '正常营业' | '暂停营业'
|
||||||
|
hours: string
|
||||||
|
needReservation: boolean
|
||||||
|
tips: string
|
||||||
|
type: string
|
||||||
|
image: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const scenicList: ScenicItem[] = [
|
||||||
|
{ id: 1, name: '武功山金顶景区', price: 70, freeCount: 1, level: '5A', status: '正常营业', hours: '08:00-18:00', needReservation: true, tips: '建议提前1天预约,山顶温差大请备好外套', type: '自然风光', image: 'https://images.unsplash.com/photo-1513415564515-763d91423bdd?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 2, name: '杨岐山孽龙洞景区', price: 68, freeCount: 6, level: '4A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '洞内温度恒定18℃,建议携带薄外套', type: '自然风光', image: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 3, name: '仙凤三宝景区', price: 50, freeCount: 6, level: '4A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '适合亲子游玩,园内有小动物喂养体验', type: '乡村田园', image: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 4, name: '武功山君澜温泉', price: 228, freeCount: 6, level: '4A', status: '正常营业', hours: '10:00-22:00', needReservation: true, tips: '需提前预约,请自备泳衣泳帽', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1433086966358-54859d0ed716?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 5, name: '凯光新天地生态旅游区', price: 90, freeCount: 6, level: '4A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '园区较大,建议穿舒适运动鞋', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1441974231531-c6227db76b6e?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 6, name: '和平农场·哎马乐园', price: 79, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:30', needReservation: false, tips: '亲子乐园,周末人流较多建议错峰', type: '乡村田园', image: 'https://images.unsplash.com/photo-1501854140801-50d01698950b?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 7, name: '武功山滑草场', price: 60, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '雨天暂停开放,请关注天气', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1551632811-561732d1e306?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 8, name: '芦溪仙凤三宝农业休闲观光园', price: 50, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '可体验采摘,季节性水果品种丰富', type: '乡村田园', image: 'https://images.unsplash.com/photo-1500382017468-9049fed747ef?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 9, name: '麻山幸福村', price: 40, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '乡村旅游景区,可体验农家生活', type: '乡村田园', image: 'https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 10, name: '东桥双月湾', price: 38, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '临水景区,请注意安全', type: '自然风光', image: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 11, name: '上栗花炮文化博览园', price: 45, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '了解花炮历史文化,适合研学', type: '文化古迹', image: 'https://images.unsplash.com/photo-1533174072545-7a4b6ad7a6c3?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 12, name: '杨岐普通寺', price: 30, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-17:00', needReservation: false, tips: '佛教圣地,请保持安静', type: '文化古迹', image: 'https://images.unsplash.com/photo-1518241353330-0f7941c2d9b5?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 13, name: '孽龙洞漂流', price: 88, freeCount: 6, level: '3A', status: '暂停营业', hours: '暂停开放', needReservation: false, tips: '季节性项目,预计6月开放', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1504280390367-361c6d9f38f4?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 14, name: '安源路矿工人运动纪念馆', price: 0, freeCount: 0, level: '4A', status: '正常营业', hours: '09:00-16:30', needReservation: false, tips: '红色教育基地,周一闭馆', type: '红色教育', image: 'https://images.unsplash.com/photo-1565008576549-57569a49371d?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 15, name: '莲花荷博园', price: 35, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '夏季荷花盛开时最佳观赏期', type: '自然风光', image: 'https://images.unsplash.com/photo-1490750967868-88aa4486c946?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 16, name: '山口岩水利风景区', price: 25, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '水利工程景观,可了解水利知识', type: '自然风光', image: 'https://images.unsplash.com/photo-1439066615861-d1af74d74000?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 17, name: '宣风三宝水上乐园', price: 65, freeCount: 6, level: '3A', status: '暂停营业', hours: '暂停开放', needReservation: false, tips: '夏季开放,请关注开园公告', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1519750013994-3d27cd3f7f49?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 18, name: '万龙山温泉', price: 168, freeCount: 6, level: '4A', status: '正常营业', hours: '10:00-22:00', needReservation: true, tips: '需提前预约,温泉养生好去处', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1545569341-9eb8b30979d9?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 19, name: '杨岐山野生动物科普园', price: 42, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '适合亲子科普教育', type: '乡村田园', image: 'https://images.unsplash.com/photo-1474511320723-9a56873571b7?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 20, name: '鸡冠山森林步道', price: 0, freeCount: 0, level: '3A', status: '正常营业', hours: '全天开放', needReservation: false, tips: '森林氧吧,适合徒步健身', type: '自然风光', image: 'https://images.unsplash.com/photo-1551632811-561732d1e306?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 21, name: '赤山杨岐山民宿集群配套景区', price: 28, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-20:00', needReservation: false, tips: '可体验民宿住宿,感受乡村风情', type: '乡村田园', image: 'https://images.unsplash.com/photo-1510798831971-661eb04b3739?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 22, name: '湘东傩文化园', price: 32, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '了解傩文化,感受非遗魅力', type: '文化古迹', image: 'https://images.unsplash.com/photo-1533174072545-7a4b6ad7a6c3?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 23, name: '广寒寨四季花海', price: 36, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '四季花卉轮番绽放,拍照打卡好去处', type: '自然风光', image: 'https://images.unsplash.com/photo-1490750967868-88aa4486c946?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 24, name: '上栗泉水湾度假村', price: 58, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-18:00', needReservation: false, tips: '休闲度假好去处,可垂钓烧烤', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 25, name: '莲花棋盘山', price: 22, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '登山步道完善,适合休闲健身', type: '自然风光', image: 'https://images.unsplash.com/photo-1444464666168-49d633b86797?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 26, name: '芦溪东阳古村', price: 26, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '古建筑群保存完好,可感受传统村落文化', type: '文化古迹', image: 'https://images.unsplash.com/photo-1528181304800-259b08848526?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 27, name: '安源欢乐谷', price: 72, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-18:00', needReservation: false, tips: '游乐设施丰富,适合亲子游玩', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1513407030348-c9836fb1966d?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 28, name: '湘东太阳广场游乐区', price: 48, freeCount: 6, level: '2A', status: '正常营业', hours: '09:00-21:00', needReservation: false, tips: '夜间灯光秀值得一看', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 29, name: '长平养生谷', price: 52, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '养生休闲好去处,空气清新', type: '自然风光', image: 'https://images.unsplash.com/photo-1518241353330-0f7941c2d9b5?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 30, name: '坊楼红色文化园', price: 0, freeCount: 0, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '红色教育基地,免费参观', type: '红色教育', image: 'https://images.unsplash.com/photo-1565008576549-57569a49371d?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 31, name: '高坑生态采摘园', price: 33, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '季节性水果采摘,体验田园乐趣', type: '乡村田园', image: 'https://images.unsplash.com/photo-1500382017468-9049fed747ef?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 32, name: '源南田园综合体', price: 39, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '田园风光优美,可体验农耕文化', type: '乡村田园', image: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 33, name: '下埠陶瓷文化小镇', price: 29, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '可体验陶瓷制作,了解陶瓷文化', type: '文化古迹', image: 'https://images.unsplash.com/photo-1528181304800-259b08848526?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 34, name: '桐木水上乐园', price: 66, freeCount: 6, level: '3A', status: '暂停营业', hours: '暂停开放', needReservation: false, tips: '夏季开放,请关注开园时间', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1519750013994-3d27cd3f7f49?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 35, name: '东源温泉度假村', price: 138, freeCount: 6, level: '4A', status: '正常营业', hours: '10:00-22:00', needReservation: true, tips: '需提前预约,温泉品质优良', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1545569341-9eb8b30979d9?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 36, name: '长丰山水景区', price: 24, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '山水相依,适合休闲散步', type: '自然风光', image: 'https://images.unsplash.com/photo-1439066615861-d1af74d74000?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 37, name: '白竺青草湖', price: 27, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '湖光山色,可垂钓泛舟', type: '自然风光', image: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 38, name: '荷尧古渡口', price: 0, freeCount: 0, level: '2A', status: '正常营业', hours: '全天开放', needReservation: false, tips: '古渡口遗址,感受历史文化', type: '文化古迹', image: 'https://images.unsplash.com/photo-1504280390367-361c6d9f38f4?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 39, name: '新泉红色研学基地', price: 31, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: true, tips: '研学活动需提前预约', type: '红色教育', image: 'https://images.unsplash.com/photo-1565008576549-57569a49371d?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 40, name: '张佳坊山地乐园', price: 55, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:30', needReservation: false, tips: '山地运动项目丰富,注意安全', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1551632811-561732d1e306?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 41, name: '南坑户外拓展基地', price: 44, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-18:00', needReservation: true, tips: '团队拓展需提前预约', type: '休闲娱乐', image: 'https://images.unsplash.com/photo-1501854140801-50d01698950b?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
{ id: 42, name: '老关荷花景区', price: 34, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '夏季荷花盛开,景色宜人', type: '自然风光', image: 'https://images.unsplash.com/photo-1490750967868-88aa4486c946?fm=jpg&q=80&w=1200&h=600&fit=crop' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const scenic = ref<ScenicItem | null>(null)
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
const id = parseInt(options?.id || '0')
|
||||||
|
scenic.value = scenicList.find(s => s.id === id) || null
|
||||||
|
})
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBookClick() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '预约功能开发中',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCallClick() {
|
||||||
|
uni.showToast({
|
||||||
|
title: '客服功能开发中',
|
||||||
|
icon: 'none',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: $color-background;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 导航栏 */
|
||||||
|
.nav-bar {
|
||||||
|
height: 88rpx;
|
||||||
|
background: $color-card;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 $spacing-3;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: $radius-base;
|
||||||
|
transition: background $transition-fast;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $color-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-arrow {
|
||||||
|
width: 20rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
border-left: 4rpx solid $color-foreground;
|
||||||
|
border-bottom: 4rpx solid $color-foreground;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
margin-left: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: $color-foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-placeholder {
|
||||||
|
width: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动区域 */
|
||||||
|
.detail-scroll {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 封面图 */
|
||||||
|
.cover-section {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 480rpx;
|
||||||
|
background: $color-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: $spacing-3;
|
||||||
|
left: $spacing-3;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
backdrop-filter: blur(8rpx);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
padding: 8rpx $spacing-2;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-dot {
|
||||||
|
width: 10rpx;
|
||||||
|
height: 10rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 信息卡片 */
|
||||||
|
.info-card {
|
||||||
|
background: $color-card;
|
||||||
|
margin: -60rpx $spacing-3 $spacing-3;
|
||||||
|
padding: $spacing-3;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
box-shadow: $shadow-base;
|
||||||
|
position: relative;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题行 */
|
||||||
|
.title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scenic-name {
|
||||||
|
font-size: $font-size-xl;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: $color-foreground;
|
||||||
|
flex: 1;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-tag {
|
||||||
|
padding: 6rpx $spacing-2;
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.level-5A {
|
||||||
|
background: #EF4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.level-4A {
|
||||||
|
background: #F59E0B;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.level-3A,
|
||||||
|
&.level-2A,
|
||||||
|
&.level-A {
|
||||||
|
background: $uv-success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 信息行 */
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
width: 20rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
background: $uv-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.closed {
|
||||||
|
background: $uv-error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
|
||||||
|
&.open {
|
||||||
|
color: $uv-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.closed {
|
||||||
|
color: $uv-error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-icon {
|
||||||
|
width: 24rpx;
|
||||||
|
height: 24rpx;
|
||||||
|
border: 3rpx solid $uv-tips-color;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 3rpx;
|
||||||
|
height: 10rpx;
|
||||||
|
background: $uv-tips-color;
|
||||||
|
top: 5rpx;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 8rpx;
|
||||||
|
height: 3rpx;
|
||||||
|
background: $uv-tips-color;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 价格区域 */
|
||||||
|
.price-section {
|
||||||
|
background: $uv-warning-light;
|
||||||
|
border-radius: $radius-base;
|
||||||
|
padding: $spacing-3;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-label {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-content-color;
|
||||||
|
margin-bottom: $spacing-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-symbol {
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
color: $uv-warning-dark;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-value {
|
||||||
|
font-size: $font-size-3xl;
|
||||||
|
color: $uv-warning-dark;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-free {
|
||||||
|
font-size: $font-size-xl;
|
||||||
|
color: $uv-success;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 权益信息 */
|
||||||
|
.benefit-section {
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-2;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-card {
|
||||||
|
flex: 1;
|
||||||
|
background: $uv-primary-light;
|
||||||
|
border-radius: $radius-base;
|
||||||
|
padding: $spacing-2;
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background: $uv-warning-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
background: $uv-success-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-title {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-content-color;
|
||||||
|
margin-bottom: $spacing-1;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-desc {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $color-foreground;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分区标题 */
|
||||||
|
.section-title {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: $color-foreground;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 温馨提示 */
|
||||||
|
.tips-section {
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
background: rgba(249, 174, 61, 0.08);
|
||||||
|
border-radius: $radius-base;
|
||||||
|
padding: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-icon {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
background: $uv-warning;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-content-color;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 景区类型 */
|
||||||
|
.type-section {
|
||||||
|
margin-bottom: 120rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
padding: $spacing-1 $spacing-3;
|
||||||
|
background: $color-muted;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-content-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 底部操作栏 */
|
||||||
|
.bottom-bar {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: $color-card;
|
||||||
|
padding: $spacing-3;
|
||||||
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-2;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 88rpx;
|
||||||
|
border-radius: $radius-full;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: transform $transition-fast;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
background: $uv-primary;
|
||||||
|
|
||||||
|
text {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
background: $color-muted;
|
||||||
|
|
||||||
|
text {
|
||||||
|
color: $uv-content-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 加载中 */
|
||||||
|
.loading-state {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
width: 64rpx;
|
||||||
|
height: 64rpx;
|
||||||
|
border: 6rpx solid $color-muted;
|
||||||
|
border-top-color: $uv-primary;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spin 0.8s linear infinite;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-tips-color;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,988 @@
|
|||||||
|
<template>
|
||||||
|
<view class="page">
|
||||||
|
<!-- 固定自定义导航栏 -->
|
||||||
|
<view class="nav-bar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||||||
|
<view class="nav-content" :style="{ height: navContentHeight + 'px' }">
|
||||||
|
<view class="nav-side">
|
||||||
|
<view class="nav-back" @click="goBack">
|
||||||
|
<view class="back-arrow" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<text class="nav-title">全部合作景区</text>
|
||||||
|
<view class="nav-side" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 页面主体(避开导航栏 + 吸顶筛选区) -->
|
||||||
|
<view class="page-body" :style="{ paddingTop: (navTotalHeight + stickyHeaderHeight) + 'px' }">
|
||||||
|
<!-- 吸顶搜索筛选区 -->
|
||||||
|
<view class="sticky-header" :style="{ top: navTotalHeight + 'px' }">
|
||||||
|
<!-- 搜索框 -->
|
||||||
|
<view class="search-box">
|
||||||
|
<view class="search-icon">
|
||||||
|
<view class="icon-circle" />
|
||||||
|
<view class="icon-handle" />
|
||||||
|
</view>
|
||||||
|
<input
|
||||||
|
class="search-input"
|
||||||
|
v-model="searchText"
|
||||||
|
placeholder="搜索景区名称"
|
||||||
|
placeholder-class="search-placeholder"
|
||||||
|
/>
|
||||||
|
<view v-if="searchText" class="clear-btn" @click="clearSearch">
|
||||||
|
<text>×</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 下拉筛选区 -->
|
||||||
|
<view class="dropdown-row">
|
||||||
|
<view class="dropdown-trigger" @click="openPicker('region')">
|
||||||
|
<text class="dropdown-label" :class="{ active: selectedRegion }">{{ selectedRegion || '景区地区' }}</text>
|
||||||
|
<view class="dropdown-arrow" />
|
||||||
|
</view>
|
||||||
|
<view class="dropdown-trigger" @click="openPicker('level')">
|
||||||
|
<text class="dropdown-label" :class="{ active: selectedLevel }">{{ selectedLevel || '景区等级' }}</text>
|
||||||
|
<view class="dropdown-arrow" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 景区列表 -->
|
||||||
|
<view class="list-area">
|
||||||
|
<view v-if="filteredScenics.length === 0" class="empty-state">
|
||||||
|
<view class="empty-icon">
|
||||||
|
<view class="empty-circle" />
|
||||||
|
<view class="empty-line line-1" />
|
||||||
|
<view class="empty-line line-2" />
|
||||||
|
</view>
|
||||||
|
<text class="empty-text">暂无匹配景区</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="list-container">
|
||||||
|
<view
|
||||||
|
v-for="scenic in filteredScenics"
|
||||||
|
:key="scenic.id"
|
||||||
|
class="scenic-card"
|
||||||
|
@click="onCardClick(scenic)"
|
||||||
|
>
|
||||||
|
<!-- 封面图 -->
|
||||||
|
<view class="card-cover">
|
||||||
|
<image class="cover-img" :src="scenic.image" mode="aspectFill" />
|
||||||
|
<view class="region-tag">
|
||||||
|
<view class="tag-dot" />
|
||||||
|
<text>{{ scenic.region }}</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="scenic.level" class="level-tag" :class="`level-${scenic.level}`">
|
||||||
|
<text>{{ scenic.level }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 信息区 -->
|
||||||
|
<view class="card-body">
|
||||||
|
<!-- 名称 + 挂牌价 同行 -->
|
||||||
|
<view class="name-price-row">
|
||||||
|
<text class="scenic-name">{{ scenic.name }}</text>
|
||||||
|
<view class="price-group">
|
||||||
|
<text v-if="scenic.price === 0" class="price-free">免费</text>
|
||||||
|
<template v-else>
|
||||||
|
<text class="price-symbol">¥</text>
|
||||||
|
<text class="price-value">{{ scenic.price }}</text>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 营业时间 + 营业状态 同行 -->
|
||||||
|
<view class="hours-status-row">
|
||||||
|
<view class="time-block">
|
||||||
|
<view class="time-icon" />
|
||||||
|
<text class="time-text">{{ scenic.hours }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="status-block">
|
||||||
|
<view class="status-icon" :class="scenic.status === '正常营业' ? 'open' : 'closed'" />
|
||||||
|
<text class="status-text" :class="scenic.status === '正常营业' ? 'open' : 'closed'">
|
||||||
|
{{ scenic.status }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 剩余次数 + 免票标签 + 预约标签 同行 -->
|
||||||
|
<view class="benefit-row">
|
||||||
|
<view v-if="scenic.freeCount > 0" class="remaining-tag">
|
||||||
|
<text>全年可用{{ scenic.freeCount }}次</text>
|
||||||
|
</view>
|
||||||
|
<view class="benefit-tag primary">
|
||||||
|
<text>{{ scenic.freeCount > 0 ? `免${scenic.freeCount}次` : '免费' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="benefit-tag" :class="scenic.needReservation ? 'warning' : 'success'">
|
||||||
|
<text>{{ scenic.needReservation ? '需预约' : '免预约' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 温馨提示 -->
|
||||||
|
<view v-if="scenic.tips" class="tips-bar">
|
||||||
|
<view class="tips-icon">!</view>
|
||||||
|
<text class="tips-text">{{ scenic.tips }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 筛选弹窗(单实例,动态内容) -->
|
||||||
|
<uni-popup
|
||||||
|
ref="filterPopup"
|
||||||
|
type="bottom"
|
||||||
|
:mask-click="true"
|
||||||
|
:safe-area="true"
|
||||||
|
background-color="#ffffff"
|
||||||
|
@change="onPopupChange"
|
||||||
|
>
|
||||||
|
<view class="popup-sheet" @touchmove.stop.prevent>
|
||||||
|
<!-- 头部:标题 + 重置 -->
|
||||||
|
<view class="popup-header">
|
||||||
|
<text class="popup-title">{{ popupTitle }}</text>
|
||||||
|
<view class="popup-reset" @click="resetFilter">
|
||||||
|
<text>重置</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 可滚动选项列表 -->
|
||||||
|
<scroll-view scroll-y class="popup-scroll">
|
||||||
|
<view
|
||||||
|
v-for="item in currentOptions"
|
||||||
|
:key="item.value"
|
||||||
|
class="popup-option"
|
||||||
|
:class="{ active: tempValue === item.value }"
|
||||||
|
@click="onOptionTap(item.value)"
|
||||||
|
>
|
||||||
|
<text>{{ item.label }}</text>
|
||||||
|
<view v-if="tempValue === item.value" class="check-mark" />
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 底部确定按钮 -->
|
||||||
|
<view class="popup-footer" @click="confirmFilter">
|
||||||
|
<text>确定筛选</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</uni-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted, getCurrentInstance } from 'vue'
|
||||||
|
|
||||||
|
interface ScenicItem {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
freeCount: number
|
||||||
|
level: string
|
||||||
|
status: '正常营业' | '暂停营业'
|
||||||
|
hours: string
|
||||||
|
needReservation: boolean
|
||||||
|
tips: string
|
||||||
|
type: string
|
||||||
|
region: string
|
||||||
|
image: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 导航栏动态高度 ==========
|
||||||
|
const statusBarHeight = ref(20)
|
||||||
|
const navContentHeight = ref(44)
|
||||||
|
const navTotalHeight = ref(64)
|
||||||
|
const stickyHeaderHeight = ref(96) // 预估,onMounted 后精确测量
|
||||||
|
|
||||||
|
// 页面加载时获取系统信息
|
||||||
|
;(function initNavBar() {
|
||||||
|
try {
|
||||||
|
const sysInfo = uni.getSystemInfoSync()
|
||||||
|
statusBarHeight.value = sysInfo.statusBarHeight || 20
|
||||||
|
} catch {
|
||||||
|
statusBarHeight.value = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
try {
|
||||||
|
const menuBtn = uni.getMenuButtonBoundingClientRect()
|
||||||
|
const capsuleHeight = menuBtn.height
|
||||||
|
const capsuleTop = menuBtn.top
|
||||||
|
const capsuleBottom = capsuleTop + capsuleHeight
|
||||||
|
// 导航栏内容区高度:胶囊上下各留等距间距
|
||||||
|
const contentH = (capsuleBottom - statusBarHeight.value) + (capsuleTop - statusBarHeight.value)
|
||||||
|
navContentHeight.value = Math.max(contentH, 44)
|
||||||
|
navTotalHeight.value = statusBarHeight.value + navContentHeight.value
|
||||||
|
} catch {
|
||||||
|
navContentHeight.value = 44
|
||||||
|
navTotalHeight.value = statusBarHeight.value + 44
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
navContentHeight.value = 44
|
||||||
|
navTotalHeight.value = statusBarHeight.value + 44
|
||||||
|
// #endif
|
||||||
|
})()
|
||||||
|
|
||||||
|
// 测量吸顶筛选区实际高度
|
||||||
|
onMounted(() => {
|
||||||
|
const query = uni.createSelectorQuery().in(getCurrentInstance())
|
||||||
|
query.select('.sticky-header').boundingClientRect((rect: any) => {
|
||||||
|
if (rect) stickyHeaderHeight.value = Math.ceil(rect.height)
|
||||||
|
}).exec()
|
||||||
|
})
|
||||||
|
|
||||||
|
// ========== 数据 ==========
|
||||||
|
const scenicList: ScenicItem[] = [
|
||||||
|
{ id: 1, name: '武功山金顶景区', price: 70, freeCount: 1, level: '5A', status: '正常营业', hours: '08:00-18:00', needReservation: true, tips: '建议提前1天预约,山顶温差大请备好外套', type: '自然风光', region: '芦溪县', image: 'https://images.unsplash.com/photo-1513415564515-763d91423bdd?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 2, name: '杨岐山孽龙洞景区', price: 68, freeCount: 6, level: '4A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '洞内温度恒定18℃,建议携带薄外套', type: '自然风光', region: '上栗县', image: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 3, name: '仙凤三宝景区', price: 50, freeCount: 6, level: '4A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '适合亲子游玩,园内有小动物喂养体验', type: '乡村田园', region: '芦溪县', image: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 4, name: '武功山君澜温泉', price: 228, freeCount: 6, level: '4A', status: '正常营业', hours: '10:00-22:00', needReservation: true, tips: '需提前预约,请自备泳衣泳帽', type: '休闲娱乐', region: '芦溪县', image: 'https://images.unsplash.com/photo-1433086966358-54859d0ed716?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 5, name: '凯光新天地生态旅游区', price: 90, freeCount: 6, level: '4A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '园区较大,建议穿舒适运动鞋', type: '休闲娱乐', region: '安源区', image: 'https://images.unsplash.com/photo-1441974231531-c6227db76b6e?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 6, name: '和平农场·哎马乐园', price: 79, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:30', needReservation: false, tips: '亲子乐园,周末人流较多建议错峰', type: '乡村田园', region: '湘东区', image: 'https://images.unsplash.com/photo-1501854140801-50d01698950b?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 7, name: '武功山滑草场', price: 60, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '雨天暂停开放,请关注天气', type: '休闲娱乐', region: '芦溪县', image: 'https://images.unsplash.com/photo-1551632811-561732d1e306?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 8, name: '芦溪仙凤三宝农业休闲观光园', price: 50, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '可体验采摘,季节性水果品种丰富', type: '乡村田园', region: '芦溪县', image: 'https://images.unsplash.com/photo-1500382017468-9049fed747ef?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 9, name: '麻山幸福村', price: 40, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '乡村旅游景区,可体验农家生活', type: '乡村田园', region: '湘东区', image: 'https://images.unsplash.com/photo-1523712999610-f77fbcfc3843?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 10, name: '东桥双月湾', price: 38, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '临水景区,请注意安全', type: '自然风光', region: '湘东区', image: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 11, name: '上栗花炮文化博览园', price: 45, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '了解花炮历史文化,适合研学', type: '文化古迹', region: '上栗县', image: 'https://images.unsplash.com/photo-1533174072545-7a4b6ad7a6c3?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 12, name: '杨岐普通寺', price: 30, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-17:00', needReservation: false, tips: '佛教圣地,请保持安静', type: '文化古迹', region: '上栗县', image: 'https://images.unsplash.com/photo-1518241353330-0f7941c2d9b5?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 13, name: '孽龙洞漂流', price: 88, freeCount: 6, level: '3A', status: '暂停营业', hours: '暂停开放', needReservation: false, tips: '季节性项目,预计6月开放', type: '休闲娱乐', region: '上栗县', image: 'https://images.unsplash.com/photo-1504280390367-361c6d9f38f4?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 14, name: '安源路矿工人运动纪念馆', price: 0, freeCount: 0, level: '4A', status: '正常营业', hours: '09:00-16:30', needReservation: false, tips: '红色教育基地,周一闭馆', type: '红色教育', region: '安源区', image: 'https://images.unsplash.com/photo-1565008576549-57569a49371d?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 15, name: '莲花荷博园', price: 35, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '夏季荷花盛开时最佳观赏期', type: '自然风光', region: '莲花县', image: 'https://images.unsplash.com/photo-1490750967868-88aa4486c946?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 16, name: '山口岩水利风景区', price: 25, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '水利工程景观,可了解水利知识', type: '自然风光', region: '芦溪县', image: 'https://images.unsplash.com/photo-1439066615861-d1af74d74000?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 17, name: '宣风三宝水上乐园', price: 65, freeCount: 6, level: '3A', status: '暂停营业', hours: '暂停开放', needReservation: false, tips: '夏季开放,请关注开园公告', type: '休闲娱乐', region: '芦溪县', image: 'https://images.unsplash.com/photo-1519750013994-3d27cd3f7f49?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 18, name: '万龙山温泉', price: 168, freeCount: 6, level: '4A', status: '正常营业', hours: '10:00-22:00', needReservation: true, tips: '需提前预约,温泉养生好去处', type: '休闲娱乐', region: '芦溪县', image: 'https://images.unsplash.com/photo-1545569341-9eb8b30979d9?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 19, name: '杨岐山野生动物科普园', price: 42, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '适合亲子科普教育', type: '乡村田园', region: '上栗县', image: 'https://images.unsplash.com/photo-1474511320723-9a56873571b7?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 20, name: '鸡冠山森林步道', price: 0, freeCount: 0, level: '3A', status: '正常营业', hours: '全天开放', needReservation: false, tips: '森林氧吧,适合徒步健身', type: '自然风光', region: '上栗县', image: 'https://images.unsplash.com/photo-1551632811-561732d1e306?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 21, name: '赤山杨岐山民宿集群配套景区', price: 28, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-20:00', needReservation: false, tips: '可体验民宿住宿,感受乡村风情', type: '乡村田园', region: '上栗县', image: 'https://images.unsplash.com/photo-1510798831971-661eb04b3739?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 22, name: '湘东傩文化园', price: 32, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '了解傩文化,感受非遗魅力', type: '文化古迹', region: '湘东区', image: 'https://images.unsplash.com/photo-1533174072545-7a4b6ad7a6c3?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 23, name: '广寒寨四季花海', price: 36, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '四季花卉轮番绽放,拍照打卡好去处', type: '自然风光', region: '湘东区', image: 'https://images.unsplash.com/photo-1490750967868-88aa4486c946?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 24, name: '上栗泉水湾度假村', price: 58, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-18:00', needReservation: false, tips: '休闲度假好去处,可垂钓烧烤', type: '休闲娱乐', region: '上栗县', image: 'https://images.unsplash.com/photo-1571896349842-33c89424de2d?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 25, name: '莲花棋盘山', price: 22, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '登山步道完善,适合休闲健身', type: '自然风光', region: '莲花县', image: 'https://images.unsplash.com/photo-1444464666168-49d633b86797?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 26, name: '芦溪东阳古村', price: 26, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '古建筑群保存完好,可感受传统村落文化', type: '文化古迹', region: '芦溪县', image: 'https://images.unsplash.com/photo-1528181304800-259b08848526?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 27, name: '安源欢乐谷', price: 72, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-18:00', needReservation: false, tips: '游乐设施丰富,适合亲子游玩', type: '休闲娱乐', region: '安源区', image: 'https://images.unsplash.com/photo-1513407030348-c9836fb1966d?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 28, name: '湘东太阳广场游乐区', price: 48, freeCount: 6, level: '2A', status: '正常营业', hours: '09:00-21:00', needReservation: false, tips: '夜间灯光秀值得一看', type: '休闲娱乐', region: '湘东区', image: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 29, name: '长平养生谷', price: 52, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '养生休闲好去处,空气清新', type: '自然风光', region: '上栗县', image: 'https://images.unsplash.com/photo-1518241353330-0f7941c2d9b5?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 30, name: '坊楼红色文化园', price: 0, freeCount: 0, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '红色教育基地,免费参观', type: '红色教育', region: '莲花县', image: 'https://images.unsplash.com/photo-1565008576549-57569a49371d?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 31, name: '高坑生态采摘园', price: 33, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '季节性水果采摘,体验田园乐趣', type: '乡村田园', region: '安源区', image: 'https://images.unsplash.com/photo-1500382017468-9049fed747ef?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 32, name: '源南田园综合体', price: 39, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-17:30', needReservation: false, tips: '田园风光优美,可体验农耕文化', type: '乡村田园', region: '芦溪县', image: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 33, name: '下埠陶瓷文化小镇', price: 29, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: false, tips: '可体验陶瓷制作,了解陶瓷文化', type: '文化古迹', region: '湘东区', image: 'https://images.unsplash.com/photo-1528181304800-259b08848526?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 34, name: '桐木水上乐园', price: 66, freeCount: 6, level: '3A', status: '暂停营业', hours: '暂停开放', needReservation: false, tips: '夏季开放,请关注开园时间', type: '休闲娱乐', region: '上栗县', image: 'https://images.unsplash.com/photo-1519750013994-3d27cd3f7f49?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 35, name: '东源温泉度假村', price: 138, freeCount: 6, level: '4A', status: '正常营业', hours: '10:00-22:00', needReservation: true, tips: '需提前预约,温泉品质优良', type: '休闲娱乐', region: '上栗县', image: 'https://images.unsplash.com/photo-1545569341-9eb8b30979d9?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 36, name: '长丰山水景区', price: 24, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '山水相依,适合休闲散步', type: '自然风光', region: '莲花县', image: 'https://images.unsplash.com/photo-1439066615861-d1af74d74000?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 37, name: '白竺青草湖', price: 27, freeCount: 6, level: '3A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '湖光山色,可垂钓泛舟', type: '自然风光', region: '湘东区', image: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 38, name: '荷尧古渡口', price: 0, freeCount: 0, level: '2A', status: '正常营业', hours: '全天开放', needReservation: false, tips: '古渡口遗址,感受历史文化', type: '文化古迹', region: '湘东区', image: 'https://images.unsplash.com/photo-1504280390367-361c6d9f38f4?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 39, name: '新泉红色研学基地', price: 31, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:00', needReservation: true, tips: '研学活动需提前预约', type: '红色教育', region: '芦溪县', image: 'https://images.unsplash.com/photo-1565008576549-57569a49371d?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 40, name: '张佳坊山地乐园', price: 55, freeCount: 6, level: '3A', status: '正常营业', hours: '09:00-17:30', needReservation: false, tips: '山地运动项目丰富,注意安全', type: '休闲娱乐', region: '芦溪县', image: 'https://images.unsplash.com/photo-1551632811-561732d1e306?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 41, name: '南坑户外拓展基地', price: 44, freeCount: 6, level: '3A', status: '正常营业', hours: '08:30-18:00', needReservation: true, tips: '团队拓展需提前预约', type: '休闲娱乐', region: '莲花县', image: 'https://images.unsplash.com/photo-1501854140801-50d01698950b?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
{ id: 42, name: '老关荷花景区', price: 34, freeCount: 6, level: '2A', status: '正常营业', hours: '08:00-18:00', needReservation: false, tips: '夏季荷花盛开,景色宜人', type: '自然风光', region: '湘东区', image: 'https://images.unsplash.com/photo-1490750967868-88aa4486c946?fm=jpg&q=80&w=800&h=400&fit=crop' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// ========== 搜索筛选 ==========
|
||||||
|
const searchText = ref('')
|
||||||
|
const selectedRegion = ref('')
|
||||||
|
const selectedLevel = ref('')
|
||||||
|
|
||||||
|
// uni-popup 单实例引用
|
||||||
|
const filterPopup = ref()
|
||||||
|
|
||||||
|
// 当前弹窗类型 & 临时选中值
|
||||||
|
const activePickerType = ref<'region' | 'level'>('region')
|
||||||
|
const tempValue = ref('')
|
||||||
|
|
||||||
|
const regionOptions = [
|
||||||
|
{ label: '全部地区', value: '' },
|
||||||
|
{ label: '安源区', value: '安源区' },
|
||||||
|
{ label: '湘东区', value: '湘东区' },
|
||||||
|
{ label: '芦溪县', value: '芦溪县' },
|
||||||
|
{ label: '上栗县', value: '上栗县' },
|
||||||
|
{ label: '莲花县', value: '莲花县' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const levelOptions = [
|
||||||
|
{ label: '全部等级', value: '' },
|
||||||
|
{ label: '5A', value: '5A' },
|
||||||
|
{ label: '4A', value: '4A' },
|
||||||
|
{ label: '3A', value: '3A' },
|
||||||
|
{ label: '2A', value: '2A' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// 动态标题 & 选项列表
|
||||||
|
const popupTitle = computed(() =>
|
||||||
|
activePickerType.value === 'region' ? '选择地区' : '选择等级'
|
||||||
|
)
|
||||||
|
|
||||||
|
const currentOptions = computed(() =>
|
||||||
|
activePickerType.value === 'region' ? regionOptions : levelOptions
|
||||||
|
)
|
||||||
|
|
||||||
|
function openPicker(type: 'region' | 'level') {
|
||||||
|
activePickerType.value = type
|
||||||
|
tempValue.value = type === 'region' ? selectedRegion.value : selectedLevel.value
|
||||||
|
filterPopup.value?.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onOptionTap(value: string) {
|
||||||
|
tempValue.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmFilter() {
|
||||||
|
if (activePickerType.value === 'region') {
|
||||||
|
selectedRegion.value = tempValue.value
|
||||||
|
} else {
|
||||||
|
selectedLevel.value = tempValue.value
|
||||||
|
}
|
||||||
|
filterPopup.value?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetFilter() {
|
||||||
|
tempValue.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPopupChange(e: { show: boolean }) {
|
||||||
|
// 弹窗关闭时无需额外处理
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearSearch() {
|
||||||
|
searchText.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤后的景区列表
|
||||||
|
const filteredScenics = computed(() => {
|
||||||
|
return scenicList.filter(scenic => {
|
||||||
|
if (searchText.value && !scenic.name.toLowerCase().includes(searchText.value.toLowerCase())) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (selectedRegion.value && scenic.region !== selectedRegion.value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (selectedLevel.value && scenic.level !== selectedLevel.value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function goBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCardClick(scenic: ScenicItem) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/scenic-detail/scenic-detail?id=${scenic.id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: $color-background;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== 固定导航栏 ====== */
|
||||||
|
.nav-bar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: $color-card;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-back {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 60rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: $radius-base;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: background $transition-fast;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $color-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-arrow {
|
||||||
|
width: 20rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
border-left: 4rpx solid $color-foreground;
|
||||||
|
border-bottom: 4rpx solid $color-foreground;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
margin-left: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: $color-foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-side {
|
||||||
|
width: 80rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== 页面主体 ====== */
|
||||||
|
.page-body {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== 吸顶搜索筛选区 ====== */
|
||||||
|
.sticky-header {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 50;
|
||||||
|
background: $color-background;
|
||||||
|
padding: $spacing-2 $spacing-3;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索框 */
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: $color-card;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
padding: 0 $spacing-3;
|
||||||
|
height: 72rpx;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: relative;
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-circle {
|
||||||
|
width: 20rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
border: 3rpx solid $uv-tips-color;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-handle {
|
||||||
|
width: 10rpx;
|
||||||
|
height: 3rpx;
|
||||||
|
background: $uv-tips-color;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 4rpx;
|
||||||
|
right: 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $color-foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-placeholder {
|
||||||
|
color: $uv-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clear-btn {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: $uv-tips-color;
|
||||||
|
font-size: 40rpx;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: $color-foreground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉筛选行 */
|
||||||
|
.dropdown-row {
|
||||||
|
display: flex;
|
||||||
|
gap: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-trigger {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: $color-card;
|
||||||
|
border-radius: $radius-base;
|
||||||
|
padding: $spacing-2 $spacing-3;
|
||||||
|
transition: background $transition-fast;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $color-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-label {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $color-foreground;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $uv-primary;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-arrow {
|
||||||
|
width: 12rpx;
|
||||||
|
height: 12rpx;
|
||||||
|
border-right: 3rpx solid $uv-tips-color;
|
||||||
|
border-bottom: 3rpx solid $uv-tips-color;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: $spacing-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== 列表区域 ====== */
|
||||||
|
|
||||||
|
/* 空状态 */
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 120rpx $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-icon {
|
||||||
|
position: relative;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
|
margin-bottom: $spacing-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-circle {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
border: 6rpx solid $uv-border-color;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-line {
|
||||||
|
position: absolute;
|
||||||
|
background: $uv-border-color;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-1 {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 8rpx;
|
||||||
|
top: 60rpx;
|
||||||
|
left: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-2 {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 8rpx;
|
||||||
|
top: 80rpx;
|
||||||
|
left: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 列表区域 */
|
||||||
|
.list-area {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 列表容器 */
|
||||||
|
.list-container {
|
||||||
|
padding: $spacing-3;
|
||||||
|
padding-top: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== 卡片 ====== */
|
||||||
|
.scenic-card {
|
||||||
|
background: $color-card;
|
||||||
|
border-radius: $radius-lg;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: $shadow-sm;
|
||||||
|
margin-bottom: $spacing-3;
|
||||||
|
transition: transform $transition-fast, box-shadow $transition-base;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
box-shadow: $shadow-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 封面图 */
|
||||||
|
.card-cover {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 320rpx;
|
||||||
|
background: $color-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cover-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: $spacing-2;
|
||||||
|
left: $spacing-2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
backdrop-filter: blur(8rpx);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
padding: 6rpx $spacing-2;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-dot {
|
||||||
|
width: 8rpx;
|
||||||
|
height: 8rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 等级标签 — 图片右上角 */
|
||||||
|
.level-tag {
|
||||||
|
position: absolute;
|
||||||
|
top: $spacing-2;
|
||||||
|
right: $spacing-2;
|
||||||
|
padding: 6rpx $spacing-2;
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.level-5A { background: #EF4444; }
|
||||||
|
&.level-4A { background: #F59E0B; }
|
||||||
|
&.level-3A,
|
||||||
|
&.level-2A { background: $uv-success; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 信息区 */
|
||||||
|
.card-body {
|
||||||
|
padding: $spacing-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 名称 + 挂牌价 同行 */
|
||||||
|
.name-price-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scenic-name {
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: $color-foreground;
|
||||||
|
flex: 1;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-symbol {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-warning;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-value {
|
||||||
|
font-size: $font-size-xl;
|
||||||
|
color: $uv-warning;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-free {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $uv-success;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 营业时间 + 营业状态 同行 */
|
||||||
|
.hours-status-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-icon {
|
||||||
|
width: 22rpx;
|
||||||
|
height: 22rpx;
|
||||||
|
border: 2rpx solid $uv-tips-color;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 2rpx;
|
||||||
|
height: 8rpx;
|
||||||
|
background: $uv-tips-color;
|
||||||
|
top: 4rpx;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 6rpx;
|
||||||
|
height: 2rpx;
|
||||||
|
background: $uv-tips-color;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-icon {
|
||||||
|
width: 14rpx;
|
||||||
|
height: 14rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 8rpx;
|
||||||
|
|
||||||
|
&.open { background: $uv-success; }
|
||||||
|
&.closed { background: $uv-error; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
|
||||||
|
&.open { color: $uv-success; }
|
||||||
|
&.closed { color: $uv-error; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 权益标签行:剩余次数 + 免票 + 预约 同行 */
|
||||||
|
.benefit-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: $spacing-1;
|
||||||
|
margin-bottom: $spacing-2;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remaining-tag {
|
||||||
|
padding: 4rpx $spacing-2;
|
||||||
|
background: rgba($uv-success, 0.1);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: $uv-success;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-tag {
|
||||||
|
padding: 4rpx $spacing-2;
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-xs;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: $font-weight-medium;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
background: $uv-primary;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warning { background: $uv-warning; }
|
||||||
|
&.success { background: $uv-success; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 温馨提示 */
|
||||||
|
.tips-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
background: rgba(249, 174, 61, 0.08);
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
padding: $spacing-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-icon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
background: $uv-warning;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
margin-right: $spacing-2;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tips-text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-content-color;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ====== uni-popup 弹窗内容 ====== */
|
||||||
|
.popup-sheet {
|
||||||
|
background: $color-card;
|
||||||
|
border-radius: $radius-xl $radius-xl 0 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $spacing-3 $spacing-3;
|
||||||
|
border-bottom: $border-width solid rgba($uv-border-color, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-title {
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: $color-foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-reset {
|
||||||
|
padding: $spacing-1 $spacing-2;
|
||||||
|
border-radius: $radius-sm;
|
||||||
|
transition: background $transition-fast;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-sm;
|
||||||
|
color: $uv-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: rgba($uv-primary, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-scroll {
|
||||||
|
max-height: 560rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $spacing-3;
|
||||||
|
min-height: 96rpx;
|
||||||
|
border-bottom: $border-width solid rgba($uv-border-color, 0.25);
|
||||||
|
transition: background $transition-fast;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $color-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-base;
|
||||||
|
color: $color-foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active text {
|
||||||
|
color: $uv-primary;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-mark {
|
||||||
|
width: 18rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
border-right: 5rpx solid $uv-primary;
|
||||||
|
border-bottom: 5rpx solid $uv-primary;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
margin-right: $spacing-1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 96rpx;
|
||||||
|
background: $uv-primary;
|
||||||
|
transition: opacity $transition-fast;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: $font-size-lg;
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
color: #fff;
|
||||||
|
letter-spacing: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user