mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-01-30 12:52:43 +08:00
refactor(date-picker): using time-picker
This commit is contained in:
parent
65aa95b606
commit
656d8c0dd4
@ -9,13 +9,13 @@
|
||||
>
|
||||
<!--EXAMPLE_START-->
|
||||
<n-date-picker
|
||||
v-model="dateTimeTimestamp"
|
||||
v-model="ts1"
|
||||
type="datetime"
|
||||
style="margin-right: 12px;"
|
||||
@change="onDateTimeChange"
|
||||
/>
|
||||
<n-date-picker
|
||||
v-model="dateTimestamp"
|
||||
v-model="ts2"
|
||||
type="date"
|
||||
@change="onDateChange"
|
||||
/>
|
||||
@ -26,18 +26,20 @@
|
||||
style="flex-wrap: nowrap;"
|
||||
>
|
||||
<n-input
|
||||
v-model="dateTimeTimestamp"
|
||||
placeholder="dateTimeTimestamp"
|
||||
:value="ts1"
|
||||
placeholder="ts1"
|
||||
type="text"
|
||||
style="margin-right: 12px;"
|
||||
@input="handleInputTs1"
|
||||
/>
|
||||
<n-input
|
||||
v-model="dateTimestamp"
|
||||
placeholder="dateTimestamp"
|
||||
:value="ts2"
|
||||
placeholder="ts2"
|
||||
type="text"
|
||||
@input="handleInputTs2"
|
||||
/>
|
||||
</div>
|
||||
<pre class="n-doc-section__inspect">datetime v-model: {{ dateTimeTimestamp }}, date v-model: {{ dateTimestamp }}</pre>
|
||||
<pre class="n-doc-section__inspect">datetime v-model: {{ JSON.stringify(ts1) }}, date v-model: {{ JSON.stringify(ts2) }}</pre>
|
||||
<n-doc-source-block>
|
||||
<!--SOURCE-->
|
||||
</n-doc-source-block>
|
||||
@ -48,8 +50,8 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
dateTimeTimestamp: 891360258000,
|
||||
dateTimestamp: 891360258000
|
||||
ts1: null,
|
||||
ts2: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -58,6 +60,13 @@ export default {
|
||||
},
|
||||
onDateChange (timestamp, dateString) {
|
||||
this.$NMessage.success(`${timestamp}, ${dateString}`)
|
||||
},
|
||||
handleInputTs1 (v) {
|
||||
v = Number(v)
|
||||
this.ts1 = Number.isNaN(v) ? null : v
|
||||
},
|
||||
handleInputTs2 (v) {
|
||||
this.ts2 = Number.isNaN(v) ? null : v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
class="n-date-picker__input"
|
||||
:placeholder="placeholder"
|
||||
:readonly="disabled ? 'disabled' : false"
|
||||
@focus="openCalendar"
|
||||
@click="handleActivatorClick"
|
||||
@blur="handleDateTimeInputBlur"
|
||||
@keyup.enter="handleDateTimeInputEnter"
|
||||
@input="handleDateTimeInputInput"
|
||||
>
|
||||
<div class="n-date-picker__icon">
|
||||
<n-icon
|
||||
@ -28,9 +28,17 @@
|
||||
>
|
||||
<div ref="content">
|
||||
<datetime-panel
|
||||
v-model="panelValue"
|
||||
v-if="type === 'datetime'"
|
||||
:value="value"
|
||||
:active="active"
|
||||
@change="handlePanelValueChange"
|
||||
@input="handlePanelInput"
|
||||
@close="closeCalendar"
|
||||
/>
|
||||
<date-panel
|
||||
v-if="type === 'date'"
|
||||
:value="value"
|
||||
:active="active"
|
||||
@input="handlePanelInput"
|
||||
@close="closeCalendar"
|
||||
/>
|
||||
</div>
|
||||
@ -44,6 +52,7 @@ import NIcon from '../../Icon'
|
||||
import detachable from '../../../mixins/detachable'
|
||||
import placeable from '../../../mixins/placeable'
|
||||
import DatetimePanel from './panel/datetime'
|
||||
import DatePanel from './panel/date'
|
||||
import clickoutside from '../../../directives/clickoutside'
|
||||
|
||||
const DATE_FORMAT = {
|
||||
@ -68,16 +77,13 @@ export default {
|
||||
},
|
||||
components: {
|
||||
NIcon,
|
||||
DatetimePanel
|
||||
DatetimePanel,
|
||||
DatePanel
|
||||
},
|
||||
mixins: [
|
||||
detachable,
|
||||
placeable
|
||||
],
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
@ -88,7 +94,7 @@ export default {
|
||||
default: 'bottom-start'
|
||||
},
|
||||
value: {
|
||||
type: [Number, String],
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
@ -111,21 +117,14 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
displayDateTimeString: '',
|
||||
displayDateString: '',
|
||||
displayTimeString: '',
|
||||
rightDisplayDateTimeString: '',
|
||||
rightDisplayDateString: '',
|
||||
rightDisplayTimeString: '',
|
||||
calendarDateTime: moment(),
|
||||
rightCalendarDateTime: moment(),
|
||||
currentDateTime: moment(),
|
||||
active: false,
|
||||
showTimeSelector: false,
|
||||
showRightTimeSelector: false,
|
||||
calendar: [],
|
||||
rightCalendar: [],
|
||||
...TIME_CONST,
|
||||
panelValue: this.value
|
||||
...TIME_CONST
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -181,75 +180,10 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlePanelValueChange (value, valueString) {
|
||||
this.$emit('change', value, valueString)
|
||||
handlePanelInput (value, valueString) {
|
||||
this.$emit('input', value, 'unavailable for now')
|
||||
this.refreshSelectedDateTimeString()
|
||||
},
|
||||
/**
|
||||
* If new datetime is null or undefined, emit null to value.
|
||||
* Else adjust new datetime by props.type and emit it to value.
|
||||
*/
|
||||
setValue (newSelectedDateTime) {
|
||||
if (newSelectedDateTime === null || newSelectedDateTime === undefined) {
|
||||
this.$emit('change', null)
|
||||
return
|
||||
}
|
||||
if (newSelectedDateTime.isValid()) {
|
||||
const adjustedDateTime = this.adjustDateTimeAccrodingToType(newSelectedDateTime)
|
||||
if (this.computedSelectedDateTime === null || adjustedDateTime.valueOf() !== this.computedSelectedDateTime.valueOf()) {
|
||||
this.$emit('change', adjustedDateTime.valueOf(), adjustedDateTime.format(this.format))
|
||||
}
|
||||
}
|
||||
},
|
||||
adjustDateTimeAccrodingToType (datetime) {
|
||||
if (this.type === 'datetime') {
|
||||
return moment(datetime).startOf('second')
|
||||
} else {
|
||||
return moment(datetime).startOf('date').hour(0)
|
||||
}
|
||||
},
|
||||
justifySelectedDateTimeAfterChangeTimeString () {
|
||||
if (this.computedSelectedDateTime === null) {
|
||||
// case here is impossible for now, because you can't clear time for now
|
||||
} else {
|
||||
const newDisplayDateTimeString = this.displayDateString + ' ' + this.displayTimeString
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
}
|
||||
},
|
||||
handleTimeInput (e) {
|
||||
const newDisplayDateTimeString = this.displayDateString + ' ' + e.target.value
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
},
|
||||
handleDateInput (e) {
|
||||
const newDisplayDateTimeString = e.target.value + ' ' + this.displayTimeString
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
},
|
||||
handleTimeInputBlur () {
|
||||
this.refreshSelectedDateTimeString()
|
||||
},
|
||||
handleDateInputBlur () {
|
||||
this.refreshSelectedDateTimeString()
|
||||
},
|
||||
handleTimeConfirmClick () {
|
||||
this.justifySelectedDateTimeAfterChangeTimeString()
|
||||
this.refreshSelectedDateTimeString()
|
||||
this.closeTimeSelector()
|
||||
},
|
||||
handleTimeCancelClick () {
|
||||
this.closeTimeSelector()
|
||||
},
|
||||
openTimeSelector () {
|
||||
if (this.computedSelectedDateTime === null) {
|
||||
this.setValue(moment())
|
||||
}
|
||||
this.showTimeSelector = true
|
||||
},
|
||||
closeTimeSelector () {
|
||||
this.showTimeSelector = false
|
||||
},
|
||||
/**
|
||||
* If not selected, display nothing,
|
||||
* else update datetime related string
|
||||
@ -260,16 +194,6 @@ export default {
|
||||
return
|
||||
}
|
||||
this.displayDateTimeString = this.computedSelectedDateTime.format(this.format)
|
||||
this.displayDateString = this.computedSelectedDateTime.format('YYYY-MM-DD')
|
||||
this.displayTimeString = this.computedSelectedDateTime.format('HH:mm:ss')
|
||||
},
|
||||
/**
|
||||
* If new time is invalid, do nothing.
|
||||
* If valid, update.
|
||||
*/
|
||||
handleDateTimeInputEnter () {
|
||||
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
},
|
||||
/**
|
||||
* If new SelectedDateTime is valid, update `selectedDateTime` and `calendarTime`
|
||||
@ -277,12 +201,18 @@ export default {
|
||||
*/
|
||||
handleDateTimeInputBlur () {
|
||||
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
/**
|
||||
* If newSelectedDateTime is invalid, display string need to be restored
|
||||
*/
|
||||
this.refreshSelectedDateTimeString()
|
||||
this.closeCalendar()
|
||||
if (newSelectedDateTime.isValid()) {
|
||||
this.$emit('input', newSelectedDateTime.valueOf())
|
||||
} else {
|
||||
this.refreshSelectedDateTimeString()
|
||||
}
|
||||
},
|
||||
handleActivatorClick (e) {
|
||||
if (this.active) {
|
||||
e.stopPropagation()
|
||||
} else {
|
||||
this.openCalendar()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Calendar view related methods
|
||||
@ -301,6 +231,12 @@ export default {
|
||||
},
|
||||
toggleCalendar () {
|
||||
|
||||
},
|
||||
handleDateTimeInputInput (v) {
|
||||
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
|
||||
if (newSelectedDateTime.isValid()) {
|
||||
this.$emit('input', newSelectedDateTime.valueOf())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<transition name="n-date-picker-calendar--transition">
|
||||
<div
|
||||
v-if="active"
|
||||
v-clickoutside.lazy="handleClickOutside"
|
||||
class="n-date-picker-calendar"
|
||||
>
|
||||
<div style="width: 100%; height: 12px" />
|
||||
<div class="n-date-picker-calendar__month-modifier">
|
||||
<div
|
||||
class="n-date-picker-calendar__fast-prev"
|
||||
@click="prevYear"
|
||||
>
|
||||
<n-icon
|
||||
type="ios-arrow-back"
|
||||
size="14"
|
||||
/>
|
||||
<n-icon
|
||||
type="ios-arrow-back"
|
||||
size="14"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="n-date-picker-calendar__prev"
|
||||
@click="prevMonth"
|
||||
>
|
||||
<n-icon
|
||||
type="ios-arrow-back"
|
||||
size="14"
|
||||
/>
|
||||
</div>
|
||||
<div class="n-date-picker-calendar__month-year">
|
||||
{{ calendarDateTime.format('MMMM') }} {{ calendarDateTime.year() }}
|
||||
</div>
|
||||
<div
|
||||
class="n-date-picker-calendar__next"
|
||||
@click="nextMonth"
|
||||
>
|
||||
<n-icon
|
||||
type="ios-arrow-forward"
|
||||
size="14"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="n-date-picker-calendar__fast-next"
|
||||
@click="nextYear"
|
||||
>
|
||||
<n-icon
|
||||
type="ios-arrow-forward"
|
||||
size="14"
|
||||
/>
|
||||
<n-icon
|
||||
type="ios-arrow-forward"
|
||||
size="14"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-date-picker-calendar__weekdays">
|
||||
<div
|
||||
v-for="weekday in weekdays"
|
||||
:key="weekday"
|
||||
class="n-date-picker-calendar__weekday"
|
||||
>
|
||||
{{ weekday }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-date-picker-calendar__divider" />
|
||||
<div class="n-date-picker-calendar__dates">
|
||||
<div
|
||||
v-for="dateItem in dateArray(calendarDateTime, valueAsMoment, currentDateTime)"
|
||||
:key="dateItem.timestamp"
|
||||
class="n-date-picker-calendar__date"
|
||||
:class="{
|
||||
'n-date-picker-calendar__date--current': dateItem.isCurrentDate,
|
||||
'n-date-picker-calendar__date--selected': dateItem.isSelectedDate,
|
||||
'n-date-picker-calendar__date--in-display-month': dateItem.isDateOfDisplayMonth
|
||||
}"
|
||||
@click="handleDateClick(dateItem)"
|
||||
>
|
||||
{{ dateItem.date }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-date-picker-calendar__actions">
|
||||
<n-button
|
||||
size="tiny"
|
||||
round
|
||||
@click="setSelectedDateTimeToNow"
|
||||
>
|
||||
Now
|
||||
</n-button>
|
||||
<n-button
|
||||
size="tiny"
|
||||
round
|
||||
auto-text-color
|
||||
type="primary"
|
||||
@click="handleConfirmClick"
|
||||
>
|
||||
Confirm
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
import { dateArray, setDate } from '../utils'
|
||||
import NIcon from '../../../Icon'
|
||||
import clickoutside from '../../../../directives/clickoutside'
|
||||
|
||||
import NButton from '../../../Button'
|
||||
import NInput from '../../../Input'
|
||||
|
||||
const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
|
||||
const DATE_FORMAT = 'YYYY-MM-DD'
|
||||
const DATE_VALIDATE_FORMAT = ['YYYY-MM-DD', 'YYYY-MM-D', 'YYYY-M-D', 'YYYY-M-DD']
|
||||
|
||||
const PLACEHOLDER = 'Select date and time'
|
||||
|
||||
const TIME_CONST = {
|
||||
weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||
hours: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],
|
||||
minutes: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59'],
|
||||
seconds: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59']
|
||||
}
|
||||
export default {
|
||||
components: {
|
||||
NButton,
|
||||
NIcon
|
||||
},
|
||||
directives: {
|
||||
clickoutside
|
||||
},
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
debug: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: PLACEHOLDER
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: DATETIME_FORMAT
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
displayDateString: '',
|
||||
calendarDateTime: moment(),
|
||||
currentDateTime: moment(),
|
||||
calendar: [],
|
||||
...TIME_CONST
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
computedHour () {
|
||||
if (this.valueAsMoment) return this.valueAsMoment.format('HH')
|
||||
else return null
|
||||
},
|
||||
computedMinute () {
|
||||
if (this.valueAsMoment) return this.valueAsMoment.format('mm')
|
||||
else return null
|
||||
},
|
||||
computedSecond () {
|
||||
if (this.valueAsMoment) return this.valueAsMoment.format('ss')
|
||||
else return null
|
||||
},
|
||||
/**
|
||||
* If value is valid return null.
|
||||
* If value is not valid, return moment(value)
|
||||
*/
|
||||
valueAsMoment () {
|
||||
if (this.value === null || this.value === undefined) return null
|
||||
const newSelectedDateTime = moment(this.value)
|
||||
if (newSelectedDateTime.isValid()) {
|
||||
return newSelectedDateTime
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
valueAsMoment (newValue) {
|
||||
if (newValue !== null) {
|
||||
this.displayDateString = newValue.format(DATE_FORMAT)
|
||||
} else {
|
||||
this.displayDateString = ''
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.valueAsMoment !== null) {
|
||||
this.displayDateString = this.valueAsMoment.format(DATE_FORMAT)
|
||||
} else {
|
||||
this.displayDateString = ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dateArray,
|
||||
handleClickOutside () {
|
||||
this.closeCalendar()
|
||||
},
|
||||
setValue (newSelectedDateTime) {
|
||||
if (newSelectedDateTime === null || newSelectedDateTime === undefined) {
|
||||
this.$emit('input', null)
|
||||
} else if (newSelectedDateTime.isValid()) {
|
||||
const adjustedDateTime = this.adjustValue(newSelectedDateTime)
|
||||
if (this.valueAsMoment === null || adjustedDateTime.valueOf() !== this.valueAsMoment.valueOf()) {
|
||||
this.refreshDisplayDateString(adjustedDateTime)
|
||||
this.$emit('input', adjustedDateTime.valueOf())
|
||||
}
|
||||
}
|
||||
},
|
||||
adjustValue (value) {
|
||||
return moment(value).startOf('day')
|
||||
},
|
||||
handleDateInput (value) {
|
||||
const date = moment(value, DATE_FORMAT, true)
|
||||
if (date.isValid()) {
|
||||
if (!this.valueAsMoment) {
|
||||
const newValue = moment()
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
} else {
|
||||
const newValue = this.valueAsMoment
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
}
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
},
|
||||
handleDateInputBlur () {
|
||||
const date = moment(this.displayDateString, DATE_VALIDATE_FORMAT, true)
|
||||
if (date.isValid()) {
|
||||
if (!this.valueAsMoment) {
|
||||
const newValue = moment()
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
} else {
|
||||
const newValue = this.valueAsMoment
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
}
|
||||
} else {
|
||||
this.refreshDisplayDateString()
|
||||
}
|
||||
},
|
||||
clearSelectedDateTime () {
|
||||
this.$emit('input', null)
|
||||
this.displayDateString = ''
|
||||
},
|
||||
setSelectedDateTimeToNow () {
|
||||
this.$emit('input', this.adjustValue(moment()).valueOf())
|
||||
this.calendarDateTime = moment()
|
||||
},
|
||||
handleDateClick (dateItem) {
|
||||
let newSelectedDateTime = moment()
|
||||
if (this.valueAsMoment !== null) {
|
||||
newSelectedDateTime = moment(this.valueAsMoment)
|
||||
}
|
||||
newSelectedDateTime = setDate(newSelectedDateTime, dateItem)
|
||||
this.$emit('input', this.adjustValue(newSelectedDateTime).valueOf())
|
||||
},
|
||||
/**
|
||||
* If not selected, display nothing,
|
||||
* else update datetime related string
|
||||
*/
|
||||
refreshDisplayDateString (time) {
|
||||
if (this.valueAsMoment === null) {
|
||||
this.displayDateString = ''
|
||||
return
|
||||
}
|
||||
if (time === undefined) {
|
||||
time = this.valueAsMoment
|
||||
}
|
||||
this.displayDateString = time.format(DATE_FORMAT)
|
||||
},
|
||||
handleConfirmClick () {
|
||||
this.$emit('confirm')
|
||||
this.closeCalendar()
|
||||
},
|
||||
closeCalendar () {
|
||||
if (this.active) {
|
||||
this.$emit('close')
|
||||
}
|
||||
},
|
||||
nextYear () {
|
||||
this.calendarDateTime.add(1, 'year')
|
||||
this.$forceUpdate()
|
||||
},
|
||||
prevYear () {
|
||||
this.calendarDateTime.subtract(1, 'year')
|
||||
this.$forceUpdate()
|
||||
},
|
||||
nextMonth () {
|
||||
this.calendarDateTime.add(1, 'month')
|
||||
this.$forceUpdate()
|
||||
},
|
||||
prevMonth () {
|
||||
this.calendarDateTime.subtract(1, 'month')
|
||||
this.$forceUpdate()
|
||||
},
|
||||
handleTimePickerInput (value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -8,100 +8,20 @@
|
||||
<div
|
||||
class="n-date-picker-calendar__date-time-input-wrapper"
|
||||
>
|
||||
<input
|
||||
<n-input
|
||||
v-model="displayDateString"
|
||||
class="n-date-picker-calendar__date-input"
|
||||
placeholder="Select date"
|
||||
@blur="handleDateInputBlur"
|
||||
@input="handleDateInput"
|
||||
>
|
||||
<div
|
||||
ref="timeSelector"
|
||||
class="n-date-picker-calendar__time-input-wrapper"
|
||||
>
|
||||
<input
|
||||
v-model="displayTimeString"
|
||||
class="n-date-picker-calendar__time-input"
|
||||
placeholder="Select time"
|
||||
@click="openTimeSelector"
|
||||
@input="handleTimeInput"
|
||||
@blur="handleTimeInputBlur"
|
||||
>
|
||||
<transition name="n-date-picker-time-selector--transition">
|
||||
<div
|
||||
v-if="showTimeSelector"
|
||||
class="n-date-picker-time-selector"
|
||||
>
|
||||
<div class="n-date-picker-time-selector__selection-wrapper">
|
||||
<div class="n-date-picker-time-selector__hour">
|
||||
<div
|
||||
v-for="hour in hours"
|
||||
:key="hour"
|
||||
class="n-date-picker-time-selector__item"
|
||||
:class="{
|
||||
'n-date-picker-time-selector__item--active':
|
||||
hour === computedHour
|
||||
}"
|
||||
@click="setHour(hour)"
|
||||
>
|
||||
{{ hour }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-date-picker-time-selector__minute">
|
||||
<div
|
||||
v-for="minute in minutes"
|
||||
:key="minute"
|
||||
class="n-date-picker-time-selector__item"
|
||||
:class="{
|
||||
'n-date-picker-time-selector__item--active':
|
||||
minute === computedMinute
|
||||
}"
|
||||
@click="setMinute(minute)"
|
||||
>
|
||||
{{ minute }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-date-picker-time-selector__hour">
|
||||
<div
|
||||
v-for="second in seconds"
|
||||
:key="second"
|
||||
class="n-date-picker-time-selector__item"
|
||||
:class="{
|
||||
'n-date-picker-time-selector__item--active':
|
||||
second === computedSecond
|
||||
}"
|
||||
@click="setSecond(second)"
|
||||
>
|
||||
{{ second }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="n-date-picker-time-selector__actions">
|
||||
<n-button
|
||||
size="tiny"
|
||||
round
|
||||
@click="handleTimeCancelClick"
|
||||
>
|
||||
Cancel
|
||||
</n-button>
|
||||
<n-button
|
||||
size="tiny"
|
||||
round
|
||||
auto-text-color
|
||||
type="primary"
|
||||
@click="handleTimeConfirmClick"
|
||||
>
|
||||
Confirm
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
/>
|
||||
<n-time-picker
|
||||
class="n-date-picker-calendar__time-input"
|
||||
:value="value"
|
||||
stop-selector-bubble
|
||||
@input="handleTimePickerInput"
|
||||
/>
|
||||
</div>
|
||||
<!-- <div
|
||||
v-else
|
||||
style="width: 100%; height: 12px;"
|
||||
/>-->
|
||||
<div class="n-date-picker-calendar__month-modifier">
|
||||
<div
|
||||
class="n-date-picker-calendar__fast-prev"
|
||||
@ -163,7 +83,7 @@
|
||||
<div class="n-date-picker-calendar__divider" />
|
||||
<div class="n-date-picker-calendar__dates">
|
||||
<div
|
||||
v-for="dateItem in dateArray(calendarDateTime, computedSelectedDateTime, currentDateTime)"
|
||||
v-for="dateItem in dateArray(calendarDateTime, valueAsMoment, currentDateTime)"
|
||||
:key="dateItem.timestamp"
|
||||
class="n-date-picker-calendar__date"
|
||||
:class="{
|
||||
@ -189,7 +109,7 @@
|
||||
round
|
||||
auto-text-color
|
||||
type="primary"
|
||||
@click="handleDateInputAndTimeInputConfirmClick"
|
||||
@click="handleConfirmClick"
|
||||
>
|
||||
Confirm
|
||||
</n-button>
|
||||
@ -205,15 +125,15 @@ import NIcon from '../../../Icon'
|
||||
import clickoutside from '../../../../directives/clickoutside'
|
||||
|
||||
import NButton from '../../../Button'
|
||||
import NTimePicker from '../../../TimePicker'
|
||||
import NInput from '../../../Input'
|
||||
|
||||
const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'
|
||||
const DATE_FORMAT = 'YYYY-MM-DD'
|
||||
const DATE_VALIDATE_FORMAT = ['YYYY-MM-DD', 'YYYY-MM-D', 'YYYY-M-D', 'YYYY-M-DD']
|
||||
|
||||
const PLACEHOLDER = 'Select date and time'
|
||||
|
||||
const DATE_FORMAT = {
|
||||
date: 'YYYY-MM-DD',
|
||||
datetime: 'YYYY-MM-DD HH:mm:ss'
|
||||
}
|
||||
const PLACEHOLDER = {
|
||||
date: 'Select date',
|
||||
datetime: 'Select date and time'
|
||||
}
|
||||
const TIME_CONST = {
|
||||
weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||
hours: ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],
|
||||
@ -224,74 +144,65 @@ const TIME_CONST = {
|
||||
export default {
|
||||
components: {
|
||||
NButton,
|
||||
NIcon
|
||||
NIcon,
|
||||
NTimePicker,
|
||||
NInput
|
||||
},
|
||||
directives: {
|
||||
clickoutside
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
value: {
|
||||
type: [Number, String],
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
debug: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: PLACEHOLDER
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: DATETIME_FORMAT
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
displayDateTimeString: '',
|
||||
displayDateString: '',
|
||||
displayTimeString: '',
|
||||
rightDisplayDateTimeString: '',
|
||||
rightDisplayDateString: '',
|
||||
rightDisplayTimeString: '',
|
||||
calendarDateTime: moment(),
|
||||
rightCalendarDateTime: moment(),
|
||||
currentDateTime: moment(),
|
||||
showTimeSelector: false,
|
||||
showRightTimeSelector: false,
|
||||
calendar: [],
|
||||
rightCalendar: [],
|
||||
...TIME_CONST
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
placeholder () {
|
||||
return PLACEHOLDER[this.type]
|
||||
},
|
||||
format () {
|
||||
return DATE_FORMAT[this.type]
|
||||
},
|
||||
computedHour () {
|
||||
if (this.computedSelectedDateTime) return this.computedSelectedDateTime.format('HH')
|
||||
if (this.valueAsMoment) return this.valueAsMoment.format('HH')
|
||||
else return null
|
||||
},
|
||||
computedMinute () {
|
||||
if (this.computedSelectedDateTime) return this.computedSelectedDateTime.format('mm')
|
||||
if (this.valueAsMoment) return this.valueAsMoment.format('mm')
|
||||
else return null
|
||||
},
|
||||
computedSecond () {
|
||||
if (this.computedSelectedDateTime) return this.computedSelectedDateTime.format('ss')
|
||||
if (this.valueAsMoment) return this.valueAsMoment.format('ss')
|
||||
else return null
|
||||
},
|
||||
/**
|
||||
* If value is valid return null.
|
||||
* If value is not valid, return moment(value)
|
||||
*/
|
||||
computedSelectedDateTime () {
|
||||
valueAsMoment () {
|
||||
if (this.value === null || this.value === undefined) return null
|
||||
const newSelectedDateTime = moment(Number(this.value))
|
||||
const newSelectedDateTime = moment(this.value)
|
||||
if (newSelectedDateTime.isValid()) {
|
||||
return newSelectedDateTime
|
||||
} else {
|
||||
@ -299,170 +210,113 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
valueAsMoment (newValue) {
|
||||
if (newValue !== null) {
|
||||
this.displayDateString = newValue.format(DATE_FORMAT)
|
||||
} else {
|
||||
this.displayDateString = ''
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
if (this.valueAsMoment !== null) {
|
||||
this.displayDateString = this.valueAsMoment.format(DATE_FORMAT)
|
||||
} else {
|
||||
this.displayDateString = ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
dateArray,
|
||||
handleClickOutside () {
|
||||
this.closeCalendar()
|
||||
console.log('clickoutside')
|
||||
},
|
||||
dateArray,
|
||||
/**
|
||||
* If new datetime is null or undefined, emit null to value.
|
||||
* Else adjust new datetime by props.type and emit it to value.
|
||||
*/
|
||||
setValue (newSelectedDateTime) {
|
||||
if (newSelectedDateTime === null || newSelectedDateTime === undefined) {
|
||||
this.$emit('change', null)
|
||||
return
|
||||
}
|
||||
if (newSelectedDateTime.isValid()) {
|
||||
const adjustedDateTime = this.adjustDateTime(newSelectedDateTime)
|
||||
if (this.computedSelectedDateTime === null || adjustedDateTime.valueOf() !== this.computedSelectedDateTime.valueOf()) {
|
||||
this.refreshSelectedDateTimeString(adjustedDateTime)
|
||||
this.$emit('change', adjustedDateTime.valueOf(), adjustedDateTime.format(this.format))
|
||||
this.$emit('input', null)
|
||||
} else if (newSelectedDateTime.isValid()) {
|
||||
const adjustedDateTime = this.adjustValue(newSelectedDateTime)
|
||||
if (this.valueAsMoment === null || adjustedDateTime.valueOf() !== this.valueAsMoment.valueOf()) {
|
||||
this.refreshDisplayDateString(adjustedDateTime)
|
||||
this.$emit('input', adjustedDateTime.valueOf())
|
||||
}
|
||||
}
|
||||
// this.$nextTick(this.refreshSelectedDateTimeString)
|
||||
},
|
||||
adjustDateTime (datetime) {
|
||||
adjustValue (datetime) {
|
||||
return moment(datetime).startOf('second')
|
||||
},
|
||||
justifySelectedDateTimeAfterChangeTimeString () {
|
||||
if (this.computedSelectedDateTime === null) {
|
||||
// case here is impossible for now, because you can't clear time for now
|
||||
handleDateInput (value) {
|
||||
const date = moment(value, DATE_FORMAT, true)
|
||||
if (date.isValid()) {
|
||||
if (!this.valueAsMoment) {
|
||||
const newValue = moment()
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
} else {
|
||||
const newValue = this.valueAsMoment
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
}
|
||||
} else {
|
||||
const newDisplayDateTimeString = this.displayDateString + ' ' + this.displayTimeString
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
// do nothing
|
||||
}
|
||||
},
|
||||
handleTimeInput (e) {
|
||||
const newDisplayDateTimeString = this.displayDateString + ' ' + e.target.value
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
},
|
||||
handleDateInput (e) {
|
||||
const newDisplayDateTimeString = e.target.value + ' ' + this.displayTimeString
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
},
|
||||
handleTimeInputBlur () {
|
||||
this.refreshSelectedDateTimeString()
|
||||
},
|
||||
handleDateInputBlur () {
|
||||
this.refreshSelectedDateTimeString()
|
||||
},
|
||||
handleTimeConfirmClick () {
|
||||
this.justifySelectedDateTimeAfterChangeTimeString()
|
||||
this.refreshSelectedDateTimeString()
|
||||
this.closeTimeSelector()
|
||||
},
|
||||
handleTimeCancelClick () {
|
||||
this.closeTimeSelector()
|
||||
},
|
||||
setHour (hour) {
|
||||
try {
|
||||
const timeArray = this.displayTimeString.split(':')
|
||||
timeArray[0] = hour
|
||||
this.displayTimeString = timeArray.join(':')
|
||||
} catch (err) {
|
||||
|
||||
} finally {
|
||||
this.justifySelectedDateTimeAfterChangeTimeString()
|
||||
const date = moment(this.displayDateString, DATE_VALIDATE_FORMAT, true)
|
||||
if (date.isValid()) {
|
||||
if (!this.valueAsMoment) {
|
||||
const newValue = moment()
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
} else {
|
||||
const newValue = this.valueAsMoment
|
||||
newValue.year(date.year())
|
||||
newValue.month(date.month())
|
||||
newValue.date(date.date())
|
||||
this.$emit('input', this.adjustValue(newValue).valueOf())
|
||||
}
|
||||
} else {
|
||||
this.refreshDisplayDateString()
|
||||
}
|
||||
},
|
||||
setMinute (minute) {
|
||||
try {
|
||||
const timeArray = this.displayTimeString.split(':')
|
||||
timeArray[1] = minute
|
||||
this.displayTimeString = timeArray.join(':')
|
||||
} catch (err) {
|
||||
|
||||
} finally {
|
||||
this.justifySelectedDateTimeAfterChangeTimeString()
|
||||
}
|
||||
},
|
||||
setSecond (second) {
|
||||
try {
|
||||
const timeArray = this.displayTimeString.split(':')
|
||||
timeArray[2] = second
|
||||
this.displayTimeString = timeArray.join(':')
|
||||
} catch (err) {
|
||||
|
||||
} finally {
|
||||
this.justifySelectedDateTimeAfterChangeTimeString()
|
||||
}
|
||||
},
|
||||
openTimeSelector () {
|
||||
if (this.computedSelectedDateTime === null) {
|
||||
this.setValue(moment())
|
||||
}
|
||||
this.showTimeSelector = true
|
||||
},
|
||||
closeTimeSelector () {
|
||||
this.showTimeSelector = false
|
||||
},
|
||||
clearSelectedDateTime () {
|
||||
this.setValue(null)
|
||||
this.displayDateTimeString = ''
|
||||
this.$emit('input', null)
|
||||
this.displayDateString = ''
|
||||
this.displayTimeString = ''
|
||||
},
|
||||
setSelectedDateTimeToNow () {
|
||||
this.setValue(moment())
|
||||
this.$emit('input', this.adjustValue(moment()).valueOf())
|
||||
this.calendarDateTime = moment()
|
||||
},
|
||||
handleDateClick (dateItem) {
|
||||
let newSelectedDateTime = moment()
|
||||
if (this.computedSelectedDateTime !== null) {
|
||||
newSelectedDateTime = moment(this.computedSelectedDateTime)
|
||||
if (this.valueAsMoment !== null) {
|
||||
newSelectedDateTime = moment(this.valueAsMoment)
|
||||
}
|
||||
newSelectedDateTime = setDate(newSelectedDateTime, dateItem)
|
||||
this.setValue(newSelectedDateTime)
|
||||
this.$emit('input', this.adjustValue(newSelectedDateTime).valueOf())
|
||||
},
|
||||
/**
|
||||
* If not selected, display nothing,
|
||||
* else update datetime related string
|
||||
*/
|
||||
refreshSelectedDateTimeString (time) {
|
||||
if (this.computedSelectedDateTime === null) {
|
||||
this.displayDateTimeString = ''
|
||||
refreshDisplayDateString (time) {
|
||||
if (this.valueAsMoment === null) {
|
||||
this.displayDateString = ''
|
||||
return
|
||||
}
|
||||
if (time === undefined) {
|
||||
time = this.computedSelectedDateTime
|
||||
time = this.valueAsMoment
|
||||
}
|
||||
this.displayDateTimeString = time.format(this.format)
|
||||
this.displayDateString = time.format('YYYY-MM-DD')
|
||||
this.displayTimeString = time.format('HH:mm:ss')
|
||||
this.displayDateString = time.format(DATE_FORMAT)
|
||||
},
|
||||
/**
|
||||
* If new time is invalid, do nothing.
|
||||
* If valid, update.
|
||||
*/
|
||||
handleDateTimeInputEnter () {
|
||||
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
},
|
||||
/**
|
||||
* If new SelectedDateTime is valid, update `selectedDateTime` and `calendarTime`
|
||||
* Whatever happened, refresh selectedDateTime
|
||||
*/
|
||||
handleDateTimeInputBlur () {
|
||||
const newSelectedDateTime = moment(this.displayDateTimeString, this.format, true)
|
||||
this.setValue(newSelectedDateTime)
|
||||
/**
|
||||
* If newSelectedDateTime is invalid, display string need to be restored
|
||||
*/
|
||||
this.refreshSelectedDateTimeString()
|
||||
},
|
||||
handleDateInputAndTimeInputConfirmClick () {
|
||||
const newDisplayDateTimeString = `${this.displayDateString.trim()} ${this.displayTimeString.trim()}`
|
||||
const newSelectedDateTime = moment(newDisplayDateTimeString, this.format, true)
|
||||
if (this.computedSelectedDateTime === null) {
|
||||
this.setValue(moment())
|
||||
} else {
|
||||
this.setValue(newSelectedDateTime)
|
||||
}
|
||||
handleConfirmClick () {
|
||||
this.$emit('confirm')
|
||||
this.closeCalendar()
|
||||
},
|
||||
closeCalendar () {
|
||||
@ -485,6 +339,9 @@ export default {
|
||||
prevMonth () {
|
||||
this.calendarDateTime.subtract(1, 'month')
|
||||
this.$forceUpdate()
|
||||
},
|
||||
handleTimePickerInput (value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,11 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.n-modal-content {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.n-modal-content--transition-enter-active {
|
||||
opacity: 1;
|
||||
|
@ -13,6 +13,7 @@
|
||||
<div
|
||||
ref="contentWrapper"
|
||||
class="n-content-wrapper"
|
||||
@click="handleContentClick"
|
||||
>
|
||||
<div
|
||||
ref="content"
|
||||
@ -21,7 +22,7 @@
|
||||
<div
|
||||
v-if="active"
|
||||
v-clickoutside.lazy="closeTimeSelector"
|
||||
class="n-time-picker"
|
||||
class="n-time-picker-selector"
|
||||
>
|
||||
<div class="n-time-picker__selection-wrapper">
|
||||
<div
|
||||
@ -92,7 +93,7 @@
|
||||
round
|
||||
auto-text-color
|
||||
type="primary"
|
||||
@click="handleComfirmClick"
|
||||
@click="handleConfirmClick"
|
||||
>
|
||||
Confirm
|
||||
</n-button>
|
||||
@ -153,14 +154,16 @@ export default {
|
||||
},
|
||||
mixins: [detachable, placeable],
|
||||
props: {
|
||||
stopSelectorBubble: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'bottom-start'
|
||||
},
|
||||
value: {
|
||||
validator (value) {
|
||||
return moment(value).isValid()
|
||||
},
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
format: {
|
||||
@ -290,9 +293,14 @@ export default {
|
||||
this.$emit('input', this.memorizedValue)
|
||||
this.active = false
|
||||
},
|
||||
handleComfirmClick () {
|
||||
handleConfirmClick () {
|
||||
this.refreshTimeString()
|
||||
this.active = false
|
||||
},
|
||||
handleContentClick (e) {
|
||||
if (this.stopSelectorBubble) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.content.style = 'position: absolute;'
|
||||
this.$nextTick().then(() => {
|
||||
this.registerScrollListeners()
|
||||
this.registerResizeListener()
|
||||
|
@ -38,7 +38,7 @@
|
||||
color: rgba(221, 238, 247, 0.3);
|
||||
height: 20px;
|
||||
}
|
||||
.n-date-picker__input, .n-date-picker-calendar__date-input, .n-date-picker-calendar__time-input {
|
||||
.n-date-picker__input, .n-date-picker-calendar__date-input {
|
||||
-webkit-appearance: none;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
|
@ -1,4 +1,4 @@
|
||||
@include b(time-picker) {
|
||||
@include b(time-picker-selector) {
|
||||
background-color: rgba(97, 104, 132, 1);
|
||||
box-shadow:0px 2px 20px 0px rgba(0,0,0,0.16);
|
||||
font-size: 12px;
|
||||
@ -6,7 +6,7 @@
|
||||
margin-top: 4px;
|
||||
width: 180px;
|
||||
overflow: hidden;
|
||||
@include fade-in-transition(time-picker, center top);
|
||||
@include fade-in-transition(time-picker, top left);
|
||||
.n-time-picker__selection-wrapper {
|
||||
position: relative;
|
||||
height: 244px;
|
||||
|
@ -7,4 +7,5 @@
|
||||
|
||||
@include b(tooltip__content) {
|
||||
padding: 8px 14px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user