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