mrr.sj.front/components/select-time-page/select-time-page.vue

452 lines
11 KiB
Vue
Raw Permalink Normal View History

2026-03-24 11:45:13 +08:00
<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"
2026-03-25 13:29:04 +08:00
:class="[getItemClass(time.state || 0),{
lastActive:selectedTimeIndex + serviceTimeNum==index,
firstActive:selectedTimeIndex==index,
isActive:
index >= selectedTimeIndex && index <= selectedTimeIndex + serviceTimeNum &&
sureTimeDataIndex === selectedDateIndex &&
selectedTimeIndex !== null,
2026-03-24 11:45:13 +08:00
}]"
@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) {
2026-03-25 13:29:04 +08:00
this.serviceTimeNum = Math.max(1, Math.ceil((newValue.server_time || 0) / 10));
2026-03-24 11:45:13 +08:00
},
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);
2026-06-02 11:39:23 +08:00
color: #FF4767 !important;
2026-03-24 11:45:13 +08:00
}
.isActive .time-picker-content__time__list__item__text {
2026-06-02 11:39:23 +08:00
color: #FF4767 !important;
2026-03-24 11:45:13 +08:00
}
/* 选中样式前后弧度 */
.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;
2026-06-02 11:39:23 +08:00
background: #FF4767;
2026-03-24 11:45:13 +08:00
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>