uniapp快遞上門提貨的時間選擇的插件

发布于:2025-08-06 ⋅ 阅读:(16) ⋅ 点赞:(0)

#項目使用到的
 插件鏈接:hbxw-timepicker预约时间选择组件 - DCloud 插件市场

適配環境 :1,微信小程序。2,支付寶小程序。3,h5。

我使用的是uniapp 編譯微信小程序基於vue3開發

先看一下實現出來的效果:


1,講解左邊是明天 後天  這些可以自定義設置的,右邊的時間間隔 也是可以自定義的 ,一小時間隔 三小時間隔  都可以  然後早上開始時間和結束時間都是可以自定義的
2,我自己寫的是三小時間隔 我項目中有多個配送方式 所以我設置的有三小時間隔還有一個小時間隔的,

 一,首先html
<hbxw-timepicker v-model:isShow="showTimePicker2" :dayRange="2" :anotherNames="['明天', '后天']"
							:minHour="9" :maxHour="18" @change="pickerChange"></hbxw-timepicker>

二,javascript部分 

	const showTimePicker3 = ref(false);
	// 存储所有时间选择器显示状态的数组
	const showTimePickers = [showTimePicker0, showTimePicker1, showTimePicker2, showTimePicker3];
	// 显示时间选择器的方法
	const pickerTime = (index) => {
		showTimePickers[index].value = true;
	};
	let date_time = ref('請選擇')
	let date_timelog = ref('請選擇')
	const sahrse = ref(true)
	// 时间选择器值改变的回调方法
	const pickerChange = (result) => {
		console.log('pickerChange 接收到的结果:', result);

		// 检查是否有有效的结果
		if (!result || !result.result) {
			console.warn('未选择有效时间,结果为 null 或 undefined');
			// 重置为默认值
			date_time.value = '請選擇';
			date_timelog.value = '請選擇';
			sahrse.value = true; // 恢复默认状态
			return;
		}

		// 提取结果中的数据
		const {
			result: {
				year,
				month,
				day,
				hourStart,
				hourEnd,
				anotherName = '今天', // 只在 anotherName 为 undefined 时生效
				hoursStr
			} = {} // 防止 result 为 undefined 时的错误
		} = result || {}; // 防止 result 为 undefined 时的错误

		// 检查关键字段是否存在
		if (!year || !month || !day || !hourStart || !hourEnd) {
			console.warn('选择的时间信息不完整:', result);
			date_time.value = '時間格式錯誤';
			date_timelog.value = '時間格式錯誤';
			return;
		}

		// 更新时间显示
		date_time.value = `${year}-${month}-${day}-${hourStart}/${hourEnd}`;
		date_timelog.value = `${anotherName||'今天'}${hoursStr}`;
		sahrse.value = false; // 禁用选择状态
	};

 三,循環時間

