merchapp/java-mall-app-shop-admin/pages/my/storeBusinessStatus/oz-timePicker/oz-timePicker.vue
2025-06-30 12:32:31 +08:00

387 lines
8.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<!-- 时间选择器弹窗 -->
<uni-popup ref="popup" type="bottom" :safe-area="false">
<view class="custom-picker">
<view class="custom-picker__header">
<view class="cancel" :style="{ color: canceColor }" @tap="onCancel">
{{ cancelText }}
</view>
<view class="title">{{ title }}</view>
<view class="confirm" :style="{ color: confirmColor }" @tap="onConfirm">
{{ confirmText }}
</view>
</view>
<view class="time-tips">
为保证有骑手接单请在配送站点营业时间00:00-24:00内选择
</view>
<picker-view
:indicator-class="indicatorClass"
:indicator-style="indicatorStyle"
class="picker-view"
:value="pickerValue"
@change="bindChange"
@pickstart="pickstart"
@pickend="pickend"
>
<picker-view-column>
<view
:class="['picker-view__item']"
v-for="(item, index) in rangeList[0]"
:key="index"
>
{{ item }}
</view>
</picker-view-column>
<picker-view-column>
<view
class="picker-view__item"
v-for="(item, index) in rangeList[1]"
:key="index"
>
{{ item }}
</view>
</picker-view-column>
<picker-view-column>
<view class="picker-view__item">{{ segmentation }}</view>
</picker-view-column>
<picker-view-column>
<view
class="picker-view__item"
v-for="(item, index) in rangeList[2]"
:key="index"
>
{{ item }}
</view>
</picker-view-column>
<picker-view-column>
<view
class="picker-view__item"
v-for="(item, index) in rangeList[3]"
:key="index"
>
{{ item }}
</view>
</picker-view-column>
</picker-view>
</view>
<view class="bottom-content">
</view>
</uni-popup>
</template>
<script>
// 滚动数据
let range = [[], [], [], []];
for (let i = 0; i <= 24; i++) {
range[0].push(i >= 10 ? String(i) : `0${i}`);
range[2].push(i >= 10 ? String(i) : `0${i}`);
}
for (let i = 0; i < 60; i++) {
range[1].push(i >= 10 ? String(i) : `0${i}`);
range[3].push(i >= 10 ? String(i) : `0${i}`);
}
export default {
name: "TimePickerPopup",
props: {
// 当前选中的值
value: {
type: Array,
default: () => ["00", "00", "00", "00"],
},
// 标题
title: {
type: String,
default: "时间",
},
// 取消按钮文字
cancelText: {
type: String,
default: "取消",
},
// 取消按钮颜色
canceColor: {
type: String,
default: "#666666",
},
// 确定按钮文字
confirmText: {
type: String,
default: "确定",
},
// 确定按钮颜色
confirmColor: {
type: String,
default: "#2bb781",
},
// 分割符
segmentation: {
type: String,
default: "-",
},
// 设置选择器中间选中框的类名 注意页面或组件的style中写了scoped时需要在类名前写/deep/
indicatorClass: {
type: String,
default: "picker-view__indicator",
},
// 设置选择器中间选中框的样式
indicatorStyle: {
type: String,
default: "",
},
maxStartHour: {
type: Number,
default: 23, // 默认23点
},
maxStartMinute: {
type: Number,
default: 30, // 默认59分钟
},
maxEndHour: {
type: Number,
default: 24, // 默认23点
},
maxEndMinute: {
type: Number,
default: 59, // 默认59分钟
},
},
data() {
return {
rangeList: [],
pickerValue: [0, 0, 0, 0],
isScoll: false, // 是否正在滚动
};
},
created() {
this.generateRangeLists();
},
watch: {
// 监听最大时间限制变化
maxStartHour() {
this.generateRangeLists();
},
maxStartMinute() {
this.generateRangeLists();
},
maxEndHour() {
this.generateRangeLists();
},
maxEndMinute() {
this.generateRangeLists();
},
},
methods: {
generateRangeLists() {
const ranges = [[], [], [], []];
// 生成开始小时范围 (0 - maxStartHour)
for (let i = 0; i <= this.maxStartHour; i++) {
ranges[0].push(i >= 10 ? String(i) : `0${i}`);
}
// 生成开始分钟范围 (0 - maxStartMinute)
for (let i = 0; i <= this.maxStartMinute; i++) {
ranges[1].push(i >= 10 ? String(i) : `0${i}`);
}
// 生成结束小时范围 (0 - maxEndHour)
for (let i = 0; i <= this.maxEndHour; i++) {
ranges[2].push(i >= 10 ? String(i) : `0${i}`);
}
// 生成结束分钟范围 (0 - maxEndMinute)
// 如果结束小时是24分钟只能是00
if (
this.pickerValue &&
this.pickerValue[2] === this.rangeList[2]?.length - 1
) {
ranges[3] = ["00"];
} else {
for (let i = 0; i <= this.maxEndMinute; i++) {
ranges[3].push(i >= 10 ? String(i) : `0${i}`);
}
}
this.rangeList = ranges;
},
/**
* 开启弹窗
*/
open() {
this.generateRangeLists();
if (Array.isArray(this.value) && this.value.length) {
this.pickerValue = this.value.map((item, index) => {
const i = this.rangeList[index].findIndex(
(child) => Number(child) == Number(this.value[index])
);
return i > -1 ? i : 0;
});
// If initial end hour is 24, ensure minute is 00
if (this.pickerValue[2] === this.rangeList[2]?.length - 1) {
this.pickerValue[3] = 0;
this.generateRangeLists();
}
} else {
this.pickerValue = [0, 0, 0, 0];
}
this.$refs.popup.open();
},
/**
* 关闭弹窗
*/
close() {
this.$refs.popup.close();
// 重置选中数据
this.pickerValue = [0, 0, 0, 0];
},
/**
* 点击确定
*/
onConfirm() {
if (!this.isScoll) {
let data = this.value || ["00", "00", "00", "00"];
if (this.pickerValue && this.pickerValue.length) {
data = this.pickerValue.map((item, index) =>
String(this.rangeList[index][item])
);
}
this.$emit("confirm", data);
this.close();
}
},
/**
* 点击取消
*/
onCancel() {
this.close();
},
/**
* 滚动开始
*/
pickstart() {
this.isScoll = true;
},
/**
* 滚动结束
*/
pickend() {
this.isScoll = false;
},
/**
* 选择器改变
* @param {Object} e
*/
bindChange(e) {
const newValue = [...e.detail.value];
// Check if end hour (index 2) is being set to 24
if (newValue[2] === this.rangeList[2]?.length - 1) {
// Assuming 24 is the last option
newValue[3] = 0; // Set to first (and only) option which is '00'
this.pickerValue = newValue;
this.generateRangeLists(); // Regenerate ranges to limit minutes
} else {
this.pickerValue = newValue;
}
},
},
};
</script>
<style lang="scss" scoped>
.custom-picker {
width: 100%;
height: 620rpx;
background-color: #fff;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
&__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 30rpx 40rpx;
.cancel {
color: #666;
}
.title {
font-weight: 500;
font-size: 32rpx;
color: #333;
}
.confirm {
color: #2bb781;
}
}
}
.picker-view {
width: 100%;
height: 100%;
margin-top: 20rpx;
&__item {
line-height: 100rpx;
text-align: center;
}
::v-deep &__indicator {
height: 100rpx;
color: #2bb781;
}
&__segmentation {
display: flex;
align-items: center;
}
}
.time-tips {
padding: 24rpx;
font-size: 26rpx;
background: #fadbd8;
}
.acitve {
&::after,
&::before {
position: initial;
}
position: relative;
z-index: 1;
background: #efefef;
margin: 0 16rpx;
border-radius: 24rpx;
height: 80rpx;
}
::v-deep .uni-picker-view-content {
z-index: 2;
}
::v-deep .uni-picker-view-indicator {
width: 82%;
}
::v-deep .picker-view__item {
margin-left: 20rpx;
width: 80%;
font-size: 36rpx;
height: 80rpx;
line-height: 80rpx;
}
::v-deep .picker-view{
height: 60%;
}
</style>