452 lines
11 KiB
Vue
452 lines
11 KiB
Vue
<template>
|
||
<uni-popup ref="popup" type="bottom" border-radius="20rpx">
|
||
<view class="time-popup">
|
||
<view class="popup-header">
|
||
<text class="popup-title">请选择服务时间</text>
|
||
<text class="popup-close" @click="closeTime">取消</text>
|
||
</view>
|
||
<view class="time-picker-content">
|
||
<!-- 日期选择 -->
|
||
<view class="time-picker-content__datas">
|
||
<view
|
||
class="time-picker-content__datas__date__item"
|
||
v-for="(date, index) in dateList"
|
||
:key="index"
|
||
@click="selectDate(index)"
|
||
>
|
||
<view class="time-picker-content__datas__date__item__box">
|
||
<image
|
||
src="/static/images/dataBox.png"
|
||
class="time-picker-content__datas__date__item__box__img"
|
||
v-if="selectedDateIndex == index"
|
||
></image>
|
||
</view>
|
||
<text
|
||
class="time-picker-content__datas__date__item__text"
|
||
:class="selectedDateIndex === index ? 'active' : ''"
|
||
>{{ date }}</text
|
||
>
|
||
</view>
|
||
</view>
|
||
<!-- 时间选择 -->
|
||
<scroll-view scroll-y="true" style="height: 600rpx; width: 690rpx">
|
||
<view class="time-picker-content__time__list" v-if="timeOptions[selectedDateIndex] && timeOptions[selectedDateIndex].length">
|
||
<view
|
||
class="time-picker-content__time__list__item"
|
||
v-for="(time, index) in timeOptions[selectedDateIndex]"
|
||
:key="index"
|
||
:class="[getItemClass(time.state || 0),{
|
||
lastActive:selectedTimeIndex + serviceTimeNum==index,
|
||
firstActive:selectedTimeIndex==index,
|
||
isActive:
|
||
index >= selectedTimeIndex && index <= selectedTimeIndex + serviceTimeNum &&
|
||
sureTimeDataIndex === selectedDateIndex &&
|
||
selectedTimeIndex !== null,
|
||
}]"
|
||
@click="selectTime(time, index)"
|
||
>
|
||
<text class="time-picker-content__time__list__item__text">{{
|
||
time.show_time
|
||
}}</text>
|
||
<!-- <text class="time-picker-content__time__list__item__state">{{
|
||
time.stateName || getStateText(time.state)
|
||
}}</text> -->
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
<view class="time-picker-content__time__sure">
|
||
<view class="time-picker-content__time__sure__box" @click="sureTime">
|
||
<text class="time-picker-content__time__sure__box__text">确认</text>
|
||
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</template>
|
||
|
||
<script>
|
||
/**
|
||
* sureTime 确认时间触发事件
|
||
* openTime 打开时间选择弹框
|
||
* closeTime 关闭时间选择弹框
|
||
* selectDate 选择日期
|
||
* selectTime 选择时间
|
||
* getItemClass 获取列表项的class
|
||
* handelGetTimeArr 获取时间段,
|
||
*/
|
||
import request from "@/utils/request";
|
||
export default {
|
||
data() {
|
||
return {
|
||
isFirstOPen: true,
|
||
sureTimeObj: {}, // 确认时间对象
|
||
dateList: ["今天", "明天", "后天"],
|
||
selectedTimeIndex: "", // 选中的时间索引
|
||
serviceTimeNum: 1, // 服务时间段数量
|
||
sureTimeDataIndex: null, // 确认的时间索引
|
||
selectedDateIndex: 0, // 选中的日期索引
|
||
startTimeObj: {
|
||
serviceTimeNum: "", // 服务时间段数量
|
||
sureTimeDataIndex: 0, // 确认的时间索引
|
||
selectedDateIndex: 0, // 选中的日期索引
|
||
}, // 开始时间对象
|
||
// 状态映射配置
|
||
stateConfig: {
|
||
1: {
|
||
class: "state-available",
|
||
text: "可约",
|
||
},
|
||
2: {
|
||
class: "state-full",
|
||
text: "约满",
|
||
},
|
||
3: {
|
||
class: "state-rest",
|
||
text: "休息",
|
||
},
|
||
4: {
|
||
class: "state-locked",
|
||
text: "锁定",
|
||
},
|
||
5: {
|
||
class: "state-unavailable",
|
||
text: "不可用",
|
||
},
|
||
},
|
||
};
|
||
},
|
||
props: {
|
||
// 时间选项数组
|
||
timeOptions: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
// 初始时间索引
|
||
firstTimeIndex: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
// 初始日期索引
|
||
firstDataIndex: {
|
||
type: Number,
|
||
default: 1,
|
||
},
|
||
// 服务信息
|
||
service: {
|
||
type: Object,
|
||
default: () => ({}),
|
||
},
|
||
publish_user_id: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
server_type: {
|
||
type: Number,
|
||
default: 0,
|
||
},
|
||
},
|
||
watch: {
|
||
service: {
|
||
handler(newValue) {
|
||
this.serviceTimeNum = Math.max(1, Math.ceil((newValue.server_time || 0) / 10));
|
||
},
|
||
deep: true,
|
||
immediate: true,
|
||
},
|
||
},
|
||
created() {},
|
||
mounted() {},
|
||
methods: {
|
||
openTime() {
|
||
console.log("打开时间选择弹框", this.selectedDateIndex);
|
||
this.isFirstOPen = false;
|
||
|
||
this.startTimeObj = {
|
||
selectedTimeIndex: this.selectedTimeIndex,
|
||
sureTimeDataIndex: this.sureTimeDataIndex,
|
||
selectedDateIndex: this.selectedDateIndex,
|
||
};
|
||
this.$refs.popup.open("bottom");
|
||
},
|
||
// 获取状态文本
|
||
getStateText(state) {
|
||
return this.stateConfig[state]?.text || "未知";
|
||
},
|
||
// 列表项的class获取方法
|
||
getItemClass(state) {
|
||
const _state = state || 0;
|
||
return this.stateConfig[_state]?.class || "state-unknown";
|
||
},
|
||
// 选择日期
|
||
selectDate(index) {
|
||
this.selectedDateIndex = index;
|
||
},
|
||
selectTime(time, index) {
|
||
if (time.state === 1) {
|
||
// 可约状态
|
||
let parms = {
|
||
user_syr_id: this.publish_user_id || this.service.publish_user_id,
|
||
reserve_time: this.timeOptions[this.selectedDateIndex][index].time,
|
||
server_id: this.service.id,
|
||
server_type: this.server_type,
|
||
};
|
||
|
||
request
|
||
.post("/user/reserve/timeCheck", parms)
|
||
.then((res) => {
|
||
if (res.code == 200) {
|
||
this.selectedTimeIndex = index;
|
||
this.sureTimeDataIndex = this.selectedDateIndex; // 更新确认时间索引
|
||
|
||
this.sureTimeObj = {
|
||
selectedDateIndex: this.selectedDateIndex,
|
||
selectedTimeIndex: this.selectedTimeIndex,
|
||
time: this.timeOptions[this.selectedDateIndex][
|
||
this.selectedTimeIndex
|
||
],
|
||
res: res,
|
||
};
|
||
this.$emit("selectTime", this.sureTimeObj);
|
||
} else {
|
||
uni.showToast({
|
||
title: "当前时间不可预约",
|
||
icon: "none",
|
||
duration: 1000,
|
||
});
|
||
}
|
||
})
|
||
.catch((err) => {
|
||
console.log("报错", err);
|
||
});
|
||
}
|
||
},
|
||
sureTime() {
|
||
this.$refs.popup.close();
|
||
this.$emit("sureTime", this.sureTimeObj);
|
||
},
|
||
handelGetTimeArr(time = null) {
|
||
// 获取时间段
|
||
let date = {
|
||
selectedDateIndex: this.selectedDateIndex,
|
||
selectedTimeIndex: this.selectedTimeIndex,
|
||
time: this.timeOptions[this.selectedDateIndex][this.selectedTimeIndex],
|
||
};
|
||
this.$emit("getTimeArr", date);
|
||
},
|
||
closeTime() {
|
||
// 关闭时间选择弹框
|
||
this.selectedTimeIndex = this.startTimeObj.selectedTimeIndex;
|
||
this.sureTimeDataIndex = this.startTimeObj.sureTimeDataIndex;
|
||
this.selectedDateIndex = this.startTimeObj.selectedDateIndex;
|
||
this.$refs.popup.close();
|
||
this.$emit("closeTime");
|
||
},
|
||
},
|
||
};
|
||
</script>
|
||
|
||
<style>
|
||
/* 全局样式,nvue不支持scoped和less,需使用普通css */
|
||
/* 时间选择弹框 */
|
||
.time-popup {
|
||
background-color: #ffffff;
|
||
border-radius: 24rpx 24rpx 0 0;
|
||
overflow: hidden;
|
||
transform: translateY(0);
|
||
transition: transform 0.3s;
|
||
z-index: 999;
|
||
}
|
||
|
||
.popup-header {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 30rpx 30rpx 36rpx 30rpx;
|
||
}
|
||
|
||
.popup-close {
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
color: #999999;
|
||
line-height: 37rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
}
|
||
|
||
.popup-title {
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 500;
|
||
font-size: 30rpx;
|
||
color: #333333;
|
||
line-height: 42rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
}
|
||
|
||
.time-picker-content {
|
||
padding: 32rpx 32rpx;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
flex-direction: row;
|
||
width: 750rpx;
|
||
}
|
||
|
||
.time-picker-content__datas {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
align-items: flex-start;
|
||
width: 690rpx;
|
||
justify-content: space-between;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.time-picker-content__datas__date__item {
|
||
width: 214rpx;
|
||
height: 70rpx;
|
||
background: #f7f8fa;
|
||
border-radius: 10rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.time-picker-content__datas__date__item__text {
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
color: #333333;
|
||
line-height: 37rpx;
|
||
text-align: left;
|
||
font-style: normal;
|
||
z-index: 2;
|
||
position: relative;
|
||
}
|
||
|
||
.time-picker-content__datas__date__item__text.active {
|
||
color: #ffffff;
|
||
}
|
||
|
||
.time-picker-content__datas__date__item__box {
|
||
width: 214rpx;
|
||
height: 74rpx;
|
||
position: absolute;
|
||
z-index: 1;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
.time-picker-content__datas__date__item__box__img {
|
||
width: 214rpx;
|
||
height: 74rpx;
|
||
|
||
}
|
||
|
||
.time-picker-content__time__list {
|
||
width: 690rpx;
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.time-picker-content__time__list__item {
|
||
width: 114rpx;
|
||
height: 66rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 26rpx;
|
||
}
|
||
|
||
.time-picker-content__time__list__item__text {
|
||
font-weight: 400;
|
||
font-size: 30rpx;
|
||
color: #333333;
|
||
line-height: 66rpx;
|
||
text-align: center;
|
||
font-style: normal;
|
||
}
|
||
|
||
.time-picker-content__time__list__item__state {
|
||
font-size: 20rpx;
|
||
}
|
||
|
||
/* 状态样式 */
|
||
.state-available {
|
||
color: #3c3638;
|
||
/* background: #f7f8fa; */
|
||
}
|
||
|
||
.state-full {
|
||
color: #3c3638;
|
||
background: #e4e9f0;
|
||
}
|
||
|
||
.state-rest {
|
||
color: #cdcdcd;
|
||
background: #f7f8f9;
|
||
}
|
||
|
||
.state-locked {
|
||
color: #3c3638;
|
||
background: #e4e9f0;
|
||
}
|
||
|
||
.state-unavailable {
|
||
color: #ffffff;
|
||
background: #e4e9f0;
|
||
}
|
||
|
||
.state-unknown {
|
||
color: #999999;
|
||
background: #f7f8fa;
|
||
}
|
||
|
||
.isActive {
|
||
background: rgba(252, 67, 124, 0.08);
|
||
color: #e8101e !important;
|
||
}
|
||
|
||
.isActive .time-picker-content__time__list__item__text {
|
||
color: #e8101e !important;
|
||
}
|
||
|
||
/* 选中样式前后弧度 */
|
||
.firstActive {
|
||
border-radius: 51rpx 0rpx 0rpx 51rpx;
|
||
}
|
||
.lastActive {
|
||
border-radius: 0rpx 51rpx 51rpx 0rpx}
|
||
|
||
.time-picker-content__time__sure {
|
||
padding: 39rpx 0;
|
||
display: flex;
|
||
flex-direction: row;
|
||
width: 690rpx;
|
||
justify-content: center;
|
||
}
|
||
|
||
.time-picker-content__time__sure__box {
|
||
width: 648rpx;
|
||
height: 94rpx;
|
||
background: #E8101E;
|
||
border-radius: 48rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.time-picker-content__time__sure__box__text {
|
||
font-family: PingFangSC, PingFang SC;
|
||
font-weight: 400;
|
||
font-size: 30rpx;
|
||
color: #ffffff;
|
||
line-height: 42rpx;
|
||
text-align: center;
|
||
font-style: normal;
|
||
}
|
||
</style>
|