roamfuding-xcx/page_fenbao/jiudian/index.vue
2026-03-26 17:47:52 +08:00

631 lines
16 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page">
<u-navbar title="酒店" :border-bottom="false" :background="bgc" back-icon-color="#262B37" title-color='#262B37'
title-size='36' height='46' id="navbar" :custom-back="btnfh">
</u-navbar>
<!-- 搜索栏 -->
<view class="search-container">
<view class="search-bar">
<image class="search-icon" src="https://api.ccttiot.com/smartmeter/img/static/uAO3fdmrrHTzqbVx9hYd" mode=""></image>
<input class="search-input" placeholder="搜索酒店、民宿" v-model="searchKeyword" @confirm="handleSearch" />
</view>
</view>
<!-- 筛选器 -->
<view class="filter-container">
<view class="filter-item-wrapper">
<view class="filter-item" @tap="showAreaPicker">
<text :class="{active: showArea}">{{ selectedArea }}</text>
<text class="arrow" :class="{ 'arrow-up': showArea }">▼</text>
</view>
</view>
<view class="filter-item-wrapper">
<view class="filter-item" @tap="showSortPicker">
<text :class="{active: showSort}">{{ selectedSort }}</text>
<text class="arrow" :class="{ 'arrow-up': showSort }">▼</text>
</view>
</view>
<view class="filter-item-wrapper">
<view class="filter-item" @tap="showPricePicker">
<text :class="{active: showPrice}">{{ selectedPrice }}</text>
<text class="arrow" :class="{ 'arrow-up': showPrice }">▼</text>
</view>
</view>
<view class="filter-item-wrapper">
<view class="filter-item" @tap="showFilterPicker">
<text :class="{active: showFilter}">筛选</text>
<text class="arrow" :class="{ 'arrow-up': showFilter }">▼</text>
</view>
</view>
<!-- 下拉菜单容器 -->
<view class="dropdown-container" v-if="showArea || showSort || showPrice || showFilter">
<!-- 区域/位置下拉菜单 -->
<view class="dropdown-menu" v-if="showArea">
<view class="dropdown-item" :class="{selected: selectedArea===item.name}" v-for="(item, index) in areaOptions" :key="index" @tap="selectArea(item)">
<text>{{ item.name }}</text>
</view>
</view>
<!-- 综合排序下拉菜单 -->
<view class="dropdown-menu" v-if="showSort">
<view class="dropdown-item" :class="{selected: selectedSort===item.name}" v-for="(item, index) in sortOptions" :key="index" @tap="selectSort(item)">
<text>{{ item.name }}</text>
</view>
</view>
<!-- 价格下拉菜单 -->
<view class="dropdown-menu" v-if="showPrice">
<view class="dropdown-item" :class="{selected: selectedPrice===item.name}" v-for="(item, index) in priceOptions" :key="index" @tap="selectPrice(item)">
<text>{{ item.name }}</text>
</view>
</view>
<!-- 筛选下拉菜单 -->
<view class="dropdown-menu" v-if="showFilter">
<view class="dropdown-item" :class="{selected: selectedFilter===item.name}" v-for="(item, index) in filterOptions" :key="index" @tap="selectFilter(item)">
<text>{{ item.name }}</text>
</view>
</view>
</view>
</view>
<!-- 酒店列表 -->
<scroll-view class="hotel-list" @scrolltolower="handqixing" scroll-y refresher-enabled @refresherrefresh="onRefresh" :refresher-triggered="isRefreshing" refresher-default-style="black">
<!-- 遮罩层 -->
<view class="dropdown-mask" v-if="showArea || showSort || showPrice || showFilter" @tap="closeAllDropdowns"></view>
<view class="hotel-item" v-for="(item, index) in hotelList" :key="index" @click="goToDetail(item)">
<view class="hotel-image">
<image :src="getFirstImage(item.picture)" mode="aspectFill"></image>
</view>
<view class="hotel-info">
<view class="hotel-name">{{ item.name }}</view>
<view class="hotel-rating">
<view class="rating-score">{{ item.averageRating != null && item.averageRating !== '' ? Number(item.averageRating).toFixed(1) : '--' }}</view>
<view class="rating-text" v-if="item.tags && item.tags.length > 0" v-for="(val,indexs) in item.tags" :key="indexs">{{val}}</view>
</view>
<view class="hotel-location">
<text>据您直线{{ item.distance || '--' }}公里</text>
<text v-if="item.address"> · {{ item.address.length > 10 ? item.address.slice(0,10) + '...' : item.address }}</text>
</view>
<view class="hotel-price" style="display: flex;justify-content: space-between;">
<text></text>
<view class="" style="display: flex;align-items: center;">
<!-- <text class="original-price" v-if="item.originalPrice">¥{{ item.originalPrice }}</text> -->
<text class="current-price" style="margin-left: 24rpx;">¥{{ item.priceMin || '0' }} <text style="color: #333;font-size: 24rpx;font-weight: 400;"></text> </text>
</view>
</view>
</view>
</view>
<view class="no-more">
当前没有更多酒店了...
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
bgc: {
backgroundColor: "#fff",
},
searchKeyword: '',
showArea: false,
showSort: false,
showPrice: false,
showFilter: false,
// 选中项显示
selectedArea: '区域/位置',
selectedSort: '综合排序',
selectedPrice: '价格',
selectedFilter: '筛选',
// 筛选选项
areaOptions: [
{name:'全部',
value:''}
],
sortOptions: [
{name: '综合排序', value: ''},
{name: '距离最近', value: 'distance_asc'},
{name: '评分最高', value: 'rating_desc'},
{name: '价格最低', value: 'price_asc'},
{name: '价格最高', value: 'price_desc'}
],
priceOptions: [{name: '价格', value: ''},
{name: '100以下', value: '0,100'},
{name: '100-200', value: '100,200'},
{name: '200-300', value: '200,300'},
{name: '300以上', value: '300'}],
filterOptions: [
{name: '全部', value: ''},
],
hotelList: [],
isRefreshing: false,
pageNum: 1,
total: 0,
lat: '',
lng: '',
selectedAreaValue: '',
selectedSortValue: '',
selectedPriceValue: '',
selectedFilterValue: '',
fanhui:''
}
},
onLoad(option) {
this.gettiaojian()
this.getshuaixuan()
// 初始化筛选选项
if(option.fanhui){
this.fanhui = option.fanhui
}
// 获取位置信息
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
this.lat = res.latitude
this.lng = res.longitude
this.getlist()
},
fail: (err) => {
console.error('获取位置失败:', err)
this.getlist()
}
})
},
// 分享到好友(会话)
onShareAppMessage: function() {
return {
title: '玩转福鼎',
path: '/page_fenbao/jiudian/index?fanhui=1'
}
},
// 分享到朋友圈
onShareTimeline: function() {
return {
title: '玩转福鼎',
query: '',
path: '/page_fenbao/jiudian/index?fanhui=1'
}
},
onShow() {
// 页面显示时关闭所有下拉菜单
this.closeAllDropdowns()
},
methods: {
btnfh(){
console.log(this.fanhui,'000');
if(this.fanhui == 1){
uni.reLaunch({
url:'/pages/index/index'
})
}else{
uni.navigateBack()
}
},
// 请求酒店筛选条件
getshuaixuan(){
this.$u.get(`/system/dict/data/type/hotel_type`).then(res =>{
if(res.code == 200){
res.data.forEach(item =>{
this.filterOptions.push({
name:item.dictLabel,
value:item.dictValue
})
})
}
})
},
// 请求酒店位置条件
gettiaojian(){
this.$u.get(`/system/dict/data/type/location`).then(res =>{
if(res.code == 200){
res.data.forEach(item =>{
this.areaOptions.push({
name:item.dictLabel,
value:item.dictValue
})
})
}
})
},
// 获取第一张图片
getFirstImage(pictureString) {
if (!pictureString) return '';
// 如果包含逗号,取第一张图片
if (pictureString.includes(',')) {
return pictureString.split(',')[0].trim();
}
return pictureString.trim();
},
// 根据选中的价格选项解析出 priceMin、priceMax最高价格、最低价格
getPriceParams() {
const val = this.selectedPriceValue
if (!val) return { priceMin: '', priceMax: '' }
if (val.includes(',')) {
const [min, max] = val.split(',')
return { priceMin: min || '', priceMax: max || '' }
}
// 如 "300" 表示 300 以上,仅最低价
return { priceMin: val, priceMax: '' }
},
// 请求酒店列表
getlist() {
const { priceMin, priceMax } = this.getPriceParams()
const priceMinParam = priceMin !== '' ? `&priceMin=${priceMin}` : ''
const priceMaxParam = priceMax !== '' ? `&priceMax=${priceMax}` : ''
this.$u.get(`/app/hotel/list?keyword=${this.searchKeyword}&pageNum=${this.pageNum}&pageSize=20&currLon=${this.lng}&currLat=${this.lat}${priceMinParam}${priceMaxParam}&sortBy=${this.selectedSortValue}&location=${this.selectedAreaValue}&type=${this.selectedFilterValue}`).then((res) => {
if(res.code == 200){
this.total = res.total
if(this.pageNum == 1){
this.pageNum++
this.hotelList = res.rows
}else{
this.pageNum++
this.hotelList = this.hotelList.concat(res.rows)
}
}
})
},
// 上拉加载更多
handqixing() {
if (this.hotelList.length < this.total) {
this.getlist()
}
},
// 下拉刷新列表
onRefresh() {
this.isRefreshing = true
this.pageNum = 1
this.getlist()
setTimeout(() => {
this.isRefreshing = false
}, 1000)
},
// 点击搜索查询列表
handleSearch() {
this.pageNum = 1
this.getlist()
},
// 点击展示下拉菜单 - 区域
showAreaPicker() {
if (this.showArea) {
this.showArea = false
} else {
this.closeAllDropdowns()
this.showArea = true
}
},
// 点击展示下拉菜单 - 排序
showSortPicker() {
if (this.showSort) {
this.showSort = false
} else {
this.closeAllDropdowns()
this.showSort = true
}
},
// 点击展示下拉菜单 - 价格
showPricePicker() {
if (this.showPrice) {
this.showPrice = false
} else {
this.closeAllDropdowns()
this.showPrice = true
}
},
// 点击展示下拉菜单 - 筛选
showFilterPicker() {
if (this.showFilter) {
this.showFilter = false
} else {
this.closeAllDropdowns()
this.showFilter = true
}
},
// 点击隐藏下拉菜单
closeAllDropdowns() {
this.showArea = false
this.showSort = false
this.showPrice = false
this.showFilter = false
},
// 点击选择区域
selectArea(item) {
this.selectedArea = item.name
this.selectedAreaValue = item.value
this.showArea = false
this.pageNum = 1
this.getlist()
},
// 点击选择排序
selectSort(item) {
this.selectedSort = item.name
this.selectedSortValue = item.value
this.showSort = false
if (this.selectedSortValue == 'distance_asc') {
uni.getLocation({
type: 'gcj02',
isHighAccuracy: true,
accuracy: 'best',
success: (res) => {
this.lat = res.latitude
this.lng = res.longitude
this.pageNum = 1
this.getlist()
},
fail: (err) => {
console.error('获取位置失败:', err)
this.lat = ''
this.lng = ''
this.pageNum = 1
this.getlist()
}
})
} else {
this.pageNum = 1
this.getlist()
}
},
// 点击选择价格
selectPrice(item) {
this.selectedPrice = item.name
this.selectedPriceValue = item.value
this.showPrice = false
this.pageNum = 1
this.getlist()
},
// 点击选择筛选
selectFilter(item) {
this.selectedFilter = item.name
this.selectedFilterValue = item.value
this.showFilter = false
this.pageNum = 1
this.getlist()
},
// 跳转到详情页
goToDetail(item) {
uni.navigateTo({
url: '/page_fenbao/jiudian/jiudianxq?id=' + item.id
})
}
}
}
</script>
<style lang="scss">
::v-deep .u-icon__icon,
::v-deep .u-title {
padding-bottom: 22rpx !important;
}
page {
background: #fff;
}
.page {
background: #fff;
min-height: 100vh;
}
// 搜索栏样式
.search-container {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background: #fff;
gap: 20rpx;
z-index: 1002;
.search-bar {
flex: 1;
display: flex;
align-items: center;
background: #f5f5f5;
border-radius: 50rpx;
padding: 16rpx 30rpx;
gap: 20rpx;
.search-icon {
width: 32rpx;
height: 32rpx;
}
.search-input {
flex: 1;
font-size: 28rpx;
color: #333;
border: none;
background: transparent;
outline: none;
&::placeholder {
color: #999;
}
}
}
}
// 筛选器样式
.filter-container {
position: relative;
display: flex;
background: #fff;
padding: 0 30rpx 20rpx;
gap: 20rpx;
z-index: 1002;
box-shadow: 0 1rpx 4rpx rgba(0, 0, 0, 0.1);
.filter-item-wrapper {
flex: 1;
.filter-item {
display: flex;
align-items: center;
justify-content: center;
padding: 10rpx 0;
font-size: 28rpx;
color: #333;
border-bottom: 2rpx solid transparent;
transition: all 0.3s ease;
text {
&.active {
color: #1EC28B;
font-weight: 600;
}
}
.arrow {
font-size: 20rpx;
color: #999;
transition: transform 0.3s ease;
margin-left: 10rpx;
}
.arrow-up {
transform: rotate(180deg);
}
}
}
}
// 下拉菜单容器样式
.dropdown-container {
position: fixed;
top: 366rpx;
left: 0;
background: #fff;
border-radius: 0 0 20rpx 20rpx;
z-index: 1001;
overflow: hidden;
width: 100%;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
.dropdown-menu {
width: 100%;
max-height: 50vh;
overflow: scroll;
.dropdown-item {
padding: 30rpx 20rpx;
font-size: 28rpx;
color: #333;
border-bottom: 1rpx solid #f0f0f0;
transition: all 0.3s ease;
background: #fff;
position: relative;
&:last-child {
border-bottom: none;
}
&:active {
background: #1EC28B;
color: #fff;
}
&.selected {
color: #1EC28B;
font-weight: 600;
}
}
}
}
// 酒店列表样式
.hotel-list {
background: #fff;
width: 750rpx;
height: 77vh;
overflow: scroll;
margin: auto;
margin-top: 20rpx;
.hotel-item {
display: flex;
background: #fff;
border-radius: 10rpx;
width: 730rpx;
margin: auto;
margin-bottom: 30rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
.hotel-image {
width: 180rpx;
height: 232rpx;
flex-shrink: 0;
border-radius: 10rpx;
overflow: hidden;
image {
width: 100%;
height: 100%;
display: block;
}
}
.hotel-info {
flex: 1;
padding: 24rpx 20rpx;
padding-left: 32rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.hotel-name {
font-size: 32rpx;
font-weight: 600;
color: #262B37;
margin-bottom: 15rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.hotel-rating {
display: flex;
align-items: center;
margin-bottom: 15rpx;
gap: 10rpx;
flex-wrap: wrap;
.rating-score {
background: #1EC28B;
color: #fff;
font-size: 24rpx;
font-weight: 600;
padding: 6rpx 14rpx;
border-radius: 6rpx;
margin-right: 8rpx;
}
.rating-text {
background: #E8FFFB;
color: #1EC28B;
font-size: 22rpx;
padding: 6rpx 14rpx;
border-radius: 6rpx;
}
}
.hotel-location {
font-size: 24rpx;
color: #999;
margin-bottom: 15rpx;
line-height: 1.5;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.hotel-price {
display: flex;
align-items: baseline;
gap: 10rpx;
width: 490rpx;
.original-price {
font-size: 24rpx;
color: #999;
text-decoration: line-through;
}
.current-price {
font-size: 32rpx;
color: #FF0000;
font-weight: 600;
}
}
}
}
.no-more {
margin-top: 30rpx;
text-align: center;
color: #ccc;
font-size: 24rpx;
padding-bottom: 30rpx;
}
}
// 遮罩层样式
.dropdown-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
z-index: 1;
}
</style>