mrr.sj.front/components/time-picker/time-date-picker.vue

430 lines
12 KiB
Vue
Raw Permalink 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" border-radius="20rpx 20rpx 0 0" background-color="#fff" style="z-index: 20000">
<!-- 时间选择滚轮 -->
<view class="region-body">
<image class="region-body__close" @click="close"
src="https://mrrplus.oss-cn-beijing.aliyuncs.com/photo/system/693c54b5-f5a5-4aa0-8d7b-6123250f9839">
</image>
<view class="region-body__header"> 请选择时间段 </view>
<picker-view v-model="pickerValue" @change="handleTimeChange" class="picker-scroll"
:indicator-style="indicatorStyle" immediate-change>
<picker-view-column v-if="pickerShowList[0]">
<view class="picker-item" v-for="(year, index) in years" :key="index">
{{ year }}年
</view>
</picker-view-column>
<picker-view-column v-if="pickerShowList[1]">
<view class="picker-item" v-for="(month, index) in months" :key="index">
{{ month }}月
</view>
</picker-view-column>
<picker-view-column v-if="pickerShowList[2]">
<view class="picker-item" v-for="(date, index) in dates[pickerValue[0]][pickerValue[1]]"
:key="index">
{{ date }}日
</view>
</picker-view-column>
<picker-view-column v-if="pickerShowList[3]">
<view class="picker-item" v-for="(hour, index) in hours" :key="index">
{{ hour }}时
</view>
</picker-view-column>
<picker-view-column v-if="pickerShowList[4]">
<view class="picker-item" v-for="(minute, index) in minutes" :key="index">
{{ minute }}
</view>
</picker-view-column>
</picker-view>
<view class="region-body__btn" :class="{'noSure':timeCompareComputed}" @tap="confirmTime">确认
{{ `(${formatTime})` }}
</view>
</view>
</uni-popup>
</template>
<script>
export default {
data() {
return {
sureTime: null,
default_times: "",
business_time: "",
indicatorStyle: "height: 68rpx;",
pickerValue: [0, 0, 0, 0, 0],
pickerShowList: [1, 1, 1, 1, 1],
years: [],
months: Array.from({
length: 12
}, (_, i) => i + 1),
dates: [],
hours: Array.from({
length: 24
}, (_, i) => i),
minutes: Array.from({
length: 60
}, (_, i) => i),
};
},
props: {
value: String,
timeIndex: {
type: Number,
default: 0,
},
timeList: {
type: Array,
},
type: {
type: String,
default: 'datetimerange', //datetimerange:年月日时分daterange年月日;yearMonth年月
},
startYear:{
type: Number,
default: 1980,
},
endDistanceYear:{
type: Number,
default: 20,//结束时间,与当前时间点相距的时间
},
},
created() {
//初始化滑块显示行数
if (this.type == 'datetimerange') {
this.pickerShowList = [1, 1, 1, 1, 1]
this.pickerValue = [0, 0, 0, 0, 0]
} else if (this.type == 'daterange') {
this.pickerShowList = [1, 1, 1]
this.pickerValue = [0, 0, 0]
} else if (this.type == 'yearMonth') {
this.pickerShowList = [1, 1]
this.pickerValue = [0, 0]
}
//初始化时间数组
this.setTimesList();
},
computed: {
//获取当月最大天数
formatTime() {
if (this.type == 'datetimerange') {
// 将“/”替换为“-”,并保持时间补零逻辑
this.sureTime = `${this.years[this.pickerValue[0]]}-${this.months[
this.pickerValue[1]
]
.toString()
.padStart(2, "0")}-${this.dates[this.pickerValue[0]][
this.pickerValue[1]
][this.pickerValue[2]]
?.toString()
.padStart(2, "0")} ${this.hours[this.pickerValue[3]]
.toString()
.padStart(2, "0")}:${this.minutes[this.pickerValue[4]]
.toString()
.padStart(2, "0")}:00`;
} else if (this.type == 'daterange') {
this.sureTime = `${this.years[this.pickerValue[0]]}-${this.months[
this.pickerValue[1]
]
.toString()
.padStart(2, "0")}-${this.dates[this.pickerValue[0]][
this.pickerValue[1]
][this.pickerValue[2]]
?.toString()
.padStart(2, "0")}`;
} else if (this.type == 'yearMonth') {
this.sureTime = `${this.years[this.pickerValue[0]]}-${this.months[
this.pickerValue[1]
]
.toString()
.padStart(2, "0")}`;
}
return this.sureTime;
},
timeCompareComputed() {
if ((this.timeIndex == 0 && this.timeList[1]) || (this.timeIndex == 1 && this.timeList[0]) && this
.formatTime) {
if (this.timeIndex == 0) {
// 开始时间
if (!this.timeCompare(this.formatTime, this.timeList[1])) {
return true;
} else {
return false;
}
} else {
// 结束时间
if (!this.timeCompare(this.timeList[0], this.formatTime)) {
return true;
} else {
return false;
}
}
}
},
},
watch: {
value: {
handler(newVal) {
if (newVal) {
this.setPickerValue();
}
},
immediate: true,
},
},
methods: {
setTimesList() {
// 初始化时间数组
const currentYear = new Date().getFullYear();
const startYear = this.startYear; // 开始年份
const endYear = currentYear + this.endDistanceYear; // 结束年份
const yearCount = endYear - startYear + 1; // 总年数
for (let i = 0; i < yearCount; i++) {
const year = startYear + i;
this.years.push(year);
this.dates[i] = [];
for (let n = 1; n <= 12; n++) {
let num = this.getMonthDay(year, n); // 使用当前循环的年份计算天数
this.dates[i][n - 1] = Array.from({
length: num
},
(_, idx) => idx + 1
);
}
}
// 无value时设置默认当前时间
if (!this.value) {
this.setDefaultPickerValue();
}
},
// 新增:设置默认当前时间的索引
setDefaultPickerValue() {
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1; // 转换为1-12
const currentDate = now.getDate();
const currentHour = now.getHours();
const currentMinute = now.getMinutes();
// 计算各维度索引
const yearIndex = this.years.findIndex(y => y === currentYear);
const monthIndex = this.months.findIndex(m => m === currentMonth);
const dayIndex = this.dates[yearIndex]?.[monthIndex]?.findIndex(d => d === currentDate) ?? 0;
const hourIndex = this.hours.findIndex(h => h === currentHour);
const minuteIndex = this.minutes.findIndex(m => m === currentMinute);
this.pickerValue = [yearIndex, monthIndex, dayIndex, hourIndex, minuteIndex];
},
setPickerValue() {
if (this.value) {
// 统一将输入的日期字符串中的“-”替换为“/”,兼容解析
const normalizedValue = this.value.replace(/-/g, '/');
if (this.type == 'datetimerange') {
// 解析时间字符串 '2024/05/27 11:31:00'
const [datePart, timePart] = normalizedValue.split(" ");
const [year, month, day] = datePart.split("/").map(Number);
// 时间部分用 : 分隔,取前两位(小时和分钟),忽略秒数
const [hour, minute] = timePart.split(":").map(Number);
// 计算各部分在数组中的索引
const yearIndex = this.years.findIndex((y) => y === year);
const monthIndex = this.months.findIndex((m) => m === month);
const dayIndex = this.dates[yearIndex]?.[monthIndex]?.findIndex((d) => d === day) ?? 0;
const hourIndex = this.hours.findIndex((h) => h === hour);
const minuteIndex = this.minutes.findIndex((m) => m === minute);
// 设置pickerValue
this.pickerValue = [
yearIndex,
monthIndex,
dayIndex,
hourIndex,
minuteIndex,
];
} else if (this.type == 'daterange') {
// 解析时间字符串 '2024/05/27'
const [year, month, day] = normalizedValue.split("/").map(Number);
// 计算各部分在数组中的索引
const yearIndex = this.years.findIndex((y) => y === year);
const monthIndex = this.months.findIndex((m) => m === month);
const dayIndex = this.dates[yearIndex]?.[monthIndex]?.findIndex((d) => d === day) ?? 0;
// 设置pickerValue
this.pickerValue = [
yearIndex,
monthIndex,
dayIndex,
];
} else if (this.type == 'yearMonth') {
// 解析时间字符串 '2024/05'
const [year, month] = normalizedValue.split("/").map(Number);
// 计算各部分在数组中的索引
const yearIndex = this.years.findIndex((y) => y === year);
const monthIndex = this.months.findIndex((m) => m === month);
// 设置pickerValue
this.pickerValue = [
yearIndex,
monthIndex
];
}
}
},
getMonthDay(year, month) {
let days = new Date(year, month, 0).getDate();
return days;
},
// 处理时间变化
handleTimeChange(e) {
this.pickerValue = e.detail.value;
},
openTimePopup() {
this.$refs.popup.open();
},
close() {
this.$refs.popup.close();
},
// 确认选择
confirmTime() {
if ((this.timeIndex == 0 && this.timeList[1]) || (this.timeIndex == 1 && this.timeList[0])) {
if (this.timeIndex == 0) {
// 开始时间
if (!this.timeCompare(this.formatTime, this.timeList[1])) {
uni.showToast({
title: "开始时间不能大于结束时间",
icon: "none",
});
return;
}
} else {
// 结束时间
if (!this.timeCompare(this.timeList[0], this.formatTime)) {
uni.showToast({
title: "结束时间不能小于开始时间",
icon: "none",
});
return;
}
}
}
this.$emit("input", this.sureTime);
this.$emit("confirmTime", this.sureTime);
this.$refs.popup.close();
},
//比较开始时间结束时间大小
timeCompare(dateStr1, dateStr2) {
if (this.timeIndex >= 0) {
// 处理日期格式:将“-”替换为“/”纯日期补充为当天0点
const formatDate = (str) => {
// 先将所有“-”替换为“/”兼容iOS解析
const normalized = str.replace(/-/g, '/');
// 判断是否包含时间部分(是否有空格)
if (!normalized.includes(' ')) {
return normalized + ' 00:00:00'; // 纯日期补全为当天0点
}
return normalized;
};
try {
// 格式化并转换为时间戳
const time1 = new Date(formatDate(dateStr1)).getTime();
const time2 = new Date(formatDate(dateStr2)).getTime();
// 时间戳比较(避免字符串比较的潜在问题)
return time2 > time1;
} catch (error) {
console.error('日期格式错误:', error);
return false; // 格式错误时返回默认值
}
} else {
return true;
}
}
},
};
</script>
<style scoped lang="less">
/* 样式部分不变 */
.region-body {
flex: 1;
overflow: hidden;
background: #fff;
border-radius: 20rpx 20rpx 0 0;
&__close {
width: 22rpx;
height: 22rpx;
position: absolute;
top: 44rpx;
right: 30rpx;
}
&__header {
padding: 40rpx 0;
font-weight: 500;
font-size: 32rpx;
color: #333333;
line-height: 45rpx;
text-align: left;
font-style: normal;
display: flex;
justify-content: center;
}
&__btn {
display: flex;
align-items: center;
justify-content: center;
width: 690rpx;
height: 80rpx;
background: #FF4767;
border-radius: 38rpx;
font-weight: 400;
font-size: 30rpx;
color: #ffffff;
line-height: 39rpx;
text-align: right;
font-style: normal;
margin: 0 30rpx;
}
.noSure {
background-color: #ccc;
}
}
.region-scroll {
height: 100%;
}
.picker-scroll {
height: 400rpx;
}
.picker-item {
height: 68rpx;
line-height: 68rpx;
text-align: center;
}
.region-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0;
border-bottom: 1rpx solid #eeeeee;
}
.region-item.checkbox-item {
padding: 20rpx 0;
width: 100%;
justify-content: flex-start !important;
align-items: center !important;
}
</style>