zhwl-miniapp/pages/tabbar/home.vue
2025-06-26 12:38:35 +08:00

906 lines
32 KiB
Vue

<template>
<view :style="'padding-bottom: ' + windowBottom + 'px;'">
<u-navbar left-icon-size="0" :placeholder="true" bgColor="#fff">
<view slot='center' class="navbar_title">{{title}}</view>
</u-navbar>
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :down="downOption" :up="upOption" :fixed="false">
<view class="header-show">
<swiper class="header-swiper" :autoplay="true" :interval="5000" :duration="1000">
<swiper-item v-for="(item, index) in banner" :key="index">
<image class="header-img" :src="$utils.setImgUrl(item)" mode=""></image>
</swiper-item>
</swiper>
<view class="header-pos" v-if="weather">
<view class="weather">
<image :src="getWeatherImg(weather.weather)" mode=""></image>
<view class="font-box">
<view>{{weather.temperature}}℃</view>
<view>{{weather.weather}}</view>
</view>
</view>
<view class="address">
<image src="../../static/image/weather/area.png" mode=""></image>
<view>{{weather.city}}</view>
<view>{{weather.reporttime ? weather.reporttime.substr(0, 10) : ''}}</view>
</view>
</view>
</view>
<view class="waper">
<view class="notice" v-if="notice">
<image src="../../static/image/home/notice.png" mode=""></image>
<u-notice-bar :url="'/pages/notice/detail?id=' + notice.id" bgColor="transparent" icon=" " style="padding-left: 0; padding-right: 0;" color="rgba(0,0,0,0.85)" :text="notice.title"></u-notice-bar>
<navigator class="more" hover-class="none" url="/pages/notice/index">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<view class="menu">
<view class="menu-box" v-for="(item, index) in menuList" :key="index" @click="menuClick(item)" v-if="item.config">
<view>
<image :src="item.icon" mode=""></image>
<view class="name">{{ item.name }}</view>
</view>
</view>
</view>
<view class="title-box" v-if="ticket.length > 0">
<view class="title">
<image src="../../static/image/home/recommend.png" mode=""></image>
<view>门票推荐</view>
</view>
<navigator class="more" hover-class="none" url="/pages/tabbar/ticketing">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<view class="shop-box" v-if="ticket.length > 0">
<navigator
hover-class="none"
class="shop box-style"
v-for="(item, index) in ticket"
:key="index"
:url="'/pages/scenic/ticket?id=' + item.id"
>
<image :src="$utils.setImgUrl(item.image11)" mode=""></image>
<view class="describe">
<view class="describe-tit">{{item.name}}</view>
<view class="orange">
<text v-if="item.isOrder == 1">提前预约</text>
<text v-if="item.refundRule == '0'">不可退</text>
<text v-if="item.refundRule == '3'">有效期可退</text>
<text v-if="item.refundRule == '4'">{{item.refundDay}}天内可退</text>
<text v-if="item.refundRule == '5'">未激活可退</text>
</view>
<view class="price">
<view><span v-if="item.salesRice > 0">¥</span>{{item.salesRice > 0 ? item.salesRice.toFixed(2) : '免费'}}</view>
<view v-if="item.price"><span>¥</span>{{item.price}}</view>
</view>
</view>
</navigator>
</view>
<view class="title-box" v-if="archivesList.length">
<view class="title">
<image src="../../static/image/home/yanxue.png" mode=""></image>
<view>研学游</view>
</view>
<navigator class="more" hover-class="none" url="/pages/strategy/archieveList?id=10&name=研学游">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<navigator :url="'/pages/strategy/detail?id=' + archivesList[0].id" hover-class="none" class="banner-box box-style" v-if="archivesList.length">
<image :src="$utils.setImgUrl(archivesList[0].image)" mode=""></image>
<view class="banner-des">
{{archivesList[0].title}}
</view>
</navigator>
<view v-if="configData && configData.examine == 'false'">
<view class="title-box" v-if="recommendList.length > 0">
<view class="title">
<image src="../../static/image/home/haoli.png" mode=""></image>
<view>好礼推荐</view>
</view>
<navigator class="more" hover-class="none" url="/pages/shop/list">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<view class="three-box" v-if="recommendList.length > 0">
<navigator :url="'/pages/shop/detail?id=' + item.id" hover-class="none" class="three-shop box-style" v-for="(item, itemIndex) in recommendList" :key="itemIndex">
<image :src="$utils.setImgUrl(item.image)" mode=""></image>
<view class="three-shop-des">
<view class="three-shop-des-tit">{{item.title}}</view>
<view class="three-price"><span>¥</span>{{item.price}}</view>
</view>
</navigator>
</view>
</view>
<view class="title-box" v-if="spot.length > 0">
<view class="title">
<image src="../../static/image/home/jingdian.png" mode=""></image>
<view>景点名片</view>
</view>
<navigator class="more" hover-class="none" url="/pages/scenic/list">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<view class="swiper-box" v-if="spot.length > 0">
<swiper :autoplay="true" :interval="5000" :duration="1000" @change="slideChange">
<swiper-item v-for="(item, index) in spot" :key="index">
<navigator
hover-class="none"
class="card-text"
:url="'/pages/scenic/spot?id=' + item.id"
>
<image :src="$utils.setImgUrl(item.image)" mode=""></image>
<view>{{item.scenicName}}</view>
</navigator>
</swiper-item>
</swiper>
<view class="swiper-dots">
<view class="swiper-dot" :class="swiperInd == index ? 'swiper-dot-active' : ''" v-for="(i, index) in spot" :key="index"></view>
</view>
</view>
<view class="title-box" v-if="strategy.length > 0">
<view class="title">
<image src="../../static/image/home/remen.png" mode=""></image>
<view>热门攻略</view>
</view>
<navigator class="more" hover-class="none" url="/pages/strategy/index">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<scroll-view class="scroll-show" scroll-x="true" v-if="strategy.length > 0">
<navigator
class="img-box card-text"
hover-class="none"
:url="'/pages/strategy/detail?id=' + item.id"
v-for="(item, index) in strategy"
:key="index"
>
<image :src="$utils.setImgUrl(item.image)" mode=""></image>
<view>{{item.title}}</view>
</navigator>
</scroll-view>
<view class="title-box" v-if="scenicSpotsList.length">
<view class="title">
<image src="../../static/image/home/zhoubian.png" mode=""></image>
<view>周边景区</view>
</view>
<navigator class="more" hover-class="none" url="/pages/strategy/archieveList?id=9&name=周边景区">
更多
<u-icon name="arrow-right" color="rgba(0, 0, 0, 0.25)" size="30rpx"></u-icon>
</navigator>
</view>
<view class="three-box" v-if="scenicSpotsList.length">
<navigator :url="'/pages/strategy/detail?id=' + item.id" hover-class="none" class="three-show box-style card-text" v-for="item in scenicSpotsList" :key="item">
<image :src="$utils.setImgUrl(item.image)" mode=""></image>
<view>{{item.title}}</view>
</navigator>
</view>
</view>
</mescroll-body>
<tabbar name="home"></tabbar>
</view>
</template>
<script>
import Vue from 'vue'
import tabbar from '@/components/tabbar/index.vue'
import MescrollMixin from "@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins.js";
export default {
components: { tabbar },
mixins: [MescrollMixin],
data () {
return {
windowBottom: 0,
upOption: { use: false, auto: false },
down: { user: true, auto: true, beforeEndDelay: 500, native: false },
configData: null,
downOption: { auto: false },
title: '',
banner: [],
notice: null,
menuList: [
// { name: '景区介绍', icon: '../../static/image/home/menu1.png', path: '/pages/scenic/index', type: 'navigate', config: true },
{ name: '景交车辆', icon: '../../static/image/home/menu3.png', path: '/pages/strategy/archieveList?id=8&name=景交车辆', type: 'navigate', config: true },
{ name: '景点名片', icon: '../../static/image/home/menu4.png', path: '/pages/scenic/list', type: 'navigate', config: true },
{ name: '预约导游', icon: '../../static/image/home/menu5.png', path: '/pages/guide/list', type: 'navigate', config: true },
{ name: '文创特产', icon: '../../static/image/home/menu6.png', path: '/pages/shop/list', type: 'navigate', config: true },
{ name: '酒店民宿', icon: '../../static/image/home/menu9.png', path: '/pages/hotel/list', type: 'navigate', config: true },
{ name: '餐饮美食', icon: '../../static/image/home/menu9.png', path: '/pages/eatery/index', type: 'navigate', config: true }
],
activity: [],
current1: 0,
current2: 0,
ticket: [],
spot: [],
strategy: [],
area: '',
weather: null,
swiperInd: 0,
archivesList: [],
scenicSpotsList: [],
recommendList: [],
location:{}
}
},
computed: {
getDistance1({location}){
return item =>{
let lat1 = item.lat,lng1=item.lng,lat2=location.lat,lng2=location.lng;
return this.$utils.getDistance(lat1, lng1, lat2, lng2)
}
}
},
async onLoad () {
uni.getLocation({
type: 'gcj02',
isHighAccuracy:true,
success: (res) => {
let latitude = res.latitude;
let longitude = res.longitude;
this.location = {
lat:latitude,
lng:longitude
};
}
})
let info = uni.getSystemInfoSync();
this.windowBottom = info.windowBottom;
this.configData = uni.getStorageSync('configData');
if (this.configData.examine == 'true') {
this.menuList[3].config = false;
this.menuList[4].config = false;
}
this.getInitData();
},
onShareAppMessage () {
return {
title: '巴松措风景区',
path: '/pages/login/index'
}
},
methods: {
menuClick (info) {
if (info.type == 'program') {
uni.navigateToMiniProgram({ appId: info.path });
}
if (info.type == 'navigate') {
uni.navigateTo({ url: info.path })
}
if (info.type == 'reLaunch') {
uni.reLaunch({ url: info.path })
}
if (info.type == 'null') {
uni.showToast({ mask: true, title: '服务暂未开放', icon: 'none' })
}
},
downCallback () {
this.getInitData();
},
async getInitData () {
// 景区详情
let scenic = await this.$http.scenicDetail({ id: this.configData.scenic.id });
if(scenic.data) {
this.title = scenic.data.scenicName;
this.banner = scenic.data.imagePage ? scenic.data.imagePage.split(',') : [];
this.area = scenic.data.coordinate;
}
// 公告
let info = await this.$http.noticeList({ flag: 'top', pageNum: 1, pageSize: 1 });
if (info.rows.length > 0) {
this.notice = info.rows[0]
}
// 广告
let activity = await this.$http.activityZoneList({ flag: 'recommend', pageNum: 1, pageSize: 1 });
this.activity = activity.rows;
// 门票推荐
let ticket = await this.$http.ticketList({ scenicId: this.configData.scenic.id, flag: 'recommend' });
this.ticket = ticket.data;
// 景点名片
let spot = await this.$http.scenicSpotList({ pageNum: 1, pageSize: 3, scenicId: this.configData.scenic.id, flag: 'recommend' });
this.spot = spot.rows;
// 热门攻略
if (this.configData.examine != 'true') {
let strategy = await this.$http.introductionList({ pageNum: 1, pageSize: 3 });
this.strategy = strategy.rows;
}
// 好礼退款
let shop = await this.$shop.getGoodsList({ pageNum: 1, pageSize: 3, flag: 'recommend' });
this.recommendList = shop.rows;
// 研学游
let archivesReq = await this.$http.archivesList({
pageNum: 1,
pageSize: 1,
channelId: 10,
flag: 'recommend'
});
this.archivesList = archivesReq.rows
// 周边景区
let scenicSpotsReq = await this.$http.archivesList({
pageNum: 1,
pageSize: 3,
channelId: 9,
flag: 'recommend'
});
this.scenicSpotsList = scenicSpotsReq.rows
console.log(scenic)
uni.request({
url: 'https://restapi.amap.com/v3/weather/weatherInfo',
method :'GET',
data:{
key: '5b8b5a840f8708a02312af2d13832042',
city: scenic.data.areaCity ? scenic.data.areaCity.substr(0, 6) : '540421',
extensions: 'base',
},
success: (res) => {
if (res.data.status == '1' && res.data.lives && res.data.lives.length > 0) {
this.weather = res.data.lives[0];
uni.setStorageSync("weather",{date:new Date().getTime(),weather:res.data.lives[0]})
}
},
});
setTimeout(() => {
this.mescroll && this.mescroll.endSuccess(1, false)
}, 1500)
},
getWeatherImg (text) {
let key = '';
switch (text) {
case '晴':
key = '1';
break;
case '多云':
key = '2';
break;
case '阴':
key = '3';
break;
case '小雨':
key = '4';
break;
case '中雨':
key = '5';
break;
case '大雨':
key = '6';
break;
case '暴雨':
key = '7';
break;
case '阵雨':
key = '8';
break;
case '雷阵雨':
key = '9';
break;
case '雷电':
key = '10';
break;
case '冰雹':
key = '11';
break;
case '轻雾':
key = '12';
break;
case '雾':
key = '13';
break;
case '浓雾':
key = '14';
break;
case '霾':
key = '15';
break;
case '雨夹雪':
key = '16';
break;
case '小雪':
key = '17';
break;
case '中雪':
key = '18';
break;
case '大雪':
key = '19';
break;
case '暴雪':
key = '20';
break;
case '冻雨':
key = '21';
break;
case '霜冻':
key = '22';
break;
case '台风':
key = '23';
break;
case '浮尘':
key = '24';
break;
case '扬沙':
key = '25';
break;
case '沙尘暴':
key = '26';
break;
default:
key = '';
break;
}
return '../../static/image/weather/' + key + '.png';
},
slideChange(e) {
this.swiperInd = e.detail.current
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .u-notice-bar{ padding-left: 0 !important; padding-right: 0 !important; }
.header-show{
width: 100%;
height: 434rpx;
box-sizing: border-box;
position: relative;
&:after{ content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 180rpx; background: linear-gradient( 180deg, rgba(0, 0, 0, 0.7) 0%, rgba(0,0,0,0) 100%); z-index: 5; }
.header-swiper{
width: 100%;
height: 100%;
.header-img{
width: 100%;
height: 100%;
}
}
.header-pos{
position: absolute;
z-index: 6;
top: 40rpx;
left: 40rpx;
right: 40rpx;
}
.weather{
display: flex;
align-items: center;
&>image{
width: 80rpx;
height: 80rpx;
}
.font-box{
margin-left: 8rpx;
color: white;
&>view:nth-child(1) {
font-size: 30rpx;
}
&>view:nth-child(2) {
font-size: 28rpx;
}
}
}
.address{
display: flex;
align-items: center;
margin-left: 8rpx;
color: white;
font-size: 26rpx;
margin-top: 4rpx;
&>view {
margin-left: 10rpx;
}
&>image{
width: 28rpx;
height: 28rpx;
}
}
}
.waper{
margin-top: -64rpx;
background: white;
border-radius: 40rpx 40rpx 0 0;
box-sizing: border-box;
padding: 32rpx 24rpx;
position: relative;
.notice{
width: 100%;
height: 80rpx;
background: linear-gradient( 90deg, rgba(#03AE80,0) 0%, rgba(#03AE80,0.05) 50%, rgba(3,174,128,0) 100%);
border-radius: 10rpx;
color: rgba(0,0,0,0.85);
display: flex;
align-items: center;
&>image{
width: 48rpx;
min-width: 48rpx;
height: 48rpx;
margin-right: 12rpx;
}
.txt{
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
font-size: 28rpx;
}
}
.more{
display: flex;
align-items: center;
font-size: 24rpx;
color: rgba(0,0,0,0.25);
margin-left: 28rpx;
cursor: pointer;
&>image{
width: 32rpx;
height: 32rpx;
margin-left: 6rpx;
}
}
.menu{
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
padding: 0 12rpx;
box-sizing: border-box;
margin-top: 32rpx;
margin-bottom: 12rpx;
.menu-box{
margin-bottom: 24rpx;
margin-right: 30rpx;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
image{
width: 80rpx;
height: 80rpx;
margin: 0 auto 12rpx;
}
.name{
font-size: 26rpx;
color: rgba(0,0,0,0.85);
line-height: 30rpx;
}
&:nth-child(5n){ margin-right: 0; }
}
}
.title-box{
display: flex;
height: 53rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
.title{
display: flex;
align-items: center;
font-weight: 600;
font-size: 36rpx;
color: rgba(0,0,0,0.85);
&>image{
width: 36rpx;
height: 36rpx;
margin-right: 12rpx;
}
}
}
.box-style{
box-shadow: 0rpx 0rpx 32rpx 0rpx rgba(0,0,0,0.05);
border-radius: 10rpx;
overflow: hidden;
}
.shop-box{
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
margin-bottom: 12rpx;
.shop{
width: 341rpx;
height: 540rpx;
background: white;
margin-bottom: 20rpx;
&>image{
width: 100%;
height: 342rpx;
}
.describe{
box-sizing: border-box;
padding: 20rpx 24rpx 24rpx;
.describe-tit{
font-weight: 600;
height: 44rpx;
font-size: 30rpx;
color: rgba(0,0,0,0.85);
line-height: 44rpx;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.orange{
font-weight: 400;
font-size: 24rpx;
color: #FFA944;
line-height: 28rpx;
height: 36rpx;
margin: 6rpx 0rpx 20rpx;
&>span{
display: inline-block;
width: 1rpx;
height: 18rpx;
background: #FFA944;
margin: 0rpx 12rpx;
}
}
.price{
display: flex;
justify-content: space-between;
align-items: flex-end;
&>view:nth-child(1){
color: #FF3333;
font-family: Arial, Arial;
font-weight: bold;
font-size: 40rpx;
color: #FF3333;
line-height: 47rpx;
&>span{
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
color: #FF3333;
line-height: 28rpx;
}
}
&>view:nth-child(2){
font-family: Arial, Arial;
font-weight: 400;
font-size: 24rpx;
color: rgba(0,0,0,0.25);
line-height: 28rpx;
text-decoration: line-through;
}
}
}
}
}
.banner-box{
height: 340rpx;
margin-bottom: 32rpx;
&>image{
width: 100%;
height: 236rpx;
}
.banner-des{
padding: 28rpx 20rpx;
box-sizing: border-box;
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 600;
font-size: 32rpx;
color: rgba(0,0,0,0.85);
line-height: 38rpx;
}
}
.three-box{
display: flex;
align-items: center;
margin-bottom: 32rpx;
.three-shop{
width: 220rpx;
height: 328rpx;
margin-right: 21rpx;
&>image{
width: 220rpx;
height: 220rpx;
object-fit: contain;
}
.three-shop-des{
box-sizing: border-box;
padding: 12rpx 20rpx;
&-tit{
margin-bottom: 4rpx;
font-weight: 600;
font-size: 28rpx;
color: rgba(0,0,0,0.85);
line-height: 41rpx;
height: 41rpx;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
}
.three-price{
font-size: 32rpx;
color: #FF3333;
line-height: 37rpx;
height: 37rpx;
&>span{
font-family: Source Han Sans CN, Source Han Sans CN;
font-weight: 400;
font-size: 24rpx;
line-height: 28rpx;
}
}
}
.three-show{
width: 220rpx;
height: 294rpx;
margin-right: 21rpx;
&>image{
width: 220rpx;
height: 294rpx;
object-fit: contain;
}
&>p{
position: absolute;
left: 20rpx;
bottom: 20rpx;
font-weight: 400;
font-size: 28rpx;
color: #FFFFFF;
line-height: 33rpx;
}
}
.three-show:last-child, .three-shop:last-child{
margin-right: 0;
}
}
.canteen-box{
margin-bottom: 32rpx;
.canteen-show{
width: 100%;
overflow: hidden;
box-sizing: border-box;
margin-bottom: 20rpx;
padding: 20rpx;
display: flex;
align-items: center;
&>image{
width: 208rpx;
min-width: 208rpx;
height: 208rpx;
border-radius: 10rpx;
margin-right: 24rpx;
}
.canteen-des{
flex: 1;
overflow: hidden;
&-tit{
font-weight: 600;
font-size: 32rpx;
color: rgba(0,0,0,0.85);
line-height: 38rpx;
margin-top: 4rpx;
}
.canteen-label{
margin-top: 10rpx;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
.canteen-left>view{
display: inline-block;
}
.bg{
padding: 4rpx 8rpx;
background: rgba(238, 89, 90, 0.1);
border-radius: 4rpx;
font-weight: 400;
font-size: 22rpx;
color: #EE595A;
height: 38rpx;
line-height: 38rpx;
border-radius: 4rpx;
}
.canteen-price{
font-size: 24rpx;
color: rgba(0,0,0,0.25);
line-height: 28rpx;
margin-left: 20rpx;
}
.canteen-distance{
font-size: 24rpx;
color: rgba(0,0,0,0.25);
}
}
.canteen-tit{
width: 100%;
height: 42rpx;
display: flex;
align-items: center;
font-size: 28rpx;
color: rgba(0,0,0,0.65);
line-height: 33rpx;
margin-bottom: 4rpx;
overflow: hidden;
&>view{
white-space: nowrap;
margin-left: 8rpx;
text-overflow: ellipsis;
overflow: hidden;
}
.time{ margin-left: 12rpx; }
}
}
}
}
.card-text{
position: relative;
width: 100%;
height: 100%;
border-radius: 10rpx;
overflow: hidden;
&>view{
position: absolute;
left: 20rpx;
right: 20rpx;
bottom: 20rpx;
font-weight: 400;
font-size: 28rpx;
color: #FFFFFF;
line-height: 33rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
&>image{
width: 100%;
height: 100%;
position: relative; border-radius: 10rpx;
&::after{ content: ""; width: 100%; height: 138rpx; background: linear-gradient( 180deg, rgba(0,0,0,0) 0%, #000000 100%); position: absolute; left: 0; bottom: 0; }
}
}
.swiper-box .card-text{
&>image{
&::after{ height: 94rpx; }
}
}
.three-box .card-text{
&>image{
&::after{ height: 130rpx; }
}
}
.swiper-box{
margin-bottom: 32rpx;
position: relative;
.swiper-dots{
bottom: 32rpx;
right: 52rpx;
position: absolute;
display: flex;
align-items: center;
height: 10rpx;
}
.swiper-dot{
width: 10rpx;
margin-right: 10rpx;
height: 10rpx;
border-radius: 5rpx;
background: rgba(255,255,255,0.3);
&:last-child{ margin-right: 0; }
}
.swiper-dot-active{
width: 30rpx;
background: #fff;
}
}
.scroll-show{
height: 266rpx;
margin-bottom: 32rpx;
white-space: nowrap;
.img-box{
width: 356rpx;
height: 266rpx;
margin-right: 20rpx;
display: inline-block;
}
}
}
</style>