654 lines
21 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>
<view class="picker-container" v-if="visible" :style="{'zIndex': zIndex}">
<view class="toolbar">
<text class="toolbar-btn toolbar-cancel" @click="cancel">取消</text>
<text class="toolbar-title" v-if="title">{{title}}</text>
<text class="toolbar-btn toolbar-sure" @click="sure">确认</text>
</view>
<view class="picker-tab">
<view class="picker-tab-item" @click="toggleTab('start')" :class="{'active':tabKey ==='start'}"><text>开始时间</text><text class="data-content">{{result.startStr ? result.startStr : '待选择'}}</text></view>
<view class="picker-tab-item" @click="toggleTab('end')" :class="{'active':tabKey ==='end'}"><text>结束时间</text><text class="data-content">{{result.endStr ? result.endStr : '待选择'}}</text></view>
</view>
<!-- 开始 -->
<picker-view
:indicator-style="indicatorStyle"
:value="valueStart"
v-if="tabKey ==='start'"
@change="bindChangeStart"
class="picker-view"
>
<picker-view-column class="picker-item year-picker" v-if="hasYear" style="padding-right:40rpx;">
<view class="item" v-for="(item,index) in years" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item month-picker" v-if="hasMonth">
<view class="item" v-for="(item,index) in months" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item day-picker" v-if="hasDay" style="margin-right: 40rpx;">
<view class="item" v-for="(item,index) in days" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item" :class="{'time-picker': hasMinute}" v-if="hasHour">
<view class="item" v-for="(item,index) in hours" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item" :class="{'time-picker': hasSecond}" v-if="hasMinute">
<view class="item" v-for="(item,index) in minutes" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item" v-if="hasSecond">
<view class="item" v-for="(item,index) in seconds" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
<!-- 结束 -->
<picker-view
:indicator-style="indicatorStyle"
:value="valueEnd"
v-if="tabKey ==='end'"
@change="bindChangeEnd"
class="picker-view"
>
<picker-view-column class="picker-item year-picker" v-if="hasYear">
<view class="item" v-for="(item,index) in yearsEnd" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item month-picker" v-if="hasMonth">
<view class="item" v-for="(item,index) in monthsEnd" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item day-picker" v-if="hasDay" style="margin-right: 40rpx;">
<view class="item" v-for="(item,index) in daysEnd" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item" :class="{'time-picker': hasMinute}" v-if="hasHour">
<view class="item" v-for="(item,index) in hoursEnd" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item" :class="{'time-picker': hasSecond}" v-if="hasMinute">
<view class="item" v-for="(item,index) in minutesEnd" :key="index">{{item}}</view>
</picker-view-column>
<picker-view-column class="picker-item" v-if="hasSecond">
<view class="item" v-for="(item,index) in secondsEnd" :key="index">{{item}}</view>
</picker-view-column>
</picker-view>
</view>
</template>
<script>
import {
createYearList,
createMonthList,
createDayList,
createHourList,
createMinuteList,
createSecondList,
createDateStr
} from '../../utils/util.js'
export default {
props: {
// 选择器标题
title: {
type: String,
default: '选择时间'
},
// 控制picker显示/隐藏
visible:{
type: Boolean,
default: false
},
// 时间选择器层级
zIndex: {
type: Number,
default: 9999
},
// 年份跨度往前的跨度如今年是2024那默认最早到2014
yearSpan: {
type: Number,
default: 10
},
// 选择器级别
level: {
type: String,
default: 'time',
validator: (value) => {
return ['date', 'time', 'year', 'month', 'day', 'hour', 'minute', 'second'].indexOf(value) !== -1;
},
}
// // 可以选择的最早日期,默认是10年前
// min: {
// type: String,
// default: () => {
// const now = new Date();
// return `${now.getFullYear() - 10}-01-01`;
// }
// },
// // 可以选择的最大日期
// max: {
// type: String,
// default: () => {
// const now = new Date();
// const maxDay = new Date(now.getFullYear(), now.getMonth(), 0).getDate();
// return `${now.getFullYear()}-12-${maxDay}`;
// }
// }
},
data() {
return {
tabKey: 'start', // start/end
years: [],
months: [],
days: [],
year: '',
month: '',
day: '',
hours: [],
minutes: [],
seconds: [],
hour: '',
minute: '',
second: '',
valueStart: [],
yearsEnd: [],
monthsEnd: [],
daysEnd: [],
yearEnd: '',
monthEnd: '',
dayEnd: '',
hoursEnd: [],
minutesEnd: [],
secondsEnd: [],
hourEnd: '',
minuteEnd: '',
secondEnd: '',
timeRange: '',
valueEnd: [],
indicatorStyle: `height: 50px;`,
result: {
values: [],
start: [],
end: [],
startStr: '',
endStr:'',
from: ''
}
}
},
computed: {
hasYear() {
return ['date', 'time', 'year', 'month', 'day', 'hour', 'minute', 'second'].includes(this.level);
},
hasMonth() {
return ['date', 'time', 'month', 'day', 'hour', 'minute', 'second'].includes(this.level);
},
hasDay() {
return ['date', 'time', 'day', 'hour', 'minute', 'second'].includes(this.level);
},
hasHour() {
return ['time', 'hour', 'minute', 'second'].includes(this.level);
},
hasMinute() {
return ['time', 'minute', 'second'].includes(this.level);
},
hasSecond() {
return ['time', 'second'].includes(this.level);
},
valIndex() {
if (this.hasSecond) {
return 6;
}
if (this.hasMinute) {
return 5;
}
if (this.hasHour) {
return 4;
}
if (this.hasDay) {
return 3;
}
if (this.hasMonth) {
return 2;
}
if (this.hasYear) {
return 1;
}
return 6;
}
},
mounted() {
this.initStart();
this.initEnd();
},
watch: {
// 开始时间切换不同的月份需要重置可以选择的天数
month(newVal) {
const maxDay = new Date(this.year, newVal, 0).getDate();
const days = [];
for (let day = 1; day <= maxDay; day ++) {
days.push(String(day).padStart(2, '0'));
}
this.days = days;
},
// 开始时间有变化就重置结束时间的选择
valueStart(newVal) {
this.initEnd();
},
// 切换年份
yearEnd(newVal) {
if (this.isWatch) {
return;
}
this.isWatch = true;
const isLimit = newVal == this.year;
// 可以选择的月份
const monthData = createMonthList(isLimit ? +this.month : 1, isLimit ? +this.month : 1);
this.monthsEnd = monthData.list;
// 可以选择的天,会根据月份有变化
const dayData = createDayList(newVal, isLimit ? this.month : 1, isLimit ? this.day : 1, isLimit ? this.day : 1);
this.daysEnd = dayData.list;
// 可选择的小时
const hourData = createHourList(isLimit ? this.hour : 0, isLimit ? this.hour : 0);
this.hoursEnd = hourData.list;
// 可选择的分钟
const minuteData = createMinuteList(isLimit ? this.minute : 0, isLimit ? this.minute : 0);
this.minutesEnd = minuteData.list;
// 可选择的秒
const secondData = createSecondList(isLimit ? this.second : 0, isLimit ? this.second : 0);
this.secondsEnd = secondData.list;
setTimeout(() => {
this.isWatch = false;
this.calculationEndValue(this.endValTemp);
}, 100);
},
// 切换年份
monthEnd(newVal) {
if (this.isWatch) {
return;
}
this.isWatch = true;
let isLimit = this.yearEnd == this.year && this.month == newVal;
// 可以选择的天,会根据月份有变化
const dayData = createDayList(this.yearEnd, newVal, isLimit ? this.day : 1, isLimit ? this.day : 1);
this.daysEnd = dayData.list;
// 可选择的小时
const hourData = createHourList(isLimit ? this.hour : 0, isLimit ? this.hour : 0);
this.hoursEnd = hourData.list;
// 可选择的分钟
const minuteData = createMinuteList(isLimit ? this.minute : 0, isLimit ? this.minute : 0);
this.minutesEnd = minuteData.list;
// 可选择的秒
const secondData = createSecondList(isLimit ? this.second : 0, isLimit ? this.second : 0);
this.secondsEnd = secondData.list;
setTimeout(() => {
this.isWatch = false;
this.calculationEndValue(this.endValTemp);
}, 100);
},
dayEnd(newVal) {
if (this.isWatch) {
return;
}
this.isWatch = true;
let isLimit = this.yearEnd == this.year && this.month == this.monthEnd && this.day === newVal;
// 可选择的小时
const hourData = createHourList(isLimit ? this.hour : 0, isLimit ? this.hour : 0);
this.hoursEnd = hourData.list;
// 可选择的分钟
const minuteData = createMinuteList(isLimit ? this.minute : 0, isLimit ? this.minute : 0);
this.minutesEnd = minuteData.list;
// 可选择的秒
const secondData = createSecondList(isLimit ? this.second : 0, isLimit ? this.second : 0);
this.secondsEnd = secondData.list;
setTimeout(() => {
this.isWatch = false;
this.calculationEndValue(this.endValTemp);
}, 100);
},
hourEnd(newVal) {
if (this.isWatch) {
return;
}
this.isWatch = true;
let isLimit = this.yearEnd == this.year
&& this.month == this.monthEnd
&& this.day === this.dayEnd
&& this.hour === newVal;
// 可选择的分钟
const minuteData = createMinuteList(isLimit ? this.minute : 0, isLimit ? this.minute : 0);
this.minutesEnd = minuteData.list;
// 可选择的秒
const secondData = createSecondList(isLimit ? this.second : 0, isLimit ? this.second : 0);
this.secondsEnd = secondData.list;
setTimeout(() => {
this.isWatch = false;
this.calculationEndValue(this.endValTemp);
}, 100);
},
minuteEnd(newVal) {
if (this.isWatch) {
return;
}
this.isWatch = true;
let isLimit = this.yearEnd == this.year
&& this.month == this.monthEnd
&& this.day === this.dayEnd
&& this.hour === this.hourEnd
&& this.minute === newVal;
// 可选择的秒
const secondData = createSecondList(isLimit ? this.second : 0, isLimit ? this.second : 0);
this.secondsEnd = secondData.list;
setTimeout(() => {
this.isWatch = false;
this.calculationEndValue(this.endValTemp);
}, 100);
}
// 切换不同的月份需要重置可以选择的天数
// monthEnd(newVal) {
// const maxDay = new Date(this.yearEnd, newVal, 0).getDate();
// const days = [];
// let minDays = 1;
// if (this.yearsEnd[this.valueEndsTemp[0]] === this.years[this.valueStartsTemp[0]] &&
// this.monthsEnd[this.valueEndsTemp[1]] === this.months[this.valueStartsTemp[1]]) {
// minDays = this.days[this.valueStartsTemp[2]]
// }
// for (let day = minDays; day <= maxDay; day ++) {
// days.push(String(day).padStart(2, '0'));
// }
// this.daysEnd = days;
// }
},
methods: {
toggleTab(type) {
this.tabKey = type;
},
initStart() {
const now = new Date();
const nowYear = now.getFullYear();
const nowMonth = now.getMonth() + 1;
const nowDay = now.getDate();
const nowHour = now.getHours();
const nowMinute = now.getMinutes();
const nowSecond = now.getSeconds();
const span = this.yearSpan !== undefined ? this.yearSpan : 10;
let nowYearIndex = -1;
let nowMonthIndex = -1;
let nowDayIndex = -1;
let nowTimeIndex = -1;
let nowHourIndex = -1;
let nowMinuteIndex = -1;
let nowSecondIndex = -1;
// 生成年份选项数据往前span年
const yearData = createYearList(nowYear, span);
this.years = yearData.list;
nowYearIndex = yearData.index;
// 可以选择的月份
const monthData = createMonthList(nowMonth, 1);
this.months = monthData.list;
nowMonthIndex = monthData.index;
// 可以选择的天,会根据月份有变化
const dayData = createDayList(nowYear, nowMonth, nowDay, 1);
console.log('---- createDayList ----:', dayData);
this.days = dayData.list;
nowDayIndex = dayData.index;
// 可选择的小时
const hourData = createHourList(nowHour, 0);
this.hours = hourData.list;
nowHourIndex = hourData.index;
// 可选择的分钟
const minuteData = createMinuteList(nowMinute, 0);
this.minutes = minuteData.list;
nowMinuteIndex = minuteData.index;
// 可选择的秒
const secondData = createSecondList(nowSecond, 0);
this.seconds = secondData.list;
nowSecondIndex = secondData.index;
this.valueStartsTemp = [nowYearIndex,nowMonthIndex,nowDayIndex,nowHourIndex, nowMinuteIndex, nowSecondIndex].filter((item) => item >= 0).slice(0, this.valIndex);
console.log('---- this.valueStartsTemp ----:', this.valueStartsTemp)
this.$nextTick(() => {
// this.value = [nowYearIndex,nowMonthIndex,nowDayIndex,nowTimeIndex];
setTimeout(() => {
this.valueStart = this.valueStartsTemp;
this.calculationStartValue(this.valueStart);
}, 0)
})
},
initEnd() {
const val = this.valueStartsTemp;
let nowYear = +this.years[val[0]];
let nowMonth = +this.months[val[1]];
let nowDay = +this.days[val[2]];
let nowHour = +this.hours[val[3]];
let nowMinute = +this.minutes[val[4]];
let nowSecond = +this.seconds[val[5]];
const span = this.yearSpan !== undefined ? this.yearSpan : 10;
let nowYearIndex = -1;
let nowMonthIndex = -1;
let nowDayIndex = -1;
let nowTimeIndex = -1;
let nowHourIndex = -1;
let nowMinuteIndex = -1;
let nowSecondIndex = -1;
// 生成年份选项数据往后span年
const yearData = createYearList(nowYear, span, nowYear);
this.yearsEnd = yearData.list;
nowYearIndex = yearData.index;
// 可以选择的月份
const monthData = createMonthList(nowMonth, nowMonth);
this.monthsEnd = monthData.list;
nowMonthIndex = monthData.index;
// 可以选择的天,会根据月份有变化
const dayData = createDayList(nowYear, nowMonth, nowDay, nowDay);
this.daysEnd = dayData.list;
nowDayIndex = dayData.index;
// 可选择的小时
const hourData = createHourList(nowHour, nowHour);
this.hoursEnd = hourData.list;
nowHourIndex = hourData.index;
// 可选择的分钟
const minuteData = createMinuteList(nowMinute, nowMinute);
this.minutesEnd = minuteData.list;
nowMinuteIndex = minuteData.index;
// 可选择的秒
const secondData = createSecondList(nowSecond, nowSecond);
this.secondsEnd = secondData.list;
nowSecondIndex = secondData.index;
this.valueEndsTemp = [nowYearIndex,nowMonthIndex,nowDayIndex,nowHourIndex, nowMinuteIndex, nowSecondIndex].filter((item) => item >= 0).slice(0, this.valIndex);
this.$nextTick(() => {
// this.value = [nowYearIndex,nowMonthIndex,nowDayIndex,nowTimeIndex];
setTimeout(() => {
this.valueEnd = this.valueEndsTemp;
this.calculationEndValue(this.valueEnd);
}, 0)
})
},
cancel() {
this.$emit('cancel');
},
sure() {
this.result.from = 'sure';
this.$emit('sure', this.result);
},
// 计算开始时间
calculationStartValue(val) {
if (!val) {
this.result.values[0] = [];
this.valueStart = [];
this.valueStartsTemp = [];
this.result.start = '';
this.result.from = '';
return;
}
this.year = this.years[val[0]];
this.month = this.months[val[1]];
this.day = this.days[val[2]];
this.hour = this.hours[val[3]];
this.minute = this.minutes[val[4]];
this.second = this.seconds[val[5]];
this.result.values[0] = val.filter((item) => item >= 0);
this.valueStart = val.filter((item) => item >= 0);
this.valueStartsTemp = val.filter((item) => item >= 0);
this.result.start = [this.year+'',this.month,this.day,this.hour,this.minute,this.second].filter((item) => item);
this.result.startStr = createDateStr(this.year,this.month,this.day,this.hour,this.minute,this.second);
},
// 计算结束时间
calculationEndValue(val) {
if (!val) {
this.result.values[0] = [];
this.valueEnd = [];
this.valueEndsTemp = [];
this.result.end = '';
this.result.from = '';
return;
}
// console.log('---- calculationEndValue ----:', val, this.yearsEnd, this.monthsEnd, this.daysEnd);
this.yearEnd = this.yearsEnd[val[0]];
this.monthEnd = this.monthsEnd[val[1]];
this.dayEnd = this.daysEnd[val[2]];
this.hourEnd = this.hoursEnd[val[3]];
this.minuteEnd = this.minutesEnd[val[4]];
this.secondEnd = this.secondsEnd[val[5]];
this.result.values[1] = val.filter((item) => item >= 0);
this.valueEnd = val.filter((item) => item >= 0);
this.valueEndsTemp = val.filter((item) => item >= 0);
this.result.end = [this.yearEnd + '',this.monthEnd,this.dayEnd,this.hourEnd,this.minuteEnd,this.secondEnd].filter((item) => item);
this.endValTemp = val;
this.result.endStr = createDateStr(this.yearEnd, this.monthEnd, this.dayEnd, this.hourEnd, this.minuteEnd, this.secondEnd);
},
bindChangeStart: function (e) {
this.calculationStartValue(e.detail.value);
this.result.from = 'start';
this.startValTemp = e.detail.value;
this.$emit('change', this.result)
},
bindChangeEnd: function (e) {
this.calculationEndValue(e.detail.value);
this.result.from = 'end';
this.$emit('change', this.result)
},
}
}
</script>
<style lang="scss" scoped>
.picker-container{
position: fixed;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
border-radius: 24rpx 24rpx 0 0;
overflow: hidden;
border-top: 1px solid #E8E8E8;
box-shadow: 0 0 15rpx rgba(0,0,0,.1);
background-color: #fff;
}
.toolbar{
display: flex;
justify-content: space-between;
align-items: center;
.toolbar-btn{
padding:36rpx 32rpx;
line-height: 44rpx;
font-size: 32rpx;
}
.toolbar-cancel{
color: rgba(0, 0, 0, 0.6);
}
.toolbar-sure{
color: rgba(40, 126, 255, 1);
}
.toolbar-title{
flex:1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 36rpx;
text-align: center;
font-weight: 700;
color: rgba(0, 0, 0, 0.9);
}
}
.picker-view {
width: 750rpx;
padding:0 32rpx;
box-sizing: border-box;
height: 400rpx;
}
.item {
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
text-align: center;
color: rgba(0, 0, 0, 0.9);
}
.picker-tab{
display: flex;
align-items: center;
.picker-tab-item{
flex: 1;
display: flex;
flex-direction: column;
font-size: 32rpx;
line-height: 1.5em;
height: 3em;
text-align: center;
border-bottom: 2px solid transparent;
&.active{
border-bottom: 2px solid rgba(40, 126, 255, 1);
}
}
.data-content{
font-size: 24rpx;
color: #999;
}
}
.picker-item{
position: relative;
overflow: visible;
}
.picker-item::after{
position: absolute;
left: 100%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 32rpx;
line-height: 1em;
display: flex;
align-items: center;
color: #999;
}
.year-picker::after{
content: '年';
}
.month-picker::after{
content: '月';
}
.day-picker::after{
content: '日';
}
.time-picker::after{
content: ':';
}
</style>