UNPKG

vxe-pc-ui

Version:
1,357 lines (1,252 loc) 89.9 kB
import { defineComponent, h, Teleport, ref, Ref, computed, reactive, inject, nextTick, watch, onUnmounted, PropType, createCommentVNode } from 'vue' import XEUtils from 'xe-utils' import { getConfig, getIcon, getI18n, globalEvents, GLOBAL_EVENT_KEYS, createEvent, useSize, renderEmptyElement } from '../../ui' import { getFuncText, getLastZIndex, nextZIndex, isEnableConf } from '../../ui/src/utils' import { getAbsolutePos, getEventTargetNode } from '../../ui/src/dom' import { toStringTimeDate, getDateQuarter } from './util' import { getSlotVNs } from '../..//ui/src/vn' import VxeButtonGroupComponent from '../../button/src/button-group' import type { VxeDatePickerConstructor, VxeDatePickerEmits, DatePickerInternalData, DatePickerReactData, VxeComponentStyleType, DatePickerMethods, VxeDatePickerPropTypes, DatePickerPrivateRef, VxeFormConstructor, VxeFormPrivateMethods, VxeFormDefines, ValueOf, VxeModalConstructor, VxeDrawerConstructor, VxeModalMethods, VxeDrawerMethods, VxeDatePickerDefines, VxeButtonGroupEvents } from '../../../types' import type { VxeTableConstructor, VxeTablePrivateMethods } from '../../../types/components/table' export default defineComponent({ name: 'VxeDatePicker', props: { modelValue: [String, Number, Date] as PropType<VxeDatePickerPropTypes.ModelValue>, immediate: { type: Boolean as PropType<VxeDatePickerPropTypes.Immediate>, default: true }, name: String as PropType<VxeDatePickerPropTypes.Name>, type: { type: String as PropType<VxeDatePickerPropTypes.Type>, default: 'date' }, clearable: { type: Boolean as PropType<VxeDatePickerPropTypes.Clearable>, default: () => getConfig().datePicker.clearable }, readonly: { type: Boolean as PropType<VxeDatePickerPropTypes.Readonly>, default: null }, disabled: { type: Boolean as PropType<VxeDatePickerPropTypes.Disabled>, default: null }, placeholder: String as PropType<VxeDatePickerPropTypes.Placeholder>, maxLength: [String, Number] as PropType<VxeDatePickerPropTypes.MaxLength>, autoComplete: { type: String as PropType<VxeDatePickerPropTypes.AutoComplete>, default: 'off' }, align: String as PropType<VxeDatePickerPropTypes.Align>, form: String as PropType<VxeDatePickerPropTypes.Form>, className: String as PropType<VxeDatePickerPropTypes.ClassName>, size: { type: String as PropType<VxeDatePickerPropTypes.Size>, default: () => getConfig().datePicker.size || getConfig().size }, multiple: Boolean as PropType<VxeDatePickerPropTypes.Multiple>, limitCount: { type: [String, Number] as PropType<VxeDatePickerPropTypes.LimitCount>, default: () => getConfig().upload.limitCount }, // date、week、month、quarter、year startDate: { type: [String, Number, Date] as PropType<VxeDatePickerPropTypes.MinDate>, default: () => getConfig().datePicker.startDate }, endDate: { type: [String, Number, Date] as PropType<VxeDatePickerPropTypes.MaxDate>, default: () => getConfig().datePicker.endDate }, minDate: [String, Number, Date] as PropType<VxeDatePickerPropTypes.MinDate>, maxDate: [String, Number, Date] as PropType<VxeDatePickerPropTypes.MaxDate>, startDay: { type: [String, Number] as PropType<VxeDatePickerPropTypes.StartDay>, default: () => getConfig().datePicker.startDay }, labelFormat: String as PropType<VxeDatePickerPropTypes.LabelFormat>, valueFormat: String as PropType<VxeDatePickerPropTypes.ValueFormat>, editable: { type: Boolean as PropType<VxeDatePickerPropTypes.Editable>, default: true }, festivalMethod: { type: Function as PropType<VxeDatePickerPropTypes.FestivalMethod>, default: () => getConfig().datePicker.festivalMethod }, disabledMethod: { type: Function as PropType<VxeDatePickerPropTypes.DisabledMethod>, default: () => getConfig().datePicker.disabledMethod }, // week selectDay: { type: [String, Number] as PropType<VxeDatePickerPropTypes.SelectDay>, default: () => getConfig().datePicker.selectDay }, prefixIcon: String as PropType<VxeDatePickerPropTypes.PrefixIcon>, suffixIcon: String as PropType<VxeDatePickerPropTypes.SuffixIcon>, placement: String as PropType<VxeDatePickerPropTypes.Placement>, transfer: { type: Boolean as PropType<VxeDatePickerPropTypes.Transfer>, default: null }, shortcutConfig: Object as PropType<VxeDatePickerPropTypes.ShortcutConfig>, // 已废弃 startWeek,被 startDay 替换 startWeek: Number as PropType<VxeDatePickerPropTypes.StartDay>, // 已废弃 maxlength: [String, Number] as PropType<VxeDatePickerPropTypes.MaxLength>, // 已废弃 autocomplete: String as PropType<VxeDatePickerPropTypes.AutoComplete> }, emits: [ 'update:modelValue', 'input', 'change', 'keydown', 'keyup', 'click', 'focus', 'blur', 'clear', 'prefix-click', 'suffix-click', 'date-prev', 'date-today', 'date-next', 'shortcut-click' ] as VxeDatePickerEmits, setup (props, context) { const { slots, emit } = context const $xeModal = inject<(VxeModalConstructor & VxeModalMethods) | null>('$xeModal', null) const $xeDrawer = inject<(VxeDrawerConstructor & VxeDrawerMethods) | null>('$xeDrawer', null) const $xeTable = inject<(VxeTableConstructor & VxeTablePrivateMethods) | null>('$xeTable', null) const $xeForm = inject<(VxeFormConstructor & VxeFormPrivateMethods) | null>('$xeForm', null) const formItemInfo = inject<VxeFormDefines.ProvideItemInfo | null>('xeFormItemInfo', null) const xID = XEUtils.uniqueId() const { computeSize } = useSize(props) const reactData = reactive<DatePickerReactData>({ initialized: false, panelIndex: 0, visiblePanel: false, isAniVisible: false, panelStyle: {}, panelPlacement: '', isActivated: false, inputValue: '', datetimePanelValue: null, datePanelValue: null, datePanelLabel: '', datePanelType: 'day', selectMonth: null, currentDate: null }) const internalData: DatePickerInternalData = { yearSize: 12, monthSize: 20, quarterSize: 8, hpTimeout: undefined } const refElem = ref() as Ref<HTMLDivElement> const refInputTarget = ref() as Ref<HTMLInputElement> const refInputPanel = ref() as Ref<HTMLDivElement> const refPanelWrapper = ref() as Ref<HTMLDivElement> const refInputTimeBody = ref() as Ref<HTMLDivElement> const refMaps: DatePickerPrivateRef = { refElem, refInput: refInputTarget } const $xeDatePicker = { xID, props, context, reactData, internalData, getRefMaps: () => refMaps } as unknown as VxeDatePickerConstructor let datePickerMethods = {} as DatePickerMethods const computeBtnTransfer = computed(() => { const { transfer } = props if (transfer === null) { const globalTransfer = getConfig().datePicker.transfer if (XEUtils.isBoolean(globalTransfer)) { return globalTransfer } if ($xeTable || $xeModal || $xeDrawer || $xeForm) { return true } } return transfer }) const computeFormReadonly = computed(() => { const { readonly } = props if (readonly === null) { if ($xeForm) { return $xeForm.props.readonly } return false } return readonly }) const computeIsDisabled = computed(() => { const { disabled } = props if (disabled === null) { if ($xeForm) { return $xeForm.props.disabled } return false } return disabled }) const computeIsDateTimeType = computed(() => { const { type } = props return type === 'time' || type === 'datetime' }) const computeIsDatePickerType = computed(() => { const isDateTimeType = computeIsDateTimeType.value return isDateTimeType || ['date', 'week', 'month', 'quarter', 'year'].indexOf(props.type) > -1 }) const computeIsClearable = computed(() => { return props.clearable }) const computeDateStartTime = computed(() => { return props.startDate ? XEUtils.toStringDate(props.startDate) : null }) const computeDateEndTime = computed(() => { return props.endDate ? XEUtils.toStringDate(props.endDate) : null }) const computeSupportMultiples = computed(() => { return ['date', 'week', 'month', 'quarter', 'year'].indexOf(props.type) > -1 }) const computeDateListValue = computed(() => { const { modelValue, multiple } = props const isDatePickerType = computeIsDatePickerType.value const dateValueFormat = computeDateValueFormat.value if (multiple && modelValue && isDatePickerType) { return XEUtils.toValueString(modelValue).split(',').map(item => { const date = parseDate(item, dateValueFormat) if (XEUtils.isValidDate(date)) { return date } return date }) } return [] }) const computeDateMultipleValue = computed(() => { const dateListValue = computeDateListValue.value const dateValueFormat = computeDateValueFormat.value return dateListValue.map(date => XEUtils.toDateString(date, dateValueFormat)) }) const computeDateMultipleLabel = computed(() => { const dateListValue = computeDateListValue.value const dateLabelFormat = computeDateLabelFormat.value return dateListValue.map(date => XEUtils.toDateString(date, dateLabelFormat)).join(', ') }) const computeLimitMaxCount = computed(() => { return props.multiple ? XEUtils.toNumber(props.limitCount) : 0 }) const computeOverCount = computed(() => { const { multiple } = props const limitMaxCount = computeLimitMaxCount.value const dateMultipleValue = computeDateMultipleValue.value if (multiple && limitMaxCount) { return dateMultipleValue.length >= limitMaxCount } return false }) const computeDateValueFormat = computed(() => { const { type, valueFormat } = props if (valueFormat) { return valueFormat } if (type === 'time') { return 'HH:mm:ss' } if (type === 'datetime') { return 'yyyy-MM-dd HH:mm:ss' } return 'yyyy-MM-dd' }) const computeDateValue = computed(() => { const { modelValue } = props const isDatePickerType = computeIsDatePickerType.value const dateValueFormat = computeDateValueFormat.value let val = null if (modelValue && isDatePickerType) { const date = parseDate(modelValue, dateValueFormat) if (XEUtils.isValidDate(date)) { val = date } } return val }) const computeIsDisabledPrevDateBtn = computed(() => { const dateStartTime = computeDateStartTime.value const { selectMonth } = reactData if (selectMonth && dateStartTime) { return selectMonth <= dateStartTime } return false }) const computeIsDisabledNextDateBtn = computed(() => { const dateEndTime = computeDateEndTime.value const { selectMonth } = reactData if (selectMonth && dateEndTime) { return selectMonth >= dateEndTime } return false }) const computeDateTimeLabel = computed(() => { const { datetimePanelValue } = reactData const hasTimeSecond = computeHasTimeSecond.value if (datetimePanelValue) { return XEUtils.toDateString(datetimePanelValue, hasTimeSecond ? 'HH:mm:ss' : 'HH:mm') } return '' }) const computeDateHMSTime = computed(() => { const dateValue = computeDateValue.value const isDateTimeType = computeIsDateTimeType.value return dateValue && isDateTimeType ? (dateValue.getHours() * 3600 + dateValue.getMinutes() * 60 + dateValue.getSeconds()) * 1000 : 0 }) const computeDateLabelFormat = computed(() => { const { labelFormat } = props const isDatePickerType = computeIsDatePickerType.value if (isDatePickerType) { return labelFormat || getI18n(`vxe.input.date.labelFormat.${props.type}`) } return null }) const computeYearList = computed(() => { const { yearSize } = internalData const { selectMonth, currentDate } = reactData const years: VxeDatePickerDefines.DateYearItem[] = [] 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() years.push({ date, isCurrent: true, isPrev: index < 0, isNow: currFullYear === itemFullYear, isNext: index >= yearSize, year: itemFullYear }) } } return years }) const computeSelectDatePanelObj = computed(() => { const isDatePickerType = computeIsDatePickerType.value let y = '' let m = '' if (isDatePickerType) { const { datePanelType, selectMonth } = reactData const yearList = computeYearList.value let year = '' let month if (selectMonth) { year = selectMonth.getFullYear() month = selectMonth.getMonth() + 1 } if (datePanelType === 'quarter' || datePanelType === 'month') { y = getI18n('vxe.datePicker.yearTitle', [year]) } else if (datePanelType === 'year') { y = yearList.length ? `${yearList[0].year} - ${yearList[yearList.length - 1].year}` : '' } else { y = getI18n('vxe.datePicker.yearTitle', [year]) m = month ? getI18n(`vxe.input.date.m${month}`) : '-' } } return { y, m } }) const computeFirstDayOfWeek = computed(() => { const { startDay, startWeek } = props return XEUtils.toNumber(XEUtils.isNumber(startDay) || XEUtils.isString(startDay) ? startDay : startWeek) as VxeDatePickerPropTypes.StartDay }) const computeWeekDatas = computed(() => { const weeks: number[] = [] const isDatePickerType = computeIsDatePickerType.value if (isDatePickerType) { let sWeek = computeFirstDayOfWeek.value weeks.push(sWeek) for (let index = 0; index < 6; index++) { if (sWeek >= 6) { sWeek = 0 } else { sWeek++ } weeks.push(sWeek) } } return weeks }) const computeDateHeaders = computed(() => { const isDatePickerType = computeIsDatePickerType.value if (isDatePickerType) { const weekDatas = computeWeekDatas.value return weekDatas.map((day) => { return { value: day, label: getI18n(`vxe.input.date.weeks.w${day}`) } }) } return [] }) const computeWeekHeaders = computed(() => { const isDatePickerType = computeIsDatePickerType.value if (isDatePickerType) { const dateHeaders = computeDateHeaders.value return [{ label: getI18n('vxe.input.date.weeks.w') }].concat(dateHeaders) } return [] }) const computeYearDatas = computed(() => { const yearList = computeYearList.value return XEUtils.chunk(yearList, 4) }) const computeQuarterList = computed(() => { const { quarterSize } = internalData const { selectMonth, currentDate } = reactData const quarters: VxeDatePickerDefines.DateQuarterItem[] = [] 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 }) const computeQuarterDatas = computed(() => { const quarterList = computeQuarterList.value return XEUtils.chunk(quarterList, 2) }) const computeMonthList = computed(() => { const { monthSize } = internalData const { selectMonth, currentDate } = reactData const months: VxeDatePickerDefines.DateMonthItem[] = [] 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 }) const computeMonthDatas = computed(() => { const monthList = computeMonthList.value return XEUtils.chunk(monthList, 4) }) const computeDayList = computed(() => { const { selectMonth, currentDate } = reactData const days: VxeDatePickerDefines.DateDayItem[] = [] if (selectMonth && currentDate) { const dateHMSTime = computeDateHMSTime.value const weekDatas = computeWeekDatas.value 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() + dateHMSTime) 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 }) const computeDayDatas = computed(() => { const dayList = computeDayList.value return XEUtils.chunk(dayList, 7) }) const computeWeekDates = computed(() => { const dayDatas = computeDayDatas.value const firstDayOfWeek = computeFirstDayOfWeek.value return dayDatas.map((list) => { const firstItem = list[0] const item: VxeDatePickerDefines.DateDayItem = { date: firstItem.date, isWeekNumber: true, isPrev: false, isCurrent: false, isNow: false, isNext: false, label: XEUtils.getYearWeek(firstItem.date, firstDayOfWeek) } return [item].concat(list) }) }) const computeHourList = computed(() => { const list: VxeDatePickerDefines.DateHourMinuteSecondItem[] = [] const isDateTimeType = computeIsDateTimeType.value if (isDateTimeType) { for (let index = 0; index < 24; index++) { list.push({ value: index, label: ('' + index).padStart(2, '0') }) } } return list }) const computeMinuteList = computed(() => { const list: VxeDatePickerDefines.DateHourMinuteSecondItem[] = [] const isDateTimeType = computeIsDateTimeType.value if (isDateTimeType) { for (let index = 0; index < 60; index++) { list.push({ value: index, label: ('' + index).padStart(2, '0') }) } } return list }) const computeHasTimeMinute = computed(() => { const dateValueFormat = computeDateValueFormat.value return !/HH/.test(dateValueFormat) || /mm/.test(dateValueFormat) }) const computeHasTimeSecond = computed(() => { const dateValueFormat = computeDateValueFormat.value return !/HH/.test(dateValueFormat) || /ss/.test(dateValueFormat) }) const computeSecondList = computed(() => { const minuteList = computeMinuteList.value return minuteList }) const computeInputReadonly = computed(() => { const { type, editable, multiple } = props const formReadonly = computeFormReadonly.value return formReadonly || multiple || !editable || type === 'week' || type === 'quarter' }) const computeDatePickerType = computed(() => { return 'text' }) const computeInpPlaceholder = computed(() => { const { placeholder } = props if (placeholder) { return getFuncText(placeholder) } const globalPlaceholder = getConfig().datePicker.placeholder if (globalPlaceholder) { return getFuncText(globalPlaceholder) } return getI18n('vxe.base.pleaseSelect') }) const computeInpImmediate = computed(() => { const { immediate } = props return immediate }) const computeShortcutOpts = computed(() => { return Object.assign({}, getConfig().datePicker.shortcutConfig, props.shortcutConfig) }) const updateModelValue = (modelValue: VxeDatePickerPropTypes.ModelValue | undefined) => { const { isActivated, visiblePanel } = reactData let val: any = '' if (modelValue) { if (XEUtils.isNumber(modelValue) && /^[0-9]{11,15}$/.test(`${modelValue}`)) { val = new Date(modelValue) } else { val = modelValue } } reactData.inputValue = val if (isActivated && visiblePanel) { dateOpenPanel() } } const parseDate = (value: VxeDatePickerPropTypes.ModelValue, format: string) => { const { type, multiple } = props if (type === 'time') { return toStringTimeDate(value) } if (XEUtils.isArray(value)) { return XEUtils.toStringDate(value[0], format) } if (XEUtils.isString(value)) { return XEUtils.toStringDate(multiple ? XEUtils.last(value.split(',')) : value, format) } return XEUtils.toStringDate(value, format) } const triggerEvent = (evnt: Event & { type: 'input' | 'change' | 'keydown' | 'keyup' | 'click' | 'focus' | 'blur' }) => { const { inputValue } = reactData dispatchEvent(evnt.type, { value: inputValue }, evnt) } const handleChange = (value: string, evnt: Event | { type: string }) => { reactData.inputValue = value emit('update:modelValue', value) if (XEUtils.toValueString(props.modelValue) !== value) { dispatchEvent('change', { value }, evnt as any) // 自动更新校验状态 if ($xeForm && formItemInfo) { $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value) } } } const inputEvent = (evnt: Event & { type: 'input' }) => { const isDatePickerType = computeIsDatePickerType.value const inpImmediate = computeInpImmediate.value const inputElem = evnt.target as HTMLInputElement const value = inputElem.value reactData.inputValue = value if (!isDatePickerType) { if (inpImmediate) { handleChange(value, evnt) } else { dispatchEvent('input', { value }, evnt) } } } const changeEvent = (evnt: Event & { type: 'change' }) => { const inpImmediate = computeInpImmediate.value if (!inpImmediate) { triggerEvent(evnt) } } const focusEvent = (evnt: Event & { type: 'focus' }) => { reactData.isActivated = true const isDatePickerType = computeIsDatePickerType.value if (isDatePickerType) { datePickerOpenEvent(evnt) } triggerEvent(evnt) } const clickPrefixEvent = (evnt: Event) => { const isDisabled = computeIsDisabled.value if (!isDisabled) { const { inputValue } = reactData dispatchEvent('prefix-click', { value: inputValue }, evnt) } } const hidePanel = () => { return new Promise<void>(resolve => { reactData.visiblePanel = false internalData.hpTimeout = setTimeout(() => { reactData.isAniVisible = false resolve() }, 350) }) } const clearValueEvent = (evnt: Event, value: VxeDatePickerPropTypes.ModelValue) => { const isDatePickerType = computeIsDatePickerType.value if (isDatePickerType) { hidePanel() } handleChange('', evnt) dispatchEvent('clear', { value }, evnt) } const clickSuffixEvent = (evnt: Event) => { const isDisabled = computeIsDisabled.value if (!isDisabled) { const { inputValue } = reactData dispatchEvent('suffix-click', { value: inputValue }, evnt) } } const dateParseValue = (value?: VxeDatePickerPropTypes.ModelValue) => { const { type } = props const dateLabelFormat = computeDateLabelFormat.value const dateValueFormat = computeDateValueFormat.value const firstDayOfWeek = computeFirstDayOfWeek.value let dValue: Date | null = null let dLabel = '' if (value) { dValue = parseDate(value, dateValueFormat) } if (XEUtils.isValidDate(dValue)) { dLabel = XEUtils.toDateString(dValue, dateLabelFormat, { firstDay: firstDayOfWeek }) // 周选择器,由于年份和第几周是冲突的行为,所以需要特殊处理,判断是否跨年,例如 // '2024-12-31' 'yyyy-MM-dd W' >> '2024-12-31 1' // '2025-01-01' 'yyyy-MM-dd W' >> '2025-01-01 1' if (dateLabelFormat && type === 'week') { const weekNum = XEUtils.getYearWeek(dValue, firstDayOfWeek) const weekDate = XEUtils.getWhatWeek(dValue, 0, weekNum === 1 ? ((6 + firstDayOfWeek) % 7) as VxeDatePickerPropTypes.StartDay : firstDayOfWeek, firstDayOfWeek) const weekFullYear = weekDate.getFullYear() if (weekFullYear !== dValue.getFullYear()) { const yyIndex = dateLabelFormat.indexOf('yyyy') if (yyIndex > -1) { const yyNum = Number(dLabel.substring(yyIndex, yyIndex + 4)) if (yyNum && !isNaN(yyNum)) { dLabel = dLabel.replace(`${yyNum}`, `${weekFullYear}`) } } } } } else { dValue = null } reactData.datePanelValue = dValue reactData.datePanelLabel = dLabel } /** * 值变化时处理 */ const changeValue = () => { const isDatePickerType = computeIsDatePickerType.value const { inputValue } = reactData if (isDatePickerType) { dateParseValue(inputValue) reactData.inputValue = props.multiple ? computeDateMultipleLabel.value : reactData.datePanelLabel } } /** * 检查初始值 */ const initValue = () => { const isDatePickerType = computeIsDatePickerType.value updateModelValue(props.modelValue) if (isDatePickerType) { changeValue() } } const dateRevert = () => { reactData.inputValue = props.multiple ? computeDateMultipleLabel.value : reactData.datePanelLabel } const dateCheckMonth = (date: Date) => { const firstDayOfWeek = computeFirstDayOfWeek.value const weekNum = XEUtils.getYearWeek(date, firstDayOfWeek) const weekStartDate = XEUtils.getWhatWeek(date, 0, firstDayOfWeek, firstDayOfWeek) const month = XEUtils.getWhatMonth(weekNum === 1 ? XEUtils.getWhatDay(weekStartDate, 6) : date, 0, 'first') if (!XEUtils.isEqual(month, reactData.selectMonth)) { reactData.selectMonth = month } } const dateChange = (date: Date, isReload?: boolean) => { const { modelValue, multiple } = props const { datetimePanelValue } = reactData const isDateTimeType = computeIsDateTimeType.value const dateValueFormat = computeDateValueFormat.value const firstDayOfWeek = computeFirstDayOfWeek.value if (props.type === 'week') { const sWeek = XEUtils.toNumber(props.selectDay) as VxeDatePickerPropTypes.SelectDay date = XEUtils.getWhatWeek(date, 0, sWeek, firstDayOfWeek) } else if (isDateTimeType) { if (datetimePanelValue) { date.setHours(datetimePanelValue.getHours()) date.setMinutes(datetimePanelValue.getMinutes()) date.setSeconds(datetimePanelValue.getSeconds()) } } const inpVal = XEUtils.toDateString(date, dateValueFormat, { firstDay: firstDayOfWeek }) dateCheckMonth(date) if (multiple) { const overCount = computeOverCount.value // 如果为多选 if (isDateTimeType) { // 如果是datetime特殊类型 const dateListValue = isReload ? [] : [...computeDateListValue.value] const datetimeRest: Date[] = [] const eqIndex = XEUtils.findIndexOf(dateListValue, val => XEUtils.isDateSame(date, val, 'yyyyMMdd')) if (eqIndex === -1) { if (overCount) { // 如果超出最大多选数量 return } dateListValue.push(date) } else { dateListValue.splice(eqIndex, 1) } dateListValue.forEach(item => { if (item) { if (datetimePanelValue) { item.setHours(datetimePanelValue.getHours()) item.setMinutes(datetimePanelValue.getMinutes()) item.setSeconds(datetimePanelValue.getSeconds()) } datetimeRest.push(item) } }) handleChange(datetimeRest.map(date => XEUtils.toDateString(date, dateValueFormat)).join(','), { type: 'update' }) } else { const dateMultipleValue = isReload ? [] : computeDateMultipleValue.value // 如果是日期类型 if (dateMultipleValue.some(val => XEUtils.isEqual(val, inpVal))) { handleChange(dateMultipleValue.filter(val => !XEUtils.isEqual(val, inpVal)).join(','), { type: 'update' }) } else { if (overCount) { // 如果超出最大多选数量 return } handleChange(dateMultipleValue.concat([inpVal]).join(','), { type: 'update' }) } } } else { // 如果为单选 if (!XEUtils.isEqual(modelValue, inpVal)) { handleChange(inpVal, { type: 'update' }) } } } const afterCheckValue = () => { const { type } = props const { inputValue, datetimePanelValue } = reactData const dateLabelFormat = computeDateLabelFormat.value const inputReadonly = computeInputReadonly.value if (!inputReadonly) { if (inputValue) { let inpDateVal: VxeDatePickerPropTypes.ModelValue = parseDate(inputValue, dateLabelFormat as string) if (XEUtils.isValidDate(inpDateVal)) { if (type === 'time') { inpDateVal = XEUtils.toDateString(inpDateVal, dateLabelFormat) if (inputValue !== inpDateVal) { handleChange(inpDateVal, { type: 'check' }) } reactData.inputValue = inpDateVal } else { let isChange = false const firstDayOfWeek = computeFirstDayOfWeek.value if (type === 'datetime') { const dateValue = computeDateValue.value if (inputValue !== XEUtils.toDateString(dateValue, dateLabelFormat) || inputValue !== XEUtils.toDateString(inpDateVal, dateLabelFormat)) { isChange = true if (datetimePanelValue) { datetimePanelValue.setHours(inpDateVal.getHours()) datetimePanelValue.setMinutes(inpDateVal.getMinutes()) datetimePanelValue.setSeconds(inpDateVal.getSeconds()) } } } else { isChange = true } reactData.inputValue = XEUtils.toDateString(inpDateVal, dateLabelFormat, { firstDay: firstDayOfWeek }) if (isChange) { dateChange(inpDateVal) } } } else { dateRevert() } } else { handleChange('', { type: 'check' }) } } } const blurEvent = (evnt: Event & { type: 'blur' }) => { const { inputValue } = reactData const inpImmediate = computeInpImmediate.value const value = inputValue if (!inpImmediate) { handleChange(value, evnt) } afterCheckValue() if (!reactData.visiblePanel) { reactData.isActivated = false } dispatchEvent('blur', { value }, evnt) // 自动更新校验状态 if ($xeForm && formItemInfo) { $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value) } } const keydownEvent = (evnt: KeyboardEvent & { type: 'keydown' }) => { triggerEvent(evnt) } const keyupEvent = (evnt: KeyboardEvent & { type: 'keyup' }) => { triggerEvent(evnt) } // 日期 const dateMonthHandle = (date: Date, offsetMonth: number) => { const firstDayOfWeek = computeFirstDayOfWeek.value const weekNum = XEUtils.getYearWeek(date, firstDayOfWeek) const weekStartDate = XEUtils.getWhatWeek(date, 0, firstDayOfWeek, firstDayOfWeek) const month = XEUtils.getWhatMonth(weekNum === 1 ? XEUtils.getWhatDay(weekStartDate, 6) : date, offsetMonth, 'first') reactData.selectMonth = month } const dateNowHandle = () => { const { type } = props const firstDayOfWeek = computeFirstDayOfWeek.value let currentDate = new Date() switch (type) { case 'week': currentDate = XEUtils.getWhatWeek(currentDate, 0, firstDayOfWeek) break case 'datetime': currentDate = new Date() reactData.datetimePanelValue = new Date() break default: currentDate = XEUtils.getWhatDay(Date.now(), 0, 'first') break } reactData.currentDate = currentDate dateMonthHandle(currentDate, 0) } const dateToggleYearTypeEvent = () => { reactData.datePanelType = 'year' } const dateToggleMonthTypeEvent = () => { let { datePanelType } = reactData if (datePanelType === 'month' || datePanelType === 'quarter') { datePanelType = 'year' } else { datePanelType = 'month' } reactData.datePanelType = datePanelType } const datePrevEvent = (evnt: Event) => { const { type } = props const { datePanelType, selectMonth, inputValue } = reactData const { yearSize } = internalData const value = inputValue const isDisabledPrevDateBtn = computeIsDisabledPrevDateBtn.value if (!isDisabledPrevDateBtn) { let viewDate if (type === 'year') { viewDate = XEUtils.getWhatYear(selectMonth, -yearSize, 'first') } else if (type === 'month' || type === 'quarter') { if (datePanelType === 'year') { viewDate = XEUtils.getWhatYear(selectMonth, -yearSize, 'first') } else { viewDate = XEUtils.getWhatYear(selectMonth, -1, 'first') } } else { if (datePanelType === 'year') { viewDate = XEUtils.getWhatYear(selectMonth, -yearSize, 'first') } else if (datePanelType === 'month') { viewDate = XEUtils.getWhatYear(selectMonth, -1, 'first') } else { viewDate = XEUtils.getWhatMonth(selectMonth, -1, 'first') } } reactData.selectMonth = viewDate dispatchEvent('date-prev', { viewType: datePanelType, viewDate, value, type }, evnt) } } const dateTodayMonthEvent = (evnt: Event) => { dateNowHandle() dateChange(reactData.currentDate, true) if (!props.multiple) { hidePanel() } dispatchEvent('date-today', { type: props.type }, evnt) } const dateNextEvent = (evnt: Event) => { const { type } = props const { datePanelType, selectMonth, inputValue } = reactData const { yearSize } = internalData const value = inputValue const isDisabledNextDateBtn = computeIsDisabledNextDateBtn.value if (!isDisabledNextDateBtn) { let viewDate if (type === 'year') { viewDate = XEUtils.getWhatYear(selectMonth, yearSize, 'first') } else if (type === 'month' || type === 'quarter') { if (datePanelType === 'year') { viewDate = XEUtils.getWhatYear(selectMonth, yearSize, 'first') } else { viewDate = XEUtils.getWhatYear(selectMonth, 1, 'first') } } else { if (datePanelType === 'year') { viewDate = XEUtils.getWhatYear(selectMonth, yearSize, 'first') } else if (datePanelType === 'month') { viewDate = XEUtils.getWhatYear(selectMonth, 1, 'first') } else { viewDate = XEUtils.getWhatMonth(selectMonth, 1, 'first') } } reactData.selectMonth = viewDate dispatchEvent('date-next', { viewType: datePanelType, value, type }, evnt) } } const isDateDisabled = (item: { date: Date }) => { const { disabledMethod } = props const { datePanelType } = reactData const dateStartTime = computeDateStartTime.value const dateEndTime = computeDateEndTime.value const { date } = item if (dateStartTime && dateStartTime.getTime() > date.getTime()) { return true } if (dateEndTime && dateEndTime.getTime() < date.getTime()) { return true } if (disabledMethod) { return disabledMethod({ type: datePanelType, viewType: datePanelType, date, $datePicker: $xeDatePicker }) } return false } const dateSelectItem = (date: Date) => { const { type, multiple } = props const { datePanelType } = reactData if (type === 'month') { if (datePanelType === 'year') { reactData.datePanelType = 'month' dateCheckMonth(date) } else { dateChange(date) if (!multiple) { hidePanel() } } } else if (type === 'year') { dateChange(date) if (!multiple) { hidePanel() } } else if (type === 'quarter') { if (datePanelType === 'year') { reactData.datePanelType = 'quarter' dateCheckMonth(date) } else { dateChange(date) if (!multiple) { hidePanel() } } } else { if (datePanelType === 'month') { reactData.datePanelType = type === 'week' ? type : 'day' dateCheckMonth(date) } else if (datePanelType === 'year') { reactData.datePanelType = 'month' dateCheckMonth(date) } else { dateChange(date) if (type === 'datetime') { // 日期带时间 } else { if (!multiple) { hidePanel() } } } } } const dateSelectEvent = (item: VxeDatePickerDefines.DateYearItem | VxeDatePickerDefines.DateQuarterItem | VxeDatePickerDefines.DateMonthItem | VxeDatePickerDefines.DateDayItem) => { if (!isDateDisabled(item)) { dateSelectItem(item.date) } } const dateMoveDay = (offsetDay: Date) => { if (!isDateDisabled({ date: offsetDay })) { const dayList = computeDayList.value if (!dayList.some((item) => XEUtils.isDateSame(item.date, offsetDay, 'yyyyMMdd'))) { dateCheckMonth(offsetDay) } dateParseValue(offsetDay) } } const dateMoveYear = (offsetYear: Date) => { if (!isDateDisabled({ date: offsetYear })) { const yearList = computeYearList.value if (!yearList.some((item) => XEUtils.isDateSame(item.date, offsetYear, 'yyyy'))) { dateCheckMonth(offsetYear) } dateParseValue(offsetYear) } } const dateMoveQuarter = (offsetQuarter: Date) => { if (!isDateDisabled({ date: offsetQuarter })) { const quarterList = computeQuarterList.value if (!quarterList.some((item) => XEUtils.isDateSame(item.date, offsetQuarter, 'yyyyq'))) { dateCheckMonth(offsetQuarter) } dateParseValue(offsetQuarter) } } const dateMoveMonth = (offsetMonth: Date) => { if (!isDateDisabled({ date: offsetMonth })) { const monthList = computeMonthList.value if (!monthList.some((item) => XEUtils.isDateSame(item.date, offsetMonth, 'yyyyMM'))) { dateCheckMonth(offsetMonth) } dateParseValue(offsetMonth) } } const dateMouseenterEvent = (item: VxeDatePickerDefines.DateYearItem | VxeDatePickerDefines.DateQuarterItem | VxeDatePickerDefines.DateMonthItem | VxeDatePickerDefines.DateDayItem) => { if (!isDateDisabled(item)) { const { datePanelType } = reactData if (datePanelType === 'month') { dateMoveMonth(item.date) } else if (datePanelType === 'quarter') { dateMoveQuarter(item.date) } else if (datePanelType === 'year') { dateMoveYear(item.date) } else { dateMoveDay(item.date) } } } const updateTimePos = (liElem: Element) => { if (liElem) { const height = (liElem as HTMLElement).offsetHeight const ulElem = liElem.parentNode as HTMLElement ulElem.scrollTop = (liElem as HTMLElement).offsetTop - height * 4 } } const dateTimeChangeEvent = (evnt: Event) => { const { datetimePanelValue } = reactData reactData.datetimePanelValue = datetimePanelValue ? new Date(datetimePanelValue.getTime()) : new Date() updateTimePos(evnt.currentTarget as HTMLLIElement) } const dateHourEvent = (evnt: MouseEvent, item: VxeDatePickerDefines.DateHourMinuteSecondItem) => { const { datetimePanelValue } = reactData if (datetimePanelValue) { datetimePanelValue.setHours(item.value) } dateTimeChangeEvent(evnt) } // const dateClearEvent = (evnt: MouseEvent) => { // const value = '' // handleChange(value, evnt) // dispatchEvent('clear', { value }, evnt) // } const dateConfirmEvent = () => { const { multiple } = props const { datetimePanelValue } = reactData const dateValue = computeDateValue.value const isDateTimeType = computeIsDateTimeType.value if (isDateTimeType) { const dateValueFormat = computeDateValueFormat.value if (multiple) { // 如果为多选 const dateMultipleValue = computeDateMultipleValue.value if (isDateTimeType) { // 如果是datetime特殊类型 const dateListValue = [...computeDateListValue.value] const datetimeRest: Date[] = [] dateListValue.forEach(item => { if (item) { if (datetimePanelValue) { item.setHours(datetimePanelValue.getHours()) item.setMinutes(datetimePanelValue.getMinutes()) item.setSeconds(datetimePanelValue.getSeconds()) } datetimeRest.push(item) } }) handleChange(datetimeRest.map(date => XEUtils.toDateString(date, dateValueFormat)).join(','), { type: 'update' }) } else { // 如果是日期类型 handleChange(dateMultipleValue.join(','), { type: 'update' }) } } else { dateChange(dateValue || reactData.currentDate) } } hidePanel() } const dateMinuteEvent = (evnt: MouseEvent, item: VxeDatePickerDefines.DateHourMinuteSecondItem) => { const { datetimePanelValue } = reactData if (datetimePanelValue) { datetimePanelValue.setMinutes(item.value) } dateTimeChangeEvent(evnt) } const dateSecondEvent = (evnt: MouseEvent, item: VxeDatePickerDefines.DateHourMinuteSecondItem) => { const { datetimePanelValue } = reactData if (datetimePanelValue) { datetimePanelValue.setSeconds(item.value) } dateTimeChangeEvent(evnt) } const dateOffsetEvent = (evnt: KeyboardEvent) => { const { isActivated, datePanelValue, datePanelType } = reactData if (isActivated) { evnt.preventDefault() const isLeftArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_LEFT) const isUpArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_UP) const isRightArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_RIGHT) const isDwArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_DOWN) if (datePanelType === 'year') { let offsetYear = XEUtils.getWhatYear(datePanelValue || Date.now(), 0, 'first') if (isLeftArrow) { offsetYear = XEUtils.getWhatYear(offsetYear, -1) } else if (isUpArrow) { offsetYear = XEUtils.getWhatYear(offsetYear, -4) } else if (isRightArrow) { offsetYear = XEUtils.getWhatYear(offsetYear, 1) } else if (isDwArrow) { offsetYear = XEUtils.getWhatYear(offsetYear, 4) } dateMoveYear(offsetYear) } else if (datePanelType === 'quarter') { let offsetQuarter = XEUtils.getWhatQuarter(datePanelValue || Date.now(), 0, 'first') if (isLeftArrow) { offsetQuarter = XEUtils.getWhatQuarter(offsetQuarter, -1) } else if (isUpArrow) { offsetQuarter = XEUtils.getWhatQuarter(offsetQuarter, -2) } else if (isRightArrow) { offsetQuarter = XEUtils.getWhatQuarter(offsetQuarter, 1) } else if (isDwArrow) { offsetQuarter = XEUtils.getWhatQuarter(offsetQuarter, 2) } dateMoveQuarter(offsetQuarter) } else if (datePanelType === 'month') { let offsetMonth = XEUtils.getWhatMonth(datePanelValue || Date.now(), 0, 'first') if (isLeftArrow) { offsetMonth = XEUtils.getWhatMonth(offsetMonth, -1) } else if (isUpArrow) { offsetMonth = XEUtils.getWhatMonth(offsetMonth, -4) } else if (isRightArrow) { offsetMonth = XEUtils.getWhatMonth(offsetMonth, 1) } else if (isDwArrow) { offsetMonth = XEUtils.getWhatMonth(offsetMonth, 4) } dateMoveMonth(offsetMonth) } else if (datePanelType === 'week') { let offsetDay = datePanelValue || XEUtils.getWhatDay(Date.now(), 0, 'first') const firstDayOfWeek = computeFirstDayOfWeek.value if (isUpArrow) { offsetDay = XEUtils.getWhatWeek(offsetDay, -1, firstDayOfWeek) } else if (isDwArrow) { offsetDay = XEUtils.getWhatWeek(offsetDay, 1, firstDayOfWeek) } dateMoveDay(offsetDay) } else { let offsetDay = datePanelValue || XEUtils.getWhatDay(Date.now(), 0, 'first') if (isLeftArrow) { offsetDay = XEUtils.getWhatDay(offsetDay, -1) } else if (isUpArrow) { offsetDay = XEUtils.