Browse Source

共享空间优化

master
wangyx 2 days ago
parent
commit
bfd8dc3f40
  1. 4
      api/index.js
  2. BIN
      images/mine/s3.png
  3. 2
      pages/mine/mine.wxml
  4. BIN
      subpages/images/icon01.png
  5. BIN
      subpages/images/icon02.png
  6. 37
      subpages/mine/mySpace/mySpace.js
  7. 12
      subpages/mine/mySpace/mySpace.wxml
  8. 2
      subpages/space/list/list.js
  9. 18
      subpages/space/list/list.wxml
  10. 2
      subpages/space/list/list.wxss
  11. 110
      subpages/space/reserve/reserve.js
  12. 1
      subpages/space/reserve/reserve.wxml
  13. 38
      subpages/space/reserve/reserve.wxss

4
api/index.js

@ -83,3 +83,7 @@ export function spacePage(pamars) {
export function spaceInfo(pamars) { export function spaceInfo(pamars) {
return fly.get(`/bys/mzShareSpace/detail`, pamars); return fly.get(`/bys/mzShareSpace/detail`, pamars);
} }
// 根据共享空间和日期查询可预约时间段;
export function queryAppointTime(pamars) {
return fly.get(`/bys/mzShareSpace/queryAppointTime`, pamars);
}

BIN
images/mine/s3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

2
pages/mine/mine.wxml

@ -79,7 +79,7 @@
<view class="service-c"> <view class="service-c">
<view class="flex p10" style="width: 180rpx;background-color: #f3f9fc;border-radius: 10rpx;" wx:for="{{serviceNavList}}" bind:tap="toInfo" data-url="{{item.url}}"> <view class="flex p10" style="width: 180rpx;background-color: #f3f9fc;border-radius: 10rpx;" wx:for="{{serviceNavList}}" bind:tap="toInfo" data-url="{{item.url}}">
<image src="{{'../../images/mine/s'+(index + 1)+'.png'}}" class="icon-40 mr-10" /> <image src="{{'../../images/mine/s'+(index + 1)+'.png'}}" class="icon-40 mr-10" />
<view>{{item.label}}</view> <view style="white-space:nowrap;">{{item.label}}</view>
</view> </view>
</view> </view>
</view> </view>

BIN
subpages/images/icon01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
subpages/images/icon02.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

37
subpages/mine/mySpace/mySpace.js

@ -93,12 +93,10 @@ Page({
const newData = res.data.records.map((item) => { const newData = res.data.records.map((item) => {
return { return {
...item, ...item,
// 格式化预约日期和时间 // 格式化预约日期和时间(保留展示所需字段)
appointmentDate: item.appointmentDate || "", appointmentDate: item.appointmentDate || "",
appointTime: item.appointTime || "", appointTime: item.appointTime || "",
// 添加状态显示 statusColor: this.getColorByStatus(item.currentStatus)
statusText: this.getStatusText(item),
statusColor: this.getStatusColor(item)
}; };
}); });
@ -151,32 +149,9 @@ Page({
}); });
}, },
// 获取状态文本 getColorByStatus(status) {
getStatusText(item) { if (status === 1) return '#17C4C4';
// 根据实际业务逻辑判断状态 if (status === 2) return '#FA9E0A';
const now = new Date(); return '#999';
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'; // 已完成 - 灰色
} }
},
}); });

12
subpages/mine/mySpace/mySpace.wxml