<template>
	<view class="hbxw-timepicker" :class="{'hbxw-timepicker-ani': isAni}"
		:style="{'z-index': zIndex, '--opacity': maskOpacity}" v-if="isShow">
		<view class="hbxw-timepicker-mask" @click="close"></view>
		<view class="hbxw-timepicker-main" :class="{'hbxw-timepicker-main-ani': isAni}">

			<!-- 标题 -->
			<view class="hbxw-timepicker-title">
				<slot name="title" :title="title" :subTitle="subTitle">
					<view class="hbxw-timepicker-title-main">{{title}}</view>
					<view class="hbxw-timepicker-title-subtitle">{{subTitle}}</view>
				</slot>
				<image src="../../static/guanbi.png" class="hbxw-timepicker-close" @click="close"></image>
			</view>

			<!-- 主内容,日期和时间选择区 -->
			<view class="hbxw-timepicker-content">
				<view class="hbxw-timepicker-day">
					<view class="hbxw-timepicker-day-item"
						:class="{'hbxw-timepicker-day-item-active': dayActiveIndex === index}"
						v-for="(day, index) in days" :key="index" @click="toggleDay(index)">
						
						{{anotherNames[index] ? anotherNames[index].replace('month', day.month).replace('day', day.day) : '2025-'+day.value}}
					</view>
				</view>
				<view class="hbxw-timepicker-time">
					<view v-if="hours.length > 0" class="hbxw-timepicker-time-item" v-for="(hour, index) in hours"
						:key="index" :class="{'hbxw-timepicker-time-item-active': hourActiveIndex === index}"
						@click="toggleHour(index)">
						<text class="hbxw-timepicker-time-val">{{hour.hoursStr}}</text>
						<view class="hbxw-timepicker-time-icon">
							<image src="../../static/gougou.png" class="hbxw-timepicker-time-img"></image>
						</view>
					</view>
					<view class="hbxw-timepicker-notime" v-else>
						<text class="hbxw-timerpicker-nodata">{{noDateTips}}</text>
					</view>
				</view>
			</view>

			<!-- 底部按钮 -->
			<slot name="btn" :result="result" v-if="isBtn">
				<view class="hbxw-timerpicker-sure" @click="sure" v-if="btnStr">{{btnStr}}</view>
			</slot>
		</view>
	</view>
