UNPKG

kui-vue

Version:

A high quality UI Toolkit built on Vue.js 2.0

451 lines (439 loc) 13.3 kB
import Calendar from './datecalendar' import Icon from "../icon"; // import { isNotEmpty } from '../_tool/utils' import dayjs from 'dayjs' import Drop from '../base/drop' import { t } from '../locale' import { CloseCircle, CalendarOutline, TimeOutline } from 'kui-icons' const duration = require('dayjs/plugin/duration'); const isBetween = require('dayjs/plugin/isBetween'); dayjs.extend(duration); dayjs.extend(isBetween); export default { name: 'DatePicker', props: { value: [String, Date, Number, Array, Object], mode: { type: String, default: 'date', validator(value) { return ["year", "month", "date", 'time', 'dateTime', "dateRange", 'dateTimeRange'].indexOf(value) >= 0; } }, disabled: Boolean, transfer: { type: Boolean, default: true }, disabledDate: { type: Function, default: e => { } }, disabledTime: { type: Function, default: e => { } }, format: String, clearable: { type: Boolean, default: true }, bordered: { type: Boolean, default: true }, pickerSize: String, size: { default: 'default', validator(value) { return ["small", "large", "default"].indexOf(value) >= 0; } }, placement: String, theme: String, shape: String, placeholder: [String, Array], dateIcon: [String, Array], presets: Array }, provide() { return { DatePicker: this, } }, data() { return { opened: false, currentValue: this.value, v1: null, // render selected v2: null, // d1: null, //render date view d2: null, h2: null, fmt: { 'year': 'YYYY', 'month': 'YYYY-MM', 'date': 'YYYY-MM-DD', 'dateRange': 'YYYY-MM-DD', 'time': 'HH:mm:ss', 'dateTime': 'YYYY-MM-DD HH:mm:ss', 'dateTimeRange': 'YYYY-MM-DD HH:mm:ss' } } }, created() { this.updateCalendDate() }, computed: { label() { let { currentValue, isRange, format, fmt, mode } = this let ft = format || fmt[mode] if (isRange) { let [v1, v2] = currentValue || [] return [v1 ? dayjs(v1).format(ft) : null, v2 ? dayjs(v2).format(ft) : null] } else { return currentValue ? dayjs(currentValue).format(ft) : null } }, isRange() { return this.mode.indexOf('Range') >= 0 }, withTime() { return this.mode.indexOf('Time') >= 0// && this.mode != 'time' } }, watch: { value(v) { if (this.v != this.currentValue) { console.log(v) if (!this.isRange) { this.currentValue = v ? dayjs(v) : '' } else { let [a, b] = v || [] this.currentValue = [a ? dayjs(a) : null, b ? dayjs(b) : null] } this.updateCalendDate() } } }, methods: { updateCalendDate() { let { currentValue, isRange } = this if (isRange) { let [a, b] = currentValue || [] // if (!this.v1 && a) { // this.v1 = dayjs(a) // } // if (!this.v2 && b) { // this.v2 = dayjs(b) // } this.d1 = a ? dayjs(a) : dayjs() this.d2 = b ? dayjs(b) : dayjs().add(1, 'month') const oneMonth = dayjs.duration(1, 'month').asDays(); const diff = this.d2.diff(this.d1, 'day'); if (diff < oneMonth) { this.d2 = dayjs(this.d1).add(1, 'month') } if (!this.v1 && a) { this.v1 = dayjs(a) } if (!this.v2 && b) { this.v2 = dayjs(b) } // this.currentValue = [dayjs(this.d1), dayjs(this.d2)] } else { this.d1 = currentValue ? dayjs(currentValue) : dayjs() if (!this.v1 && currentValue) { this.v1 = dayjs(currentValue) } } }, clear(e) { let v = null; if (!this.isRange) { this.currentValue = null v = '' this.v1 = null } else { this.currentValue = [] v = [] this.v1 = null this.v2 = null } this.updateCalendDate() this.$emit("input", v); this.$emit("change", v, v); e && e.stopPropagation() }, toggleDrop() { if (this.disabled) { return false; } this.opened = !this.opened; if (this.opened) { this.updateCalendDate() } else { this.validValue() } }, picker1Update(value, type) { let { v1, v2, withTime, format, fmt, mode, isRange } = this if (isRange) { if (!type) { //day let result = dayjs(value) if (!v1) { this.v1 = result this.currentValue = [dayjs(value), v2] } else if (v1 && !v2) { this.v2 = result this.currentValue = [v1, this.v2] if (!withTime) { this.opened = false } } else if (v1 && v2) { this.v1 = result this.v2 = null this.currentValue = [dayjs(value), null] } this.updateStr() } else { let _v1 = (v1 || dayjs(this.d1))[type](value) this.v1 = _v1 if (v2) { const oneMonth = dayjs.duration(1, 'month').asDays(); const diff = _v1.diff(v2, 'day'); // console.log(oneMonth, diff) if (diff > oneMonth) { v2 = dayjs(_v1).add(1, 'month') } this.v2 = v2 } this.currentValue = [_v1, v2] this.updateStr() } } else { let result = !type ? dayjs(value) : (this.v1 || dayjs())[type](value) this.v1 = dayjs(result) this.currentValue = dayjs(result) this.updateStr() } }, picker2Update(value, type) { let { v1, v2, withTime, format, fmt, mode } = this if (!type) { //day let result = dayjs(value) if (!v1) { this.v1 = result this.currentValue = [dayjs(value), v2] } else if (v1 && !v2) { this.v2 = result this.currentValue = [v1, this.v2] if (!withTime) { this.opened = false } } else if (v1 && v2) { this.v1 = result this.v2 = null this.currentValue = [dayjs(value), null] } this.updateStr() } else { let _v2 = (v2 || dayjs(this.d2))[type](value) this.v2 = _v2 if (v1) { const oneMonth = dayjs.duration(1, 'month').asDays(); const diff = _v2.diff(v1, 'day'); // console.log(oneMonth, diff) if (diff < 0) { v1 = dayjs(_v2).subtract(1, 'month') } this.v1 = v1 } this.currentValue = [v1, _v2] this.updateStr() } }, updateStr() { let { v1, v2, isRange, format, fmt, mode } = this let ft = format || fmt[mode] let dateStr = isRange ? [v1 ? v1.format(ft) : null, v2 ? v2.format(ft) : null] : v1.format(ft) this.$emit('input', dateStr) this.$emit('change', this.currentValue, dateStr) this.updateCalendDate() }, validValue(e) { // 只有一个值的时候, 直接置空 if (this.isRange) { let [a, b] = this.currentValue || [] if ((a && !b) || (!a && b)) { this.clear(e) } } }, getPresetsNode() { let { presets } = this if (presets && presets.length > 1) { let childs = [] for (let i = 0; i < presets.length; i++) { childs.push(<Button theme="normal" size="small" onClick={() => this.setPreset(presets[i])}>{presets[i].label}</Button>) } return <div class="k-date-picker-presets">{childs}</div> } return null }, setPreset({ value }) { let { isRange, format, fmt, mode } = this let ft = format || fmt[mode] if (isRange) { let [a, b] = value || [] if (a && b) { this.v1 = dayjs(a) this.v2 = dayjs(b) this.currentValue = [dayjs(a), dayjs(b)] let dateStr = [dayjs(a).format(ft), dayjs(b).format(ft)] this.$emit('input', dateStr) this.$emit('change', this.currentValue, dateStr) } } else { this.v1 = dayjs(value) this.currentValue = dayjs(value) let dateStr = this.v1.format(ft) this.$emit('input', dateStr) this.$emit('change', this.currentValue, dateStr) } this.opened = false }, }, render() { // console.log(t('k.datePicker')) let { currentValue, placeholder, disabled, clearable, v1, v2, d1, d2, h2, opened, size, label, transfer, bordered, theme, shape, dateIcon, format, mode, disabledTime, isRange, withTime, disabledDate, pickerSize } = this let childNode = []; if (dateIcon === undefined) { dateIcon = CalendarOutline } if (mode == 'time') { dateIcon = TimeOutline } dateIcon && childNode.push(<Icon type={dateIcon} class="k-icon-calendar" />) let dv1, dv2; if (isRange) { placeholder = placeholder || [] if (placeholder && !Array.isArray(placeholder)) { console.error('Please set placeholder as array !') placeholder = [] } let p1 = placeholder[0] || t('k.datePicker.startDate'), p2 = placeholder[1] || t('k.datePicker.endDate') let [l1, l2] = label if (l1) { childNode.push(<div class="k-datepicker-value">{l1}</div>) } else { childNode.push(<div class="k-datepicker-placeholder">{p1}</div>) } childNode.push(<div class="k-datepicker-separator">~</div>) if (l2) { childNode.push(<div class="k-datepicker-value">{l2}</div>) } else { childNode.push(<div class="k-datepicker-placeholder">{p2}</div>) } let [a, b] = currentValue || [] dv1 = a dv2 = b } else { placeholder = placeholder || t('k.datePicker.placeholder') if (label) { childNode.push(<div class="k-datepicker-value">{label}</div>) } else if (placeholder) { childNode.push(<div class="k-datepicker-placeholder">{placeholder}</div>) } dv1 = currentValue } // console.log(dv1, dv2) let calendar = [] let presetsNode = this.getPresetsNode() if (presetsNode) { calendar.push(presetsNode) } const leftProps = { props: { format, mode, opened, disabledTime, disabledDate, value: dv1, date: d1, v1, v2, h2, pickerSize: pickerSize || size }, on: { input: (e, f) => this.picker1Update(e, f), close: (v) => { if (v) { this.opened = false } }, hd: (v) => { this.h2 = v }, np: (v) => { this.d1 = v if (this.isRange && (this.d1.isSame(this.d2, 'month') || this.d1.isAfter(d2, 'month'))) { this.d2 = v.add(1, 'month') } } } } calendar.push(<Calendar {...leftProps} />) if (isRange) { let rightProps = { props: { format, opened, mode, disabledTime, disabledDate, isRight: true, value: dv2, date: d2, v1, v2, h2, pickerSize }, on: { input: (e, f) => this.picker2Update(e, f), close: (v, e) => { if (v) { this.opened = false this.validValue(e) } }, hd: (v) => { this.h2 = v }, np: (v) => { this.d2 = v if (this.d2.isSame(this.d1, 'month') || this.d2.isBefore(d1, 'month')) { this.d1 = v.subtract(1, 'month') } } } }; calendar.push(<Calendar {...rightProps} />) } const props = { props: { className: ['k-datepicker-dropdown', { 'k-datepicker-range-dropdown': isRange }], transfer: true, selection: this.$el, value: this.opened, placement: 'bottom-left', transitionName: 'k-date-picker' }, on: { // render: () => { // }, input: e => { this.opened = e }, hide: () => { this.opened = false this.validValue() }, } } let overlay = <Drop {...props}>{calendar}</Drop > let showClear = !disabled && clearable && ((isRange && v1 && v2) || (!isRange && v1)) showClear && childNode.push(<Icon class="k-datepicker-clearable" type={CloseCircle} onClick={this.clear} />) const selectCls = [ "k-datepicker-selection", { "k-datepicker-has-clear": showClear } ] const classes = ['k-datepicker', { 'k-datepicker-open': opened }, { 'k-datepicker-range': isRange }, { 'k-datepicker-borderless': bordered === false }, { 'k-datepicker-sm': size == 'small' }, { 'k-datepicker-lg': size == 'large' }, { 'k-datepicker-with-time': withTime }, { 'k-datepicker-disabled': disabled }, { 'k-datepicker-light': theme == 'light' }, { 'k-datepicker-circle': shape == 'circle' }, ] return ( <div tabIndex="0" class={classes}> <div class={selectCls} onClick={this.toggleDrop}> {childNode} </div> {overlay} </div> ) } }