@ -2,15 +2,16 @@
<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}}"> <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="card" wx:key="id" wx:for="{{list}}">
<view class="flex flex-sb"> <view class="flex flex-sb">
<view class="name font-bold">{{item.apartmentName}}</view> <view class="flex name font-bold">
<image src="{{'../../images/icon01.png'}}" class="icon-40 mr-10" />
{{item.apartmentName}}
</view>
</view> </view>
<van-divider dashed /> <van-divider dashed />
<view class="item flex"> <view class="item flex">
<image src="{{item.imgUrls[0]}}" style="width: 200rpx;height:152rpx;margin-right: 16rpx;border-radius: 10rpx;" mode="aspectFill" /> <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="flex flex-col flex-1">
<view class="space-name font-bold" style="margin:10rpx 0 10rpx 0;"> <view class="space-name font-bold" style="margin:10rpx 0 10rpx 0;">{{item.name}}</view>
{{item.name}}
</view>
<view class="address" style="color: #666; font-size: 28rpx; margin-bottom: 10rpx;"> <view class="address" style="color: #666; font-size: 28rpx; margin-bottom: 10rpx;">
{{item.address}} {{item.address}}
</view> </view>
@ -18,12 +19,11 @@
{{item.appointmentDate}} {{item.appointTime}} {{item.appointmentDate}} {{item.appointTime}}
</view> </view>
<view class="status" style="color:{{item.statusColor}}; font-size: 28rpx;"> <view class="status" style="color:{{item.statusColor}}; font-size: 28rpx;">
{{item.statusText}} {{item.currentStatus==1?'已预约':item.currentStatus==2?'使用中':item.currentStatus==3?'已完成':''}}
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 加载更多提示 --> <!-- 加载更多提示 -->
<view class="loading-more" wx:if="{{loading}}" style="text-align: center; padding: 20rpx; color: #999;"> <view class="loading-more" wx:if="{{loading}}" style="text-align: center; padding: 20rpx; color: #999;">
加载中... 加载中...

2
subpages/space/list/list.js

@ -60,7 +60,7 @@ Page({
onShareAppMessage() {}, onShareAppMessage() {},
toReserve(e) { toReserve(e) {
wx.navigateTo({ 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}`, 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[0]}&address=${e.currentTarget.dataset.item.address}`,
}); });
}, },
getList(isRefresh = false) { getList(isRefresh = false) {

18
subpages/space/list/list.wxml

@ -1,15 +1,19 @@
<!-- subpages/space/list/list.wxml --> <!-- subpages/space/list/list.wxml -->
<scroll-view scroll-y class="scroll-view" bindscrolltolower="scrolltolower" wx:if="{{list.length>0}}"> <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="card " wx:key="index" wx:for="{{list}}">
<view class="flex flex-sb">
<view class="flex name font-bold">
<image src="{{'../../images/icon01.png'}}" class="icon-40 mr-10" />
{{item.address}}
</view>
</view>
<van-divider dashed />
<view class="item flex"> <view class="item flex">
<image src="{{item.imgUrls[0]}}" style="width: 200rpx;height:152rpx;margin-right: 16rpx;border-radius: 10rpx;" mode="" /> <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-col flex-1">
<!-- <view class="flex flex-sb"> <!-- <view class="flex flex-sb"> -->
<view class="name font-bold">{{item.name}}</view> <!-- </view> -->
</view> --> <view class="position" style="margin:10rpx 0 10rpx 0;">{{item.name}}</view>
<view class="position" style="margin:10rpx 0 10rpx 0;">
{{item.name}}
</view>
<view class="date">{{item.appointmentWeekText}}</view> <view class="date">{{item.appointmentWeekText}}</view>
<view class="date" wx:if="{{item.appointmentTimeText}}">{{item.appointmentTimeText}}</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==='1'}}">{{item.inDate}} 至 {{item.outDate}}</view>
@ -25,7 +29,6 @@
</van-button> </van-button>
</view> </view>
</view> </view>
<!-- 加载更多提示 --> <!-- 加载更多提示 -->
<view wx:if="{{list.length > 0}}" class="load-more"> <view wx:if="{{list.length > 0}}" class="load-more">
<view wx:if="{{loading}}" class="loading-text"> <view wx:if="{{loading}}" class="loading-text">
@ -33,5 +36,4 @@
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
<no-data isShow="{{list.length === 0 && !loading}}"></no-data> <no-data isShow="{{list.length === 0 && !loading}}"></no-data>

2
subpages/space/list/list.wxss

