542 lines
13 KiB
Vue
542 lines
13 KiB
Vue
<template>
|
|
<view class="have-fun tabbar-page">
|
|
<view class="top-box">
|
|
<view class="v12-justify-start v12-align-center">
|
|
<view class="flex jc-end">
|
|
<view class="city-box" @click="goCity('cloud')">
|
|
<text style="white-space:nowrap; width: 90rpx" class="v12-primary-text one-t">{{ cityName }}</text>
|
|
<image :src="webUrl+'/orderIcon/map.png'" mode="scaleToFill"></image>
|
|
</view>
|
|
</view>
|
|
<view class="search-box v12-primary-border flex jc-between ai-center">
|
|
<input
|
|
v-model="name"
|
|
type="text"
|
|
placeholder="请输入关键词~"
|
|
placeholder-style="color:#949494"
|
|
@confirm="search"
|
|
>
|
|
<view class="search-btn v12-primary v12-white-text v12-radius-60" @click="search">
|
|
<text class="v12-font-bold">搜索</text>
|
|
<image
|
|
class="icon v12-ml-1"
|
|
:src="webUrl+'/orderIcon/搜索 (1).png'"
|
|
mode="scaleToFill"
|
|
/>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view>
|
|
|
|
<scroll-view class="type-box flex" scroll-x enable-flex>
|
|
<view class="first-box">
|
|
<view class="first-box__inner">
|
|
<view
|
|
:class="{
|
|
'active': typeIndex === -1
|
|
}"
|
|
class="item flex-0 flex flex-col jc-center ai-center"
|
|
@click="tapType(-1)"
|
|
>
|
|
<image :src="townConfig.icon" mode="scaleToFill"/>
|
|
<view class="name">{{ townConfig.label }}</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="scroll-box">
|
|
<view
|
|
v-for="(item, index) in typeList"
|
|
:key="index"
|
|
:class="{
|
|
'active': typeIndex === index
|
|
}"
|
|
class="item flex-0 flex flex-col jc-center ai-center"
|
|
@click="tapType(index)"
|
|
>
|
|
<image :src="item.icon" mode="scaleToFill"/>
|
|
<view class="name">{{ item.name }}</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
<view class="type-banner-wrap">
|
|
<view v-if="currType.titleImage" class="title">
|
|
<image
|
|
:src="currType.titleImage"
|
|
mode="heightFix"
|
|
class="img"
|
|
/>
|
|
</view>
|
|
<view v-if="currType.carousel" class="slider-wrap">
|
|
<swiper
|
|
indicatorDots="true"
|
|
indicator-color="rgba(255, 255, 255, .3)"
|
|
indicator-active-color="#ffffff"
|
|
autoplay
|
|
circular
|
|
style="height: 330rpx;"
|
|
>
|
|
<block
|
|
v-for="(item, bannerIndex) in currType.carousel"
|
|
:key="bannerIndex"
|
|
>
|
|
<swiper-item>
|
|
<view class="swiper-item" @click="typeBannerItemClick(item)">
|
|
<image :src="item.carouselImage" class="img" />
|
|
</view>
|
|
</swiper-item>
|
|
</block>
|
|
</swiper>
|
|
</view>
|
|
</view>
|
|
<view class="body" v-if="typeIndex === -1">
|
|
<view class="town-card" v-for="(town, i) in townList" :key="i" @click="toTown(town)">
|
|
<!-- <view class="town-title">{{ town.name }}</view> -->
|
|
<image :src="town.frontImage" mode="scaleToFill"/>
|
|
<view class="v12-primary enter-btn">点击进入
|
|
<view class="icon-box"><u-icon name="arrow-rightward" color="#fff" size="8"></u-icon></view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="body" v-else>
|
|
<view class="v12-justify-between v12-align-center">
|
|
<text class="v12-font-bold" v-if="currType.carousel">推荐</text>
|
|
<view class="v12-dark1-text v12-font-28 v12-align-center" @click="handleRefresh">
|
|
<u-icon name="reload"></u-icon>
|
|
换一换
|
|
</view>
|
|
</view>
|
|
<view v-if="isLoad">
|
|
<view v-if="hotelList.length > 0">
|
|
<view class="list-wrapper">
|
|
<view class="list">
|
|
<view
|
|
v-for="(item, index) in hotelEvenList"
|
|
:key="index"
|
|
class="item"
|
|
@click="goInnDetail(item)"
|
|
>
|
|
<fun-hotel-item :item="item" />
|
|
</view>
|
|
</view>
|
|
<view class="list">
|
|
<view
|
|
v-for="(item, index) in hotelOddList"
|
|
:key="index"
|
|
class="item"
|
|
@click="goInnDetail(item)"
|
|
>
|
|
<fun-hotel-item :item="item" />
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
<view class="v4-nodata" v-else>
|
|
<image src="@/static/images/img_nodata.png" mode="scaleToFill"/>
|
|
<view class="text">暂无数据</view>
|
|
</view>
|
|
</view>
|
|
<goo-skeleton
|
|
v-else
|
|
:show-avatar="false"
|
|
/>
|
|
</view>
|
|
<xdd-tabbar :curr-index="4" />
|
|
</view>
|
|
</template>
|
|
<script>
|
|
import { getHotelList, getHotelTypeList, getAncientTownIcon, getAncientTownList } from "@/api/inn.js"
|
|
import { getCurAddress, getLocation } from "@/utils/common"
|
|
import FunHotelItem from './components/HotelItem'
|
|
import { pageListenMixins } from '@/mixins/pageListenMixins'
|
|
import XddTabbar from '@/components/xdd-tabbar'
|
|
export default {
|
|
components: {
|
|
FunHotelItem,
|
|
XddTabbar
|
|
},
|
|
mixins: [pageListenMixins],
|
|
data() {
|
|
return {
|
|
webUrl: this.$VUE_APP_RESOURCES_URL,
|
|
name: '',
|
|
page: 1,
|
|
typeList: [],
|
|
typeIndex: -1,
|
|
// 当前选中的类型
|
|
currType: {},
|
|
cityName: '',
|
|
hotelList: [],
|
|
isLoad: false,
|
|
pageKeyId: Object.freeze('findFunIndex'),
|
|
isNext: false,
|
|
townConfig: {},
|
|
townList: [],
|
|
randomSeed: null
|
|
}
|
|
},
|
|
computed: {
|
|
hotelOddList() {
|
|
const arr = this.hotelList.filter(function(item, index) { return index % 2 === 1 })
|
|
return arr
|
|
},
|
|
hotelEvenList() {
|
|
const arr = this.hotelList.filter(function(item, index) { return index % 2 === 0 })
|
|
return arr
|
|
}
|
|
},
|
|
onReachBottom() {
|
|
// 后端接口结构需要调整下,需要补充总页数,前端可判断当前页数大于等于总页数则不发送网络请求
|
|
if(this.isNext) {
|
|
this.page++
|
|
this.fetchList()
|
|
}
|
|
},
|
|
onLoad() {
|
|
this.currType = {}
|
|
getHotelTypeList().then(({data}) => {
|
|
this.typeList = data
|
|
this.currType = this.typeIndex === -1 ? {} : data[this.typeIndex]
|
|
this.getMapData()
|
|
})
|
|
this.getIcon()
|
|
},
|
|
onShow() {
|
|
const memCityName = uni.getStorageSync('cityName')
|
|
this.page = 1
|
|
// this.typeIndex = 0
|
|
this.name = ''
|
|
if (memCityName.length) {
|
|
this.cityName = memCityName
|
|
uni.removeStorageSync('cityName')
|
|
this.name = ''
|
|
}
|
|
},
|
|
watch: {
|
|
cityName: {
|
|
handler(value) {
|
|
if(value) {
|
|
this.search()
|
|
}
|
|
},
|
|
immediate: true,
|
|
deep: true
|
|
}
|
|
},
|
|
methods: {
|
|
handleRefresh() {
|
|
uni.showLoading()
|
|
this.fetchList(1, this.randomSeed)
|
|
},
|
|
toTown(town) {
|
|
uni.navigateTo({
|
|
url: `/pages/town/index?id=${town.id}`
|
|
})
|
|
},
|
|
getIcon() {
|
|
getAncientTownIcon().then(res => {
|
|
this.townConfig = res.data
|
|
})
|
|
},
|
|
goCity() {
|
|
uni.navigateTo({
|
|
url: `/pages/chose-city/chose-city?type=2&city=${this.cityName}`
|
|
})
|
|
},
|
|
goInnDetail(item) {
|
|
uni.navigateTo({
|
|
url: `/pagesInn/inn/innHome?id=${item.id}&from=fun`
|
|
})
|
|
},
|
|
async getMapData() {
|
|
const map = await getLocation()
|
|
if (map.length > 1) {
|
|
const {latitude, longitude} = map[1]
|
|
const address = await getCurAddress(latitude, longitude)
|
|
if(!this.cityName) {
|
|
this.cityName = address[1].data.result.ad_info.city
|
|
}
|
|
// this.search()
|
|
}
|
|
},
|
|
tapType(index) {
|
|
|
|
if (this.typeIndex === index) return
|
|
this.typeIndex = index
|
|
|
|
this.currType = index === -1 ? {} : this.typeList[index]
|
|
this.name = ''
|
|
this.search()
|
|
},
|
|
search() {
|
|
this.isLoad = false
|
|
this.page = 1
|
|
this.hotelList = []
|
|
this.fetchList()
|
|
},
|
|
fetchList(random = 0, randomSeed) {
|
|
if(this.typeIndex === -1) {
|
|
const params = {
|
|
cityName: this.name,
|
|
page: 1,
|
|
limit: 999
|
|
}
|
|
getAncientTownList(params).then(res => {
|
|
this.townList = res.data.records
|
|
})
|
|
return
|
|
}
|
|
const param = {
|
|
page: this.page,
|
|
type: this.typeList[this.typeIndex].id,
|
|
cityName: this.cityName,
|
|
random: random,
|
|
randomSeed: randomSeed
|
|
}
|
|
const name = this.name.trim()
|
|
if (name.length > 0) {
|
|
param.name = name
|
|
}
|
|
getHotelList(param).then(res => {
|
|
const { success, data, msg } = res
|
|
if (success) {
|
|
if(random === 1) {
|
|
this.randomSeed = msg
|
|
this.hotelList = []
|
|
}
|
|
for (let i = 0; i < data.length; i++) {
|
|
const cover = data[i].cover
|
|
data[i].hide = true
|
|
// 视频封面取第一帧图片
|
|
if (data[i].coverType === 2) {
|
|
data[i].videoCover = cover
|
|
data[i].cover = (cover + '?vframe/jpg/offset/1')
|
|
} else {
|
|
data[i].videoCover = ''
|
|
}
|
|
this.hotelList.push(data[i])
|
|
if(data.length < 10) {
|
|
this.isNext = false
|
|
} else {
|
|
this.isNext = true
|
|
}
|
|
}
|
|
}
|
|
}).finally(() => {
|
|
this.isLoad = true
|
|
uni.hideLoading()
|
|
})
|
|
},
|
|
typeBannerItemClick(item) {
|
|
if (!item.hotelId) return
|
|
uni.navigateTo({ url: `/pagesInn/inn/innHome?id=${item.hotelId}` })
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style scoped lang="less">
|
|
.icon-box{
|
|
border: 1rpx solid #fff;
|
|
border-radius: 100%;
|
|
width: 16rpx;
|
|
height: 16rpx;
|
|
margin-left: 5rpx;
|
|
padding: 2rpx;
|
|
}
|
|
.enter-btn{
|
|
color: #fff;
|
|
width: fit-content;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 10rpx 16rpx;
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
border-radius: 30rpx 0;
|
|
font-size: 24rpx;
|
|
}
|
|
.town-title{
|
|
border-radius: 100rpx;
|
|
/* border-color: #333; */
|
|
// mix-blend-mode: difference;
|
|
width: fit-content;
|
|
padding: 5rpx 20rpx;
|
|
border: 1rpx solid #fff;
|
|
color: #fff;
|
|
position: absolute;
|
|
margin: auto;
|
|
top: 20rpx;
|
|
left: 0;
|
|
right: 0;
|
|
}
|
|
.town-card{
|
|
width: 100%;
|
|
height: 400rpx;
|
|
background: #fff;
|
|
border-radius: 30rpx;
|
|
position: relative;
|
|
overflow: hidden;
|
|
margin-bottom: 30rpx;
|
|
image{
|
|
width: -webkit-fit-content;
|
|
width: inherit;
|
|
height: -webkit-fit-content;
|
|
height: inherit;
|
|
}
|
|
}
|
|
.first-box{
|
|
padding-right: 15rpx;
|
|
position: sticky;
|
|
left: 0;
|
|
background-color: #f5f5f5;
|
|
z-index: 9;
|
|
}
|
|
.first-box__inner{
|
|
padding: 10rpx;
|
|
background: #fff;
|
|
border-radius: 30rpx;
|
|
}
|
|
.scroll-box{
|
|
display: flex;
|
|
height: fit-content;
|
|
background: #fff;
|
|
padding: 10rpx;
|
|
border-radius: 30rpx;
|
|
}
|
|
.search-btn{
|
|
position: absolute;
|
|
top: 2rpx;
|
|
bottom: 2rpx;
|
|
right: 2rpx;
|
|
padding: 0rpx 20rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
font-size: 28rpx;
|
|
}
|
|
.have-fun {
|
|
//padding-top: 120rpx;
|
|
|
|
.top-box {
|
|
padding: 32rpx 0 0rpx;
|
|
background: #f5f5f5;
|
|
|
|
.search-box {
|
|
position: relative;
|
|
width: 575rpx;
|
|
height: 60rpx;
|
|
box-sizing: border-box;
|
|
// margin: 0 auto;
|
|
padding: 0 24rpx 0 32rpx;
|
|
border: 2rpx solid #BBD2D2;
|
|
border-radius: 30rpx;
|
|
|
|
input {
|
|
font-size: 24rpx;
|
|
}
|
|
|
|
.icon {
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
}
|
|
}
|
|
|
|
.type-box {
|
|
height: 200rpx;
|
|
box-sizing: border-box;
|
|
white-space: nowrap;
|
|
padding: 20rpx 20rpx 0 20rpx;
|
|
|
|
.item {
|
|
width: 154rpx;
|
|
height: 154rpx;
|
|
// margin-right: 20rpx;
|
|
border-radius: 26rpx;
|
|
|
|
image {
|
|
width: 92rpx;
|
|
height: 92rpx;
|
|
}
|
|
|
|
.name {
|
|
margin-top: 12rpx;
|
|
color: #949494;
|
|
font-size: 24rpx;
|
|
line-height: 34rpx;
|
|
}
|
|
}
|
|
|
|
.active {
|
|
background: #DCF2FE;
|
|
|
|
.name {
|
|
color: #333;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.body {
|
|
padding: 20rpx 20rpx;
|
|
background: #f5f5f5;
|
|
}
|
|
|
|
.city-box {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
padding: 8rpx 20rpx 8rpx 20rpx;
|
|
border-radius: 30px;
|
|
background: #f5f5f5;
|
|
|
|
image {
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
margin-right: 4rpx;
|
|
}
|
|
|
|
text {
|
|
color: #333;
|
|
font-size: 28rpx;
|
|
}
|
|
}
|
|
|
|
.list-wrapper {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
.list {
|
|
width: 348rpx;
|
|
.item {
|
|
width: 100%;
|
|
box-sizing: border-box;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.tabbar-page {
|
|
padding: 0 0 180rpx 0;
|
|
}
|
|
.type-banner-wrap {
|
|
padding: 0 20rpx;
|
|
background-color: #f5f5f5;
|
|
.title {
|
|
padding: 0 0 20rpx;
|
|
.img {
|
|
display: block;
|
|
height: 48rpx;
|
|
}
|
|
}
|
|
.slider-wrap {
|
|
width: 100%;
|
|
height: 330rpx;
|
|
padding: 0 0 20rpx 0;
|
|
.swiper-item {
|
|
.img {
|
|
display: block;
|
|
width: 100%;
|
|
height: 330rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|