</template>
<script>
    export default {
        props: {
            isShow: {
                type: Boolean,
                default: false
            },
			   businessType: {
			      type: String,
			      default: '' 
			    },
				  created() {
				    // 组件初始化时读取缓存,如果父组件没传值,则用缓存值
				    if (!this.businessType) {
				      const storedType = uni.getStorageSync('type_title');
				      // 确保缓存值是合法的(散货/板货/包车)
				      const validTypes = ['散貨', '板貨', '包車'];
				      if (validTypes.includes(storedType)) {
				        this.businessType = storedType; // 这里需要注意:props 不建议直接修改,更好的方式是用 data 接收
				      }
				    }
				  },
            title: {
                type: String,
                default: '期望上门时间'
            },
            subTitle: {
                type: String,
                // default: '快递1小时内上门取件,请自行做好数据备份'
            },
            // 是否显示1小时内
            isFast: {
                type: Boolean,
                default: true
            },
            // 日期别名,用于一些特殊场景,如需要显示今天明天后天...
            anotherNames: {
                type: Array,
                default() {
                    return ['明天', '后天'];// 这里只保留明天和后天
                }
            },
            dayRange: {
                type: Number,
                default: 3
            },
            minHour: {
                type: Number,
                default: 9
            },
            maxHour: {
                type: Number,
                default: 19
            },
            isBtn: {
                type: Boolean,
                default: true
            },
            isAni: {
                type: Boolean,
                default: true
            },
            zIndex: {
                type: Number,
                default: 9999
            },
            maskOpacity: {
                type: Number,
                default:.76
            },
            noDateTips: {
                type: String,
                default: '今日已暂无服务'
            },
            isTwo: {
                type: Boolean,
                default: true
            },
            isAutoClose: {
                type: Boolean,
                default: false
            }
        },
        model: {
            prop: 'isShow',
            event: 'update'
        },
        watch: {
            isShow(newVal, oldVal) {
                if (newVal) {
                    this.init();
                }
            }
        },
        data() {
            return {
                days: [],
                dayActiveIndex: 0,
                hourActiveIndex: 0,
				currentBusinessType: uni.getStorageSync('type_title') || '散貨'
            }
        },
        computed: {
            // 可选时间列表
           hours() {
           let nowDate = new Date();
               let hoursResult = [];
               let firstHour = this.minHour;
               // 根据业务类型设置时间间隔
               let interval = this.currentBusinessType === '包車'? 1 : 3; 
         
               for (let i = firstHour; i < this.maxHour; i += interval) { 
                 const endHour = i + interval;
                 if (endHour > this.maxHour) break; 
         
                 hoursResult.push({
                   start: i,
                   end: endHour,
                   hoursStr: `${this.isTwo? ('0' + i).slice(-2) : i}:00~${this.isTwo? ('0' + endHour).slice(-2) : endHour}:00`
                 });
               }
               return hoursResult;
             },
            // 当前选中结果
            result() {
                if (this.days.length === 0 || this.hours.length === 0) {
                    return null;
                }
                const {
                    year,
                    month,
                    day
                } = this.days[this.dayActiveIndex];
                const {
                    start,
                    end,
                    hoursStr
                } = this.hours[this.hourActiveIndex] || {};
                // console.log('---- result ----:',  year,month,day, start, end, hoursStr);
                return {
                    year: year,
                    month: this.isTwo? ('0' + month).slice(-2) : month,
                    day: this.isTwo? ('0' + day).slice(-2) : day,
                    hourStart: this.isTwo? ('0' + start).slice(-2) : start,
                    hourEnd: this.isTwo? ('0' + end).slice(-2) : end,
                    hoursStr: hoursStr,
                    anotherName: this.anotherNames[this.dayActiveIndex] || ''
                }
            },
            btnStr() {
                let hoursStr = '';
                if (!this.result) {
                    return '待选择';
                }
                if (this.result.hourStart === this.result.hourEnd) {
                    hoursStr = `${this.result.hourStart}:00(${this.result.hoursStr})`
                } else {
                    hoursStr = this.result.hoursStr;
                }
                // return `预约${this.result.year}年${this.result.month}月${this.result.day}日 ${hoursStr}`
            }
        },
        methods: {
            // 插件初如化
            init() {
                let firstDate = new Date();
                this.days = [];
                // 只生成明天和后天的数据
                for (let i = 1; i < 3; i++) {
                    const dateItem = new Date(firstDate.setDate(firstDate.getDate() + i));
                    this.days.push({
                        year: dateItem.getFullYear(),
                        month: dateItem.getMonth() + 1,
                        day: dateItem.getDate(),
                        value: `${dateItem.getMonth() + 1}-${dateItem.getDate()}`
                    })
                }
                // console.log('---- hbxw - timepicker ----:',  this.days);
            },
            // 切换月份
            toggleDay(index) {
                this.dayActiveIndex = index;
                this.hourActiveIndex = 0;
                this.$nextTick(() => {
                    this.$emit('change', {
                        result: this.result,
                        form: 'day'
                    });
                });
            },
            // 切换时间
            toggleHour(index) {
                this.hourActiveIndex = index;
                this.$nextTick(() => {
                    this.$emit('change', {
                        result: this.result,
                        form: 'hour'
                    });
                    if (this.isAutoClose) {
                        this.$emit('update:isShow', false);
                    }
                });
                this.$emit('change', {
                    result: this.result,
                    form: 'close'
                });
                this.$emit('update:isShow', false);
            },
            // 确认按钮
            sure() {
                this.$emit('change', {
                    result: this.result,
                    form:'sure'
                });
            },
            // 关闭弹窗方法
            close() {
                this.$emit('change', {
                    result: this.result,
                    form: 'close'
                });
                this.$emit('update:isShow', false);
            }
        }
    }