@ -1,6 +1,6 @@
/* subpages/space/list/list.wxss */ /* subpages/space/list/list.wxss */
.card{ .card{
height:280rpx ; height:370rpx ;
} }
.name { .name {
font-size: 32rpx; font-size: 32rpx;

110
subpages/space/reserve/reserve.js

@ -1,12 +1,12 @@
// subpages/space/reserve/reserve.js // subpages/space/reserve/reserve.js
import { appointment, spaceInfo } from "../../../api/index"; import { appointment, spaceInfo, queryAppointTime } from "../../../api/index";
Page({ Page({
/** /**
* 页面的初始数据 * 页面的初始数据
*/ */
data: { data: {
bannerUrl: 'https://img.yzcdn.cn/vant/cat.jpeg', bannerUrl: '',
roomName: '第一会议室', roomName: '第一会议室',
openDate: '周一至周五', openDate: '周一至周五',
openTimeText: '上午09:00-下午18:00', openTimeText: '上午09:00-下午18:00',
@ -18,7 +18,8 @@ Page({
chosenText: '', chosenText: '',
spaceDetail: null, spaceDetail: null,
appointDates: [], appointDates: [],
appointmentTimes: [] appointmentTimes: [],
address: '',
}, },
/** /**
@ -32,6 +33,7 @@ Page({
openDate: options.openDate, openDate: options.openDate,
openTimeText: options.openTimeText, openTimeText: options.openTimeText,
bannerUrl: options.imgUrls, bannerUrl: options.imgUrls,
address: options.address,
}); });
this.getDetail(); // 获取详情后会自动初始化日期和时间段 this.getDetail(); // 获取详情后会自动初始化日期和时间段
}, },
@ -78,7 +80,7 @@ Page({
this.setData({ this.setData({
spaceDetail: res.data, spaceDetail: res.data,
appointDates: res.data.appointDates || [], appointDates: res.data.appointDates || [],
appointmentTimes: res.data.appointmentTimes || [] appointmentTimes: []
}); });
// 根据接口数据初始化日期和时间段 // 根据接口数据初始化日期和时间段
this.initDatesFromAPI(); this.initDatesFromAPI();
@ -86,7 +88,7 @@ Page({
} }
}).catch(err => { }).catch(err => {
wx.showToast({ wx.showToast({
title: err.msg || '获取详情失败', title: err.msg ,
icon: 'none' icon: 'none'
}); });
}) })
@ -115,12 +117,20 @@ Page({
initDatesFromAPI() { initDatesFromAPI() {
const { appointDates } = this.data; const { appointDates } = this.data;
if (!appointDates || appointDates.length === 0) { if (!appointDates || appointDates.length === 0) {
this.initDates(); // 如果没有接口数据,使用默认逻辑 // 删除默认逻辑:当无可预约日期时,直接清空并返回
this.setData({
dateList: [],
selectedDateIndex: 0,
timeSlots: [],
rangeStartIndex: -1,
rangeEndIndex: -1,
chosenText: ''
});
return; return;
} }
const today = new Date().toISOString().split('T')[0]; // 今天的日期 YYYY-MM-DD const today = new Date().toISOString().split('T')[0]; // 今天的日期 YYYY-MM-DD
const dates = appointDates.map((item, index) => { const dates = appointDates.map((item) => {
const date = new Date(item.appointDate); const date = new Date(item.appointDate);
const isToday = item.appointDate === today; const isToday = item.appointDate === today;
return { return {
@ -145,60 +155,46 @@ Page({
dateList: dates, dateList: dates,
selectedDateIndex: defaultIndex, selectedDateIndex: defaultIndex,
}); });
},
initTimeSlots() { // 初始化默认日期的时间段(调用后端 queryAppointTime)
const ranges = [ const defaultDate = dates[defaultIndex] && dates[defaultIndex].date;
['09:00', '09:30'], ['09:30', '10:00'], ['10:00', '10:30'], ['10:30', '11:00'], if (defaultDate) {
['11:00', '11:30'], ['11:30', '12:00'], ['12:00', '12:30'], ['12:30', '13:00'], this.fetchTimeSlotsForDate(defaultDate);
['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: '' });
}, },
// 根据接口数据初始化时间段
// 根据接口数据初始化时间段(新的数据结构:时间段挂在 appointDates 每个日期项内)
initTimeSlotsFromAPI() { initTimeSlotsFromAPI() {
const { appointmentTimes } = this.data; const { appointDates, selectedDateIndex } = this.data;
if (!appointDates || appointDates.length === 0) return;
const dateItem = appointDates[selectedDateIndex] || {};
const appointmentTimes = dateItem.appointmentTimes || dateItem.times || [];
if (!appointmentTimes || appointmentTimes.length === 0) { if (!appointmentTimes || appointmentTimes.length === 0) {
this.initTimeSlots(); // 如果没有接口数据,使用默认逻辑 this.setData({ timeSlots: [], rangeStartIndex: -1, rangeEndIndex: -1, chosenText: '' });
return; return;
} }
const slots = appointmentTimes.map((item, index) => { const slots = appointmentTimes.map((item) => {
// 解析时间段,例如 "09:00至09:29" -> start: "09:00", end: "09:29" const timeMatch = (item.appointmentTime || '').match(/(\d{2}:\d{2})至(\d{2}:\d{2})/);
const timeMatch = item.appointmentTime.match(/(\d{2}:\d{2})至(\d{2}:\d{2})/);
let start = '00:00'; let start = '00:00';
let end = '00:30'; let end = '00:30';
if (timeMatch) { if (timeMatch) {
start = timeMatch[1]; start = timeMatch[1];
end = timeMatch[2]; end = timeMatch[2];
} }
return { return {
id: item.id, id: item.id,
apiId: item.id, // 保存接口返回的ID apiId: item.id,
start: start, start,
end: end, end,
timeText: item.appointmentTime, timeText: item.appointmentTime,
status: item.canAppoint ? 'available' : 'disabled' status: item.canAppoint ? 'available' : 'disabled'
}; };
}); });
this.setData({ this.setData({ timeSlots: slots, rangeStartIndex: -1, rangeEndIndex: -1, chosenText: '' });
timeSlots: slots,
rangeStartIndex: -1,
rangeEndIndex: -1,
chosenText: ''
});
}, },
selectDate(e) { selectDate(e) {
@ -215,7 +211,8 @@ Page({
} }
this.setData({ selectedDateIndex: index }); this.setData({ selectedDateIndex: index });
this.initTimeSlotsFromAPI(); // 使用接口数据初始化时间段 // 每次选择都请求后端查询当日可预约时间段
this.fetchTimeSlotsForDate(selectedDate.date);
}, },
toggleSlot(e) { toggleSlot(e) {
@ -334,5 +331,36 @@ Page({
icon: 'none' icon: 'none'
}); });
}); });
},
// 根据日期查询可预约时间段
fetchTimeSlotsForDate(date) {
const { id } = this.data;
if (!id || !date) return;
queryAppointTime({ id, currentDate: date })
.then((res) => {
if (res.code === 200 && Array.isArray(res.data)) {
const { appointDates, selectedDateIndex } = this.data;
const dateItem = appointDates[selectedDateIndex] || {};
dateItem.appointmentTimes = res.data; // 将查询到的时间段更新到 appointDates 的对应日期项中
appointDates[selectedDateIndex] = dateItem;
this.setData({
appointDates, // 更新 appointDates 数组
appointmentTimes: [], // 清空独立的 appointmentTimes
});
this.initTimeSlotsFromAPI(); // 重新初始化时间段
} else {
wx.showToast({
title: res.msg || "获取时间段失败",
icon: "none",
});
}
})
.catch((err) => {
wx.showToast({
title: err.msg || "获取时间段失败",
icon: "none",
});
});
} }
}) })

1
subpages/space/reserve/reserve.wxml

@ -5,6 +5,7 @@
</view> </view>
<view class=" banner-overlay"> <view class=" banner-overlay">
<view class="room-name">{{roomName}}</view> <view class="room-name">{{roomName}}</view>
<view class="open-time">{{address}}</view>
<view class="open-time">{{openDate}}</view> <view class="open-time">{{openDate}}</view>
<view class="open-time">{{openTimeText}}</view> <view class="open-time">{{openTimeText}}</view>
</view> </view>

38
subpages/space/reserve/reserve.wxss

@ -3,22 +3,27 @@
background: #f8f8f8; background: #f8f8f8;
min-height: 100vh; min-height: 100vh;
} }
.banner { .banner {
position: relative; position: relative;
} }
.banner-overlay { .banner-overlay {
padding: 20rpx; padding: 20rpx;
background: #fff; background: #fff;
} }
.room-name { .room-name {
font-size: 32rpx; font-size: 32rpx;
font-weight: 600; font-weight: 600;
} }
.open-time { .open-time {
margin-top: 8rpx; margin-top: 8rpx;
font-size: 26rpx; font-size: 26rpx;
color: #BFBFBF; color: #BFBFBF;
} }
.section { .section {
margin: 0 18rpx; margin: 0 18rpx;
margin-top: 12rpx; margin-top: 12rpx;
@ -27,27 +32,32 @@
border-radius: 20rpx; border-radius: 20rpx;
} }
.section-row { .section-row {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.section-title { .section-title {
font-size: 32rpx; font-size: 32rpx;
font-weight: 600; font-weight: 600;
margin-bottom: 16rpx; margin-bottom: 16rpx;
margin-left: 10rpx; margin-left: 10rpx;
} }
.range-switch { .range-switch {
display: flex; display: flex;
align-items: center; align-items: center;
color: #666; color: #666;
font-size: 26rpx; font-size: 26rpx;
} }
.date-strip { .date-strip {
white-space: nowrap; white-space: nowrap;
padding-bottom: 12rpx; padding-bottom: 12rpx;
} }
.date-item { .date-item {
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
@ -59,9 +69,11 @@
color: #666; color: #666;
margin-right: 16rpx; margin-right: 16rpx;
} }
.date-item .date-label { .date-item .date-label {
font-size: 26rpx; font-size: 26rpx;
} }
.date-item .date-day { .date-item .date-day {
margin-top: 8rpx; margin-top: 8rpx;
width: 56rpx; width: 56rpx;
@ -70,62 +82,78 @@
text-align: center; text-align: center;
border-radius: 50%; border-radius: 50%;
} }
.date-item.active { .date-item.active {
/* background: #e6fffb; */ /* background: #e6fffb; */
color: #13c2c2; color: #13c2c2;
} }
.date-item.active .date-day { .date-item.active .date-day {
background: #13c2c2; background: #13c2c2;
color: #fff; color: #fff;
} }
.date-item.disabled { .date-item.disabled {
color: #bfbfbf; color: #bfbfbf;
opacity: 0.5; opacity: 0.5;
} }
.date-item.disabled .date-day { .date-item.disabled .date-day {
background: #f0f0f0; background: #f0f0f0;
color: #bfbfbf; color: #bfbfbf;
} }
.slot-grid { .slot-grid {
display: flex; display: grid;
flex-wrap: wrap; grid-template-columns: repeat(4, 1fr);
grid-column-gap: 16rpx;
grid-row-gap: 16rpx;
margin-top: 12rpx; margin-top: 12rpx;
} }
.slot { .slot {
width: calc(25% - 16rpx); width: 100%;
margin-right: 16rpx; margin: 0;
margin-top: 16rpx; box-sizing: border-box;
border-radius: 16rpx; border-radius: 16rpx;
padding: 12rpx 0; padding: 12rpx 0;
text-align: center; text-align: center;
background: #f7f8fa; background: #f7f8fa;
color: #000; color: #000;
border: 1px solid rgba(111, 195, 160, 1); border: 1px solid rgba(111, 195, 160, 1);
} }
.slot:nth-child(4n) { .slot:nth-child(4n) {
margin-right: 0; margin-right: 0;
} }
.slot .slot-line { .slot .slot-line {
font-size: 28rpx; font-size: 28rpx;
} }
.slot .slot-sep { .slot .slot-sep {
font-size: 24rpx; font-size: 24rpx;
color: inherit; color: inherit;
} }
.slot.disabled { .slot.disabled {
background: #ededed; background: #ededed;
color: #bfbfbf; color: #bfbfbf;
border: none; border: none;
} }
.slot.selected { .slot.selected {
background: #13c2c2; background: #13c2c2;
color: #fff; color: #fff;
} }
.chosen { .chosen {
margin-top: 20rpx; margin-top: 20rpx;
color: #13c2c2; color: #13c2c2;
font-size: 26rpx; font-size: 26rpx;
} }
.footer { .footer {
padding: 24rpx; padding: 24rpx;
} }
Loading…
Cancel
Save