20 changed files with 1232 additions and 28 deletions
@ -0,0 +1,182 @@ |
|||||
|
// subpages/mine/mySpace/mySpace.js
|
||||
|
import { appointmentRecList } from "../../../api/index"; |
||||
|
Page({ |
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
list: [], |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
total: 0, |
||||
|
loading: false, |
||||
|
refreshing: false, |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad(options) {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow() { |
||||
|
this.setData({ |
||||
|
list: [], |
||||
|
pageNum: 1, |
||||
|
}); |
||||
|
this.getList(); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload() {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh() { |
||||
|
this.setData({ |
||||
|
refreshing: true, |
||||
|
pageNum: 1, |
||||
|
list: [] |
||||
|
}); |
||||
|
this.getList().finally(() => { |
||||
|
wx.stopPullDownRefresh(); |
||||
|
this.setData({ |
||||
|
refreshing: false |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom() {}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage() {}, |
||||
|
toReserve(e) { |
||||
|
wx.navigateTo({ |
||||
|
url: `/subpages/space/reserve/reserve?id=${e.currentTarget.dataset.item.id}`, |
||||
|
}); |
||||
|
}, |
||||
|
getList() { |
||||
|
if (this.data.loading) return; |
||||
|
|
||||
|
this.setData({ |
||||
|
loading: true |
||||
|
}); |
||||
|
|
||||
|
let parm = { |
||||
|
pageSize: this.data.pageSize, |
||||
|
pageNum: this.data.pageNum, |
||||
|
}; |
||||
|
|
||||
|
return appointmentRecList(parm) |
||||
|
.then((res) => { |
||||
|
if (res.code === 200) { |
||||
|
const newData = res.data.records.map((item) => { |
||||
|
return { |
||||
|
...item, |
||||
|
// 格式化预约日期和时间
|
||||
|
appointmentDate: item.appointmentDate || "", |
||||
|
appointTime: item.appointTime || "", |
||||
|
// 添加状态显示
|
||||
|
statusText: this.getStatusText(item), |
||||
|
statusColor: this.getStatusColor(item) |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
this.setData({ |
||||
|
list: this.data.pageNum === 1 ? newData : this.data.list.concat(newData), |
||||
|
total: res.data.total, |
||||
|
loading: false |
||||
|
}); |
||||
|
} |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
this.setData({ |
||||
|
loading: false |
||||
|
}); |
||||
|
wx.showToast({ |
||||
|
title: err.msg || "获取数据失败", |
||||
|
duration: 2000, |
||||
|
icon: "none", |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
scrolltolower() { |
||||
|
if (this.data.loading) return; |
||||
|
|
||||
|
if (this.data.list.length < this.data.total) { |
||||
|
this.setData({ |
||||
|
pageNum: this.data.pageNum + 1, |
||||
|
}); |
||||
|
this.getList(); |
||||
|
} else if (this.data.list.length > 0) { |
||||
|
wx.showToast({ |
||||
|
icon: "none", |
||||
|
title: "没有更多了", |
||||
|
}); |
||||
|
} |
||||
|
}, |
||||
|
toEvaluate(e) { |
||||
|
wx.navigateTo({ |
||||
|
url: `/subpages/mine/evaluate/evaluate?id=${ |
||||
|
e.currentTarget.dataset.item.checkInRecId |
||||
|
}&obj=${JSON.stringify({ |
||||
|
apartmentName: e.currentTarget.dataset.item.apartmentName, |
||||
|
buildingName: e.currentTarget.dataset.item.buildingName, |
||||
|
buildingName: e.currentTarget.dataset.item.buildingName, |
||||
|
roomType: e.currentTarget.dataset.item.roomType, |
||||
|
unitName: e.currentTarget.dataset.item.unitName, |
||||
|
checkInRecId: e.currentTarget.dataset.item.checkInRecId, |
||||
|
houseName: e.currentTarget.dataset.item.houseName, |
||||
|
})}`,
|
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 获取状态文本
|
||||
|
getStatusText(item) { |
||||
|
// 根据实际业务逻辑判断状态
|
||||
|
const now = new Date(); |
||||
|
const appointmentDate = new Date(item.appointmentDate); |
||||
|
|
||||
|
if (appointmentDate > now) { |
||||
|
return '已预约'; |
||||
|
} else if (appointmentDate.toDateString() === now.toDateString()) { |
||||
|
return '使用中'; |
||||
|
} else { |
||||
|
return '已完成'; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
// 获取状态颜色
|
||||
|
getStatusColor(item) { |
||||
|
const now = new Date(); |
||||
|
const appointmentDate = new Date(item.appointmentDate); |
||||
|
|
||||
|
if (appointmentDate > now) { |
||||
|
return '#17C4C4'; // 已预约 - 青色
|
||||
|
} else if (appointmentDate.toDateString() === now.toDateString()) { |
||||
|
return '#FA9E0A'; // 使用中 - 橙色
|
||||
|
} else { |
||||
|
return '#999'; // 已完成 - 灰色
|
||||
|
} |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"no-data": "../../../components/noData/nodata", |
||||
|
"van-divider": "@vant/weapp/divider/index", |
||||
|
"van-button": "@vant/weapp/button/index", |
||||
|
"van-rate": "@vant/weapp/rate/index" |
||||
|
}, |
||||
|
"navigationBarTitleText": "我的共享空间", |
||||
|
"enablePullDownRefresh": true, |
||||
|
"backgroundTextStyle": "dark" |
||||
|
} |
@ -0,0 +1,32 @@ |
|||||
|
<!-- subpages/mine/mySpace/mySpace.wxml --> |
||||
|
<scroll-view scroll-y class="scroll-view" bindscrolltolower="scrolltolower" wx:if="{{list.length>0}}" enable-back-to-top refresher-enabled="{{true}}" bindrefresherrefresh="onPullDownRefresh" refresher-triggered="{{refreshing}}"> |
||||
|
<view class="card" wx:key="id" wx:for="{{list}}"> |
||||
|
<view class="flex flex-sb"> |
||||
|
<view class="name font-bold">{{item.apartmentName}}</view> |
||||
|
</view> |
||||
|
<van-divider dashed /> |
||||
|
<view class="item flex"> |
||||
|
<image src="{{item.imgUrls[0]}}" style="width: 200rpx;height:152rpx;margin-right: 16rpx;border-radius: 10rpx;" mode="aspectFill" /> |
||||
|
<view class="flex flex-col flex-1"> |
||||
|
<view class="space-name font-bold" style="margin:10rpx 0 10rpx 0;"> |
||||
|
{{item.name}} |
||||
|
</view> |
||||
|
<view class="address" style="color: #666; font-size: 28rpx; margin-bottom: 10rpx;"> |
||||
|
{{item.address}} |
||||
|
</view> |
||||
|
<view class="date" style="color: #333; font-size: 28rpx; margin-bottom: 10rpx;"> |
||||
|
{{item.appointmentDate}} {{item.appointTime}} |
||||
|
</view> |
||||
|
<view class="status" style="color:{{item.statusColor}}; font-size: 28rpx;"> |
||||
|
{{item.statusText}} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 加载更多提示 --> |
||||
|
<view class="loading-more" wx:if="{{loading}}" style="text-align: center; padding: 20rpx; color: #999;"> |
||||
|
加载中... |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
<no-data isShow="{{list.length === 0 && !loading}}"></no-data> |
@ -0,0 +1,37 @@ |
|||||
|
/* subpages/mine/mySpace/mySpace.wxss */ |
||||
|
|
||||
|
|
||||
|
.name { |
||||
|
font-size: 32rpx; |
||||
|
} |
||||
|
|
||||
|
.position { |
||||
|
font-size: 30rpx; |
||||
|
line-height: 32rpx; |
||||
|
} |
||||
|
|
||||
|
.date { |
||||
|
font-size: 26rpx; |
||||
|
color: #BFBFBF; |
||||
|
line-height: 40rpx; |
||||
|
} |
||||
|
.status{ |
||||
|
font-size: 26rpx; |
||||
|
margin-top: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.doc { |
||||
|
color: #08b3b3; |
||||
|
font-size: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.scroll-view { |
||||
|
padding: 20rpx; |
||||
|
box-sizing: border-box; |
||||
|
background: #eff0f3; |
||||
|
min-height: 100vh; |
||||
|
} |
@ -0,0 +1,202 @@ |
|||||
|
// subpages/space/list/list.js
|
||||
|
import { spacePage } from "../../../api/index"; |
||||
|
Page({ |
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
list: [], |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
total: 0, |
||||
|
loading: false, |
||||
|
hasMore: true, |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad(options) {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow() { |
||||
|
this.getList(true); // 页面显示时刷新数据
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload() {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh() { |
||||
|
this.getList(true); // 下拉刷新
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom() { |
||||
|
this.loadMore(); // 上拉加载更多
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage() {}, |
||||
|
toReserve(e) { |
||||
|
wx.navigateTo({ |
||||
|
url: `/subpages/space/reserve/reserve?id=${e.currentTarget.dataset.item.id}&roomName=${e.currentTarget.dataset.item.name}&openDate=${e.currentTarget.dataset.item.appointmentWeekText}&openTimeText=${e.currentTarget.dataset.item.appointmentTimeText}&imgUrls=${e.currentTarget.dataset.item.imgUrls}`, |
||||
|
}); |
||||
|
}, |
||||
|
getList(isRefresh = false) { |
||||
|
// 如果正在加载中,直接返回
|
||||
|
if (this.data.loading) return; |
||||
|
|
||||
|
// 如果是刷新,重置分页参数
|
||||
|
if (isRefresh) { |
||||
|
this.setData({ |
||||
|
pageNum: 1, |
||||
|
list: [], |
||||
|
hasMore: true, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 如果没有更多数据,直接返回
|
||||
|
if (!this.data.hasMore && !isRefresh) { |
||||
|
wx.showToast({ |
||||
|
icon: "none", |
||||
|
title: "没有更多了", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.setData({ loading: true }); |
||||
|
|
||||
|
let parm = { |
||||
|
pageSize: this.data.pageSize, |
||||
|
pageNum: this.data.pageNum, |
||||
|
}; |
||||
|
|
||||
|
spacePage(parm) |
||||
|
.then((res) => { |
||||
|
if (res.code === 200) { |
||||
|
const newData = res.data.records.map((item) => { |
||||
|
return { |
||||
|
...item, |
||||
|
// 处理可预约周几的显示
|
||||
|
appointmentWeekText: this.formatAppointmentWeek( |
||||
|
item.appointmentWeek |
||||
|
), |
||||
|
// 处理预约时间段的显示
|
||||
|
appointmentTimeText: this.formatAppointmentTime( |
||||
|
item.appointmentTimeAm, |
||||
|
item.appointmentTimePm |
||||
|
), |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
const currentList = isRefresh ? [] : this.data.list; |
||||
|
const updatedList = currentList.concat(newData); |
||||
|
|
||||
|
// 判断是否还有更多数据
|
||||
|
const hasMore = newData.length === this.data.pageSize && updatedList.length < res.data.total; |
||||
|
|
||||
|
this.setData({ |
||||
|
list: updatedList, |
||||
|
total: res.data.total, |
||||
|
hasMore: hasMore, |
||||
|
loading: false, |
||||
|
}); |
||||
|
|
||||
|
// 如果是下拉刷新,停止刷新动画
|
||||
|
if (isRefresh) { |
||||
|
wx.stopPullDownRefresh(); |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
.catch((err) => { |
||||
|
this.setData({ loading: false }); |
||||
|
|
||||
|
wx.showToast({ |
||||
|
title: err.msg || "加载失败", |
||||
|
duration: 2000, |
||||
|
icon: "none", |
||||
|
}); |
||||
|
|
||||
|
// 如果是下拉刷新,停止刷新动画
|
||||
|
if (isRefresh) { |
||||
|
wx.stopPullDownRefresh(); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
scrolltolower() { |
||||
|
this.loadMore(); |
||||
|
}, |
||||
|
|
||||
|
loadMore() { |
||||
|
if (!this.data.hasMore) { |
||||
|
wx.showToast({ |
||||
|
icon: "none", |
||||
|
title: "没有更多了", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 增加页码
|
||||
|
this.setData({ |
||||
|
pageNum: this.data.pageNum + 1, |
||||
|
}); |
||||
|
|
||||
|
this.getList(); |
||||
|
}, |
||||
|
|
||||
|
// 格式化可预约周几
|
||||
|
formatAppointmentWeek(appointmentWeek) { |
||||
|
if (!appointmentWeek || !Array.isArray(appointmentWeek)) { |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
// 将中文周几转换为显示格式
|
||||
|
const weekMap = { |
||||
|
一: "周一", |
||||
|
二: "周二", |
||||
|
三: "周三", |
||||
|
四: "周四", |
||||
|
五: "周五", |
||||
|
六: "周六", |
||||
|
日: "周日", |
||||
|
}; |
||||
|
|
||||
|
return appointmentWeek.map((week) => weekMap[week] || week).join(","); |
||||
|
}, |
||||
|
|
||||
|
// 格式化预约时间段
|
||||
|
formatAppointmentTime(appointmentTimeAm, appointmentTimePm) { |
||||
|
const timeSlots = []; |
||||
|
|
||||
|
if (appointmentTimeAm) { |
||||
|
timeSlots.push(`上午 ${appointmentTimeAm}`); |
||||
|
} |
||||
|
|
||||
|
if (appointmentTimePm) { |
||||
|
timeSlots.push(`下午 ${appointmentTimePm}`); |
||||
|
} |
||||
|
|
||||
|
return timeSlots.join(" "); |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,11 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"no-data": "../../../components/noData/nodata", |
||||
|
"van-divider": "@vant/weapp/divider/index", |
||||
|
"van-button": "@vant/weapp/button/index", |
||||
|
"van-rate": "@vant/weapp/rate/index" |
||||
|
}, |
||||
|
"navigationBarTitleText": "共享空间", |
||||
|
"enablePullDownRefresh": true, |
||||
|
"onReachBottomDistance": 50 |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
<!-- subpages/space/list/list.wxml --> |
||||
|
<scroll-view scroll-y class="scroll-view" bindscrolltolower="scrolltolower" wx:if="{{list.length>0}}"> |
||||
|
<view class="card " wx:key="index" wx:for="{{list}}"> |
||||
|
<view class="item flex"> |
||||
|
<image src="{{item.imgUrls[0]}}" style="width: 200rpx;height:152rpx;margin-right: 16rpx;border-radius: 10rpx;" mode="" /> |
||||
|
<view class="flex flex-col flex-1"> |
||||
|
<!-- <view class="flex flex-sb"> |
||||
|
<view class="name font-bold">{{item.name}}</view> |
||||
|
</view> --> |
||||
|
<view class="position" style="margin:10rpx 0 10rpx 0;"> |
||||
|
{{item.name}} |
||||
|
</view> |
||||
|
<view class="date">{{item.appointmentWeekText}}</view> |
||||
|
<view class="date" wx:if="{{item.appointmentTimeText}}">{{item.appointmentTimeText}}</view> |
||||
|
<view class="date" wx:if="{{item.status==='1'}}">{{item.inDate}} 至 {{item.outDate}}</view> |
||||
|
<view class="date" wx:if="{{item.status==='5'}}"> |
||||
|
{{item.inDate}} 至 {{item.actualOutDate}} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
<!-- <van-divider dashed /> --> |
||||
|
<view class="flex flex-sb px-20 btn"> |
||||
|
<van-button round size="small" bind:click="toReserve" data-item="{{item}}" color="linear-gradient(to right, #0DC6C6, #13C2C2,#46DBD5)" custom-style="position:absolute;right:0rpx;bottom:-60rpx;"> |
||||
|
预约 |
||||
|
</van-button> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 加载更多提示 --> |
||||
|
<view wx:if="{{list.length > 0}}" class="load-more"> |
||||
|
<view wx:if="{{loading}}" class="loading-text"> |
||||
|
<text>加载中...</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
|
||||
|
<no-data isShow="{{list.length === 0 && !loading}}"></no-data> |
@ -0,0 +1,60 @@ |
|||||
|
/* subpages/space/list/list.wxss */ |
||||
|
.card{ |
||||
|
height:280rpx ; |
||||
|
} |
||||
|
.name { |
||||
|
font-size: 32rpx; |
||||
|
} |
||||
|
.position{ |
||||
|
font-size: 30rpx; |
||||
|
line-height: 32rpx; |
||||
|
} |
||||
|
.date { |
||||
|
font-size: 26rpx; |
||||
|
color: #BFBFBF; |
||||
|
line-height: 40rpx; |
||||
|
} |
||||
|
.btn{ |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.doc { |
||||
|
color: #08b3b3; |
||||
|
font-size: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.scroll-view { |
||||
|
padding: 20rpx; |
||||
|
box-sizing: border-box; |
||||
|
background: #eff0f3; |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
|
||||
|
/* 加载更多样式 */ |
||||
|
.load-more { |
||||
|
padding: 20rpx 0; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.loading-text, .no-more-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #999; |
||||
|
} |
||||
|
|
||||
|
.loading-text text::before { |
||||
|
content: ''; |
||||
|
display: inline-block; |
||||
|
width: 20rpx; |
||||
|
height: 20rpx; |
||||
|
border: 2rpx solid #ccc; |
||||
|
border-top-color: #0DC6C6; |
||||
|
border-radius: 50%; |
||||
|
animation: spin 1s linear infinite; |
||||
|
margin-right: 10rpx; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
|
||||
|
@keyframes spin { |
||||
|
0% { transform: rotate(0deg); } |
||||
|
100% { transform: rotate(360deg); } |
||||
|
} |
@ -0,0 +1,338 @@ |
|||||
|
// subpages/space/reserve/reserve.js
|
||||
|
import { appointment, spaceInfo } from "../../../api/index"; |
||||
|
Page({ |
||||
|
|
||||
|
/** |
||||
|
* 页面的初始数据 |
||||
|
*/ |
||||
|
data: { |
||||
|
bannerUrl: 'https://img.yzcdn.cn/vant/cat.jpeg', |
||||
|
roomName: '第一会议室', |
||||
|
openDate: '周一至周五', |
||||
|
openTimeText: '上午09:00-下午18:00', |
||||
|
dateList: [], |
||||
|
selectedDateIndex: 0, |
||||
|
timeSlots: [], |
||||
|
rangeStartIndex: -1, |
||||
|
rangeEndIndex: -1, |
||||
|
chosenText: '', |
||||
|
spaceDetail: null, |
||||
|
appointDates: [], |
||||
|
appointmentTimes: [] |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面加载 |
||||
|
*/ |
||||
|
onLoad(options) { |
||||
|
console.log("11",options); |
||||
|
this.setData({ |
||||
|
id: options.id, |
||||
|
roomName: options.roomName, |
||||
|
openDate: options.openDate, |
||||
|
openTimeText: options.openTimeText, |
||||
|
bannerUrl: options.imgUrls, |
||||
|
}); |
||||
|
this.getDetail(); // 获取详情后会自动初始化日期和时间段
|
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面初次渲染完成 |
||||
|
*/ |
||||
|
onReady() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面显示 |
||||
|
*/ |
||||
|
onShow() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面隐藏 |
||||
|
*/ |
||||
|
onHide() {}, |
||||
|
|
||||
|
/** |
||||
|
* 生命周期函数--监听页面卸载 |
||||
|
*/ |
||||
|
onUnload() {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面相关事件处理函数--监听用户下拉动作 |
||||
|
*/ |
||||
|
onPullDownRefresh() {}, |
||||
|
|
||||
|
/** |
||||
|
* 页面上拉触底事件的处理函数 |
||||
|
*/ |
||||
|
onReachBottom() {}, |
||||
|
|
||||
|
/** |
||||
|
* 用户点击右上角分享 |
||||
|
*/ |
||||
|
onShareAppMessage() { }, |
||||
|
// 获取详情
|
||||
|
getDetail() { |
||||
|
spaceInfo({ id: this.data.id }).then(res => { |
||||
|
console.log(res); |
||||
|
if (res.code === 200 && res.data) { |
||||
|
this.setData({ |
||||
|
spaceDetail: res.data, |
||||
|
appointDates: res.data.appointDates || [], |
||||
|
appointmentTimes: res.data.appointmentTimes || [] |
||||
|
}); |
||||
|
// 根据接口数据初始化日期和时间段
|
||||
|
this.initDatesFromAPI(); |
||||
|
this.initTimeSlotsFromAPI(); |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
wx.showToast({ |
||||
|
title: err.msg || '获取详情失败', |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
}) |
||||
|
}, |
||||
|
|
||||
|
initDates() { |
||||
|
const weekMap = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; |
||||
|
const today = new Date(); |
||||
|
const dates = []; |
||||
|
for (let i = 0; i < 7; i++) { |
||||
|
const d = new Date(today.getFullYear(), today.getMonth(), today.getDate() + i); |
||||
|
const isToday = i === 0; |
||||
|
dates.push({ |
||||
|
label: isToday ? '今天' : weekMap[d.getDay()], |
||||
|
day: d.getDate(), |
||||
|
date: `${d.getFullYear()}-${('0' + (d.getMonth() + 1)).slice(-2)}-${('0' + d.getDate()).slice(-2)}`, |
||||
|
}); |
||||
|
} |
||||
|
this.setData({ |
||||
|
dateList: dates, |
||||
|
selectedDateIndex: 0, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 根据接口数据初始化日期
|
||||
|
initDatesFromAPI() { |
||||
|
const { appointDates } = this.data; |
||||
|
if (!appointDates || appointDates.length === 0) { |
||||
|
this.initDates(); // 如果没有接口数据,使用默认逻辑
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const today = new Date().toISOString().split('T')[0]; // 今天的日期 YYYY-MM-DD
|
||||
|
const dates = appointDates.map((item, index) => { |
||||
|
const date = new Date(item.appointDate); |
||||
|
const isToday = item.appointDate === today; |
||||
|
return { |
||||
|
label: isToday ? '今天' : item.week, |
||||
|
day: date.getDate(), |
||||
|
date: item.appointDate, |
||||
|
canAppoint: item.canAppoint, |
||||
|
disabled: !item.canAppoint |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
// 找到第一个可预约的日期作为默认选中
|
||||
|
let defaultIndex = 0; |
||||
|
for (let i = 0; i < dates.length; i++) { |
||||
|
if (dates[i].canAppoint) { |
||||
|
defaultIndex = i; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
this.setData({ |
||||
|
dateList: dates, |
||||
|
selectedDateIndex: defaultIndex, |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
initTimeSlots() { |
||||
|
const ranges = [ |
||||
|
['09:00', '09:30'], ['09:30', '10:00'], ['10:00', '10:30'], ['10:30', '11:00'], |
||||
|
['11:00', '11:30'], ['11:30', '12:00'], ['12:00', '12:30'], ['12:30', '13:00'], |
||||
|
['13:00', '13:30'], ['13:30', '14:00'], ['14:00', '14:30'], ['14:30', '15:00'], |
||||
|
['15:00', '15:30'], ['15:30', '16:00'], ['16:00', '16:30'], ['16:30', '17:00'], |
||||
|
['17:00', '17:30'], ['17:30', '18:00'], ['18:00', '18:30'], ['18:30', '19:00'], |
||||
|
]; |
||||
|
const slots = ranges.map((r, idx) => ({ |
||||
|
id: `${r[0]}-${r[1]}`, |
||||
|
start: r[0], |
||||
|
end: r[1], |
||||
|
status: idx < 3 ? 'disabled' : 'available' |
||||
|
})); |
||||
|
this.setData({ timeSlots: slots, rangeStartIndex: -1, rangeEndIndex: -1, chosenText: '' }); |
||||
|
}, |
||||
|
|
||||
|
// 根据接口数据初始化时间段
|
||||
|
initTimeSlotsFromAPI() { |
||||
|
const { appointmentTimes } = this.data; |
||||
|
if (!appointmentTimes || appointmentTimes.length === 0) { |
||||
|
this.initTimeSlots(); // 如果没有接口数据,使用默认逻辑
|
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const slots = appointmentTimes.map((item, index) => { |
||||
|
// 解析时间段,例如 "09:00至09:29" -> start: "09:00", end: "09:29"
|
||||
|
const timeMatch = item.appointmentTime.match(/(\d{2}:\d{2})至(\d{2}:\d{2})/); |
||||
|
let start = '00:00'; |
||||
|
let end = '00:30'; |
||||
|
|
||||
|
if (timeMatch) { |
||||
|
start = timeMatch[1]; |
||||
|
end = timeMatch[2]; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
id: item.id, |
||||
|
apiId: item.id, // 保存接口返回的ID
|
||||
|
start: start, |
||||
|
end: end, |
||||
|
timeText: item.appointmentTime, |
||||
|
status: item.canAppoint ? 'available' : 'disabled' |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
this.setData({ |
||||
|
timeSlots: slots, |
||||
|
rangeStartIndex: -1, |
||||
|
rangeEndIndex: -1, |
||||
|
chosenText: '' |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
selectDate(e) { |
||||
|
const { index } = e.currentTarget.dataset; |
||||
|
const selectedDate = this.data.dateList[index]; |
||||
|
|
||||
|
// 检查是否可预约
|
||||
|
if (selectedDate.disabled) { |
||||
|
wx.showToast({ |
||||
|
title: '该日期不可预约', |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.setData({ selectedDateIndex: index }); |
||||
|
this.initTimeSlotsFromAPI(); // 使用接口数据初始化时间段
|
||||
|
}, |
||||
|
|
||||
|
toggleSlot(e) { |
||||
|
const { index } = e.currentTarget.dataset; |
||||
|
const list = this.data.timeSlots.slice(); |
||||
|
const slot = list[index]; |
||||
|
if (slot.status === 'disabled') return; |
||||
|
|
||||
|
const { rangeStartIndex, rangeEndIndex } = this.data; |
||||
|
|
||||
|
// 无选择 -> 单选
|
||||
|
if (rangeStartIndex === -1) { |
||||
|
for (let i = 0; i < list.length; i++) if (list[i].status === 'selected') list[i].status = 'available'; |
||||
|
list[index].status = 'selected'; |
||||
|
this.setData({ |
||||
|
timeSlots: list, |
||||
|
rangeStartIndex: index, |
||||
|
rangeEndIndex: index, |
||||
|
chosenText: `${slot.start} - ${slot.end}` |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 已有单选
|
||||
|
if (rangeStartIndex !== -1 && rangeEndIndex === rangeStartIndex) { |
||||
|
// 点击同一格 -> 清空
|
||||
|
if (index === rangeStartIndex) { |
||||
|
list[index].status = 'available'; |
||||
|
this.setData({ timeSlots: list, rangeStartIndex: -1, rangeEndIndex: -1, chosenText: '' }); |
||||
|
return; |
||||
|
} |
||||
|
// 点击另一格 -> 扩展成区间(需避开禁用)
|
||||
|
const start = Math.min(rangeStartIndex, index); |
||||
|
const end = Math.max(rangeStartIndex, index); |
||||
|
for (let i = start; i <= end; i++) if (list[i].status === 'disabled') { |
||||
|
wx.showToast({ icon: 'none', title: '所选区间包含不可预约时段' }); |
||||
|
return; |
||||
|
} |
||||
|
for (let i = start; i <= end; i++) list[i].status = 'selected'; |
||||
|
this.setData({ |
||||
|
timeSlots: list, |
||||
|
rangeStartIndex: start, |
||||
|
rangeEndIndex: end, |
||||
|
chosenText: `${list[start].start} - ${list[end].end}` |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 已有区间 -> 下一次点击无论何处都折叠为所点单格
|
||||
|
if (rangeStartIndex !== -1 && rangeEndIndex !== -1) { |
||||
|
// 清空之前区间
|
||||
|
for (let i = 0; i < list.length; i++) { |
||||
|
if (list[i].status === 'selected') list[i].status = 'available'; |
||||
|
} |
||||
|
// 选中新点为单选
|
||||
|
list[index].status = 'selected'; |
||||
|
this.setData({ |
||||
|
timeSlots: list, |
||||
|
rangeStartIndex: index, |
||||
|
rangeEndIndex: index, |
||||
|
chosenText: `${list[index].start} - ${list[index].end}` |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
confirmReserve() { |
||||
|
const { rangeStartIndex, rangeEndIndex, timeSlots, selectedDateIndex, dateList, id } = this.data; |
||||
|
if (rangeStartIndex === -1) { |
||||
|
wx.showToast({ icon: 'none', title: '请先选择预约时段' }); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
const start = rangeStartIndex; |
||||
|
const end = rangeEndIndex === -1 ? rangeStartIndex : rangeEndIndex; |
||||
|
const selectedDate = dateList[selectedDateIndex]; |
||||
|
const startSlot = timeSlots[start]; |
||||
|
const endSlot = timeSlots[end]; |
||||
|
|
||||
|
// 收集选中的时间段ID
|
||||
|
const selectedTimeIds = []; |
||||
|
for (let i = start; i <= end; i++) { |
||||
|
if (timeSlots[i].apiId) { |
||||
|
selectedTimeIds.push(timeSlots[i].apiId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const appointmentData = { |
||||
|
shareSpaceId: id, |
||||
|
appointmentDate: selectedDate.date, |
||||
|
timeIds: selectedTimeIds, |
||||
|
}; |
||||
|
|
||||
|
console.log('预约数据:', appointmentData); |
||||
|
|
||||
|
// 调用预约接口
|
||||
|
appointment(appointmentData).then(res => { |
||||
|
if (res.code === 200) { |
||||
|
wx.showToast({ |
||||
|
title: '预约成功', |
||||
|
icon: 'success' |
||||
|
}); |
||||
|
// 可以跳转到预约成功页面或返回上一页
|
||||
|
setTimeout(() => { |
||||
|
wx.navigateBack(); |
||||
|
}, 1500); |
||||
|
} else { |
||||
|
wx.showToast({ |
||||
|
title: res.msg || '预约失败', |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
} |
||||
|
}).catch(err => { |
||||
|
wx.showToast({ |
||||
|
title: err.msg || '预约失败', |
||||
|
icon: 'none' |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
}) |
@ -0,0 +1,8 @@ |
|||||
|
{ |
||||
|
"usingComponents": { |
||||
|
"van-image": "@vant/weapp/image/index", |
||||
|
"van-divider": "@vant/weapp/divider/index", |
||||
|
"van-button": "@vant/weapp/button/index", |
||||
|
"van-tag": "@vant/weapp/tag/index" |
||||
|
} |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
<!-- subpages/space/reserve/reserve.wxml --> |
||||
|
<view class="page"> |
||||
|
<view class="banner"> |
||||
|
<van-image width="100%" height="360rpx" src="{{bannerUrl}}" fit="cover" radius="0" /> |
||||
|
</view> |
||||
|
<view class=" banner-overlay"> |
||||
|
<view class="room-name">{{roomName}}</view> |
||||
|
<view class="open-time">{{openDate}}</view> |
||||
|
<view class="open-time">{{openTimeText}}</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="section"> |
||||
|
<scroll-view scroll-x class="date-strip"> |
||||
|
<view class="date-item {{selectedDateIndex === index ? 'active' : ''}} {{item.disabled ? 'disabled' : ''}}" wx:for="{{dateList}}" wx:key="index" data-index="{{index}}" bindtap="selectDate"> |
||||
|
<view class="date-label">{{item.label}}</view> |
||||
|
<view class="date-day">{{item.day}}</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
<view class="section-title">预约时段</view> |
||||
|
<view class="slot-grid"> |
||||
|
<view wx:for="{{timeSlots}}" wx:key="index" class="slot {{item.status}}" data-index="{{index}}" bindtap="toggleSlot"> |
||||
|
<view class="slot-line">{{item.start}}</view> |
||||
|
<view class="slot-sep">至</view> |
||||
|
<view class="slot-line">{{item.end}}</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<view class="chosen" wx:if="{{chosenText}}">已选择:{{chosenText}}</view> |
||||
|
</view> |
||||
|
<view class="footer"> |
||||
|
<van-button type="primary" block round color="linear-gradient(90deg, #0DC6C6, #13C2C2, #46DBD5)" custom-style="width:400rpx;height:76rpx;" bind:click="confirmReserve"> |
||||
|
确定 |
||||
|
</van-button> |
||||
|
</view> |
||||
|
</view> |
@ -0,0 +1,131 @@ |
|||||
|
/* subpages/space/reserve/reserve.wxss */ |
||||
|
.page { |
||||
|
background: #f8f8f8; |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
.banner { |
||||
|
position: relative; |
||||
|
} |
||||
|
.banner-overlay { |
||||
|
padding: 20rpx; |
||||
|
background: #fff; |
||||
|
} |
||||
|
.room-name { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
.open-time { |
||||
|
margin-top: 8rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #BFBFBF; |
||||
|
} |
||||
|
.section { |
||||
|
margin: 0 18rpx; |
||||
|
margin-top: 12rpx; |
||||
|
padding: 18rpx; |
||||
|
background: #fff; |
||||
|
border-radius: 20rpx; |
||||
|
|
||||
|
} |
||||
|
.section-row{ |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
.section-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
margin-bottom: 16rpx; |
||||
|
margin-left: 10rpx; |
||||
|
} |
||||
|
.range-switch{ |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
color: #666; |
||||
|
font-size: 26rpx; |
||||
|
} |
||||
|
.date-strip { |
||||
|
white-space: nowrap; |
||||
|
padding-bottom: 12rpx; |
||||
|
} |
||||
|
.date-item { |
||||
|
display: inline-flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
width: 100rpx; |
||||
|
height: 120rpx; |
||||
|
border-radius: 16rpx; |
||||
|
color: #666; |
||||
|
margin-right: 16rpx; |
||||
|
} |
||||
|
.date-item .date-label { |
||||
|
font-size: 26rpx; |
||||
|
} |
||||
|
.date-item .date-day { |
||||
|
margin-top: 8rpx; |
||||
|
width: 56rpx; |
||||
|
height: 56rpx; |
||||
|
line-height: 56rpx; |
||||
|
text-align: center; |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
.date-item.active { |
||||
|
/* background: #e6fffb; */ |
||||
|
color: #13c2c2; |
||||
|
} |
||||
|
.date-item.active .date-day { |
||||
|
background: #13c2c2; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.date-item.disabled { |
||||
|
color: #bfbfbf; |
||||
|
opacity: 0.5; |
||||
|
} |
||||
|
.date-item.disabled .date-day { |
||||
|
background: #f0f0f0; |
||||
|
color: #bfbfbf; |
||||
|
} |
||||
|
.slot-grid { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
margin-top: 12rpx; |
||||
|
} |
||||
|
.slot { |
||||
|
width: calc(25% - 16rpx); |
||||
|
margin-right: 16rpx; |
||||
|
margin-top: 16rpx; |
||||
|
border-radius: 16rpx; |
||||
|
padding: 12rpx 0; |
||||
|
text-align: center; |
||||
|
background: #f7f8fa; |
||||
|
color: #000; |
||||
|
border:1px solid rgba(111, 195, 160, 1); |
||||
|
} |
||||
|
.slot:nth-child(4n) { |
||||
|
margin-right: 0; |
||||
|
} |
||||
|
.slot .slot-line { |
||||
|
font-size: 28rpx; |
||||
|
} |
||||
|
.slot .slot-sep { |
||||
|
font-size: 24rpx; |
||||
|
color: inherit; |
||||
|
} |
||||
|
.slot.disabled { |
||||
|
background: #ededed; |
||||
|
color: #bfbfbf; |
||||
|
border: none; |
||||
|
} |
||||
|
.slot.selected { |
||||
|
background: #13c2c2; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.chosen{ |
||||
|
margin-top: 20rpx; |
||||
|
color: #13c2c2; |
||||
|
font-size: 26rpx; |
||||
|
} |
||||
|
.footer { |
||||
|
padding: 24rpx; |
||||
|
} |
Loading…
Reference in new issue