vxe-table-select-area
Version:
一个基于 vxe-table 的可区域选中复制、粘贴的组件
1,571 lines (1,539 loc) • 69.9 kB
JavaScript
import XEUtils from 'xe-utils'
import GlobalConfig from '../../v-x-e-table/src/conf'
import vSize from '../../mixins/size'
import UtilTools, { getFuncText } from '../../tools/utils'
import DomTools from '../../tools/dom'
import { GlobalEvent } from '../../tools/event'
import { toStringTimeDate, getDateQuarter } from './date'
import { handleNumber, toFloatValueFixed } from './number'
import { warnLog } from '../../tools/log'
const yearSize = 12
const monthSize = 20
const quarterSize = 8
function getNumberValue (_vm, val) {
const { type, exponential, digitsValue, inpMaxlength } = _vm
const restVal = (type === 'float' ? toFloatValueFixed(val, digitsValue) : XEUtils.toValueString(val))
if (exponential && (val === restVal || XEUtils.toValueString(val).toLowerCase() === XEUtils.toNumber(restVal).toExponential())) {
return val
}
return restVal.slice(0, inpMaxlength)
}
function renderDateLabel (h, _vm, item, label) {
const festivalMethod = _vm.festivalMethod
if (festivalMethod) {
const festivalRest = festivalMethod({ $input: _vm, type: _vm.datePanelType, viewType: _vm.datePanelType, ...item })
const festivalItem = festivalRest ? (XEUtils.isString(festivalRest) ? { label: festivalRest } : festivalRest) : {}
const extraItem = festivalItem.extra ? (XEUtils.isString(festivalItem.extra) ? { label: festivalItem.extra } : festivalItem.extra) : null
const labels = [
h('span', {
class: ['vxe-input--date-label', {
'is-notice': festivalItem.notice
}]
}, extraItem && extraItem.label ? [
h('span', label),
h('span', {
class: ['vxe-input--date-label--extra', extraItem.important ? 'is-important' : '', extraItem.className],
style: extraItem.style
}, XEUtils.toValueString(extraItem.label))
] : label)
]
const festivalLabel = festivalItem.label
if (festivalLabel) {
// 默认最多支持3个节日重叠
const festivalLabels = XEUtils.toValueString(festivalLabel).split(',')
labels.push(
h('span', {
class: ['vxe-input--date-festival', festivalItem.important ? 'is-important' : '', festivalItem.className],
style: festivalItem.style
}, [
festivalLabels.length > 1 ? h('span', {
class: ['vxe-input--date-festival--overlap', `overlap--${festivalLabels.length}`]
}, festivalLabels.map(label => h('span', label.substring(0, 3)))) : h('span', {
class: 'vxe-input--date-festival--label'
}, festivalLabels[0].substring(0, 3))
])
)
}
return labels
}
return label
}
function isDateDisabled (_vm, item) {
const disabledMethod = _vm.disabledMethod
return disabledMethod && disabledMethod({ $input: _vm, type: _vm.datePanelType, viewType: _vm.datePanelType, date: item.date })
}
function renderDateDayTable (h, _vm) {
const { datePanelType, dateValue, datePanelValue, dateHeaders, dayDatas, multiple, dateListValue } = _vm
const matchFormat = 'yyyy-MM-dd'
return [
h('table', {
class: `vxe-input--date-${datePanelType}-view`,
attrs: {
cellspacing: 0,
cellpadding: 0,
border: 0
}
}, [
h('thead', [
h('tr', dateHeaders.map(item => {
return h('th', item.label)
}))
]),
h('tbody', dayDatas.map(rows => {
return h('tr', rows.map(item => {
return h('td', {
class: {
'is--prev': item.isPrev,
'is--current': item.isCurrent,
'is--now': item.isNow,
'is--next': item.isNext,
'is--disabled': isDateDisabled(_vm, item),
'is--selected': multiple ? dateListValue.some(val => XEUtils.isDateSame(val, item.date, matchFormat)) : XEUtils.isDateSame(dateValue, item.date, matchFormat),
'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
},
on: {
click: () => _vm.dateSelectEvent(item),
mouseenter: () => _vm.dateMouseenterEvent(item)
}
}, renderDateLabel(h, _vm, item, item.label))
}))
}))
])
]
}
function renderDateWeekTable (h, _vm) {
const { datePanelType, dateValue, datePanelValue, weekHeaders, weekDates, multiple, dateListValue } = _vm
const matchFormat = 'yyyyMMdd'
return [
h('table', {
class: `vxe-input--date-${datePanelType}-view`,
attrs: {
cellspacing: 0,
cellpadding: 0,
border: 0
}
}, [
h('thead', [
h('tr', weekHeaders.map(item => {
return h('th', item.label)
}))
]),
h('tbody', weekDates.map(rows => {
const isSelected = multiple ? rows.some((item) => dateListValue.some(val => XEUtils.isDateSame(val, item.date, matchFormat))) : rows.some(item => XEUtils.isDateSame(dateValue, item.date, matchFormat))
const isHover = rows.some(item => XEUtils.isDateSame(datePanelValue, item.date, matchFormat))
return h('tr', rows.map(item => {
return h('td', {
class: {
'is--prev': item.isPrev,
'is--current': item.isCurrent,
'is--now': item.isNow,
'is--next': item.isNext,
'is--disabled': isDateDisabled(_vm, item),
'is--selected': isSelected,
'is--hover': isHover
},
on: {
click: () => _vm.dateSelectEvent(item),
mouseenter: () => _vm.dateMouseenterEvent(item)
}
}, renderDateLabel(h, _vm, item, item.label))
}))
}))
])
]
}
function renderDateMonthTable (h, _vm) {
const { dateValue, datePanelType, monthDatas, datePanelValue, multiple, dateListValue } = _vm
const matchFormat = 'yyyyMM'
return [
h('table', {
class: `vxe-input--date-${datePanelType}-view`,
attrs: {
cellspacing: 0,
cellpadding: 0,
border: 0
}
}, [
h('tbody', monthDatas.map(rows => {
return h('tr', rows.map(item => {
return h('td', {
class: {
'is--prev': item.isPrev,
'is--current': item.isCurrent,
'is--now': item.isNow,
'is--next': item.isNext,
'is--disabled': isDateDisabled(_vm, item),
'is--selected': multiple ? dateListValue.some(val => XEUtils.isDateSame(val, item.date, matchFormat)) : XEUtils.isDateSame(dateValue, item.date, matchFormat),
'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
},
on: {
click: () => _vm.dateSelectEvent(item),
mouseenter: () => _vm.dateMouseenterEvent(item)
}
}, renderDateLabel(h, _vm, item, GlobalConfig.i18n(`vxe.input.date.months.m${item.month}`)))
}))
}))
])
]
}
function renderDateQuarterTable (h, _vm) {
const { dateValue, datePanelType, quarterDatas, datePanelValue, multiple, dateListValue } = _vm
const matchFormat = 'yyyyq'
return [
h('table', {
class: `vxe-input--date-${datePanelType}-view`,
attrs: {
cellspacing: 0,
cellpadding: 0,
border: 0
}
}, [
h('tbody', quarterDatas.map(rows => {
return h('tr', rows.map(item => {
return h('td', {
class: {
'is--prev': item.isPrev,
'is--current': item.isCurrent,
'is--now': item.isNow,
'is--next': item.isNext,
'is--disabled': isDateDisabled(_vm, item),
'is--selected': multiple ? dateListValue.some(val => XEUtils.isDateSame(val, item.date, matchFormat)) : XEUtils.isDateSame(dateValue, item.date, matchFormat),
'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
},
on: {
click: () => _vm.dateSelectEvent(item),
mouseenter: () => _vm.dateMouseenterEvent(item)
}
}, renderDateLabel(h, _vm, item, GlobalConfig.i18n(`vxe.input.date.quarters.q${item.quarter}`)))
}))
}))
])
]
}
function renderDateYearTable (h, _vm) {
const { dateValue, datePanelType, yearDatas, datePanelValue, multiple, dateListValue } = _vm
const matchFormat = 'yyyy'
return [
h('table', {
class: `vxe-input--date-${datePanelType}-view`,
attrs: {
cellspacing: 0,
cellpadding: 0,
border: 0
}
}, [
h('tbody', yearDatas.map(rows => {
return h('tr', rows.map(item => {
return h('td', {
class: {
'is--prev': item.isPrev,
'is--current': item.isCurrent,
'is--now': item.isNow,
'is--next': item.isNext,
'is--disabled': isDateDisabled(item),
'is--selected': multiple ? dateListValue.some(val => XEUtils.isDateSame(val, item.date, matchFormat)) : XEUtils.isDateSame(dateValue, item.date, matchFormat),
'is--hover': XEUtils.isDateSame(datePanelValue, item.date, matchFormat)
},
on: {
click: () => _vm.dateSelectEvent(item),
mouseenter: () => _vm.dateMouseenterEvent(item)
}
}, renderDateLabel(h, _vm, item, item.year))
}))
}))
])
]
}
function renderDateTable (h, _vm) {
const { datePanelType } = _vm
switch (datePanelType) {
case 'week' :
return renderDateWeekTable(h, _vm)
case 'month' :
return renderDateMonthTable(h, _vm)
case 'quarter' :
return renderDateQuarterTable(h, _vm)
case 'year' :
return renderDateYearTable(h, _vm)
}
return renderDateDayTable(h, _vm)
}
function renderDatePanel (h, _vm) {
const { datePanelType, selectDatePanelLabel, isDisabledPrevDateBtn, isDisabledNextDateBtn, multiple, supportMultiples } = _vm
return [
h('div', {
class: 'vxe-input--date-picker-header'
}, [
h('div', {
class: 'vxe-input--date-picker-type-wrapper'
}, [
datePanelType === 'year' ? h('span', {
class: 'vxe-input--date-picker-label'
}, selectDatePanelLabel) : h('span', {
class: 'vxe-input--date-picker-btn',
on: {
click: _vm.dateToggleTypeEvent
}
}, selectDatePanelLabel)
]),
h('div', {
class: 'vxe-input--date-picker-btn-wrapper'
}, [
h('span', {
class: ['vxe-input--date-picker-btn vxe-input--date-picker-prev-btn', {
'is--disabled': isDisabledPrevDateBtn
}],
on: {
click: _vm.datePrevEvent
}
}, [
h('i', {
class: 'vxe-icon-caret-left'
})
]),
h('span', {
class: 'vxe-input--date-picker-btn vxe-input--date-picker-current-btn',
on: {
click: _vm.dateTodayMonthEvent
}
}, [
h('i', {
class: 'vxe-icon-dot'
})
]),
h('span', {
class: ['vxe-input--date-picker-btn vxe-input--date-picker-next-btn', {
'is--disabled': isDisabledNextDateBtn
}],
on: {
click: _vm.dateNextEvent
}
}, [
h('i', {
class: 'vxe-icon-caret-right'
})
]),
multiple && supportMultiples ? h('span', {
class: 'vxe-input--date-picker-btn vxe-input--date-picker-confirm-btn'
}, [
h('button', {
class: 'vxe-input--date-picker-confirm',
attrs: {
type: 'button'
},
on: {
click: _vm.dateConfirmEvent
}
}, GlobalConfig.i18n('vxe.button.confirm'))
]) : null
])
]),
h('div', {
class: 'vxe-input--date-picker-body'
}, renderDateTable(h, _vm))
]
}
function renderTimePanel (h, _vm) {
const { dateTimeLabel, datetimePanelValue, hourList, minuteList, secondList } = _vm
return [
h('div', {
class: 'vxe-input--time-picker-header'
}, [
h('span', {
class: 'vxe-input--time-picker-title'
}, dateTimeLabel),
h('button', {
class: 'vxe-input--time-picker-confirm',
attrs: {
type: 'button'
},
on: {
click: _vm.dateConfirmEvent
}
}, GlobalConfig.i18n('vxe.button.confirm'))
]),
h('div', {
ref: 'timeBody',
class: 'vxe-input--time-picker-body'
}, [
h('ul', {
class: 'vxe-input--time-picker-hour-list'
}, hourList.map((item, index) => {
return h('li', {
key: index,
class: {
'is--selected': datetimePanelValue && datetimePanelValue.getHours() === item.value
},
on: {
click: (evnt) => _vm.dateHourEvent(evnt, item)
}
}, item.label)
})),
h('ul', {
class: 'vxe-input--time-picker-minute-list'
}, minuteList.map((item, index) => {
return h('li', {
key: index,
class: {
'is--selected': datetimePanelValue && datetimePanelValue.getMinutes() === item.value
},
on: {
click: (evnt) => _vm.dateMinuteEvent(evnt, item)
}
}, item.label)
})),
h('ul', {
class: 'vxe-input--time-picker-second-list'
}, secondList.map((item, index) => {
return h('li', {
key: index,
class: {
'is--selected': datetimePanelValue && datetimePanelValue.getSeconds() === item.value
},
on: {
click: (evnt) => _vm.dateSecondEvent(evnt, item)
}
}, item.label)
}))
])
]
}
function renderPanel (h, _vm) {
const { type, vSize, isDatePickerType, transfer, animatVisible, visiblePanel, panelPlacement, panelStyle } = _vm
const renders = []
if (isDatePickerType) {
if (type === 'datetime') {
renders.push(
h('div', {
class: 'vxe-input--panel-layout-wrapper'
}, [
h('div', {
class: 'vxe-input--panel-left-wrapper'
}, renderDatePanel(h, _vm)),
h('div', {
class: 'vxe-input--panel-right-wrapper'
}, renderTimePanel(h, _vm))
])
)
} else if (type === 'time') {
renders.push(
h('div', {
class: 'vxe-input--panel-wrapper'
}, renderTimePanel(h, _vm))
)
} else {
renders.push(
h('div', {
class: 'vxe-input--panel-wrapper'
}, renderDatePanel(h, _vm))
)
}
return h('div', {
ref: 'panel',
class: ['vxe-table--ignore-clear vxe-input--panel', `type--${type}`, {
[`size--${vSize}`]: vSize,
'is--transfer': transfer,
'animat--leave': animatVisible,
'animat--enter': visiblePanel
}],
attrs: {
placement: panelPlacement
},
style: panelStyle
}, renders)
}
return null
}
function renderNumberIcon (h, _vm) {
return h('span', {
class: 'vxe-input--number-suffix'
}, [
h('span', {
class: ['vxe-input--number-prev is--prev', {
'is--disabled': _vm.isDisabledAddNumber
}],
on: {
mousedown: _vm.numberMousedownEvent,
mouseup: _vm.numberStopDown,
mouseleave: _vm.numberStopDown
}
}, [
h('i', {
class: ['vxe-input--number-prev-icon', GlobalConfig.icon.INPUT_PREV_NUM]
})
]),
h('span', {
class: ['vxe-input--number-next is--next', {
'is--disabled': _vm.isDisabledSubtractNumber
}],
on: {
mousedown: _vm.numberMousedownEvent,
mouseup: _vm.numberStopDown,
mouseleave: _vm.numberStopDown
}
}, [
h('i', {
class: ['vxe-input--number-next-icon', GlobalConfig.icon.INPUT_NEXT_NUM]
})
])
])
}
function renderDatePickerIcon (h, _vm) {
return h('span', {
class: 'vxe-input--date-picker-suffix',
on: {
click: _vm.datePickerOpenEvent
}
}, [
h('i', {
class: ['vxe-input--date-picker-icon', GlobalConfig.icon.INPUT_DATE]
})
])
}
function renderSearchIcon (h, _vm) {
return h('span', {
class: 'vxe-input--search-suffix',
on: {
click: _vm.searchEvent
}
}, [
h('i', {
class: ['vxe-input--search-icon', GlobalConfig.icon.INPUT_SEARCH]
})
])
}
function renderPasswordIcon (h, _vm) {
const { showPwd } = _vm
return h('span', {
class: 'vxe-input--password-suffix',
on: {
click: _vm.passwordToggleEvent
}
}, [
h('i', {
class: ['vxe-input--password-icon', showPwd ? GlobalConfig.icon.INPUT_SHOW_PWD : GlobalConfig.icon.INPUT_PWD]
})
])
}
function rendePrefixIcon (h, _vm) {
const { $scopedSlots, prefixIcon } = _vm
const icons = []
if ($scopedSlots.prefix) {
icons.push(
h('span', {
class: 'vxe-input--prefix-icon'
}, $scopedSlots.prefix.call(this, {}, h))
)
} else if (prefixIcon) {
icons.push(
h('i', {
class: ['vxe-input--prefix-icon', prefixIcon]
})
)
}
return icons.length ? h('span', {
class: 'vxe-input--prefix',
on: {
click: _vm.clickPrefixEvent
}
}, icons) : null
}
function renderSuffixIcon (h, _vm) {
const { $scopedSlots, inputValue, isClearable, disabled, suffixIcon } = _vm
const icons = []
if ($scopedSlots.suffix) {
icons.push(
h('span', {
class: 'vxe-input--suffix-icon'
}, $scopedSlots.suffix.call(this, {}, h))
)
} else if (suffixIcon) {
icons.push(
h('i', {
class: ['vxe-input--suffix-icon', suffixIcon]
})
)
}
if (isClearable) {
icons.push(
h('i', {
class: ['vxe-input--clear-icon', GlobalConfig.icon.INPUT_CLEAR]
})
)
}
return icons.length ? h('span', {
class: ['vxe-input--suffix', {
'is--clear': isClearable && !disabled && !(inputValue === '' || XEUtils.eqNull(inputValue))
}],
on: {
click: _vm.clickSuffixEvent
}
}, icons) : null
}
function renderExtraSuffixIcon (h, _vm) {
const { controls, isPawdType, isNumType, isDatePickerType, isSearch } = _vm
let icons
if (isPawdType) {
icons = renderPasswordIcon(h, _vm)
} else if (isNumType) {
if (controls) {
icons = renderNumberIcon(h, _vm)
}
} else if (isDatePickerType) {
icons = renderDatePickerIcon(h, _vm)
} else if (isSearch) {
icons = renderSearchIcon(h, _vm)
}
return icons ? h('span', {
class: 'vxe-input--extra-suffix'
}, [icons]) : null
}
export default {
name: 'VxeInput',
mixins: [vSize],
model: {
prop: 'value',
event: 'modelValue'
},
props: {
value: [String, Number, Date],
immediate: { type: Boolean, default: true },
name: String,
type: { type: String, default: 'text' },
clearable: { type: Boolean, default: () => GlobalConfig.input.clearable },
readonly: Boolean,
disabled: Boolean,
placeholder: String,
maxlength: [String, Number],
autocomplete: { type: String, default: 'off' },
align: String,
form: String,
className: String,
size: { type: String, default: () => GlobalConfig.input.size || GlobalConfig.size },
multiple: Boolean,
// number、integer、float
min: { type: [String, Number], default: null },
max: { type: [String, Number], default: null },
step: [String, Number],
exponential: { type: Boolean, default: () => GlobalConfig.input.exponential },
// number、integer、float、password
controls: { type: Boolean, default: () => GlobalConfig.input.controls },
// float
digits: { type: [String, Number], default: () => GlobalConfig.input.digits },
// date、week、month、year
dateConfig: Object,
startDate: { type: [String, Number, Date], default: () => GlobalConfig.input.startDate },
endDate: { type: [String, Number, Date], default: () => GlobalConfig.input.endDate },
minDate: [String, Number, Date],
maxDate: [String, Number, Date],
// 已废弃 startWeek,被 startDay 替换
startWeek: Number,
startDay: { type: [String, Number], default: () => GlobalConfig.input.startDay },
labelFormat: { type: String, default: () => GlobalConfig.input.labelFormat },
valueFormat: { type: String, default: () => GlobalConfig.input.valueFormat },
editable: { type: Boolean, default: true },
festivalMethod: { type: Function, default: () => GlobalConfig.input.festivalMethod },
disabledMethod: { type: Function, default: () => GlobalConfig.input.disabledMethod },
// week
selectDay: { type: Number, default: () => GlobalConfig.input.selectDay },
prefixIcon: String,
suffixIcon: String,
placement: String,
transfer: { type: Boolean, default: () => GlobalConfig.input.transfer }
},
inject: {
$xeform: {
default: null
},
$xeformiteminfo: {
default: null
}
},
data () {
return {
panelIndex: 0,
showPwd: false,
visiblePanel: false,
animatVisible: false,
panelStyle: null,
panelPlacement: null,
isActivated: false,
inputValue: this.value,
datetimePanelValue: null,
datePanelValue: null,
datePanelLabel: '',
datePanelType: 'day',
selectMonth: null,
currentDate: null
}
},
computed: {
isNumType () {
return ['number', 'integer', 'float'].indexOf(this.type) > -1
},
isDatePickerType () {
return this.isDateTimeType || ['date', 'week', 'month', 'quarter', 'year'].indexOf(this.type) > -1
},
isDateTimeType () {
const { type } = this
return type === 'time' || type === 'datetime'
},
isPawdType () {
return this.type === 'password'
},
isSearch () {
return this.type === 'search'
},
stepValue () {
const { type, step } = this
if (type === 'integer') {
return XEUtils.toInteger(step) || 1
} else if (type === 'float') {
return XEUtils.toNumber(step) || (1 / Math.pow(10, this.digitsValue))
}
return XEUtils.toNumber(step) || 1
},
digitsValue () {
return XEUtils.toInteger(this.digits) || 1
},
isClearable () {
return this.clearable && (this.isPawdType || this.isNumType || this.isDatePickerType || this.type === 'text' || this.type === 'search')
},
isDisabledPrevDateBtn () {
const { selectMonth, dateStartTime } = this
if (selectMonth) {
return selectMonth <= dateStartTime
}
return false
},
isDisabledNextDateBtn () {
const { selectMonth, dateEndTime } = this
if (selectMonth) {
return selectMonth >= dateEndTime
}
return false
},
dateStartTime () {
return this.startDate ? XEUtils.toStringDate(this.startDate) : null
},
dateEndTime () {
return this.endDate ? XEUtils.toStringDate(this.endDate) : null
},
supportMultiples () {
return ['date', 'week', 'month', 'quarter', 'year'].includes(this.type)
},
dateListValue () {
const { value, multiple, isDatePickerType, dateValueFormat } = this
if (multiple && value && isDatePickerType) {
return XEUtils.toValueString(value).split(',').map(item => {
const date = this.parseDate(item, dateValueFormat)
if (XEUtils.isValidDate(date)) {
return date
}
return null
})
}
return []
},
dateMultipleValue () {
const { dateListValue, dateValueFormat } = this
return dateListValue.map(date => XEUtils.toDateString(date, dateValueFormat))
},
dateMultipleLabel () {
const { dateListValue, dateLabelFormat } = this
return dateListValue.map(date => XEUtils.toDateString(date, dateLabelFormat)).join(', ')
},
dateValue () {
const { value, isDatePickerType, dateValueFormat } = this
let val = null
if (value && isDatePickerType) {
const date = this.parseDate(value, dateValueFormat)
if (XEUtils.isValidDate(date)) {
val = date
}
}
return val
},
dateTimeLabel () {
const { datetimePanelValue } = this
if (datetimePanelValue) {
return XEUtils.toDateString(datetimePanelValue, 'HH:mm:ss')
}
return ''
},
hmsTime () {
const { dateValue } = this
return dateValue && (this.isDateTimeType) ? (dateValue.getHours() * 3600 + dateValue.getMinutes() * 60 + dateValue.getSeconds()) * 1000 : 0
},
dateLabelFormat () {
if (this.isDatePickerType) {
return this.labelFormat || GlobalConfig.i18n(`vxe.input.date.labelFormat.${this.type}`)
}
return null
},
dateValueFormat () {
const { type } = this
return type === 'time' ? 'HH:mm:ss' : (this.valueFormat || (type === 'datetime' ? 'yyyy-MM-dd HH:mm:ss' : 'yyyy-MM-dd'))
},
selectDatePanelLabel () {
if (this.isDatePickerType) {
const { datePanelType, selectMonth, yearList } = this
let year = ''
let month
if (selectMonth) {
year = selectMonth.getFullYear()
month = selectMonth.getMonth() + 1
}
if (datePanelType === 'quarter') {
return GlobalConfig.i18n('vxe.input.date.quarterLabel', [year])
} else if (datePanelType === 'month') {
return GlobalConfig.i18n('vxe.input.date.monthLabel', [year])
} else if (datePanelType === 'year') {
return yearList.length ? `${yearList[0].year} - ${yearList[yearList.length - 1].year}` : ''
}
return GlobalConfig.i18n('vxe.input.date.dayLabel', [year, month ? GlobalConfig.i18n(`vxe.input.date.m${month}`) : '-'])
}
return ''
},
firstDayOfWeek () {
const { startDay, startWeek } = this
return XEUtils.toNumber(XEUtils.isNumber(startDay) || XEUtils.isString(startDay) ? startDay : startWeek)
},
weekDatas () {
const weeks = []
if (this.isDatePickerType) {
let { firstDayOfWeek: sWeek } = this
weeks.push(sWeek)
for (let index = 0; index < 6; index++) {
if (sWeek >= 6) {
sWeek = 0
} else {
sWeek++
}
weeks.push(sWeek)
}
}
return weeks
},
dateHeaders () {
if (this.isDatePickerType) {
return this.weekDatas.map(day => {
return {
value: day,
label: GlobalConfig.i18n(`vxe.input.date.weeks.w${day}`)
}
})
}
return []
},
weekHeaders () {
if (this.isDatePickerType) {
return [{ label: GlobalConfig.i18n('vxe.input.date.weeks.w') }].concat(this.dateHeaders)
}
return []
},
yearList () {
const { selectMonth, currentDate } = this
const months = []
if (selectMonth && currentDate) {
const currFullYear = currentDate.getFullYear()
const selectFullYear = selectMonth.getFullYear()
const startYearDate = new Date(selectFullYear - selectFullYear % yearSize, 0, 1)
for (let index = -4; index < yearSize + 4; index++) {
const date = XEUtils.getWhatYear(startYearDate, index, 'first')
const itemFullYear = date.getFullYear()
months.push({
date,
isCurrent: true,
isPrev: index < 0,
isNow: currFullYear === itemFullYear,
isNext: index >= yearSize,
year: itemFullYear
})
}
}
return months
},
yearDatas () {
return XEUtils.chunk(this.yearList, 4)
},
quarterList () {
const { selectMonth, currentDate } = this
const quarters = []
if (selectMonth && currentDate) {
const currFullYear = currentDate.getFullYear()
const currQuarter = getDateQuarter(currentDate)
const firstYear = XEUtils.getWhatYear(selectMonth, 0, 'first')
const selFullYear = firstYear.getFullYear()
for (let index = -2; index < quarterSize - 2; index++) {
const date = XEUtils.getWhatQuarter(firstYear, index)
const itemFullYear = date.getFullYear()
const itemQuarter = getDateQuarter(date)
const isPrev = itemFullYear < selFullYear
quarters.push({
date,
isPrev,
isCurrent: itemFullYear === selFullYear,
isNow: itemFullYear === currFullYear && itemQuarter === currQuarter,
isNext: !isPrev && itemFullYear > selFullYear,
quarter: itemQuarter
})
}
}
return quarters
},
quarterDatas () {
return XEUtils.chunk(this.quarterList, 2)
},
monthList () {
const { selectMonth, currentDate } = this
const months = []
if (selectMonth && currentDate) {
const currFullYear = currentDate.getFullYear()
const currMonth = currentDate.getMonth()
const selFullYear = XEUtils.getWhatYear(selectMonth, 0, 'first').getFullYear()
for (let index = -4; index < monthSize - 4; index++) {
const date = XEUtils.getWhatYear(selectMonth, 0, index)
const itemFullYear = date.getFullYear()
const itemMonth = date.getMonth()
const isPrev = itemFullYear < selFullYear
months.push({
date,
isPrev,
isCurrent: itemFullYear === selFullYear,
isNow: itemFullYear === currFullYear && itemMonth === currMonth,
isNext: !isPrev && itemFullYear > selFullYear,
month: itemMonth
})
}
}
return months
},
monthDatas () {
return XEUtils.chunk(this.monthList, 4)
},
dayList () {
const { weekDatas, selectMonth, currentDate, hmsTime } = this
const days = []
if (selectMonth && currentDate) {
const currFullYear = currentDate.getFullYear()
const currMonth = currentDate.getMonth()
const currDate = currentDate.getDate()
const selFullYear = selectMonth.getFullYear()
const selMonth = selectMonth.getMonth()
const selDay = selectMonth.getDay()
const prevOffsetDate = -weekDatas.indexOf(selDay)
const startDayDate = new Date(XEUtils.getWhatDay(selectMonth, prevOffsetDate).getTime() + hmsTime)
for (let index = 0; index < 42; index++) {
const date = XEUtils.getWhatDay(startDayDate, index)
const itemFullYear = date.getFullYear()
const itemMonth = date.getMonth()
const itemDate = date.getDate()
const isPrev = date < selectMonth
days.push({
date,
isPrev,
isCurrent: itemFullYear === selFullYear && itemMonth === selMonth,
isNow: itemFullYear === currFullYear && itemMonth === currMonth && itemDate === currDate,
isNext: !isPrev && selMonth !== itemMonth,
label: itemDate
})
}
}
return days
},
dayDatas () {
return XEUtils.chunk(this.dayList, 7)
},
weekDates () {
const { dayDatas, firstDayOfWeek } = this
return dayDatas.map(list => {
const firstItem = list[0]
const item = {
date: firstItem.date,
isWeekNumber: true,
isPrev: false,
isCurrent: false,
isNow: false,
isNext: false,
label: XEUtils.getYearWeek(firstItem.date, firstDayOfWeek)
}
return [item].concat(list)
})
},
hourList () {
const list = []
if (this.isDateTimeType) {
for (let index = 0; index < 24; index++) {
list.push({
value: index,
label: ('' + index).padStart(2, 0)
})
}
}
return list
},
minuteList () {
const list = []
if (this.isDateTimeType) {
for (let index = 0; index < 60; index++) {
list.push({
value: index,
label: ('' + index).padStart(2, 0)
})
}
}
return list
},
secondList () {
return this.minuteList
},
inpImmediate () {
const { type, immediate } = this
return immediate || !(type === 'text' || type === 'number' || type === 'integer' || type === 'float')
},
inpPlaceholder () {
const { placeholder } = this
if (placeholder) {
return getFuncText(placeholder)
}
return ''
},
inputType () {
const { isDatePickerType, isNumType, isPawdType, type, showPwd } = this
if (isDatePickerType || isNumType || (isPawdType && showPwd) || type === 'number') {
return 'text'
}
return type
},
inpMaxlength () {
const { isNumType, maxlength } = this
// 数值最大长度限制 16 位,包含小数
return isNumType && !XEUtils.toNumber(maxlength) ? 16 : maxlength
},
inpReadonly () {
const { type, readonly, editable, multiple } = this
return readonly || multiple || !editable || (type === 'week' || type === 'quarter')
},
numValue () {
const { type, isNumType, inputValue } = this
if (isNumType) {
return type === 'integer' ? XEUtils.toInteger(handleNumber(inputValue)) : XEUtils.toNumber(handleNumber(inputValue))
}
return 0
},
isDisabledSubtractNumber () {
const { min, isNumType, inputValue, numValue } = this
// 当有值时再进行判断
if ((inputValue || inputValue === 0) && isNumType && min !== null) {
return numValue <= XEUtils.toNumber(min)
}
return false
},
isDisabledAddNumber () {
const { max, isNumType, inputValue, numValue } = this
// 当有值时再进行判断
if ((inputValue || inputValue === 0) && isNumType && max !== null) {
return numValue >= XEUtils.toNumber(max)
}
return false
}
},
watch: {
value (val) {
this.inputValue = val
this.changeValue()
},
type () {
// 切换类型是重置内置变量
Object.assign(this, {
inputValue: this.value,
datetimePanelValue: null,
datePanelValue: null,
datePanelLabel: '',
datePanelType: 'day',
selectMonth: null,
currentDate: null
})
this.initValue()
},
dateLabelFormat () {
if (this.isDatePickerType) {
this.dateParseValue(this.datePanelValue)
this.inputValue = this.multiple ? this.dateMultipleLabel : this.datePanelLabel
}
}
},
created () {
this.initValue()
GlobalEvent.on(this, 'mousewheel', this.handleGlobalMousewheelEvent)
GlobalEvent.on(this, 'mousedown', this.handleGlobalMousedownEvent)
GlobalEvent.on(this, 'keydown', this.handleGlobalKeydownEvent)
GlobalEvent.on(this, 'blur', this.handleGlobalBlurEvent)
},
mounted () {
if (this.dateConfig) {
warnLog('vxe.error.removeProp', ['date-config'])
}
if (this.isDatePickerType) {
if (this.transfer) {
document.body.appendChild(this.$refs.panel)
}
}
},
beforeDestroy () {
const panelElem = this.$refs.panel
if (panelElem && panelElem.parentNode) {
panelElem.parentNode.removeChild(panelElem)
}
},
destroyed () {
this.numberStopDown()
GlobalEvent.off(this, 'mousewheel')
GlobalEvent.off(this, 'mousedown')
GlobalEvent.off(this, 'keydown')
GlobalEvent.off(this, 'blur')
},
render (h) {
const { name, form, inputType, inpPlaceholder, inpMaxlength, inpReadonly, className, controls, inputValue, isDatePickerType, visiblePanel, isActivated, vSize, type, align, readonly, disabled, autocomplete } = this
const childs = []
const prefix = rendePrefixIcon(h, this)
const suffix = renderSuffixIcon(h, this)
// 前缀图标
if (prefix) {
childs.push(prefix)
}
// 输入框
childs.push(
h('input', {
ref: 'input',
class: 'vxe-input--inner',
domProps: {
value: inputValue
},
attrs: {
name,
form,
type: inputType,
placeholder: inpPlaceholder,
maxlength: inpMaxlength,
readonly: inpReadonly,
disabled,
autocomplete
},
on: {
keydown: this.keydownEvent,
keyup: this.triggerEvent,
wheel: this.wheelEvent,
click: this.clickEvent,
input: this.inputEvent,
change: this.changeEvent,
focus: this.focusEvent,
blur: this.blurEvent
}
})
)
// 后缀图标
if (suffix) {
childs.push(suffix)
}
// 特殊功能图标
childs.push(renderExtraSuffixIcon(h, this))
// 面板容器
if (isDatePickerType) {
childs.push(renderPanel(h, this))
}
return h('div', {
class: ['vxe-input', `type--${type}`, className, {
[`size--${vSize}`]: vSize,
[`is--${align}`]: align,
'is--controls': controls,
'is--prefix': !!prefix,
'is--suffix': !!suffix,
'is--readonly': readonly,
'is--visivle': visiblePanel,
'is--disabled': disabled,
'is--active': isActivated
}]
}, childs)
},
methods: {
focus () {
this.isActivated = true
this.$refs.input.focus()
return this.$nextTick()
},
blur () {
this.$refs.input.blur()
this.isActivated = false
return this.$nextTick()
},
triggerEvent (evnt) {
const { $refs, inputValue } = this
this.$emit(evnt.type, { $panel: $refs.panel, value: inputValue, $event: evnt })
},
emitModel (value, evnt) {
this.inputValue = value
this.$emit('modelValue', value)
this.$emit('input', { value, $event: evnt })
if (XEUtils.toValueString(this.value) !== value) {
this.$emit('change', { value, $event: evnt })
// 自动更新校验状态
if (this.$xeform && this.$xeformiteminfo) {
this.$xeform.triggerItemEvent(evnt, this.$xeformiteminfo.itemConfig.field, value)
}
}
},
emitInputEvent (value, evnt) {
const { inpImmediate, isDatePickerType } = this
this.inputValue = value
if (!isDatePickerType) {
if (inpImmediate) {
this.emitModel(value, evnt)
} else {
this.$emit('input', { value, $event: evnt })
}
}
},
inputEvent (evnt) {
const value = evnt.target.value
this.emitInputEvent(value, evnt)
},
changeEvent (evnt) {
const { inpImmediate } = this
if (!inpImmediate) {
this.triggerEvent(evnt)
}
},
focusEvent (evnt) {
this.isActivated = true
const { isDatePickerType } = this
if (isDatePickerType) {
this.datePickerOpenEvent(evnt)
}
this.triggerEvent(evnt)
},
blurEvent (evnt) {
const { inputValue, inpImmediate } = this
const value = inputValue
if (!inpImmediate) {
this.emitModel(value, evnt)
}
this.afterCheckValue()
if (!this.visiblePanel) {
this.isActivated = false
}
this.$emit('blur', { value, $event: evnt })
},
keydownEvent (evnt) {
const { exponential, controls, isNumType } = this
if (isNumType) {
const isCtrlKey = evnt.ctrlKey
const isShiftKey = evnt.shiftKey
const isAltKey = evnt.altKey
const keyCode = evnt.keyCode
if (!isCtrlKey && !isShiftKey && !isAltKey && (keyCode === 32 || ((!exponential || keyCode !== 69) && (keyCode >= 65 && keyCode <= 90)) || (keyCode >= 186 && keyCode <= 188) || keyCode >= 191)) {
evnt.preventDefault()
}
if (controls) {
this.numberKeydownEvent(evnt)
}
}
this.triggerEvent(evnt)
},
wheelEvent (evnt) {
if (this.isNumType && this.controls) {
if (this.isActivated) {
const delta = evnt.deltaY
if (delta > 0) {
this.numberNextEvent(evnt)
} else if (delta < 0) {
this.numberPrevEvent(evnt)
}
evnt.preventDefault()
}
}
this.triggerEvent(evnt)
},
clickEvent (evnt) {
this.triggerEvent(evnt)
},
clickPrefixEvent (evnt) {
const { $refs, disabled, inputValue } = this
if (!disabled) {
this.$emit('prefix-click', { $panel: $refs.panel, value: inputValue, $event: evnt })
}
},
clickSuffixEvent (evnt) {
const { $refs, disabled, inputValue } = this
if (!disabled) {
if (DomTools.hasClass(evnt.currentTarget, 'is--clear')) {
this.emitModel('', evnt)
this.clearValueEvent(evnt, '')
} else {
this.$emit('suffix-click', { $panel: $refs.panel, value: inputValue, $event: evnt })
}
}
},
clearValueEvent (evnt, value) {
const { $refs, type, isNumType } = this
if (this.isDatePickerType) {
this.hidePanel()
}
if (isNumType || ['text', 'search', 'password'].indexOf(type) > -1) {
this.focus()
}
this.$emit('clear', { $panel: $refs.panel, value, $event: evnt })
},
parseDate (value, format) {
const { type } = this
if (type === 'time') {
return toStringTimeDate(value)
}
return XEUtils.toStringDate(value, format)
},
/**
* 检查初始值
*/
initValue () {
const { type, isDatePickerType, inputValue, digitsValue } = this
if (isDatePickerType) {
this.changeValue()
} else if (type === 'float') {
if (inputValue) {
const validValue = toFloatValueFixed(inputValue, digitsValue)
if (inputValue !== validValue) {
this.emitModel(validValue, { type: 'init' })
}
}
}
},
/**
* 值变化时处理
*/
changeValue () {
if (this.isDatePickerType) {
this.dateParseValue(this.inputValue)
this.inputValue = this.multiple ? this.dateMultipleLabel : this.datePanelLabel
}
},
afterCheckValue () {
const { type, exponential, inpReadonly, inputValue, isDatePickerType, isNumType, datetimePanelValue, dateLabelFormat, min, max, firstDayOfWeek } = this
if (!inpReadonly) {
if (isNumType) {
if (inputValue) {
let inpNumVal = type === 'integer' ? XEUtils.toInteger(handleNumber(inputValue)) : XEUtils.toNumber(handleNumber(inputValue))
if (!this.vaildMinNum(inpNumVal)) {
inpNumVal = min
} else if (!this.vaildMaxNum(inpNumVal)) {
inpNumVal = max
}
if (exponential) {
const inpStringVal = XEUtils.toValueString(inputValue).toLowerCase()
if (inpStringVal === XEUtils.toNumber(inpNumVal).toExponential()) {
inpNumVal = inpStringVal
}
}
this.emitModel(getNumberValue(this, inpNumVal), { type: 'check' })
}
} else if (isDatePickerType) {
if (inputValue) {
if (type === 'week' || type === 'quarter') {
// 周和季度选择器不支持解析,无需处理
} else {
let inpDateVal = this.parseDate(inputValue, dateLabelFormat)
if (XEUtils.isValidDate(inpDateVal)) {
if (type === 'time') {
inpDateVal = toStringTimeDate(inpDateVal)
if (inputValue !== inpDateVal) {
this.emitModel(inpDateVal, { type: 'check' })
}
this.inputValue = inpDateVal
} else {
let isChange = false
if (type === 'datetime') {
if (inputValue !== XEUtils.toDateString(this.dateValue, dateLabelFormat) || inputValue !== XEUtils.toDateString(inpDateVal, dateLabelFormat)) {
isChange = true
datetimePanelValue.setHours(inpDateVal.getHours())
datetimePanelValue.setMinutes(inpDateVal.getMinutes())
datetimePanelValue.setSeconds(inpDateVal.getSeconds())
}
} else {
isChange = true
}
this.inputValue = XEUtils.toDateString(inpDateVal, dateLabelFormat, { firstDay: firstDayOfWeek })
if (isChange) {
this.dateChange(inpDateVal)
}
}
} else {
this.dateRevert()
}
}
} else {
this.emitModel('', { type: 'check' })
}
}
}
},
// 密码
passwordToggleEvent (evnt) {
const { disabled, readonly, showPwd } = this
if (!disabled && !readonly) {
this.showPwd = !showPwd
}
this.$emit('toggle-visible', { visible: this.showPwd, $event: evnt })
},
// 密码
// 搜索
searchEvent (evnt) {
this.$emit('search-click', { $event: evnt })
},
// 搜索
// 数值
vaildMinNum (num) {
return this.min === null || num >= XEUtils.toNumber(this.min)
},
vaildMaxNum (num) {
return this.max === null || num <= XEUtils.toNumber(this.max)
},
numberStopDown () {
clearTimeout(this.downbumTimeout)
},
numberDownPrevEvent (evnt) {
this.downbumTimeout = setTimeout(() => {
this.numberPrevEvent(evnt)
this.numberDownPrevEvent(evnt)
}, 60)
},
numberDownNextEvent (evnt) {
this.downbumTimeout = setTimeout(() => {
this.numberNextEvent(evnt)
this.numberDownNextEvent(evnt)
}, 60)
},
numberKeydownEvent (evnt) {
const { keyCode } = evnt
const isUpArrow = keyCode === 38
const isDwArrow = keyCode === 40
if (isUpArrow || isDwArrow) {
evnt.preventDefault()
if (isUpArrow) {
this.numberPrevEvent(evnt)
} else {
this.numberNextEvent(evnt)
}
}
},
numberMousedownEvent (evnt) {
this.numberStopDown()
if (evnt.button === 0) {
const isPrevNumber = DomTools.hasClass(evnt.currentTarget, 'is--prev')
if (isPrevNumber) {
this.numberPrevEvent(evnt)
} else {
this.numberNextEvent(evnt)
}
this.downbumTimeout = setTimeout(() => {
if (isPrevNumber) {
this.numberDownPrevEvent(evnt)
} else {
this.numberDownNextEvent(evnt)
}
}, 500)
}
},
numberPrevEvent (evnt) {
const { disabled, readonly, isDisabledAddNumber } = this
clearTimeout(this.downbumTimeout)
if (!disabled && !readonly && !isDisabledAddNumber) {
this.numberChange(true, evnt)
}
this.$emit('prev-number', { $event: evnt })
},
numberNextEvent (evnt) {
const { disabled, readonly, isDisabledSubtractNumber } = this
clearTimeout(this.downbumTimeout)
if (!disabled && !readonly && !isDisabledSubtractNumber) {
this.numberChange(false, evnt)
}
this.$emit('next-number', { $event: evnt })
},
numberChange (isPlus, evnt) {
const { min, max, type, inputValue, stepValue } = this
const numValue = type === 'integer' ? XEUtils.toInteger(handleNumber(inputValue)) : XEUtils.toNumber(handleNumber(inputValue))
const newValue = isPlus ? XEUtils.add(numValue, stepValue) : XEUtils.subtract(numValue, stepValue)
let restNum
if (!this.vaildMinNum(newValue)) {
restNum = min
} else if (!this.vaildMaxNum(newValue)) {
restNum = max
} else {
restNum = newValue
}
this.emitInputEvent(getNumberValue(this, restNum), evnt)
},
// 数值
// 日期
datePickerOpenEvent (evnt) {
const { readonly } = this
if (!readonly) {
evnt.preventDefault()
this.showPanel()
}
},
dateMonthHandle (date, offsetMonth) {
this.selectMonth = XEUtils.getWhatMonth(date, offsetMonth, 'first')
},
dateNowHandle () {
const currentDate = XEUtils.getWhatDay(Date.now(), 0, 'first')
this.currentDate = currentDate
this.dateMonthHandle(currentDate, 0)
},
dateToggleTypeEvent () {
let { datePanelType } = this
if (datePanelType === 'month' || datePanelType === 'quarter') {
datePanelType = 'year'
} else {
datePanelType = 'month'
}
this.datePanelType = datePanelType
},
datePrevEvent (evnt) {
const { isDisabledPrevDateBtn, type, datePanelType } = this
if (!isDisabledPrevDateBtn) {
if (type === 'year') {
this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -yearSize, 'first')
} else if (type === 'month' || type === 'quarter') {
if (datePanelType === 'year') {
this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -yearSize, 'first')
} else {
this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -1, 'first')
}
} else {
if (datePanelType === 'year') {
this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -yearSize, 'first')
} else if (datePanelType === 'month') {
this.selectMonth = XEUtils.getWhatYear(this.selectMonth, -1, 'first')
} else {
this.selectMonth = XEUtils.getWhatMonth(this.selectMonth, -1, 'first')
}
}
this.$emit('date-prev', { type, $event: evnt })
}
},
dateTodayMonthEvent (evnt) {
this.dateNowHandle()
if (!this.multiple) {
this.dateChange(this.currentDate)
this.hidePanel()
}
this.$emit('date-today', { type: this.type, $event: evnt })
},
dateNextEvent (evnt) {
const { isDisabledNextDateBtn, type, datePanelType } = this
if (!isDisabledNextDateBtn) {
if (type === 'year') {
this.selectMonth = XEUtils.getWhatYear(this.selectMonth, yearSize, 'first')
} else if (type === 'month' || type === 'quarter') {
if (datePanelType === 'year') {