mand-mobile/components/date-picker/index.vue

574 lines
14 KiB
Vue
Raw Normal View History

2018-03-26 16:04:04 +08:00
<template>
<div class="md-date-picker" :class="[type]">
<md-picker
ref="picker"
v-model="isPickerShow"
:data="columnData"
:cols="columnData.length"
:default-value="columnDataDefault"
:title="title"
2018-11-20 11:19:34 +08:00
:describe="describe"
2018-03-26 16:04:04 +08:00
:ok-text="okText"
:cancel-text="cancelText"
:is-view="isView"
:mask-closable="maskClosable"
2018-03-26 16:04:04 +08:00
@initialed="$emit('initialed')"
@change="$_onPickerChange"
@confirm="$_onPickerConfirm"
@cancel="$_onPickerCancel"
2018-03-26 16:04:04 +08:00
@show="$_onPickerShow"
@hide="$_onPickerHide"
></md-picker>
</div>
</template>
<script>
import Picker from '../picker'
import pickerMixin from '../picker/mixins'
2018-03-26 16:04:04 +08:00
import {
toObject,
toArray,
2018-03-26 16:04:04 +08:00
warn
} from '../_util'
// yyyy-MM-dd hh:mm:ss => Year-Month-Date Hour:Minute
const TYPE_FORMAT = {
'yyyy': 'Year',
'MM': 'Month',
'dd': 'Date',
'hh': 'Hour',
'mm': 'Minute'
}
const TYPE_FORMAT_INVERSE = toObject(
Object.keys(TYPE_FORMAT).map(item => {
return {
[TYPE_FORMAT[item]]: item
}
})
)
const TYPE_METHODS = {
'Year': 'getFullYear',
'Month': 'getMonth',
'Date': 'getDate',
'Hour': 'getHours',
'Minute': 'getMinutes'
}
export default {
name: 'md-date-picker',
mixins: [pickerMixin],
2018-03-26 16:04:04 +08:00
components: {
[Picker.name]: Picker
},
props: {
type: { // date, time, datetime custom
type: String,
default: 'date'
},
customTypes: { // yyyy, MM, dd, hh, mm
type: Array,
default () {
return []
},
validator (val) {
let res = true
val.forEach(type => {
type = TYPE_FORMAT[type] || type
/* istanbul ignore if */
if (!(type in TYPE_METHODS)) {
return (res = false)
}
})
return res
}
},
minDate: {
type: Date
},
maxDate: {
type: Date
},
defaultDate: {
type: Date
},
minuteStep: {
type: Number,
default: 1
},
unitText: {
type: Array,
default () {
return ['年', '月', '日', '时', '分']
}
},
todayText: {
type: String,
default: ''
},
textRender: {
type: [Function, String],
default: ''
},
// Mixin Props
// value: {
// type: Boolean,
// default: false
// },
// title: {
// type: String
// },
// describe: {
// type: String
// },
// okText: {
// type: String
// },
// cancelText: {
// type: String
// },
// isView: {
// type: Boolean,
// default: false
// },
// maskClosable: {
// type: Boolean,
// default: true,
// }
2018-03-26 16:04:04 +08:00
},
data () {
return {
isPickerShow: false,
currentDateIns: new Date(),
columnData: [],
oldColumnData: null,
2018-03-26 16:04:04 +08:00
columnDataDefault: [],
columnDataGenerator: [],
}
},
computed: {
picker () {
return this.$refs['picker']
},
currentYear () {
return this.currentDateIns.getFullYear()
},
currentMonth () {
return this.currentDateIns.getMonth() + 1
},
currentDate () {
return this.currentDateIns.getDate()
},
currentHours () {
return this.currentDateIns.getHours()
},
currentMinutes () {
return this.currentDateIns.getMinutes()
2018-03-26 16:04:04 +08:00
}
},
watch: {
value (val) {
this.isPickerShow = val
},
isPickerShow (val) {
if (!val) {
this.$emit('input', val)
}
},
defaultDate () {
this.$_initPickerColumn()
},
minDate () {
this.$_initPickerColumn()
},
maxDate () {
this.$_initPickerColumn()
}
},
mounted () {
this.$_initPicker()
},
methods: {
// MARK: private methods
$_initPicker () {
if (!this.isView && this.value) {
this.isPickerShow = this.value
}
this.picker.inheritPickerApi(this)
this.$_initPickerColumn()
},
$_initPickerColumn () {
this.$_resetPickerColumn()
2018-03-26 16:04:04 +08:00
this.$_initColumnDataGenerator()
this.$_initColumnData(0, this.columnDataDefault)
},
$_resetPickerColumn() {
this.oldColumnData = null
this.columnData = []
this.columnDataDefault = []
this.columnDataGenerator = []
2018-03-26 16:04:04 +08:00
},
$_initColumnData (columnIndex, defaultDate = [], isSetColumn = true) {
const columnData = this.columnData
const columnDataGenerator = this.columnDataGenerator
for (let i = columnIndex, len = columnDataGenerator.length; i < len; i++) {
// Collect parameters for columnDataGenerator
const columnDataGeneratorParams = []
const generator = columnDataGenerator[i]
for (let j = 0; j < i; j++) {
const _generator = columnDataGenerator[j]
if (defaultDate[j] && _generator) {
columnDataGeneratorParams.push({
type: _generator.type,
value: defaultDate[j]
})
2018-03-26 16:04:04 +08:00
continue
}
const itemIndex = this.picker.getColumnIndex(j) || 0
/* istanbul ignore else */
2018-03-26 16:04:04 +08:00
if (columnData[j]) {
columnDataGeneratorParams.push(columnData[j][itemIndex])
2018-03-26 16:04:04 +08:00
} else {
columnDataGeneratorParams.push('')
warn(`DatePicker columnData of index ${j} is void`)
}
}
2018-03-26 16:04:04 +08:00
// Generator colume data with columnDataGeneratorParams
const curColumnData = generator ? generator.apply(this, columnDataGeneratorParams) : ''
// set picker column data & refresh picker
isSetColumn && this.picker.setColumnValues(i, curColumnData)
// store column date
this.$set(columnData, i, curColumnData)
}
isSetColumn && this.picker.refresh(null, columnIndex)
},
$_initColumnDataGenerator () {
this.$_generateYearData.type = 'Year'
this.$_generateMonthData.type = 'Month'
this.$_generateDateData.type = 'Date'
this.$_generateHourData.type = 'Hour'
this.$_generateMinuteData.type = 'Minute'
const defaultDate = this.$_getDefaultDate()
2018-03-26 16:04:04 +08:00
switch (this.type) {
case 'date':
this.$_initColumnDataGeneratorForDate(defaultDate)
break
case 'time':
this.$_initColumnDataGeneratorForTime(defaultDate)
break
case 'datetime':
this.$_initColumnDataGeneratorForDate(defaultDate)
this.$_initColumnDataGeneratorForTime(defaultDate)
break
default:
this.$_initColumnDataGeneratorForCustom(defaultDate)
break
}
},
$_initColumnDataGeneratorForDate (defaultDate) {
this.columnDataGenerator = this.columnDataGenerator.concat([
this.$_generateYearData,
this.$_generateMonthData,
this.$_generateDateData
])
this.columnDataDefault = defaultDate ? this.columnDataDefault.concat([
defaultDate.getFullYear(),
defaultDate.getMonth() + 1,
defaultDate.getDate()
]) : []
},
$_initColumnDataGeneratorForTime (defaultDate) {
this.columnDataGenerator = this.columnDataGenerator.concat([
this.$_generateHourData,
this.$_generateMinuteData
])
this.columnDataDefault = defaultDate ? this.columnDataDefault.concat([
defaultDate.getHours(),
defaultDate.getMinutes()
]) : []
2018-03-26 16:04:04 +08:00
},
$_initColumnDataGeneratorForCustom (defaultDate) {
this.customTypes.forEach(type => {
2018-03-26 16:04:04 +08:00
type = TYPE_FORMAT[type] || type
this.columnDataGenerator.push(this[`$_generate${type}Data`])
if (defaultDate) {
let value = defaultDate[TYPE_METHODS[type]]()
if (type === 'Month') {
value += 1
}
this.columnDataDefault.push(value)
}
})
},
$_getDefaultDate () {
const defaultDate = this.defaultDate
const minDate = this.minDate
const maxDate = this.maxDate
if (!defaultDate) {
return defaultDate
}
if (minDate && defaultDate.getTime() < minDate.getTime()) {
return minDate
}
if (maxDate && defaultDate.getTime() > maxDate.getTime()) {
return maxDate
}
return defaultDate
},
$_getGeneratorArguments (args) {
const defaultArguments = {
Year: this.currentYear,
Month: this.currentMonth,
Date: this.currentDate,
Hour: this.currentHours,
Minute: this.currentMinutes
}
args.map(item => {
defaultArguments[item.type] = item.value
})
return defaultArguments
},
2018-03-26 16:04:04 +08:00
$_generateYearData () {
const start = this.minDate ? this.minDate.getFullYear() : this.currentYear - 20
const end = this.maxDate ? this.maxDate.getFullYear() : this.currentYear + 20
/* istanbul ignore if */
2018-03-26 16:04:04 +08:00
if (start > end) {
warn('MinDate Year should be earlier than MaxDate')
return
}
return this.$_generateData(start, end, 'Year', this.unitText[0], 1)
},
$_generateMonthData () {
const args = this.$_getGeneratorArguments(toArray(arguments))
2018-03-26 16:04:04 +08:00
let start, end
if (this.$_isDateTimeEqual(this.minDate, args.Year)) {
2018-03-26 16:04:04 +08:00
start = this.minDate.getMonth() + 1
} else {
start = 1
}
if (this.$_isDateTimeEqual(this.maxDate, args.Year)) {
2018-03-26 16:04:04 +08:00
end = this.maxDate.getMonth() + 1
} else {
end = 12
}
return this.$_generateData(start, end, 'Month', this.unitText[1] || '', 1, arguments)
2018-03-26 16:04:04 +08:00
},
$_generateDateData () {
const args = this.$_getGeneratorArguments(toArray(arguments))
2018-03-26 16:04:04 +08:00
let start, end
if (this.$_isDateTimeEqual(this.minDate, args.Year, args.Month)) {
2018-03-26 16:04:04 +08:00
start = this.minDate.getDate()
} else {
start = 1
}
if (this.$_isDateTimeEqual(this.maxDate, args.Year, args.Month)) {
2018-03-26 16:04:04 +08:00
end = this.maxDate.getDate()
} else {
end = new Date(args.Year, args.Month, 0).getDate()
2018-03-26 16:04:04 +08:00
}
const dateData = this.$_generateData(start, end, 'Date', this.unitText[2] || '', 1, arguments)
if (this.$_isDateTimeEqual(this.currentDateIns, args.Year, args.Month) &&
2018-03-26 16:04:04 +08:00
this.currentDate >= start && this.currentDate <= end &&
this.todayText) {
const currentDateIndex = this.currentDate - start
const currentDate = dateData[currentDateIndex].text
dateData[currentDateIndex].text = this.todayText.replace('&', currentDate)
}
return dateData
},
$_generateHourData () {
const args = this.$_getGeneratorArguments(toArray(arguments))
let start, end
if (this.$_isDateTimeEqual(this.minDate, args.Year, args.Month, args.Date)) {
start = this.minDate.getHours()
} else {
start = 0
}
2018-03-26 16:04:04 +08:00
if (this.$_isDateTimeEqual(this.maxDate, args.Year, args.Month, args.Date)) {
end = this.maxDate.getHours()
} else {
2018-03-26 16:04:04 +08:00
end = 23
}
/* istanbul ignore if */
if (end < start) {
end = 23
2018-03-26 16:04:04 +08:00
}
/* istanbul ignore if */
2018-03-26 16:04:04 +08:00
if (start > end) {
warn('MinDate Hour should be earlier than MaxDate')
return
}
return this.$_generateData(start, end, 'Hour', this.unitText[3] || '', 1, arguments)
},
$_generateMinuteData () {
const args = this.$_getGeneratorArguments(toArray(arguments))
let start, end
if (this.$_isDateTimeEqual(this.minDate, args.Year, args.Month, args.Date, args.Hour)) {
start = this.minDate.getMinutes()
} else {
start = 0
}
2018-03-26 16:04:04 +08:00
if (this.$_isDateTimeEqual(this.maxDate, args.Year, args.Month, args.Date, args.Hour)) {
end = this.maxDate.getMinutes()
} else {
end = 59
2018-03-26 16:04:04 +08:00
}
return this.$_generateData(start, end, 'Minute', this.unitText[4] || '', this.minuteStep, arguments)
},
$_generateData (from, to, type, unit, step = 1, args = []) {
2018-03-26 16:04:04 +08:00
let count = from
let text
const data = []
const defaultArgs = toArray(args).map(item => {
return typeof item === 'object' ? item.value : item
})
2018-03-26 16:04:04 +08:00
while (count <= to) {
this.textRender
&& (text = this.textRender.apply(this, [
TYPE_FORMAT_INVERSE[type],
...defaultArgs,
2018-03-26 16:04:04 +08:00
count
]))
data.push({
text: text || `${count}${unit}`,
value: count,
typeFormat: TYPE_FORMAT_INVERSE[type] || type,
type
})
count += step
}
return data
},
/**
* Determine whether year, month, date, etc of
* the current date are equal to the given value
* @params Date
* @params year, month, date ...
*/
$_isDateTimeEqual () {
const methods = Object.keys(TYPE_METHODS).map(key => {
return TYPE_METHODS[key]
})
const args = toArray(arguments)
const date = args[0]
let res = true
if (!date) {
return res = false
}
for (let i = 1; i < args.length; i++) {
const methodName = methods[i - 1]
const curVal = date[methodName]() + Number(methodName === 'getMonth')
const targetVal = +args[i]
if (curVal !== targetVal) {
res = false
break
}
}
return res
},
2018-03-26 16:04:04 +08:00
// MARK: events handler
$_onPickerShow () {
this.oldColumnData = [...this.columnData]
2018-03-26 16:04:04 +08:00
this.$emit('show')
},
$_onPickerHide () {
this.$emit('hide')
},
$_onPickerChange (columnIndex, itemIndex, value) {
this.$emit('change', columnIndex, itemIndex, value)
if (columnIndex < this.columnData.length - 1) {
this.$_initColumnData(columnIndex + 1)
}
},
$_onPickerConfirm (columnsValue) {
this.$emit('confirm', columnsValue)
},
$_onPickerCancel () {
this.$emit('cancel')
if (this.oldColumnData) {
this.columnData = [...this.oldColumnData]
}
},
2018-03-26 16:04:04 +08:00
getFormatDate (format = 'yyyy-MM-dd hh:mm') {
const columnValues = this.picker.getColumnValues()
2018-03-26 16:04:04 +08:00
columnValues.forEach(item => {
/* istanbul ignore if */
if (!item) {
return
}
let value = item.value
2018-03-26 16:04:04 +08:00
if (value < 10) {
value = '0' + value
}
format = format.replace(item.type, value)
format = format.replace(TYPE_FORMAT_INVERSE[item.type], value)
})
return format
}
}
}
</script>
<style lang="stylus">
.md-date-picker
.column-item
font-size date-picker-font-size !important
overflow visible !important
// &.datetime .column-item
// font-size date-time-picker-font-size !important
2018-03-26 16:04:04 +08:00
</style>