完善功能

This commit is contained in:
wangxiaowei
2025-12-04 17:30:32 +08:00
parent 331d6facdb
commit f59ed2e36d
21 changed files with 1642 additions and 399 deletions

View File

@ -1,14 +1,106 @@
<template>
<view class="">
<!-- 费用明细弹窗 -->
<Popup :show="billPopup" :width='750' :padding="0" type="bottom" backgroundColor="#FBFBFB" radius="32rpx 32rpx 0 0">
<view class="ww100 box-s-b pop-improt typeof pr time-popup">
<image style="width: 64rpx;height: 64rpx;position: absolute; top: 26rpx;right: 30rpx;" src="@/static/icon/close2.png" mode="" @click="closeBillPopup"></image>
<view class="d-c-c pt42">
<text class="f34 fb">费用明细</text>
</view>
<view class="bg-white bill-info">
<!-- 网球场 -->
<view v-if="typeId == 1">
<view class="title1 d-b-c">
<view>场地费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.cdf.total"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>场地费(¥{{ bill.cdf.price }}元/小时)</view>
<view>x{{ bill.cdf.nums }}</view>
</view>
</view>
<!-- 篮球场 -->
<view v-if="typeId == 2">
<view class="title1 d-b-c">
<view>使用费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.cdf.total"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>¥{{ bill.cdf.price }}元/人</view>
<view>x1</view>
</view>
</view>
<view style="margin-top: 52rpx;" v-if="typeId == 1">
<view class="title1 d-b-c">
<view>灯光费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.dgf.total"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>灯光费(¥{{ bill.dgf.price }}元/小时)</view>
<view>x{{ bill.dgf.nums }}</view>
</view>
</view>
<view class="line"></view>
<view class="title3 d-b-c">
<view>实付金额</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.total"></price-format>
</view>
</view>
</view>
<view class="price2 bg-white" style="margin: 0; padding: 56rpx 22rpx 42rpx;">
<view class="d-b-c price-block" style="margin: 0;">
<view class="d-f d-c j-c-b">
<view class="">
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" :price="bill.total"></price-format>
</view>
<view class="d-f j-c-c a-i-c" style="margin-top: 10rpx;" @click="closeBillPopup">
<view class="price-detail">费用明细</view>
<image style="width: 14rpx;height: 8rpx;margin-left: 10rpx;" src="@/static/icon/up.png" mode=""></image>
</view>
</view>
<view class="price-btn" @tap="toConfirm">立即支付<text class="" v-if="countSelectedTime > 0">({{countSelectedTime}}小时)</text></view>
</view>
</view>
</view>
</Popup>
<navbar title="确认订单"></navbar>
<!-- 预约信息 -->
<view class="bg-white box pr">
<view class="current"></view>
<view class="title">预约信息</view>
<view class="desc">预约场地:这里是场地的名称</view>
<view class="desc">预约时间:2025-03-18 09:00-12:00</view>
<view class="desc">预约时长:3小时</view>
<template v-if="typeId == 1">
<view class="desc">预约场地:{{ room.title }}</view>
<view class="desc">
预约时间:{{ date && date.dayLabel ? date.dayLabel : '' }}
{{ date && date.hour ? date.hour : '' }}:{{ date && date.minute ? date.minute : '' }}
</view>
<view class="desc">预约时长:{{ date && date.duration ? date.duration : 0 }}小时</view>
</template>
<template v-if="typeId == 2">
<view class="desc">预约场地:{{ room.title }}</view>
<view class="desc">
预约时间:{{ basketballDate }}
</view>
<view class="desc">预约人数:1人</view>
</template>
</view>
<!-- 其他须知 -->
@ -17,14 +109,22 @@
<view class="title">
其他须知
</view>
<view class="desc2">
<view class="dot"></view>
<view class="">17点前预约100元/小时</view>
</view>
<view class="desc2">
<view class="dot"></view>
<view class="">17点后需要加收灯光费,120元/小时</view>
</view>
<template v-if="typeId == 1">
<view class="desc2">
<view class="dot"></view>
<view class="">17点前预约100元/小时</view>
</view>
<view class="desc2">
<view class="dot"></view>
<view class="">17点后需要加收灯光费,120元/小时</view>
</view>
</template>
<template v-if="typeId == 2">
<view class="desc2">
<view class="dot"></view>
<view class="">默认选择4小时,注意闭馆时间</view>
</view>
</template>
</view>
<!-- 退订规则 -->
@ -50,79 +150,16 @@
<view class="d-b-c price-block">
<view class="d-f d-c j-c-b">
<view class="">
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" price="100"></price-format>
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" :price="bill.total"></price-format>
</view>
<view class="d-f j-c-c a-i-c" style="margin-top: 10rpx;" @tap="handleShowBill">
<view class="price-detail">费用明细</view>
<image style="width: 14rpx;height: 8rpx;margin-left: 10rpx;" src="@/static/icon/down.png" mode=""></image>
</view>
</view>
<view class="price-btn" @tap="toConfirm">立即预定<text class="" v-if="countSelectedTime > 0">({{countSelectedTime}}小时)</text></view>
<view class="price-btn" @tap="toConfirm">立即支付<text class="" v-if="countSelectedTime > 0">({{countSelectedTime}}小时)</text></view>
</view>
</view>
<!-- 费用明细弹窗 -->
<Popup :show="billPopup" :width='750' :padding="0" type="bottom" backgroundColor="#FBFBFB" radius="32rpx 32rpx 0 0">
<view class="ww100 box-s-b pop-improt typeof pr time-popup">
<image style="width: 64rpx;height: 64rpx;position: absolute; top: 26rpx;right: 30rpx;" src="@/static/icon/close2.png" mode="" @click="closeBillPopup"></image>
<view class="d-c-c pt42">
<text class="f34 fb">费用明细</text>
</view>
<view class="bg-white bill-info">
<view class="">
<view class="title1 d-b-c">
<view>场地费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" price="100"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>场地费(¥100元/小时)</view>
<view>x3</view>
</view>
</view>
<view style="margin-top: 52rpx;">
<view class="title1 d-b-c">
<view>灯光费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" price="100"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>灯光费(¥50元/小时)</view>
<view>x3</view>
</view>
</view>
<view class="line"></view>
<view class="title3 d-b-c">
<view>实付金额</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" price="100"></price-format>
</view>
</view>
</view>
<view class="price2 bg-white" style="margin: 0; padding: 56rpx 22rpx 42rpx;">
<view class="d-b-c price-block" style="margin: 0;">
<view class="d-f d-c j-c-b">
<view class="">
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" price="100"></price-format>
</view>
<view class="d-f j-c-c a-i-c" style="margin-top: 10rpx;" @click="closeBillPopup">
<view class="price-detail">费用明细</view>
<image style="width: 14rpx;height: 8rpx;margin-left: 10rpx;" src="@/static/icon/up.png" mode=""></image>
</view>
</view>
<view class="price-btn">立即预定<text class="" v-if="countSelectedTime > 0">({{countSelectedTime}}小时)</text></view>
</view>
</view>
</view>
</Popup>
</view>
</template>
@ -138,12 +175,124 @@
data() {
return {
venueId: 0,
roomId: 0,
typeId: 1, // 网球场1 篮球场2
billPopup: false,
showPrice: true
showPrice: true,
adding: true,
basketballDate: null,
venue: {},
room: {},
countSelectedTime: 0,
bill: {
cdf: {
nums: 0, // 场地费小时数
price: 0, // 场地费单价
total: 0 // 场地费总价
},
dgf: {
nums: 0, // 灯光数量
price: 0, // 灯光单价
total: 0 // 灯光总价
},
total: 0 // 总价
}
};
},
onLoad(args) {
this.venueId = args.venueId || 0;
this.roomId = args.roomId || 0;
this.typeId = args.typeId || 1;
this.basketballDate = args.date || null;
console.log("🚀 ~ this.date:", this.date)
this.getData();
},
methods: {
getData() {
let self = this;
uni.showLoading({
title: '加载中'
});
const reserveDate = uni.getStorageSync('reserveDate') || null
self.date = reserveDate
self.countSelectedTime = reserveDate && reserveDate.duration ? reserveDate.duration : 0
if (self.typeId == 2) {
self.countSelectedTime = 4
}
// 获取场馆详情
self._post(
'ground.ground/groundDetails',
{
app_id: self.getAppId(),
id: self.venueId,
latitude: uni.getStorageSync('latitude') || '',
longitude: uni.getStorageSync('longitude') || '',
},
function (res) {
if (res.code) {
self.loadding = false;
self.venue = res.data.lists
}
}
)
// 获取场馆包间详情
self._post(
'ground.ground/groundRoomDetails',
{
app_id: self.getAppId(),
id: self.roomId, // 场馆包间ID
},
function(res) {
console.log("🚀 ~ res:", res)
if (res.code) {
self.room = res.data.lists;
}
self.loadding = false;
}
)
// 计算费用明细
if (self.countSelectedTime > 0) {
self._post(
'ground.ground/countPrice',
{
app_id: self.getAppId(),
room_id: self.roomId,
nums: self.countSelectedTime,
type_id: self.typeId,
},
function(res) {
const result = res.data.lists
self.bill = {
total: result.order_amount,
cdf: {
nums: result.nums,
price: result.room_price,
total: result.room_all_price
},
dgf: {
nums: result.nums,
price: result.light_price,
total: result.light_all_price
}
}
console.log("🚀 ~ self.bill:", self.bill)
self.loadding = false;
}
)
} else {
self.loadding = false;
}
},
// 显示费用明细
handleShowBill() {
this.showPrice = false;
@ -154,6 +303,62 @@
this.billPopup = false;
this.showPrice = true;
},
// 去支付
toConfirm() {
if (this.countSelectedTime === 0) {
uni.showToast({title: '请选择时间后再预定', icon: 'none'});
return;
}
let self = this;
uni.showLoading({
title: '加载中'
});
self._post(
'order.groundOrder/submitStoreOrder',
{
app_id: self.getAppId(),
ground_id: self.venueId,
room_id: self.roomId,
hours: 1,
day_time: self.date ? self.date.date : '',
start_time: self.date ? self.date.startTime : '',
end_time: self.date ? self.date.endTime : '',
},
function(res) {
console.log("🚀 ~ order res:", res)
self._post(
'user.groundOrder/pay',
{
app_id: self.getAppId(),
order_id: res.data.lists.id
},
function(res) {
const data = res.data
console.log("🚀 ~ pay data:", data)
uni.requestPayment({
provider: 'wxpay',
timeStamp: data.payment.timeStamp,
nonceStr: data.payment.nonceStr,
package: 'prepay_id=' + data.payment.prepay_id,
signType: 'MD5',
paySign: data.payment.paySign,
success: res => {
console.log("🚀 ~ pay success res:", res)
},
fail: res => {
console.log("🚀 ~ pay fail res:", res)
uni.reLaunch({
url: '/pages/order/cg-my-order',
});
},
});
}
)
self.loadding = false;
}
)
}
}
};
</script>

