|
@@ -0,0 +1,940 @@
|
|
|
|
+<template>
|
|
|
|
+ <view class="uni-datetime-picker">
|
|
|
|
+ <view @click="initTimePicker">
|
|
|
|
+ <slot>
|
|
|
|
+ <view class="uni-datetime-picker-timebox-pointer"
|
|
|
|
+ :class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
|
|
|
|
+ <text class="uni-datetime-picker-text">{{time}}</text>
|
|
|
|
+ <view v-if="!time" class="uni-datetime-picker-time">
|
|
|
|
+ <text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </slot>
|
|
|
|
+ </view>
|
|
|
|
+ <view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
|
|
|
|
+ <view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
|
|
|
|
+ :style="fixNvueBug">
|
|
|
|
+ <view class="uni-title">
|
|
|
|
+ <text class="uni-datetime-picker-text">{{selectTimeText}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ <view v-if="dateShow" class="uni-datetime-picker__container-box">
|
|
|
|
+ <picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
|
|
|
|
+ @change="bindDateChange">
|
|
|
|
+ <picker-view-column>
|
|
|
|
+ <view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
|
|
|
|
+ <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </picker-view-column>
|
|
|
|
+ <picker-view-column>
|
|
|
|
+ <view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
|
|
|
|
+ <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </picker-view-column>
|
|
|
|
+ <picker-view-column>
|
|
|
|
+ <view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
|
|
|
|
+ <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </picker-view-column>
|
|
|
|
+ </picker-view>
|
|
|
|
+ <!-- 兼容 nvue 不支持伪类 -->
|
|
|
|
+ <text class="uni-datetime-picker-sign sign-left">-</text>
|
|
|
|
+ <text class="uni-datetime-picker-sign sign-right">-</text>
|
|
|
|
+ </view>
|
|
|
|
+ <view v-if="timeShow" class="uni-datetime-picker__container-box">
|
|
|
|
+ <picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
|
|
|
|
+ :indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
|
|
|
|
+ <picker-view-column>
|
|
|
|
+ <view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
|
|
|
|
+ <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </picker-view-column>
|
|
|
|
+ <picker-view-column>
|
|
|
|
+ <view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
|
|
|
|
+ <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </picker-view-column>
|
|
|
|
+ <picker-view-column v-if="!hideSecond">
|
|
|
|
+ <view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
|
|
|
|
+ <text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </picker-view-column>
|
|
|
|
+ </picker-view>
|
|
|
|
+ <!-- 兼容 nvue 不支持伪类 -->
|
|
|
|
+ <text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
|
|
|
|
+ <text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
|
|
|
|
+ </view>
|
|
|
|
+ <view class="uni-datetime-picker-btn">
|
|
|
|
+ <view @click="clearTime">
|
|
|
|
+ <text class="uni-datetime-picker-btn-text">{{clearText}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ <view class="uni-datetime-picker-btn-group">
|
|
|
|
+ <view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
|
|
|
|
+ <text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ <view @click="setTime">
|
|
|
|
+ <text class="uni-datetime-picker-btn-text">{{okText}}</text>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+ </view>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+ import {
|
|
|
|
+ initVueI18n
|
|
|
|
+ } from '@dcloudio/uni-i18n'
|
|
|
|
+ import i18nMessages from './i18n/index.js'
|
|
|
|
+ const {
|
|
|
|
+ t
|
|
|
|
+ } = initVueI18n(i18nMessages)
|
|
|
|
+ import {
|
|
|
|
+ fixIosDateFormat
|
|
|
|
+ } from './util'
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * DatetimePicker 时间选择器
|
|
|
|
+ * @description 可以同时选择日期和时间的选择器
|
|
|
|
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
|
|
|
|
+ * @property {String} type = [datetime | date | time] 显示模式
|
|
|
|
+ * @property {Boolean} multiple = [true|false] 是否多选
|
|
|
|
+ * @property {String|Number} value 默认值
|
|
|
|
+ * @property {String|Number} start 起始日期或时间
|
|
|
|
+ * @property {String|Number} end 起始日期或时间
|
|
|
|
+ * @property {String} return-type = [timestamp | string]
|
|
|
|
+ * @event {Function} change 选中发生变化触发
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ export default {
|
|
|
|
+ name: 'UniDatetimePicker',
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ indicatorStyle: `height: 50px;`,
|
|
|
|
+ visible: false,
|
|
|
|
+ fixNvueBug: {},
|
|
|
|
+ dateShow: true,
|
|
|
|
+ timeShow: true,
|
|
|
|
+ title: '日期和时间',
|
|
|
|
+ // 输入框当前时间
|
|
|
|
+ time: '',
|
|
|
|
+ // 当前的年月日时分秒
|
|
|
|
+ year: 1920,
|
|
|
|
+ month: 0,
|
|
|
|
+ day: 0,
|
|
|
|
+ hour: 0,
|
|
|
|
+ minute: 0,
|
|
|
|
+ second: 0,
|
|
|
|
+ // 起始时间
|
|
|
|
+ startYear: 1920,
|
|
|
|
+ startMonth: 1,
|
|
|
|
+ startDay: 1,
|
|
|
|
+ startHour: 0,
|
|
|
|
+ startMinute: 0,
|
|
|
|
+ startSecond: 0,
|
|
|
|
+ // 结束时间
|
|
|
|
+ endYear: 2120,
|
|
|
|
+ endMonth: 12,
|
|
|
|
+ endDay: 31,
|
|
|
|
+ endHour: 23,
|
|
|
|
+ endMinute: 59,
|
|
|
|
+ endSecond: 59,
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ options: {
|
|
|
|
+ // #ifdef MP-TOUTIAO
|
|
|
|
+ virtualHost: false,
|
|
|
|
+ // #endif
|
|
|
|
+ // #ifndef MP-TOUTIAO
|
|
|
|
+ virtualHost: true
|
|
|
|
+ // #endif
|
|
|
|
+ },
|
|
|
|
+ props: {
|
|
|
|
+ type: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: 'datetime'
|
|
|
|
+ },
|
|
|
|
+ value: {
|
|
|
|
+ type: [String, Number],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ modelValue: {
|
|
|
|
+ type: [String, Number],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ start: {
|
|
|
|
+ type: [Number, String],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ end: {
|
|
|
|
+ type: [Number, String],
|
|
|
|
+ default: ''
|
|
|
|
+ },
|
|
|
|
+ returnType: {
|
|
|
|
+ type: String,
|
|
|
|
+ default: 'string'
|
|
|
|
+ },
|
|
|
|
+ disabled: {
|
|
|
|
+ type: [Boolean, String],
|
|
|
|
+ default: false
|
|
|
|
+ },
|
|
|
|
+ border: {
|
|
|
|
+ type: [Boolean, String],
|
|
|
|
+ default: true
|
|
|
|
+ },
|
|
|
|
+ hideSecond: {
|
|
|
|
+ type: [Boolean, String],
|
|
|
|
+ default: false
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ watch: {
|
|
|
|
+ // #ifndef VUE3
|
|
|
|
+ value: {
|
|
|
|
+ handler(newVal) {
|
|
|
|
+ if (newVal) {
|
|
|
|
+ this.parseValue(fixIosDateFormat(newVal))
|
|
|
|
+ this.initTime(false)
|
|
|
|
+ } else {
|
|
|
|
+ this.time = ''
|
|
|
|
+ this.parseValue(Date.now())
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ immediate: true
|
|
|
|
+ },
|
|
|
|
+ // #endif
|
|
|
|
+ // #ifdef VUE3
|
|
|
|
+ modelValue: {
|
|
|
|
+ handler(newVal) {
|
|
|
|
+ if (newVal) {
|
|
|
|
+ this.parseValue(fixIosDateFormat(newVal))
|
|
|
|
+ this.initTime(false)
|
|
|
|
+ } else {
|
|
|
|
+ this.time = ''
|
|
|
|
+ this.parseValue(Date.now())
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ immediate: true
|
|
|
|
+ },
|
|
|
|
+ // #endif
|
|
|
|
+ type: {
|
|
|
|
+ handler(newValue) {
|
|
|
|
+ if (newValue === 'date') {
|
|
|
|
+ this.dateShow = true
|
|
|
|
+ this.timeShow = false
|
|
|
|
+ this.title = '日期'
|
|
|
|
+ } else if (newValue === 'time') {
|
|
|
|
+ this.dateShow = false
|
|
|
|
+ this.timeShow = true
|
|
|
|
+ this.title = '时间'
|
|
|
|
+ } else {
|
|
|
|
+ this.dateShow = true
|
|
|
|
+ this.timeShow = true
|
|
|
|
+ this.title = '日期和时间'
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ immediate: true
|
|
|
|
+ },
|
|
|
|
+ start: {
|
|
|
|
+ handler(newVal) {
|
|
|
|
+ this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
|
|
|
|
+ },
|
|
|
|
+ immediate: true
|
|
|
|
+ },
|
|
|
|
+ end: {
|
|
|
|
+ handler(newVal) {
|
|
|
|
+ this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
|
|
|
|
+ },
|
|
|
|
+ immediate: true
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
|
|
|
+ months(newVal) {
|
|
|
|
+ this.checkValue('month', this.month, newVal)
|
|
|
|
+ },
|
|
|
|
+ days(newVal) {
|
|
|
|
+ this.checkValue('day', this.day, newVal)
|
|
|
|
+ },
|
|
|
|
+ hours(newVal) {
|
|
|
|
+ this.checkValue('hour', this.hour, newVal)
|
|
|
|
+ },
|
|
|
|
+ minutes(newVal) {
|
|
|
|
+ this.checkValue('minute', this.minute, newVal)
|
|
|
|
+ },
|
|
|
|
+ seconds(newVal) {
|
|
|
|
+ this.checkValue('second', this.second, newVal)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ computed: {
|
|
|
|
+ // 当前年、月、日、时、分、秒选择范围
|
|
|
|
+ years() {
|
|
|
|
+ return this.getCurrentRange('year')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ months() {
|
|
|
|
+ return this.getCurrentRange('month')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ days() {
|
|
|
|
+ return this.getCurrentRange('day')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ hours() {
|
|
|
|
+ return this.getCurrentRange('hour')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ minutes() {
|
|
|
|
+ return this.getCurrentRange('minute')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ seconds() {
|
|
|
|
+ return this.getCurrentRange('second')
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // picker 当前值数组
|
|
|
|
+ ymd() {
|
|
|
|
+ return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
|
|
|
|
+ },
|
|
|
|
+ hms() {
|
|
|
|
+ return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 当前 date 是 start
|
|
|
|
+ currentDateIsStart() {
|
|
|
|
+ return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 当前 date 是 end
|
|
|
|
+ currentDateIsEnd() {
|
|
|
|
+ return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 当前年、月、日、时、分、秒的最小值和最大值
|
|
|
|
+ minYear() {
|
|
|
|
+ return this.startYear
|
|
|
|
+ },
|
|
|
|
+ maxYear() {
|
|
|
|
+ return this.endYear
|
|
|
|
+ },
|
|
|
|
+ minMonth() {
|
|
|
|
+ if (this.year === this.startYear) {
|
|
|
|
+ return this.startMonth
|
|
|
|
+ } else {
|
|
|
|
+ return 1
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ maxMonth() {
|
|
|
|
+ if (this.year === this.endYear) {
|
|
|
|
+ return this.endMonth
|
|
|
|
+ } else {
|
|
|
|
+ return 12
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ minDay() {
|
|
|
|
+ if (this.year === this.startYear && this.month === this.startMonth) {
|
|
|
|
+ return this.startDay
|
|
|
|
+ } else {
|
|
|
|
+ return 1
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ maxDay() {
|
|
|
|
+ if (this.year === this.endYear && this.month === this.endMonth) {
|
|
|
|
+ return this.endDay
|
|
|
|
+ } else {
|
|
|
|
+ return this.daysInMonth(this.year, this.month)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ minHour() {
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ if (this.currentDateIsStart) {
|
|
|
|
+ return this.startHour
|
|
|
|
+ } else {
|
|
|
|
+ return 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ return this.startHour
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ maxHour() {
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ if (this.currentDateIsEnd) {
|
|
|
|
+ return this.endHour
|
|
|
|
+ } else {
|
|
|
|
+ return 23
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ return this.endHour
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ minMinute() {
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ if (this.currentDateIsStart && this.hour === this.startHour) {
|
|
|
|
+ return this.startMinute
|
|
|
|
+ } else {
|
|
|
|
+ return 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ if (this.hour === this.startHour) {
|
|
|
|
+ return this.startMinute
|
|
|
|
+ } else {
|
|
|
|
+ return 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ maxMinute() {
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ if (this.currentDateIsEnd && this.hour === this.endHour) {
|
|
|
|
+ return this.endMinute
|
|
|
|
+ } else {
|
|
|
|
+ return 59
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ if (this.hour === this.endHour) {
|
|
|
|
+ return this.endMinute
|
|
|
|
+ } else {
|
|
|
|
+ return 59
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ minSecond() {
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
|
|
|
|
+ return this.startSecond
|
|
|
|
+ } else {
|
|
|
|
+ return 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ if (this.hour === this.startHour && this.minute === this.startMinute) {
|
|
|
|
+ return this.startSecond
|
|
|
|
+ } else {
|
|
|
|
+ return 0
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ maxSecond() {
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
|
|
|
|
+ return this.endSecond
|
|
|
|
+ } else {
|
|
|
|
+ return 59
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ if (this.hour === this.endHour && this.minute === this.endMinute) {
|
|
|
|
+ return this.endSecond
|
|
|
|
+ } else {
|
|
|
|
+ return 59
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * for i18n
|
|
|
|
+ */
|
|
|
|
+ selectTimeText() {
|
|
|
|
+ return t("uni-datetime-picker.selectTime")
|
|
|
|
+ },
|
|
|
|
+ okText() {
|
|
|
|
+ return t("uni-datetime-picker.ok")
|
|
|
|
+ },
|
|
|
|
+ clearText() {
|
|
|
|
+ return t("uni-datetime-picker.clear")
|
|
|
|
+ },
|
|
|
|
+ cancelText() {
|
|
|
|
+ return t("uni-datetime-picker.cancel")
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ mounted() {
|
|
|
|
+ // #ifdef APP-NVUE
|
|
|
|
+ const res = uni.getSystemInfoSync();
|
|
|
|
+ this.fixNvueBug = {
|
|
|
|
+ top: res.windowHeight / 2,
|
|
|
|
+ left: res.windowWidth / 2
|
|
|
|
+ }
|
|
|
|
+ // #endif
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ methods: {
|
|
|
|
+ /**
|
|
|
|
+ * @param {Object} item
|
|
|
|
+ * 小于 10 在前面加个 0
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ lessThanTen(item) {
|
|
|
|
+ return item < 10 ? '0' + item : item
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 解析时分秒字符串,例如:00:00:00
|
|
|
|
+ * @param {String} timeString
|
|
|
|
+ */
|
|
|
|
+ parseTimeType(timeString) {
|
|
|
|
+ if (timeString) {
|
|
|
|
+ let timeArr = timeString.split(':')
|
|
|
|
+ this.hour = Number(timeArr[0])
|
|
|
|
+ this.minute = Number(timeArr[1])
|
|
|
|
+ this.second = Number(timeArr[2])
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
|
|
|
|
+ * @param {String | Number} datetime
|
|
|
|
+ */
|
|
|
|
+ initPickerValue(datetime) {
|
|
|
|
+ let defaultValue = null
|
|
|
|
+ if (datetime) {
|
|
|
|
+ defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
|
|
|
|
+ } else {
|
|
|
|
+ defaultValue = Date.now()
|
|
|
|
+ defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
|
|
|
|
+ }
|
|
|
|
+ this.parseValue(defaultValue)
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 初始值规则:
|
|
|
|
+ * - 用户设置初始值 value
|
|
|
|
+ * - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
|
|
|
|
+ * - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
|
|
|
|
+ * - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
|
|
|
|
+ * - 无起始终止时间,则初始值为 value
|
|
|
|
+ * - 无初始值 value,则初始值为当前本地时间 Date.now()
|
|
|
|
+ * @param {Object} value
|
|
|
|
+ * @param {Object} dateBase
|
|
|
|
+ */
|
|
|
|
+ compareValueWithStartAndEnd(value, start, end) {
|
|
|
|
+ let winner = null
|
|
|
|
+ value = this.superTimeStamp(value)
|
|
|
|
+ start = this.superTimeStamp(start)
|
|
|
|
+ end = this.superTimeStamp(end)
|
|
|
|
+
|
|
|
|
+ if (start && end) {
|
|
|
|
+ if (value < start) {
|
|
|
|
+ winner = new Date(start)
|
|
|
|
+ } else if (value > end) {
|
|
|
|
+ winner = new Date(end)
|
|
|
|
+ } else {
|
|
|
|
+ winner = new Date(value)
|
|
|
|
+ }
|
|
|
|
+ } else if (start && !end) {
|
|
|
|
+ winner = start <= value ? new Date(value) : new Date(start)
|
|
|
|
+ } else if (!start && end) {
|
|
|
|
+ winner = value <= end ? new Date(value) : new Date(end)
|
|
|
|
+ } else {
|
|
|
|
+ winner = new Date(value)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return winner
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 转换为可比较的时间戳,接受日期、时分秒、时间戳
|
|
|
|
+ * @param {Object} value
|
|
|
|
+ */
|
|
|
|
+ superTimeStamp(value) {
|
|
|
|
+ let dateBase = ''
|
|
|
|
+ if (this.type === 'time' && value && typeof value === 'string') {
|
|
|
|
+ const now = new Date()
|
|
|
|
+ const year = now.getFullYear()
|
|
|
|
+ const month = now.getMonth() + 1
|
|
|
|
+ const day = now.getDate()
|
|
|
|
+ dateBase = year + '/' + month + '/' + day + ' '
|
|
|
|
+ }
|
|
|
|
+ if (Number(value)) {
|
|
|
|
+ value = parseInt(value)
|
|
|
|
+ dateBase = 0
|
|
|
|
+ }
|
|
|
|
+ return this.createTimeStamp(dateBase + value)
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 解析默认值 value,字符串、时间戳
|
|
|
|
+ * @param {Object} defaultTime
|
|
|
|
+ */
|
|
|
|
+ parseValue(value) {
|
|
|
|
+ if (!value) {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time' && typeof value === "string") {
|
|
|
|
+ this.parseTimeType(value)
|
|
|
|
+ } else {
|
|
|
|
+ let defaultDate = null
|
|
|
|
+ defaultDate = new Date(value)
|
|
|
|
+ if (this.type !== 'time') {
|
|
|
|
+ this.year = defaultDate.getFullYear()
|
|
|
|
+ this.month = defaultDate.getMonth() + 1
|
|
|
|
+ this.day = defaultDate.getDate()
|
|
|
|
+ }
|
|
|
|
+ if (this.type !== 'date') {
|
|
|
|
+ this.hour = defaultDate.getHours()
|
|
|
|
+ this.minute = defaultDate.getMinutes()
|
|
|
|
+ this.second = defaultDate.getSeconds()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (this.hideSecond) {
|
|
|
|
+ this.second = 0
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 解析可选择时间范围 start、end,年月日字符串、时间戳
|
|
|
|
+ * @param {Object} defaultTime
|
|
|
|
+ */
|
|
|
|
+ parseDatetimeRange(point, pointType) {
|
|
|
|
+ // 时间为空,则重置为初始值
|
|
|
|
+ if (!point) {
|
|
|
|
+ if (pointType === 'start') {
|
|
|
|
+ this.startYear = 1920
|
|
|
|
+ this.startMonth = 1
|
|
|
|
+ this.startDay = 1
|
|
|
|
+ this.startHour = 0
|
|
|
|
+ this.startMinute = 0
|
|
|
|
+ this.startSecond = 0
|
|
|
|
+ }
|
|
|
|
+ if (pointType === 'end') {
|
|
|
|
+ this.endYear = 2120
|
|
|
|
+ this.endMonth = 12
|
|
|
|
+ this.endDay = 31
|
|
|
|
+ this.endHour = 23
|
|
|
|
+ this.endMinute = 59
|
|
|
|
+ this.endSecond = 59
|
|
|
|
+ }
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (this.type === 'time') {
|
|
|
|
+ const pointArr = point.split(':')
|
|
|
|
+ this[pointType + 'Hour'] = Number(pointArr[0])
|
|
|
|
+ this[pointType + 'Minute'] = Number(pointArr[1])
|
|
|
|
+ this[pointType + 'Second'] = Number(pointArr[2])
|
|
|
|
+ } else {
|
|
|
|
+ if (!point) {
|
|
|
|
+ pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ if (Number(point)) {
|
|
|
|
+ point = parseInt(point)
|
|
|
|
+ }
|
|
|
|
+ // datetime 的 end 没有时分秒, 则不限制
|
|
|
|
+ const hasTime = /[0-9]:[0-9]/
|
|
|
|
+ if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
|
|
|
|
+ point)) {
|
|
|
|
+ point = point + ' 23:59:59'
|
|
|
|
+ }
|
|
|
|
+ const pointDate = new Date(point)
|
|
|
|
+ this[pointType + 'Year'] = pointDate.getFullYear()
|
|
|
|
+ this[pointType + 'Month'] = pointDate.getMonth() + 1
|
|
|
|
+ this[pointType + 'Day'] = pointDate.getDate()
|
|
|
|
+ if (this.type === 'datetime') {
|
|
|
|
+ this[pointType + 'Hour'] = pointDate.getHours()
|
|
|
|
+ this[pointType + 'Minute'] = pointDate.getMinutes()
|
|
|
|
+ this[pointType + 'Second'] = pointDate.getSeconds()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 获取 年、月、日、时、分、秒 当前可选范围
|
|
|
|
+ getCurrentRange(value) {
|
|
|
|
+ const range = []
|
|
|
|
+ for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
|
|
|
|
+ range.push(i)
|
|
|
|
+ }
|
|
|
|
+ return range
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 字符串首字母大写
|
|
|
|
+ capitalize(str) {
|
|
|
|
+ return str.charAt(0).toUpperCase() + str.slice(1)
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
|
|
|
|
+ checkValue(name, value, values) {
|
|
|
|
+ if (values.indexOf(value) === -1) {
|
|
|
|
+ this[name] = values[0]
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ // 每个月的实际天数
|
|
|
|
+ daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
|
|
|
|
+ return new Date(year, month, 0).getDate();
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 生成时间戳
|
|
|
|
+ * @param {Object} time
|
|
|
|
+ */
|
|
|
|
+ createTimeStamp(time) {
|
|
|
|
+ if (!time) return
|
|
|
|
+ if (typeof time === "number") {
|
|
|
|
+ return time
|
|
|
|
+ } else {
|
|
|
|
+ time = time.replace(/-/g, '/')
|
|
|
|
+ if (this.type === 'date') {
|
|
|
|
+ time = time + ' ' + '00:00:00'
|
|
|
|
+ }
|
|
|
|
+ return Date.parse(time)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 生成日期或时间的字符串
|
|
|
|
+ */
|
|
|
|
+ createDomSting() {
|
|
|
|
+ const yymmdd = this.year +
|
|
|
|
+ '-' +
|
|
|
|
+ this.lessThanTen(this.month) +
|
|
|
|
+ '-' +
|
|
|
|
+ this.lessThanTen(this.day)
|
|
|
|
+
|
|
|
|
+ let hhmmss = this.lessThanTen(this.hour) +
|
|
|
|
+ ':' +
|
|
|
|
+ this.lessThanTen(this.minute)
|
|
|
|
+
|
|
|
|
+ if (!this.hideSecond) {
|
|
|
|
+ hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (this.type === 'date') {
|
|
|
|
+ return yymmdd
|
|
|
|
+ } else if (this.type === 'time') {
|
|
|
|
+ return hhmmss
|
|
|
|
+ } else {
|
|
|
|
+ return yymmdd + ' ' + hhmmss
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 初始化返回值,并抛出 change 事件
|
|
|
|
+ */
|
|
|
|
+ initTime(emit = true) {
|
|
|
|
+ this.time = this.createDomSting()
|
|
|
|
+ if (!emit) return
|
|
|
|
+ if (this.returnType === 'timestamp' && this.type !== 'time') {
|
|
|
|
+ this.$emit('change', this.createTimeStamp(this.time))
|
|
|
|
+ this.$emit('input', this.createTimeStamp(this.time))
|
|
|
|
+ this.$emit('update:modelValue', this.createTimeStamp(this.time))
|
|
|
|
+ } else {
|
|
|
|
+ this.$emit('change', this.time)
|
|
|
|
+ this.$emit('input', this.time)
|
|
|
|
+ this.$emit('update:modelValue', this.time)
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户选择日期或时间更新 data
|
|
|
|
+ * @param {Object} e
|
|
|
|
+ */
|
|
|
|
+ bindDateChange(e) {
|
|
|
|
+ const val = e.detail.value
|
|
|
|
+ this.year = this.years[val[0]]
|
|
|
|
+ this.month = this.months[val[1]]
|
|
|
|
+ this.day = this.days[val[2]]
|
|
|
|
+ },
|
|
|
|
+ bindTimeChange(e) {
|
|
|
|
+ const val = e.detail.value
|
|
|
|
+ this.hour = this.hours[val[0]]
|
|
|
|
+ this.minute = this.minutes[val[1]]
|
|
|
|
+ this.second = this.seconds[val[2]]
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 初始化弹出层
|
|
|
|
+ */
|
|
|
|
+ initTimePicker() {
|
|
|
|
+ if (this.disabled) return
|
|
|
|
+ const value = fixIosDateFormat(this.time)
|
|
|
|
+ this.initPickerValue(value)
|
|
|
|
+ this.visible = !this.visible
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 触发或关闭弹框
|
|
|
|
+ */
|
|
|
|
+ tiggerTimePicker(e) {
|
|
|
|
+ this.visible = !this.visible
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户点击“清空”按钮,清空当前值
|
|
|
|
+ */
|
|
|
|
+ clearTime() {
|
|
|
|
+ this.time = ''
|
|
|
|
+ this.$emit('change', this.time)
|
|
|
|
+ this.$emit('input', this.time)
|
|
|
|
+ this.$emit('update:modelValue', this.time)
|
|
|
|
+ this.tiggerTimePicker()
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 用户点击“确定”按钮
|
|
|
|
+ */
|
|
|
|
+ setTime() {
|
|
|
|
+ this.initTime()
|
|
|
|
+ this.tiggerTimePicker()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style lang="scss">
|
|
|
|
+ $uni-primary: #007aff !default;
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker {
|
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
|
+ /* width: 100%; */
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-view {
|
|
|
|
+ height: 130px;
|
|
|
|
+ width: 270px;
|
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-item {
|
|
|
|
+ height: 50px;
|
|
|
|
+ line-height: 50px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-btn {
|
|
|
|
+ margin-top: 60px;
|
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
|
+ display: flex;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ /* #endif */
|
|
|
|
+ flex-direction: row;
|
|
|
|
+ justify-content: space-between;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-btn-text {
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ color: $uni-primary;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-btn-group {
|
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
|
+ display: flex;
|
|
|
|
+ /* #endif */
|
|
|
|
+ flex-direction: row;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-cancel {
|
|
|
|
+ margin-right: 30px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-mask {
|
|
|
|
+ position: fixed;
|
|
|
|
+ bottom: 0px;
|
|
|
|
+ top: 0px;
|
|
|
|
+ left: 0px;
|
|
|
|
+ right: 0px;
|
|
|
|
+ background-color: rgba(0, 0, 0, 0.4);
|
|
|
|
+ transition-duration: 0.3s;
|
|
|
|
+ z-index: 998;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-popup {
|
|
|
|
+ border-radius: 8px;
|
|
|
|
+ padding: 30px;
|
|
|
|
+ width: 270px;
|
|
|
|
+ /* #ifdef APP-NVUE */
|
|
|
|
+ height: 500px;
|
|
|
|
+ /* #endif */
|
|
|
|
+ /* #ifdef APP-NVUE */
|
|
|
|
+ width: 330px;
|
|
|
|
+ /* #endif */
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ position: fixed;
|
|
|
|
+ top: 50%;
|
|
|
|
+ left: 50%;
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
+ transition-duration: 0.3s;
|
|
|
|
+ z-index: 999;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .fix-nvue-height {
|
|
|
|
+ /* #ifdef APP-NVUE */
|
|
|
|
+ height: 330px;
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-time {
|
|
|
|
+ color: grey;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-column {
|
|
|
|
+ height: 50px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-timebox {
|
|
|
|
+
|
|
|
|
+ border: 1px solid #E5E5E5;
|
|
|
|
+ border-radius: 5px;
|
|
|
|
+ padding: 7px 10px;
|
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-timebox-pointer {
|
|
|
|
+ /* #ifndef APP-NVUE */
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-disabled {
|
|
|
|
+ opacity: 0.4;
|
|
|
|
+ /* #ifdef H5 */
|
|
|
|
+ cursor: not-allowed !important;
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-text {
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ line-height: 50px
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker-sign {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 53px;
|
|
|
|
+ /* 减掉 10px 的元素高度,兼容nvue */
|
|
|
|
+ color: #999;
|
|
|
|
+ /* #ifdef APP-NVUE */
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ /* #endif */
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .sign-left {
|
|
|
|
+ left: 86px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .sign-right {
|
|
|
|
+ right: 86px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .sign-center {
|
|
|
|
+ left: 135px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .uni-datetime-picker__container-box {
|
|
|
|
+ position: relative;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ margin-top: 40px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .time-hide-second {
|
|
|
|
+ width: 180px;
|
|
|
|
+ }
|
|
|
|
+</style>
|