330 lines
7.4 KiB
Vue
330 lines
7.4 KiB
Vue
|
|
<template>
|
||
|
|
<view class="add-page">
|
||
|
|
<!-- 其他内容 -->
|
||
|
|
|
||
|
|
<!-- 时间选择弹框 -->
|
||
|
|
<view class="popup-mask" v-if="showTimePicker" @click="closeTimePicker"></view>
|
||
|
|
<view class="time-picker" :class="{ show: showTimePicker }">
|
||
|
|
<view class="picker-header">
|
||
|
|
<text class="cancel" @click="closeTimePicker">取消</text>
|
||
|
|
<text class="title">选择时间</text>
|
||
|
|
<text class="confirm" @click="confirmTime">确定</text>
|
||
|
|
</view>
|
||
|
|
<view class="time-range">
|
||
|
|
<view class="time-block" :class="{ active: timeType === 'start' }" @click="switchTimeType('start')">
|
||
|
|
<text class="time-value">{{formatTime(startTime)}}</text>
|
||
|
|
<text class="time-label">开始时间</text>
|
||
|
|
</view>
|
||
|
|
<text class="time-separator">至</text>
|
||
|
|
<view class="time-block" :class="{ active: timeType === 'end' }" @click="switchTimeType('end')">
|
||
|
|
<text class="time-value">{{formatTime(endTime)}}</text>
|
||
|
|
<text class="time-label">结束时间</text>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
<view class="picker-content">
|
||
|
|
<picker-view
|
||
|
|
:value="pickerValue"
|
||
|
|
@change="handleTimeChange"
|
||
|
|
class="picker-view"
|
||
|
|
:indicator-style="indicatorStyle"
|
||
|
|
>
|
||
|
|
<picker-view-column>
|
||
|
|
<view class="picker-item" v-for="(hour, index) in hours" :key="index">
|
||
|
|
{{hour}}
|
||
|
|
</view>
|
||
|
|
</picker-view-column>
|
||
|
|
<picker-view-column>
|
||
|
|
<view class="picker-item" v-for="(minute, index) in minutes" :key="index">
|
||
|
|
{{minute}}
|
||
|
|
</view>
|
||
|
|
</picker-view-column>
|
||
|
|
<picker-view-column>
|
||
|
|
<view class="picker-item">
|
||
|
|
-
|
||
|
|
</view>
|
||
|
|
</picker-view-column>
|
||
|
|
<picker-view-column>
|
||
|
|
<view class="picker-item" v-for="(hour, index) in hours" :key="index">
|
||
|
|
{{hour}}
|
||
|
|
</view>
|
||
|
|
</picker-view-column>
|
||
|
|
<picker-view-column>
|
||
|
|
<view class="picker-item" v-for="(minute, index) in minutes" :key="index">
|
||
|
|
{{minute}}
|
||
|
|
</view>
|
||
|
|
</picker-view-column>
|
||
|
|
</picker-view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</view>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
export default {
|
||
|
|
data() {
|
||
|
|
return {
|
||
|
|
showTimePicker: true,
|
||
|
|
pickerValue: [19, 34, 0, 20, 34],
|
||
|
|
hours: Array.from({length: 24}, (_, i) => i < 10 ? `0${i}` : `${i}`),
|
||
|
|
minutes: Array.from({length: 60}, (_, i) => i < 10 ? `0${i}` : `${i}`),
|
||
|
|
timeType: 'start',
|
||
|
|
indicatorStyle: 'height: 80rpx;'
|
||
|
|
}
|
||
|
|
},
|
||
|
|
computed: {
|
||
|
|
startTime() {
|
||
|
|
return {
|
||
|
|
hour: this.hours[this.pickerValue[0]],
|
||
|
|
minute: this.minutes[this.pickerValue[1]]
|
||
|
|
}
|
||
|
|
},
|
||
|
|
endTime() {
|
||
|
|
return {
|
||
|
|
hour: this.hours[this.pickerValue[3]],
|
||
|
|
minute: this.minutes[this.pickerValue[4]]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
methods: {
|
||
|
|
// 打开时间选择器
|
||
|
|
openTimePicker() {
|
||
|
|
this.showTimePicker = true
|
||
|
|
setTimeout(() => {
|
||
|
|
const mask = document.querySelector('.popup-mask')
|
||
|
|
if (mask) mask.classList.add('show')
|
||
|
|
}, 0)
|
||
|
|
},
|
||
|
|
// 关闭时间选择器
|
||
|
|
closeTimePicker() {
|
||
|
|
const mask = document.querySelector('.popup-mask')
|
||
|
|
if (mask) mask.classList.remove('show')
|
||
|
|
|
||
|
|
setTimeout(() => {
|
||
|
|
this.showTimePicker = false
|
||
|
|
}, 300)
|
||
|
|
},
|
||
|
|
// 切换时间类型(开始/结束)
|
||
|
|
switchTimeType(type) {
|
||
|
|
this.timeType = type
|
||
|
|
},
|
||
|
|
// 处理时间变化
|
||
|
|
handleTimeChange(e) {
|
||
|
|
const values = e.detail.value
|
||
|
|
console.log(values)
|
||
|
|
// 检查开始时间是否大于结束时间
|
||
|
|
const startMinutes = parseInt(this.hours[values[0]]) * 60 + parseInt(this.minutes[values[1]])
|
||
|
|
const endMinutes = parseInt(this.hours[values[3]]) * 60 + parseInt(this.minutes[values[4]])
|
||
|
|
|
||
|
|
if (startMinutes >= endMinutes) {
|
||
|
|
// 如果开始时间大于等于结束时间,将结束时间设置为开始时间后一小时
|
||
|
|
const newEndHour = (parseInt(this.hours[values[0]]) + 1) % 24
|
||
|
|
values[3] = newEndHour
|
||
|
|
values[4] = values[1]
|
||
|
|
}
|
||
|
|
|
||
|
|
this.pickerValue = values
|
||
|
|
},
|
||
|
|
// 格式化时间显示
|
||
|
|
formatTime(time) {
|
||
|
|
return `${time.hour}:${time.minute}`
|
||
|
|
},
|
||
|
|
// 确认选择
|
||
|
|
confirmTime() {
|
||
|
|
const result = {
|
||
|
|
start: this.formatTime(this.startTime),
|
||
|
|
end: this.formatTime(this.endTime)
|
||
|
|
}
|
||
|
|
console.log('Selected time range:', result)
|
||
|
|
this.closeTimePicker()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style>
|
||
|
|
/* 遮罩层 */
|
||
|
|
.popup-mask {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
bottom: 0;
|
||
|
|
background-color: rgba(0, 0, 0, 0.5);
|
||
|
|
z-index: 998;
|
||
|
|
opacity: 0;
|
||
|
|
transition: opacity 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.popup-mask.show {
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 时间选择器 */
|
||
|
|
.time-picker {
|
||
|
|
position: fixed;
|
||
|
|
left: 0;
|
||
|
|
right: 0;
|
||
|
|
bottom: -100%;
|
||
|
|
background-color: #fff;
|
||
|
|
z-index: 999;
|
||
|
|
border-radius: 24rpx 24rpx 0 0;
|
||
|
|
/* #ifdef H5 */
|
||
|
|
transition: bottom 0.3s ease;
|
||
|
|
/* #endif */
|
||
|
|
/* #ifdef APP-PLUS || MP-WEIXIN */
|
||
|
|
transform: translateY(100%);
|
||
|
|
transition: transform 0.3s ease;
|
||
|
|
/* #endif */
|
||
|
|
}
|
||
|
|
|
||
|
|
/* #ifdef H5 */
|
||
|
|
.time-picker.show {
|
||
|
|
bottom: 0;
|
||
|
|
}
|
||
|
|
/* #endif */
|
||
|
|
|
||
|
|
/* #ifdef APP-PLUS || MP-WEIXIN */
|
||
|
|
.time-picker.show {
|
||
|
|
transform: translateY(0);
|
||
|
|
}
|
||
|
|
/* #endif */
|
||
|
|
|
||
|
|
/* 选择器头部 */
|
||
|
|
.picker-header {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
height: 110rpx;
|
||
|
|
padding: 0 32rpx;
|
||
|
|
border-bottom: 1rpx solid #F5F5F5;
|
||
|
|
}
|
||
|
|
|
||
|
|
.cancel {
|
||
|
|
font-size: 32rpx;
|
||
|
|
color: #666666;
|
||
|
|
}
|
||
|
|
|
||
|
|
.title {
|
||
|
|
font-size: 36rpx;
|
||
|
|
color: #333333;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.confirm {
|
||
|
|
font-size: 32rpx;
|
||
|
|
color: #4080FF;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 时间范围选择 */
|
||
|
|
.time-range {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
padding: 32rpx;
|
||
|
|
background: #F8F9FC;
|
||
|
|
}
|
||
|
|
|
||
|
|
.time-block {
|
||
|
|
flex: 1;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
align-items: center;
|
||
|
|
position: relative;
|
||
|
|
background: #FFFFFF;
|
||
|
|
border-radius: 12rpx;
|
||
|
|
padding: 24rpx 0;
|
||
|
|
transition: all 0.3s ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
.time-block.active {
|
||
|
|
background: #ECF2FF;
|
||
|
|
}
|
||
|
|
|
||
|
|
.time-label {
|
||
|
|
font-size: 26rpx;
|
||
|
|
color: #999999;
|
||
|
|
margin-top: 8rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
.time-value {
|
||
|
|
font-size: 40rpx;
|
||
|
|
color: #333333;
|
||
|
|
font-weight: 500;
|
||
|
|
}
|
||
|
|
|
||
|
|
.time-block.active .time-value {
|
||
|
|
color: #4080FF;
|
||
|
|
}
|
||
|
|
|
||
|
|
.time-separator {
|
||
|
|
font-size: 28rpx;
|
||
|
|
color: #999999;
|
||
|
|
margin: 0 24rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 选择器内容区 */
|
||
|
|
.picker-content {
|
||
|
|
height: 480rpx;
|
||
|
|
position: relative;
|
||
|
|
padding: 0 32rpx;
|
||
|
|
background-color: #FFFFFF;
|
||
|
|
}
|
||
|
|
|
||
|
|
.picker-view {
|
||
|
|
width: 100%;
|
||
|
|
height: 100%;
|
||
|
|
}
|
||
|
|
|
||
|
|
.picker-item {
|
||
|
|
height: 80rpx;
|
||
|
|
line-height: 80rpx;
|
||
|
|
text-align: center;
|
||
|
|
font-size: 36rpx;
|
||
|
|
color: #333333;
|
||
|
|
font-weight: 400;
|
||
|
|
}
|
||
|
|
|
||
|
|
.picker-indicator .time-label {
|
||
|
|
font-size: 24rpx;
|
||
|
|
color: #999999;
|
||
|
|
background-color: #F5F7FA;
|
||
|
|
padding: 8rpx 32rpx;
|
||
|
|
border-radius: 8rpx;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 修改选择器中间指示器的样式 */
|
||
|
|
.uni-picker-view-indicator {
|
||
|
|
height: 80rpx !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
.uni-picker-view-mask {
|
||
|
|
background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4)),
|
||
|
|
linear-gradient(0deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.4)) !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 平台特定样式 */
|
||
|
|
/* #ifdef H5 */
|
||
|
|
.picker-view {
|
||
|
|
height: 480rpx !important;
|
||
|
|
}
|
||
|
|
/* #endif */
|
||
|
|
|
||
|
|
/* #ifdef APP-PLUS */
|
||
|
|
.picker-view {
|
||
|
|
height: 480rpx !important;
|
||
|
|
}
|
||
|
|
/* #endif */
|
||
|
|
|
||
|
|
/* #ifdef MP-WEIXIN */
|
||
|
|
.picker-view {
|
||
|
|
height: 480rpx !important;
|
||
|
|
}
|
||
|
|
|
||
|
|
.picker-item {
|
||
|
|
display: flex;
|
||
|
|
justify-content: center;
|
||
|
|
align-items: center;
|
||
|
|
}
|
||
|
|
/* #endif */
|
||
|
|
</style>
|