View File

@ -1,35 +1,123 @@
<template>
<view style="padding-bottom: 40rpx">
<view style="padding-bottom: 40rpx;">
<Popup :show="timePopup" :width="750" :padding="0" type="bottom" radius="32rpx 32rpx 0 0">
<reserve-time
@confirm="confirmSelectTime"
@close="timePopup = false"
/>
</Popup>
<!-- 费用明细弹窗 -->
<Popup :show="billPopup" :width='750' :padding="0" type="bottom" backgroundColor="#FBFBFB" radius="32rpx 32rpx 0 0">
<view class="ww100 box-s-b pop-improt typeof pr time-popup">
<image style="width: 64rpx;height: 64rpx;position: absolute; top: 26rpx;right: 30rpx;" src="@/static/icon/close2.png" mode="" @click="closeBillPopup"></image>
<view class="d-c-c pt42" style="margin-top: 38rpx;">
<text class="f34 fb">费用明细</text>
</view>
<view class="bg-white bill-info">
<!-- 网球场 -->
<view v-if="venue.type_id == 1">
<view class="title1 d-b-c">
<view>场地费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.cdf.total"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>场地费(¥{{ bill.cdf.price }}元/小时)</view>
<view>x{{ bill.cdf.nums }}</view>
</view>
</view>
<!-- 篮球场 -->
<view v-if="venue.type_id == 2">
<view class="title1 d-b-c">
<view>使用费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.cdf.total"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>¥{{ bill.cdf.price }}元/人</view>
<view>x1</view>
</view>
</view>
<view style="margin-top: 52rpx;" v-if="venue.type_id == 1">
<view class="title1 d-b-c">
<view>灯光费</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.dgf.total"></price-format>
</view>
</view>
<view class="title2 d-b-c">
<view>灯光费(¥{{ bill.dgf.price }}元/小时)</view>
<view>x{{ bill.dgf.nums }}</view>
</view>
</view>
<view class="line"></view>
<view class="title3 d-b-c">
<view>实付金额</view>
<view>
<price-format color="#303133" :subscript-size="30" :first-size="30" :second-size="30" :price="bill.total"></price-format>
</view>
</view>
</view>
<view class="price2 bg-white" style="margin: 0; padding: 56rpx 22rpx 42rpx;">
<view class="d-b-c price-block" style="margin: 0;">
<view class="d-f d-c j-c-b">
<view class="">
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" :price="bill.total"></price-format>
</view>
<view class="d-f j-c-c a-i-c" style="margin-top: 10rpx;" @click="closeBillPopup">
<view class="price-detail">费用明细</view>
<image style="width: 14rpx;height: 8rpx;margin-left: 10rpx;" src="@/static/icon/up.png" mode=""></image>
</view>
</view>
<view class="price-btn" @tap="toReserve">立即预约</view>
</view>
</view>
</view>
</Popup>
<navbar title="预约网球场馆"></navbar>
<view class="banner">
<!-- <view class="banner">
<banner :itemData="bannerData"></banner>
</view>
</view> -->
<!-- 信息介绍 -->
<view class="info-block">
<view class="info-title">秀湖网球中心</view>
<view class="d-f">
<uni-rate v-model="value" active-color="#FF5951" :size="18"/>
<text class="rate">4.0推荐</text>
<view class="info-title mx-30rpx">{{ venue.name }}</view>
<view class="d-f mx-30rpx">
<uni-rate v-model="venue.star" active-color="#FF5951" :size="18" />
<text class="rate">{{ venue.star }}推荐</text>
</view>
<view class="time">营业时间:周一至周日 06:00-22:00</view>
<view class="time mx-30rpx">营业时间:{{ venue.day_time }} {{ venue.start_time }}-{{ venue.end_time }}</view>
<view class="line"></view>
<view class="d-b-c">
<view class="d-b-c mx-30rpx">
<view class="d-f">
<image style="width: 36rpx;height: 36rpx;margin-top: 4rpx;" src="@/static/icon/location2.png" mode=""></image>
<image style="width: 36rpx;height: 36rpx;margin-top: 4rpx;" src="@/static/icon/location2.png"
mode=""></image>
<view class="">
<view class="address-time">嘉兴市秀洲区秀园路秀湖公园(西南角)</view>
<view class="address-time">距您14km</view>
<view class="address-time">{{ venue.address }}</view>
<view class="address-time">距您{{ venue.distance }}km</view>
</view>
</view>
<view class="d-f">
<view class="d-f d-c a-i-c" style="margin-right: 20rpx;" @tap="handleLocation">
<image style="width: 64rpx;height: 64rpx;margin-top: 2rpx" src="@/static/icon/share.png" mode=""></image>
<image style="width: 64rpx;height: 64rpx;margin-top: 2rpx" src="@/static/icon/share.png"
mode=""></image>
<view class="mark-text">导航</view>
</view>
<view class="d-f d-c a-i-c" @tap="handleCall">
<image style="width: 64rpx;height: 64rpx;margin-top: 2rpx" src="@/static/icon/mobile.png" mode=""></image>
<image style="width: 64rpx;height: 64rpx;margin-top: 2rpx" src="@/static/icon/mobile.png"
mode=""></image>
<view class="mark-text">电话</view>
</view>
</view>
@ -39,9 +127,8 @@
<!-- 分隔线 -->
<view class="split-line"></view>
<!-- 场馆信息 -->
<view class="info-block">
<view class="info-title">场馆信息</view>
<!-- 网球场——场馆信息 -->
<view class="info-block mx-30rpx" v-if="typeId == 1">
<view class="d-f">
<view class="tab" v-for="(item, index) in tab" :key="index"
:style="currentTab === item.type ? 'background-color: #F0F5FF; color: #365A9A;' : ''"
@ -51,22 +138,21 @@
</view>
<view class="">
<view class="">
<view class="" v-for="(item, index) in venueRoomLists" :key="index">
<view class="d-b-c">
<view class="">
<image style="width: 200rpx;height: 200rpx;border-radius: 10rpx; margin-right: 32rpx;" src="https://6548.cn/uploads/20241019/ca61afebae2b1066b74fb42b791d8b29.jpg" mode=""></image>
<image style="width: 200rpx;height: 200rpx;border-radius: 10rpx; margin-right: 32rpx;" :src="item.img" mode=""></image>
</view>
<view class="flex-1">
<view class="cg-name">这个是场馆的分场名称</view>
<view class="cg-name">{{ item.title }}</view>
<view class="d-b-c">
<view class="">
<price-format color="#FF5951" :subscript-size="26" :first-size="38" :second-size="26" price="100"></price-format>
<price-format color="#FF5951" :subscript-size="26" :first-size="38" :second-size="26" :price="item.price"></price-format>
</view>
<view class="reserve-btn" @tap="heandleToReserve">
<view class="reserve-btn" @tap="heandleToReserve(item.id)">
预定
</view>
</view>
</view>
</view>
<view class="d-f a-i-c" style="margin-top: 16rpx;">
@ -79,195 +165,570 @@
</view>
</view>
</view>
<!-- 篮球场——场馆信息 -->
<view class="info-block" v-if="typeId == 2">
<view class="tab-bar-scroll mx-30rpx">
<view class="tab-bar">
<view v-for="(item, idx) in venueRoomLists" :key="item.display" class="tab-bar-item"
:class="{ active: idx === selectedRoomIndex}" @click="handleTabClick(idx)">
{{ item.title }}
</view>
</view>
</view>
<view class="line"></view>
<view class="mx-30rpx">
<view class="reserve-time">预定时间</view>
<view class="reserve-desc" @click="timePopup = true">
<view class="reserve-desc-title">默认4小时,注意闭馆时间</view>
<view class="reserve-desc-info">
<view class="">{{ date || '请选择' }}</view>
<view class="">
<image class="" src="@/static/icon/right.png" style="width: 32rpx; height: 32rpx;"></image>
</view>
</view>
</view>
</view>
</view>
<view class="price" v-if="showPrice && typeId == 2">
<view class="line"></view>
<view class="d-b-c price-block">
<view class="d-f d-c j-c-b">
<view class="">
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" :price="bill.total"></price-format>
</view>
<view class="d-f j-c-c a-i-c" style="margin-top: 10rpx;" @tap="handleShowBill">
<view class="price-detail">费用明细</view>
<image style="width: 14rpx;height: 8rpx;margin-left: 10rpx;" src="@/static/icon/down.png" mode=""></image>
</view>
</view>
<view class="price-btn" @tap="toReserve">立即预约</view>
</view>
</view>
</view>
</template>
<script>
import navbar from '@/components/navbar.vue';
import banner from '@/components/diy/banner/banner.vue';
import priceFormat from '@/components/price-format/price-format.vue';
export default {
components: {
navbar,
banner,
priceFormat
},
data() {
return {
bannerData: [],
value: 4,
currentTab: 1,
tab: [
{type: 1, name: '今天'},
{type: 2, name: '明天'},
{type: 3, name: '后天'},
]
};
},
import navbar from '@/components/navbar.vue';
import banner from '@/components/diy/banner/banner.vue';
import priceFormat from '@/components/price-format/price-format.vue';
import ReserveTime from '@/components/reserve-time'
import Popup from '@/components/uni-popup.vue';
onLoad(args) {
this.getData();
export default {
components: {
navbar,
banner,
priceFormat,
Popup,
ReserveTime
},
data() {
return {
id: 0,
typeId: 1,
bannerData: {
data: [],
style: { btnColor: "#ffffff", background: "#ffffff", btnShape: "round", imgShape: "round", height: "330" }
},
selectedRoomIndex: 0, // 篮球场--场馆信息-选中tab索引
value: 4,
currentTab: 1,
tab: [
{ type: 1, name: '今天' },
{ type: 2, name: '明天' },
{ type: 3, name: '后天' },
],
venue: {},
venueRoomLists: [],
loadding: true,
timePopup: false,
date: '',
showPrice: true,
bill: {
cdf: {
nums: 0, // 场地费小时数
price: 0, // 场地费单价
total: 0 // 场地费总价
},
dgf: {
nums: 0, // 灯光数量
price: 0, // 灯光单价
total: 0 // 灯光总价
},
total: 0 // 总价
},
billPopup: false,
};
},
},
onLoad(args) {
this.id = args.id || 0
this.typeId = args.typeId || 1
methods: {
getData() {
let self = this;
uni.showLoading({
title: '加载中'
});
self._get(
'index/index',
{
url: self.url
},
function(res) {
self.bannerData = res.data.items[0];
console.log("🚀 ~ self.bannerData:", self.bannerData)
this.getData()
this.handleGetVenueRoom()
},
methods: {
getData() {
let self = this;
uni.showLoading({
title: '加载中'
});
// 获取场馆详情
self._post(
'ground.ground/groundDetails',
{
app_id: self.getAppId(),
id: self.id,
latitude: uni.getStorageSync('latitude') || '',
longitude: uni.getStorageSync('longitude') || '',
},
function (res) {
if (res.code) {
self.loadding = false;
self.venue = res.data.lists
res.data.lists.image_arr.map(items => {
self.bannerData.data.push({ imgUrl: items, height: '400px' })
})
}
);
},
}
)
},
// 切换tab
handleChangeTab(e) {
this.currentTab = e.type;
},
// 获取场馆包间列表
handleGetVenueRoom() {
let self = this;
uni.showLoading({
title: '加载中'
});
self._post(
'ground.ground/groundRoomLists',
{
app_id: self.getAppId(),
ground_id: self.id,
},
function (res) {
if (res.code) {
self.venueRoomLists = res.data.lists
console.log("🚀 ~ self.venueRoomLists:", self.venueRoomLists)
self.loadding = false;
}
}
)
},
// 跳转预定页面
heandleToReserve() {
uni.navigateTo({
url: '/bundle/reserve/reserve'
// 篮球场场馆-切换tab
handleTabClick(idx) {
this.selectedRoomIndex = idx
},
// 切换tab
handleChangeTab(e) {
this.currentTab = e.type;
this.handleGetVenueRoom()
},
// 跳转预定页面
heandleToReserve(id) {
uni.navigateTo({
url: `/bundle/reserve/reserve?venueId=${this.venue.id}&roomId=${id}`
});
},
// 处理导航
handleLocation() {
uni.openLocation({
latitude: this.venue.latitude,
longitude: this.venue.longitude,
name: this.venue.name,
address: this.venue.address,
scale: 18
});
},
// 处理拨打电话
handleCall() {
uni.makePhoneCall({
phoneNumber: this.venue.contact_phone
});
},
// 确认选择时间
confirmSelectTime(e) {
this.date = e.value
let self = this
// 计算费用明细
uni.showLoading({
title: '加载中'
});
// 计算费用明细
self._post(
'ground.ground/countPrice',
{
app_id: self.getAppId(),
room_id: self.id,
nums: 4,
type_id: self.venue.type_id,
},
function(res) {
const result = res.data.lists
self.bill = {
total: result.order_amount,
cdf: {
nums: result.nums,
price: result.room_price,
total: result.room_all_price
},
dgf: {
nums: result.nums,
price: result.light_price,
total: result.light_all_price
}
}
self.loadding = false;
}
)
},
// 显示费用明细
handleShowBill() {
this.showPrice = false;
this.billPopup = true;
},
closeBillPopup() {
this.billPopup = false;
this.showPrice = true;
},
// 篮球场-立即预约
toReserve() {
if (!this.date) {
uni.showToast({
title: '请选择预约时间',
icon: 'none'
});
},
return;
}
// 处理导航
handleLocation() {
uni.openLocation({
latitude: 30.74621,
longitude: 120.76055,
name: '秀湖网球中心',
address: '嘉兴市秀洲区秀园路秀湖公园(西南角)',
scale: 18
});
},
// 处理拨打电话
handleCall() {
uni.makePhoneCall({
phoneNumber: '0573-82069999'
});
},
}
};
uni.navigateTo({
url: `/bundle/reserve/confirm?venueId=${this.venue.id}&roomId=${this.venueRoomLists[this.selectedRoomIndex].id}&date=${this.date}&typeId=${this.venue.type_id}`
});
},
}
};
</script>
<style lang="scss">
page {
background-color: #fff;
page {
background-color: #fff;
}
.banner {
.diy-banner-box {
margin-bottom: 0 !important;
}
}
.info-block {
.info-title {
font-weight: bold;
font-size: 34rpx;
color: #303133;
line-height: 48rpx;
margin-bottom: 10rpx;
}
.banner {
.diy-banner-box {
margin-bottom: 0 !important;
}
.rate {
margin-left: 8rpx;
font-weight: 400;
font-size: 26rpx;
color: #606266;
line-height: 36rpx;
}
.info-block {
margin: 0 30rpx;
.time {
font-size: 26rpx;
color: #606266;
line-height: 48rpx;
}
.info-title {
font-weight: bold;
font-size: 34rpx;
color: #303133;
line-height: 48rpx;
margin-bottom: 10rpx;
}
.line {
height: 2rpx;
background-color: #F6F7F9;
margin: 24rpx 0;
}
.rate {
margin-left: 8rpx;
.address-time {
font-weight: 400;
font-size: 26rpx;
color: #606266;
line-height: 36rpx;
}
.tab {
width: 108rpx;
height: 52rpx;
text-align: center;
line-height: 52rpx;
background-color: #F7F7F7;
font-size: 26rpx;
color: #606266;
border-radius: 8rpx;
margin-top: 16rpx;
margin-right: 10rpx;
margin-bottom: 32rpx;
}
.cg-name {
font-size: 28rpx;
color: #303133;
line-height: 40rpx;
margin-bottom: 74rpx;
}
.reserve-btn {
width: 104rpx;
height: 52rpx;
border-radius: 10rpx;
border: 2rpx solid #365A9A;
font-weight: 400;
font-size: 26rpx;
color: #365A9A;
line-height: 52rpx;
text-align: center;
}
.time-block {
text-align: center;
margin-right: 8rpx;
.time-block-text {
font-weight: 400;
font-size: 26rpx;
color: #606266;
line-height: 36rpx;
font-size: 20rpx;
color: #365A9A;
line-height: 28rpx;
text-align: center;
}
.time {
font-size: 26rpx;
color: #606266;
line-height: 48rpx;
.time-block-box {
width: 30rpx;
height: 12rpx;
background: #365A9A;
border-radius: 6rpx;
}
}
}
.split-line {
height: 20rpx;
background-color: #F6F7F9;
margin-top: 12rpx;
margin-bottom: 28rpx;
}
.tab-bar-scroll {
overflow-x: auto;
background: #fff;
/* 隐藏滚动条,兼容主流浏览器 */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* IE 10+ */
}
.tab-bar {
display: flex;
flex-direction: row;
background: #fff;
}
.tab-bar-item:first-child{
padding: 0 !important;
}
.tab-bar-item {
flex-shrink: 0;
padding: 0 32rpx;
height: 62rpx;
line-height: 62rpx;
font-size: 32rpx;
color: #303133;
margin: 10rpx 16rpx 10rpx 0;
border-bottom: 4rpx solid transparent;
cursor: pointer;
}
.tab-bar-item.active {
color: #365A9A;
font-weight: bold;
position: relative;
}
.tab-bar-item.active::after {
content: '';
display: block;
width: 60rpx;
height: 10rpx;
background: #365A9A;
border-radius: 6rpx;
position: absolute;
left: 50%;
bottom: -10rpx;
transform: translateX(-50%);
}
.mx-30rpx {
margin-left: 30rpx;
margin-right: 30rpx;
}
.reserve-time {
font-weight: 500;
font-size: 32rpx;
color: #303133;
line-height: 44rpx;
}
.reserve-desc {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 22rpx;
color: #606266;
}
.reserve-desc-info {
display: flex;
align-items: center;
}
.box {
border-radius: 16rpx;
padding: 32rpx 30rpx;
margin: 0 30rpx;
}
.title {
font-size: 32rpx;
color: #303133;
line-height: 44rpx;
margin-bottom: 28rpx;
}
.desc {
font-weight: 500;
font-size: 26rpx;
color: #303133;
line-height: 48rpx;
margin-bottom: 16rpx;
}
.desc:last-child {
margin-bottom: 0;
}
.current {
position: absolute;
left: 0;
top: 38rpx;
width: 8rpx;
height: 32rpx;
background-color: #365A9A;
border-radius: 4rpx;
}
.dot {
width: 8rpx;
height: 8rpx;
background: #6A6363;
margin-right: 12rpx;
}
.mt20 {
margin-top: 20rpx;
}
.desc2 {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.desc2:last-child {
margin-bottom: 0;
}
.price {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
.line {
height: 2rpx;
background-color: #F6F7F9;
margin: 24rpx 0;
background: #E5E5E5;
width: 100%;
}
.address-time {
font-weight: 400;
font-size: 26rpx;
color: #606266;
line-height: 36rpx;
.price-block {
margin: 42rpx 22rpx;
}
.tab {
width: 108rpx;
height: 52rpx;
text-align: center;
line-height: 52rpx;
background-color: #F7F7F7;
font-size: 26rpx;
color: #606266;
border-radius: 8rpx;
margin-top: 16rpx;
margin-right: 10rpx;
margin-bottom: 32rpx;
}
.cg-name {
font-size: 28rpx;
color: #303133;
line-height: 40rpx;
margin-bottom: 74rpx;
}
.reserve-btn {
width: 104rpx;
height: 52rpx;
border-radius: 10rpx;
border: 2rpx solid #365A9A;
font-weight: 400;
font-size: 26rpx;
.price-detail {
color: #365A9A;
line-height: 52rpx;
text-align: center;
font-size: 24rpx;
line-height: 34rpx;
}
.time-block {
text-align: center;
margin-right: 8rpx;
.time-block-text {
font-weight: 400;
font-size: 20rpx;
color: #365A9A;
line-height: 28rpx;
text-align: center;
}
.time-block-box {
width: 30rpx;
height: 12rpx;
background: #365A9A;
border-radius: 6rpx;
}
}
}
.split-line {
height: 20rpx;
background-color: #F6F7F9;
margin-top: 12rpx;
margin-bottom: 28rpx;
.price-btn {
width: 368rpx;
height: 90rpx;
line-height: 90rpx;
text-align: center;
background: #365A9A;
border-radius: 8rpx;
font-size: 32rpx;
color: #FFF;
}
.bill-info {
border-radius: 16rpx;
margin: 32rpx 30rpx 22rpx;
padding: 48rpx 30rpx 30rpx;
.title1 {
font-size: 30rpx;
color: #303133;
line-height: 42rpx;
}
.title2 {
margin-top: 12rpx;
font-weight: 400;
font-size: 24rpx;
color: #909399;
line-height: 34rpx;
}
.line {
border: 2rpx solid #F6F7F9;
margin: 34rpx 0 30rpx;
}
.title3 {
font-size: 30rpx;
color: #303133;
line-height: 42rpx;
}
}
</style>

View File

@ -7,59 +7,34 @@
</view>
<view class="html">
<view class="cg-name">这里是场馆的名称场馆的名称</view>
<view class="cg-name">{{ venue.name }}</view>
<view class="line"></view>
<view class="" v-html="content"></view>
<view v-html="venue.textarea1"></view>
</view>
<view class="yy-btn">
<view class="btn" @tap="timePopup = true">立即预约</view>
</view>
<Popup :show="timePopup" :width='750' :padding="0" type="bottom" radius="32rpx 32rpx 0 0">
<view class="ww100 box-s-b pop-improt typeof pr time-popup">
<image style="width: 64rpx;height: 64rpx;position: absolute; top: 26rpx;right: 30rpx;" src="@/static/icon/close2.png" mode="" @tap="timePopup = false"></image>
<view class="d-c-c pt42">
<text class="f34 fb">选择时间</text>
</view>
<view class="notice">示例:07:00代表07:01-07:59</view>
<view class="mx-30 mt-28">
<view class="d-f a-i-c">
<view class="time-item" :class="index == currentTime ? 'active' : ''" v-for="(item, index) in time" :key="index" @tap="handleFilterTime(index)">
{{ item.time }}
</view>
</view>
</view>
<view class="mt-30">
<view class="date-grid">
<view @click="!item.disabled && handleSelectTime(item.time)" class="date-item" v-for="(item, index) in date" :key="index"
:style="item.disabled ? 'background-color: #F7F7F7; color: #C9C9C9;' : selectedTime.includes(item.time) ? 'background-color: #E6EFFF;color: #365A9A;' : 'background-color:#F7F7F7; color: #303133;'"
>
{{ item.time }}
</view>
</view>
</view>
<view class="price">
<view class="line"></view>
<view class="d-b-c price-block">
<view class="d-f d-c j-c-b">
<view class="">
合计: <price-format color="#FF5951" :subscript-size="26" :first-size="40" :second-size="40" price="100"></price-format>
</view>
<view class="d-f j-c-c a-i-c" style="margin-top: 10rpx;" @tap="handleShowBill">
<view class="price-detail">费用明细</view>
<image style="width: 14rpx;height: 8rpx;margin-left: 10rpx;" src="@/static/icon/down.png" mode=""></image>
</view>
</view>
<view class="price-btn" @tap="toConfirm">立即预定<text class="" v-if="countSelectedTime > 0">({{countSelectedTime}}小时)</text></view>
</view>
</view>
</view>
<!-- <Popup :show="timePopup" :width="750" :padding="0" type="bottom" radius="32rpx 32rpx 0 0">
<booking-time
v-model="timePopup"
:day="date"
@selectedTime="onSelectedTime"
/>
</Popup> -->
<Popup :show="timePopup" :width="750" :padding="0" type="bottom" radius="32rpx 32rpx 0 0">
<template v-if="venue.type_id == 1">
<booking-time
@confirm="confirmPicker"
/>
</template>
<template v-if="venue.type_id == 2">
<reserve-time
@confirm="confirmPicker"
/>
</template>
</Popup>
<Popup :show="billPopup" :width='750' :padding="0" type="bottom" backgroundColor="#FBFBFB" radius="32rpx 32rpx 0 0">
@ -131,16 +106,23 @@
import banner from '@/components/diy/banner/banner.vue';
import priceFormat from '@/components/price-format/price-format.vue';
import Popup from '@/components/uni-popup.vue';
import BookingTime from '@/components/booking-time.vue'
import ReserveTime from '@/components/reserve-time'
export default {
components: {
navbar,
banner,
priceFormat,
Popup
Popup,
ReserveTime,
BookingTime
// BookingTime
},
data() {
return {
venueId: 0,
roomId: 0,
bannerData: [],
value: 4,
currentTab: 1,
@ -151,39 +133,62 @@
],
content: '<p>欢迎来到秀湖网球中心!我们提供优质的网球场地和设施,适合各类网球爱好者。无论您是初学者还是专业选手,我们都能满足您的需求。我们的场地配备了先进的照明系统和舒适的休息区,让您在愉快的环境中享受网球运动。立即预定,开启您的网球之旅吧!</p>',
timePopup: false,
time: [
{type: 1, time: '3/16周日'},
{type: 2, time: '3/17周一'},
{type: 3, time: '3/18周二'},
],
currentTime: 0,
date: [
{type: 1, time: '06:00', disabled: false},
{type: 2, time: '07:00', disabled: false},
{type: 3, time: '08:00', disabled: false},
{type: 4, time: '09:00', disabled: false},
{type: 5, time: '10:00', disabled: true},
{type: 6, time: '11:00', disabled: false},
{type: 7, time: '12:00', disabled: false},
{type: 8, time: '13:00', disabled: true},
{type: 9, time: '14:00', disabled: false},
{type: 10, time: '15:00', disabled: true},
{type: 11, time: '16:00', disabled: true},
{type: 12, time: '17:00', disabled: false},
{type: 13, time: '18:00', disabled: false},
{type: 14, time: '19:00', disabled: false},
{type: 15, time: '20:00', disabled: false},
{type: 16, time: '21:00', disabled: false},
{type: 17, time: '22:00', disabled: false},
date: {
minimum_time: 2,
time: [
{
display: "12/02周二",
date: "2025-12-02",
time_slots: [
{start_time: "08:00", timestamp: 1764633600, datetime: "2025-12-02 08:00", disabled: 1},
{start_time: "09:00", timestamp: 1764637200, datetime: "2025-12-02 09:00", disabled: 1},
{start_time: "10:00", timestamp: 1764640800, datetime: "2025-12-02 10:00", disabled: 1},
{start_time: "11:00", timestamp: 1764644400, datetime: "2025-12-02 11:00", disabled: 1},
{start_time: "12:00", timestamp: 1764648000, datetime: "2025-12-02 12:00", disabled: 1},
{start_time: "13:00", timestamp: 1764651600, datetime: "2025-12-02 13:00", disabled: 1},
{start_time: "14:00", timestamp: 1764655200, datetime: "2025-12-02 14:00", disabled: 1},
{start_time: "15:00", timestamp: 1764658800, datetime: "2025-12-02 15:00", disabled: 1},
{start_time: "16:00", timestamp: 1764662400, datetime: "2025-12-02 16:00", disabled: 1},
{start_time: "17:00", timestamp: 1764666000, datetime: "2025-12-02 17:00", disabled: 1}
],
timestamp: 1764640505
],
},
{
display: "12/03周三",
date: "2025-12-03",
time_slots: [
{start_time: "08:00", timestamp: 1764633600, datetime: "2025-12-02 08:00", disabled: 1},
{start_time: "09:00", timestamp: 1764637200, datetime: "2025-12-02 09:00", disabled: 1},
{start_time: "10:00", timestamp: 1764640800, datetime: "2025-12-02 10:00", disabled: 1},
{start_time: "11:00", timestamp: 1764644400, datetime: "2025-12-02 11:00", disabled: 1},
{start_time: "12:00", timestamp: 1764648000, datetime: "2025-12-02 12:00", disabled: 1},
{start_time: "13:00", timestamp: 1764651600, datetime: "2025-12-02 13:00", disabled: 1},
{start_time: "14:00", timestamp: 1764655200, datetime: "2025-12-02 14:00", disabled: 1},
{start_time: "15:00", timestamp: 1764658800, datetime: "2025-12-02 15:00", disabled: 1},
{start_time: "16:00", timestamp: 1764662400, datetime: "2025-12-02 16:00", disabled: 1},
{start_time: "17:00", timestamp: 1764666000, datetime: "2025-12-02 17:00", disabled: 1}
],
timestamp: 1764640505
}
]
},
selectedTime: [],
countSelectedTime: 0,
billPopup: false,
loadding: true,
venue: {},
bannerData: {
data: [],
style: {btnColor: "#ffffff", background: "#ffffff", btnShape: "round", imgShape: "round", height: "330"}
},
};
},
onLoad(args) {
this.venueId = args.venueId || 0;
this.roomId = args.roomId || 0;
this.getData();
},
@ -193,16 +198,39 @@
uni.showLoading({
title: '加载中'
});
self._get(
'index/index',
// 获取场馆详情
self._post(
'ground.ground/groundDetails',
{
url: self.url
app_id: self.getAppId(),
id: self.venueId, // 场馆ID
latitude: uni.getStorageSync('latitude') || '',
longitude: uni.getStorageSync('longitude') || '',
},
function(res) {
self.bannerData = res.data.items[0];
console.log("🚀 ~ self.bannerData:", self.bannerData)
if (res.code) {
self.venue = res.data.lists
res.data.lists.image_arr.map(items => {
self.bannerData.data.push({imgUrl: items, height: '400px'})
})
}
}
);
)
// 获取时间预约
self._post(
'ground.ground/get7Time',
{
app_id: self.getAppId()
},
function(res) {
if (res.code) {
self.date = res.data.lists
}
self.loadding = false;
}
)
},
// 切换tab
@ -210,24 +238,6 @@
this.currentTab = e.type;
},
// 处理导航
handleLocation() {
uni.openLocation({
latitude: 30.74621,
longitude: 120.76055,
name: '秀湖网球中心',
address: '嘉兴市秀洲区秀园路秀湖公园(西南角)',
scale: 18
});
},
// 处理拨打电话
handleCall() {
uni.makePhoneCall({
phoneNumber: '0573-82069999'
});
},
// 选择时间
handleFilterTime(index) {
this.currentTime = index;
@ -258,13 +268,29 @@
this.timePopup = true;
},
// 预约时间选择回调
onSelectedTime(data) {
console.log("🚀 ~ data:", data)
// data: [selectedDay, selectedTime, selectedTimeStamp, countSelectedTime]
this.selectedTime = data[1] || [];
this.countSelectedTime = data[3] || 0;
uni.setStorageSync('reserveDate', data);
this.toConfirm()
},
// 确认订单
toConfirm() {
uni.navigateTo({
url: '/bundle/reserve/confirm'
url: `/bundle/reserve/confirm?venueId=${this.venue.id}&roomId=${this.roomId}`
});
},
confirmPicker(e) {
console.log("🚀 ~ e:", e)
}
}
};
}
</script>
<style lang="scss">

0
common/order.js Normal file
View File

326
components/booking-time.vue Normal file
View File

@ -0,0 +1,326 @@
<template>
<view class="time-block">
<view class="time-block-close" @click="showPopup = false">
<image class="" src="@/static/icon_close.png" style="width: 60rpx;height: 60rpx;"> </image>
</view>
<view class="time-title">选择时间</view>
<view class="time-yellow">
示例:07:00代表07:01-07:59
</view>
<view>
<view class="booking-time">
<!-- 顶部日期tab -->
<view class="tab-bar-scroll">
<view class="tab-bar">
<view v-for="(item, idx) in day.time" :key="item.display"
class="tab-bar-item"
:class="{active: idx === selectedDay}"
@click="handleTabClick(idx)">
{{ item.display }}
</view>
</view>
</view>
<!-- 时间格子 -->
<view v-if="day.time && day.time[selectedDay]">
<view class="time-grid-wrap">
<view class="time-grid">
<view v-for="item2 in day.time[selectedDay].time_slots" :key="item2.start_time"
class="time-cell"
:class="[
item2.disabled == 0
? 'cell-disabled'
: selectedTime.includes(item2.start_time)
? 'cell-selected'
: 'cell-normal'
]"
@click="item2.disabled == 1 && handleSelectTime(item2.start_time, item2.timestamp, day.time[selectedDay].time_slots)">
{{ item2.start_time }}
</view>
</view>
</view>
<!-- 分割线 -->
<view class="divider"></view>
<!-- 底部按钮 -->
<view class="time-footer">
<view class="btn-reset" @click="handleResetSelectedTime">重置</view>
<view class="btn-confirm" @click="handleConfirmSelectedTime">
<text>确定</text>
<text v-if="countSelectedTime">({{ countSelectedTime }}小时)</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'BookingTime',
props: {
value: { // v-model
type: Boolean,
default: false
},
day: {
type: Object,
default: () => ({})
}
},
data() {
return {
OSS: this.$root.OSS || '', // 或 inject 方式
showPopup: this.value,
selectedDay: 0,
selectedTime: [],
selectedTimeStamp: [],
countSelectedTime: 0
}
},
watch: {
value(val) {
this.showPopup = val
},
showPopup(val) {
this.$emit('input', val)
}
},
methods: {
handleTabClick(idx) {
if (this.selectedDay !== idx) {
this.selectedDay = idx;
this.handleChangeTimeTab();
}
},
handleSelectTime(time, timestamp, timeSlots) {
const availableSlots = timeSlots.filter(slot => slot.disabled == 1)
const times = availableSlots.map(slot => slot.start_time)
const timestamps = availableSlots.map(slot => slot.timestamp)
const idx = times.indexOf(time)
const selectedIdxArr = this.selectedTime.map(t => times.indexOf(t)).sort((a, b) => a - b)
if (this.selectedTime.length === 0) {
this.selectedTime = [time]
this.selectedTimeStamp = [timestamp]
} else if (this.selectedTime.includes(time)) {
const minIdx = selectedIdxArr[0]
const maxIdx = selectedIdxArr[selectedIdxArr.length - 1]
if (idx === minIdx) {
this.selectedTime = times.slice(idx + 1, maxIdx + 1)
this.selectedTimeStamp = timestamps.slice(idx + 1, maxIdx + 1)
} else if (idx === maxIdx) {
this.selectedTime = times.slice(minIdx, idx)
this.selectedTimeStamp = timestamps.slice(minIdx, idx)
} else {
this.selectedTime = times.slice(minIdx, idx)
this.selectedTimeStamp = timestamps.slice(minIdx, idx)
}
} else {
const allIdx = selectedIdxArr.concat(idx)
const minIdx = Math.min(...allIdx)
const maxIdx = Math.max(...allIdx)
this.selectedTime = times.slice(minIdx, maxIdx + 1)
this.selectedTimeStamp = timestamps.slice(minIdx, maxIdx + 1)
}
this.countSelectedTime = this.handleCalcContinuousHours(this.selectedTime)
},
handleConfirmSelectedTime() {
if (this.selectedTime.length === 0) {
uni.showToast({
title: '请选择时间',
icon: 'none'
});
return
}
if (this.countSelectedTime < this.day.minimum_time) {
uni.showToast({
title: this.day.minimum_time + '小时起订',
icon: 'none'
});
return
}
const data = [
this.day.time[this.selectedDay].display,
this.selectedTime.sort(),
this.selectedTimeStamp.sort(),
this.countSelectedTime,
this.day.time[this.selectedDay].date,
]
this.$emit('selectedTime', data)
this.showPopup = false
},
handleChangeTimeTab() {
this.selectedTime = []
this.selectedTimeStamp = []
this.countSelectedTime = 0
},
handleCalcContinuousHours(times) {
// 新逻辑:选中多少时间块就是多少小时
return times.length;
},
handleResetSelectedTime() {
this.selectedTime = []
this.selectedTimeStamp = []
}
}
}
</script>
<style lang="scss" scoped>
.booking-time {
/deep/ .wd-tabs__line {
background-color: #4C9F44 !important;
}
}
.tab-bar-scroll {
overflow-x: auto;
background: #fff;
}
.tab-bar {
display: flex;
flex-direction: row;
padding: 0 30rpx;
background: #fff;
}
.tab-bar-item {
flex-shrink: 0;
padding: 0 32rpx;
height: 62rpx;
line-height: 62rpx;
font-size: 32rpx;
color: #303133;
margin: 10rpx 16rpx 10rpx 0;
border-bottom: 4rpx solid transparent;
cursor: pointer;
}
.tab-bar-item.active {
color: #365A9A;
font-weight: bold;
position: relative;
}
.tab-bar-item.active::after {
content: '';
display: block;
width: 60rpx;
height: 10rpx;
background: #365A9A;
border-radius: 6rpx;
position: absolute;
left: 50%;
bottom: -10rpx;
transform: translateX(-50%);
}
.divider {
width: 100%;
height: 2rpx;
background: #E5E5E5;
margin: 32rpx 0 0 0;
}
.time-title {
font-size: 36rpx;
color: #121212;
line-height: 50rpx;
text-align: center;
padding-top: 50rpx;
padding-bottom: 40rpx;
}
.time-grid-wrap {
height: 500rpx;
margin-top: 30rpx;
}
.time-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20rpx 20rpx;
padding: 0 30rpx;
}
.time-cell {
height: 72rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
line-height: 40rpx;
box-sizing: border-box;
background: #F7F7F7;
color: #303133;
transition: background 0.2s, color 0.2s;
}
.cell-disabled {
background: #F7F7F7 !important;
color: #C9C9C9 !important;
}
.cell-selected {
background: #E6EFFF !important;
color: #365A9A !important;
}
.cell-normal {
background: #F7F7F7 !important;
color: #303133 !important;
}
.time-footer {
width: 100%;
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #fff;
height: 152rpx;
font-size: 32rpx;
line-height: 44rpx;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
z-index: 10;
}
.btn-reset {
width: 330rpx;
height: 90rpx;
background: #F6F7F8;
border-radius: 8rpx;
color: #303133;
margin-right: 30rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
}
.btn-confirm {
width: 330rpx;
height: 90rpx;
background: #365A9A;
border-radius: 8rpx;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
}
.time-block {
position: relative;
padding-bottom: 78rpx;
}
.time-block-close {
position: absolute;
top: 18rpx;
right: 30rpx;
}
.time-yellow {
width: 100%;
background: #FFFBE5;
font-weight: 500;
font-size: 26rpx;
color: #E2950F;
line-height: 56rpx;
padding: 10rpx 30rpx;
text-align: left;
}
</style>

179
components/reserve-time.vue Normal file
View File

@ -0,0 +1,179 @@
<template>
<view style="position: relative;">
<view class="uni-padding-wrap">
<view class="" style="font-size: 36rpx; line-height: 50rpx; color: #121212; text-align: center;width: 100%;margin-top: 52rpx;">选择时间</view>
<image src="@/static/icon/close2.png" style="width: 60rpx;height: 60rpx; position: absolute; top: 30rpx; right: 30rpx;" @click="closePopup"/>
</view>
<picker-view v-if="visible" :indicator-style="indicatorStyle" :value="value" @change="bindChange" class="picker-view">
<picker-view-column>
<view class="item" v-for="(item,index) in dateList" :key="index">{{item.label}}</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item,index) in hourList" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column>
<view class="item" v-for="(item,index) in minuteList" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
<view class="line"></view>
<view class="btn">
<view class="btn1" @click="reset">重置</view>
<view class="btn2" @click="confirm">确定</view>
</view>
</view>
</template>
<script>
export default {
data: function () {
const date = new Date();
const weekMap = ['日', '一', '二', '三', '四', '五', '六'];
// 生成前天、昨天、今天、明天、后天
const dateList = [];
for (let i = -2; i <= 2; i++) {
const d = new Date(date.getFullYear(), date.getMonth(), date.getDate() + i);
const mm = (d.getMonth() + 1).toString().padStart(2, '0');
const dd = d.getDate().toString().padStart(2, '0');
const week = weekMap[d.getDay()];
dateList.push({
label: `${mm}月${dd}日周${week}`,
date: d
});
}
// 小时 6-22
const hourList = [];
for (let i = 6; i <= 22; i++) {
hourList.push(i < 10 ? `0${i}` : `${i}`);
}
// 分钟 00\10\20\30\40\50
const minuteList = [];
for (let i = 0; i < 60; i += 10) {
minuteList.push(i < 10 ? `0${i}` : `${i}`);
}
// 默认选中今天
let dateIndex = 2;
// 当前小时和分钟
const now = new Date();
let hourIndex = hourList.findIndex(h => parseInt(h) === now.getHours());
if (hourIndex === -1) hourIndex = 0;
let minuteIndex = minuteList.findIndex(m => parseInt(m) === now.getMinutes());
if (minuteIndex === -1) minuteIndex = 0;
return {
title: 'picker-view',
dateList,
hourList,
minuteList,
value: [dateIndex, hourIndex, minuteIndex], // 默认选中今天、当前小时、当前分钟
visible: true,
indicatorStyle: `height: 50px;`
}
},
mounted() {
},
methods: {
bindChange: function (e) {
const val = e.detail.value;
// 选中项索引分别为dateList、hourList、minuteList
this.value = val;
},
// 重置
reset: function () {
const now = new Date();
// 日期始终选中“今天”
let dateIndex = 2;
// 重新生成小时列表,确保与当前小时对齐
const hourList = [];
for (let i = 6; i <= 21; i++) {
hourList.push(i < 10 ? `0${i}` : `${i}`);
}
let hourIndex = hourList.findIndex(h => parseInt(h) === now.getHours());
if (hourIndex === -1) hourIndex = 0;
// 重新生成分钟列表,确保与当前分钟对齐
const minuteList = [];
for (let i = 0; i < 60; i += 10) {
minuteList.push(i < 10 ? `0${i}` : `${i}`);
}
let minuteIndex = minuteList.findIndex(m => parseInt(m) === now.getMinutes());
if (minuteIndex === -1) minuteIndex = 0;
this.value = [dateIndex, hourIndex, minuteIndex];
},
// 确认
confirm() {
// 获取选中索引
const [dateIdx, hourIdx, minuteIdx] = this.value;
const dateObj = this.dateList[dateIdx];
const hour = this.hourList[hourIdx];
const minute = this.minuteList[minuteIdx];
// 传递给父组件
this.$emit('confirm', {
date: dateObj.date,
dateLabel: dateObj.label,
hour,
minute,
value: `${dateObj.label} ${hour}:${minute}`
});
this.$emit('close');
},
closePopup() {
this.$emit('close');
}
}
}
</script>
<style>
.uni-padding-wrap {
display: flex;
}
.picker-view {
width: 750rpx;
height: 600rpx;
margin-top: 20rpx;
}
.item {
line-height: 100rpx;
text-align: center;
}
.line {
margin-top: 62rpx;
height: 2rpx;
background: #E5E5E5;
}
.btn {
margin-top: 44rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
}
.btn1, .btn2 {
width: 335rpx;
height: 90rpx;
text-align: center;
line-height: 90rpx;
font-size: 32rpx;
border-radius: 8rpx;
margin-bottom: 60rpx;
}
.btn1 {
background: #F6F7F8;
color: #303133;
}
.btn2 {
background: #365A9A;
color: #fff;
}
</style>

View File

@ -1,5 +1,7 @@
//var app_url = 'http://www.jjj-shop.com';
var app_url = 'https://6548.cn';
// var app_url = 'https://6548.cn';
var app_url = 'https://xh.stnav.com';
// 如果是本地测试环境
if(process.env.NODE_ENV === 'development'){
//#ifdef H5

View File

@ -145,7 +145,7 @@
"quickapp" : {},
/* 快应用特有相关 */
"mp-weixin" : {
"appid" : "wxa184cbbc1bbe7621",
"appid" : "wx0f98e0cd9033a82b",
"setting" : {
"urlCheck" : false,
"es6" : true,
@ -153,9 +153,10 @@
"minified" : true
},
"usingComponents" : true,
"requiredPrivateInfos" : [ "getLocation" ],
"permission" : {
"scope.userLocation" : {
"desc" : "你的位置信息将用于小程序位置接口的效果展示"
"desc" : "获取您与体育场馆的距离"
}
}
},
@ -172,9 +173,9 @@
"base" : "/h5/"
},
"devServer" : {
"port" : 8080, //端口
"port" : 8080, //端口
"https" : true,
"disableHostCheck" : true,
"disableHostCheck" : true,
"proxy" : {
"/api" : {
"target" : "https://6548.cn",
@ -193,5 +194,5 @@
}
}
},
"sassImplementationName": "node-sass"
"sassImplementationName" : "node-sass"
}

View File

@ -1,17 +1,17 @@
<template>
<view :data-theme="theme()" :class="theme() || ''" style="padding-bottom: 44rpx;">
<view class="top_head pr" :style="'background-image: url(../../static/bg.png); background-size:100% auto;background-color:#F6F7F9;'">
<view class="top_head pr" :style="'background-image: url(https://xh.stnav.com/uploads/sport/ground2.png); background-size:100% auto;background-color:#F6F7F9;'">
<view class="head_top" :style="'height:' + topBarTop() + 'px;'"></view>
<view class="title" :style="topBarHeight() == 0 ? '' : 'height:' + topBarHeight() + 'px;'">
秀湖网球中心
</view>
</view>
<view :style="'background: url(../../static/bg.png) no-repeat; background-size:100% auto;'">
<view :style="'background: url(https://xh.stnav.com/uploads/sport/ground2.png) no-repeat; background-size:100% auto;'">
<view v-if="thisindex == 0"><diy style="position: relative;" :diyItems="items"></diy></view>
<view class="notice">
<image style="width: 40rpx;height: 40rpx;" src="@/static/icon/notice.png" mode=""></image>
<view class="notice-txt">目前仅开放1-2号场地预约,3-6号场地预约敬请期待</view>
<view class="notice-txt">{{ notice.notice_title }}</view>
</view>
<!-- 预约球馆 -->
@ -20,40 +20,21 @@
<image style="width: 126rpx;height: 36rpx;" src="@/static/yycg.png" mode=""></image>
<view class="title-txt">更多场馆信息立即预约</view>
</view>
<view class="ball">
<view class="ball" v-for="(item, index) in venueList" :key="index">
<view class="ball-info">
<image style="width: 690rpx;height: 320rpx;" src="@/static/wqzx.png" mode="aspectFit"></image>
<view class="ball-title">
<image style="width: 690rpx;height: 320rpx;" :src="item.image" mode="aspectFit"></image>
<!-- <view class="ball-title">
<image style="width: 108rpx;height: 160rpx;" src="@/static/wq.png" mode="aspectFill"></image>
<view style="background-image: url(../../static/wqbg.png);">
<image style="width: 160rpx;height: 44rpx;" src="@/static/wqyd_txt.png" mode="aspectFill"></image>
</view>
</view>
</view> -->
</view>
<view class="ball-time">
<view class="ball-center-title">秀湖网球中心</view>
<view class="ball-center-title">{{ item.name }}</view>
<view class="d-b-c">
<view class="reserve-time">营业时间:06:00-22:00</view>
<view class="reserve-btn" @tap="handleToReserve(BallType.Tennis)">立即预约</view>
</view>
</view>
</view>
<view class="ball">
<view class="ball-info">
<image style="width: 690rpx;height: 320rpx;" src="@/static/lqzx.png" mode="aspectFit"></image>
<view class="ball-title" style="bottom: 24rpx; left: 28rpx;">
<image style="width: 64rpx;height: 64rpx;" src="@/static/lq.png" mode="aspectFill"></image>
<view style="background-image: url(../../static/wqbg.png); bottom: 0; left: 20rpx;" >
<image style="width: 160rpx;height: 44rpx;" src="@/static/lqyd_txt.png" mode="aspectFill"></image>
</view>
</view>
</view>
<view class="ball-time">
<view class="ball-center-title">秀湖蓝球中心</view>
<view class="d-b-c ">
<view class="reserve-time">营业时间:06:00-22:00</view>
<view class="reserve-btn" @tap="handleToReserve(BallType.Basketball)">立即预约</view>
<view class="reserve-time">营业时间:{{ item.start_time }}-{{ item.end_time }}</view>
<view class="reserve-btn" @tap="handleToReserve(item.id, item.type_id)">立即预约</view>
</view>
</view>
</view>
@ -67,7 +48,7 @@
</view>
<view class="">
<image style="width: 690rpx;height: 292rpx; margin-top: 20rpx;" src="@/static/jcss.png" mode=""></image>
<image style="width: 690rpx;height: 292rpx; margin-top: 20rpx;" src="https://xh.stnav.com/uploads/sport/ground3.png" mode=""></image>
</view>
</view>
@ -79,17 +60,17 @@
</view>
<view class="d-b-c" style="margin-top: 34rpx;">
<view>
<image style="width: 116rpx;height: 134rpx;" src="@/static/kf.png" mode=""></image>
<image style="width: 116rpx;height: 134rpx;" src="https://xh.stnav.com/uploads/sport/ground4.png" mode=""></image>
</view>
<view class="">
<view class="d-f">
<image style="width: 24rpx;height: 24rpx;margin-top: 4rpx;" src="@/static/icon/address.png" mode=""></image>
<view class="address-time">嘉兴市秀洲区秀园路秀湖公园(西南角)</view>
<view class="address-time">{{ company.name }}</view>
</view>
<view class="d-f" style="margin-top: 8rpx;">
<image style="width: 24rpx;height: 24rpx;margin-top: 2rpx" src="@/static/icon/time.png" mode=""></image>
<view class="address-time" style="height: 32rpx;">营业时间:08:00-20:00</view>
<view class="address-time" style="height: 32rpx;">营业时间:{{ company.start_time }}-{{ company.end_time }}</view>
</view>
</view>
<view class="d-f">
@ -200,7 +181,10 @@ export default {
open: 0
},
noticePopup: false,
tipsPopup: false
tipsPopup: false,
venueList: [], // 场馆列表
notice: '',
company: {}
};
},
watch: {
@ -263,6 +247,24 @@ export default {
this.getData();
this.getList();
this.getTabbar();
// 获取经纬度
if (!uni.getStorageSync('longitude') || !uni.getStorageSync('latitude')) {
uni.getLocation({
type: 'wgs84',
success(res) {
uni.setStorageSync('longitude', res.longitude);
uni.setStorageSync('latitude', res.latitude);
},
fail() {
uni.showToast({
title: '获取定位失败,请点击右下角按钮打开定位权限',
duration: 2000,
icon:"none"
});
},
})
}
},
onPullDownRefresh() {
if (this.thisindex == 0) {
@ -301,6 +303,47 @@ export default {
uni.showLoading({
title: '加载中'
});
// 获取场馆列表
self._post(
'ground.ground/groundLists',
{
app_id: self.getAppId()
},
function(res) {
if (res.code) {
self.venueList = res.data.lists
}
}
)
// 获取公告
self._post(
'home.notice/noticeLists',
{
app_id: self.getAppId()
},
function(res) {
if (res.code) {
self.notice = res.data.lists[0]
console.log("🚀 ~ self.notice :", self.notice )
}
}
)
// 公司信息
self._post(
'home.index/company',
{
app_id: self.getAppId()
},
function(res) {
if (res.code) {
self.company = res.data.lists
}
}
)
self._get(
'index/index',
{
@ -544,10 +587,10 @@ export default {
// 处理导航
handleLocation() {
uni.openLocation({
latitude: 30.74621,
longitude: 120.76055,
name: '秀湖网球中心',
address: '嘉兴市秀洲区秀园路秀湖公园(西南角)',
latitude: this.company.latitude,
longitude: this.company.longitude,
name: this.company.name,
address: this.company.address,
scale: 18
});
},
@ -555,14 +598,14 @@ export default {
// 处理拨打电话
handleCall() {
uni.makePhoneCall({
phoneNumber: '0573-82069999'
phoneNumber: this.company.phone
});
},
// 场馆预约
handleToReserve(type) {
handleToReserve(id, typeId) {
uni.navigateTo({
url: '/bundle/reserve/details?type=' + type
url: `/bundle/reserve/details?id=${id}&typeId=${typeId}`
});
}
}

View File

@ -1,5 +1,5 @@
<template>
<view :data-theme='theme()' :class="theme() || ''" :style="'background-image: url(../../../static/my_bg.png); background-repeat: no-repeat; background-size:100% auto;background-color:#F6F7F9;padding-bottom: 40rpx;'">
<view :data-theme='theme()' :class="theme() || ''" :style="'background-image: url(https://xh.stnav.com/uploads/sport/ground1.png); background-repeat: no-repeat; background-size:100% auto;background-color:#F6F7F9;padding-bottom: 40rpx;'">
<!-- #ifdef APP-PLUS -->
<header-bar></header-bar>
<!-- #endif -->

Binary file not shown.

BIN
static/icon_close.png Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.