</script>
<style lang="scss" scoped>
	@keyframes showAni {
		0% {
			opacity: 0;
			transform: translateY(40%);
		}

		100% {
			transform: translateY(0);
			opacity: 1;
		}
	}

	.hbxw-timepicker {
		width: 100%;
		height: 100%;
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 9999
	}

	.hbxw-timepicker-mask {
		background-color: rgba(0, 0, 0, var(--opacity));
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 9998;
	}

	.hbxw-timepicker-main {
		position: absolute;
		left: 0;
		bottom: 0;
		z-index: 9999;
		width: 100%;
		display: flex;
		height: 48%;
		border-top-left-radius: 20px;
		border-top-right-radius: 20px;
		flex-direction: column;
		align-items: center;
		// border-radius: 40rpx 40rpx 0 0;
		// background-color: #F7F9FA;
		background-color: white;
		transform-origin: center bottom;
		opacity: 0;

		&.hbxw-timepicker-main-ani {
			opacity: 0;
		}
	}

	.hbxw-timepicker-ani {
		.hbxw-timepicker-main-ani {
			animation: showAni .3s linear 0.1s 1 forwards;
		}
	}

	.hbxw-timepicker-title {
		width: 100%;
		display: flex;
		flex-direction: column;
		position: relative;
		padding: 39rpx 32rpx 27rpx 32rpx;
		box-sizing: border-box;
		border-bottom: 1px solid #DCDFE0;

		.hbxw-timepicker-title-main {
			font-size: 32rpx;
			font-weight: bold;
			line-height: 54rpx;
			color: #000;
		}

		.hbxw-timepicker-title-subtitle {
			font-size: 25rpx;
			line-height: 48rpx;
			color: #000;
		}

		.hbxw-timepicker-close {
			width: 24rpx;
			height: 24rpx;
			position: absolute;
			top: 27rpx;
			right: 27rpx;
		}
	}

	.hbxw-timepicker-content {
		display: flex;
		flex-direction: row;
		width: 100%;
		// border-radius: 40rpx;
		height: 740rpx;
		overflow: hidden;
		background-color: white;
	}

	.hbxw-timerpicker-sure {
		width: 686rpx;
		height: 100rpx;
		background-color: #E44A6C;
		border-radius: 50rpx;
		text-align: center;
		font-size: 32rpx;
		line-height: 100rpx;
		font-weight: bold;
		margin: 51rpx 0 32rpx 0;
		color: #000;
	}

	.hbxw-timepicker-day {
		width: 370rpx;
		height: 100%;
		overflow-y: auto;
		background-color: #F7F7F7;

		.hbxw-timepicker-day-item {
			width: 100%;
			height: 110rpx;
			font-size: 26rpx;
			text-align: center;
			line-height: 110rpx;
			box-sizing: border-box;
			// border-bottom: 1px solid #DCDFE0;
			color: #737E85;

			&:nth-last-of-type(1) {
				border-bottom-color: transparent;
			}
		}

		.hbxw-timepicker-day-item-active {
			font-weight: bold;
			border-bottom: 1px solid white;
			background-color: white;
			color: #DA4C43;
			;
		}
	}

	.hbxw-timepicker-time {
		flex: 1;
		padding: 0 32rpx;
		height: 100%;
		overflow-y: auto;

		.hbxw-timepicker-time-item {
			height: 110rpx;
			flex: none;
			box-sizing: border-box;
			width: 100%;
			display: flex;
			flex-direction: row;
			justify-content: space-between;
			align-items: center;
			border-bottom: 1px solid #EBEDF0;
		}

		.hbxw-timepicker-time-item-active {
			.hbxw-timepicker-time-val {
				// color:#549204;
				color: #DA4C43;
			}

			.hbxw-timepicker-time-icon {

				// background-color: #AAF24E;
				// width: 30px;
				// height: 30px;
				.hbxw-timepicker-time-img {
					opacity: 1;
				}
			}
		}

		.hbxw-timepicker-time-val {
			font-size: 28rpx;
			color: #000;
		}

		.hbxw-timepicker-time-icon {
			width: 32rpx;
			height: 32rpx;
			box-sizing: border-box;
			border-radius: 50%;
			display: flex;
			flex-direction: row;
			justify-content: center;
			align-items: center;

			// border:1px solid #A2A4A6;
			.hbxw-timepicker-time-img {
				width: 52rpx;
				height: 52rpx;
				opacity: 0;
			}
		}
	}

	.hbxw-timepicker-notime {
		width: 100%;
		height: 100%;
		display: flex;
		flex-direction: row;
		align-items: center;
		justify-content: center;
	}

	.hbxw-timerpicker-nodata {
		font-size: 24rpx;
		color: #737E85;
	}
</style>


网站公告

今日签到

点亮在社区的每一天
去签到