UNPKG

vxe-pc-ui

Version:
1,203 lines (1,202 loc) 114 kB
import { defineComponent, h, Teleport, ref, computed, reactive, onMounted, inject, nextTick, watch, onBeforeUnmount, 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, eqEmptyValue } from '../../ui/src/utils'; import { hasClass, getAbsolutePos, getEventTargetNode } from '../../ui/src/dom'; import { toStringTimeDate, getDateQuarter } from '../../date-picker/src/util'; import { handleNumber, toFloatValueFixed } from '../../number-input/src/util'; import { getSlotVNs } from '../..//ui/src/vn'; export default defineComponent({ name: 'VxeInput', props: { modelValue: [String, Number, Date], immediate: { type: Boolean, default: true }, name: String, type: { type: String, default: 'text' }, clearable: { type: Boolean, default: () => getConfig().input.clearable }, readonly: { type: Boolean, default: null }, disabled: { type: Boolean, default: null }, placeholder: { type: String, default: null }, maxLength: { type: [String, Number], default: () => getConfig().input.maxLength }, autoComplete: { type: String, default: 'off' }, autoFocus: { type: Boolean, default: null }, align: String, form: String, className: String, size: { type: String, default: () => getConfig().input.size || getConfig().size }, multiple: Boolean, // text showWordCount: Boolean, countMethod: Function, // number、integer、float min: { type: [String, Number], default: null }, max: { type: [String, Number], default: null }, step: [String, Number], trim: { type: Boolean, default: () => getConfig().input.trim }, exponential: { type: Boolean, default: () => getConfig().input.exponential }, // number、integer、float、password controls: { type: Boolean, default: () => getConfig().input.controls }, // float digits: { type: [String, Number], default: () => getConfig().input.digits }, // date、week、month、quarter、year startDate: { type: [String, Number, Date], default: () => getConfig().input.startDate }, endDate: { type: [String, Number, Date], default: () => getConfig().input.endDate }, minDate: [String, Number, Date], maxDate: [String, Number, Date], // 已废弃 startWeek,被 startDay 替换 startWeek: Number, startDay: { type: [String, Number], default: () => getConfig().input.startDay }, labelFormat: String, valueFormat: String, editable: { type: Boolean, default: true }, festivalMethod: { type: Function, default: () => getConfig().input.festivalMethod }, disabledMethod: { type: Function, default: () => getConfig().input.disabledMethod }, // week selectDay: { type: [String, Number], default: () => getConfig().input.selectDay }, prefixIcon: String, suffixIcon: String, placement: String, transfer: { type: Boolean, default: null }, // 已废弃 maxlength: [String, Number], // 已废弃 autocomplete: String }, emits: [ 'update:modelValue', 'input', 'change', 'keydown', 'keyup', 'wheel', 'click', 'focus', 'blur', 'clear', 'search-click', 'toggle-visible', 'prev-number', 'next-number', 'prefix-click', 'suffix-click', 'date-prev', 'date-today', 'date-next' ], setup(props, context) { const { slots, emit } = context; const $xeSelect = inject('$xeSelect', null); const $xeTreeSelect = inject('$xeTreeSelect', null); const $xeModal = inject('$xeModal', null); const $xeDrawer = inject('$xeDrawer', null); const $xeTable = inject('$xeTable', null); const $xeForm = inject('$xeForm', null); const formItemInfo = inject('xeFormItemInfo', null); const xID = XEUtils.uniqueId(); const { computeSize } = useSize(props); const reactData = reactive({ initialized: false, panelIndex: 0, showPwd: false, visiblePanel: false, isAniVisible: false, panelStyle: {}, panelPlacement: '', isActivated: false, inputValue: props.modelValue, datetimePanelValue: null, datePanelValue: null, datePanelLabel: '', datePanelType: 'day', selectMonth: null, currentDate: null }); const internalData = { yearSize: 12, monthSize: 20, quarterSize: 8, hpTimeout: undefined, dnTimeout: undefined }; const refElem = ref(); const refInputTarget = ref(); const refInputPanel = ref(); const refPanelWrapper = ref(); const refInputTimeBody = ref(); const refMaps = { refElem, refInput: refInputTarget }; const $xeInput = { xID, props, context, reactData, internalData, getRefMaps: () => refMaps }; let inputMethods = {}; const parseDate = (value, format) => { const { type } = props; if (type === 'time') { return toStringTimeDate(value); } return XEUtils.toStringDate(value, format); }; const computeBtnTransfer = computed(() => { const { transfer } = props; if (transfer === null) { const globalTransfer = getConfig().input.transfer; if (XEUtils.isBoolean(globalTransfer)) { return globalTransfer; } if ($xeTable || $xeModal || $xeDrawer || $xeForm) { return true; } } return transfer; }); const computeFormReadonly = computed(() => { if ($xeForm) { return $xeForm.props.readonly; } return false; }); const computeIsReadonly = computed(() => { const { readonly } = props; return readonly; }); const computeIsDisabled = computed(() => { const { disabled } = props; if (disabled === null) { if ($xeForm) { return $xeForm.props.disabled; } return false; } return disabled; }); const computeInpMaxLength = computed(() => { const { maxLength, maxlength } = props; const maxLen = maxLength || maxlength; const isNumType = computeIsNumType.value; // 数值最大长度限制 16 位,包含小数 if (isNumType) { if (!XEUtils.toNumber(maxLen)) { return 16; } } return maxLen; }); const computeIsDateTimeType = computed(() => { const { type } = props; return type === 'time' || type === 'datetime'; }); const computeIsNumType = computed(() => { return ['number', 'integer', 'float'].indexOf(props.type) > -1; }); const computeInputCount = computed(() => { return XEUtils.getSize(reactData.inputValue); }); const computeIsCountError = computed(() => { const inputCount = computeInputCount.value; const inpMaxLength = computeInpMaxLength.value; return inpMaxLength && inputCount > XEUtils.toNumber(inpMaxLength); }); const computeIsDatePickerType = computed(() => { const isDateTimeType = computeIsDateTimeType.value; return isDateTimeType || ['date', 'week', 'month', 'quarter', 'year'].indexOf(props.type) > -1; }); const computeIsPawdType = computed(() => { return props.type === 'password'; }); const computeIsSearchType = computed(() => { return props.type === 'search'; }); const computeDigitsValue = computed(() => { return XEUtils.toInteger(props.digits) || 1; }); const computeStepValue = computed(() => { const { type } = props; const digitsValue = computeDigitsValue.value; const step = props.step; if (type === 'integer') { return XEUtils.toInteger(step) || 1; } else if (type === 'float') { return XEUtils.toNumber(step) || (1 / Math.pow(10, digitsValue)); } return XEUtils.toNumber(step) || 1; }); const computeIsClearable = computed(() => { const { type } = props; const isNumType = computeIsNumType.value; const isDatePickerType = computeIsDatePickerType.value; const isPawdType = computeIsPawdType.value; return props.clearable && (isPawdType || isNumType || isDatePickerType || type === 'text' || type === 'search'); }); 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 null; }); } 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 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 ''; }); const computeYearList = computed(() => { const { selectMonth, currentDate } = reactData; const { yearSize } = internalData; const years = []; 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); }); const computeWeekDatas = computed(() => { const weeks = []; 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 { selectMonth, currentDate } = reactData; const { quarterSize } = internalData; 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; }); const computeQuarterDatas = computed(() => { const quarterList = computeQuarterList.value; return XEUtils.chunk(quarterList, 2); }); const computeMonthList = computed(() => { const { selectMonth, currentDate } = reactData; const { monthSize } = internalData; 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; }); const computeMonthDatas = computed(() => { const monthList = computeMonthList.value; return XEUtils.chunk(monthList, 4); }); const computeDayList = computed(() => { const { selectMonth, currentDate } = reactData; const days = []; 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 = { 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 = []; 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 = []; 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 isReadonly = computeIsReadonly.value; return isReadonly || multiple || !editable || type === 'week' || type === 'quarter'; }); const computeInputType = computed(() => { const { type } = props; const { showPwd } = reactData; const isNumType = computeIsNumType.value; const isDatePickerType = computeIsDatePickerType.value; const isPawdType = computeIsPawdType.value; if (isDatePickerType || isNumType || (isPawdType && showPwd) || type === 'number') { return 'text'; } return type; }); const computeInpPlaceholder = computed(() => { const { placeholder } = props; if (placeholder) { return getFuncText(placeholder); } if (XEUtils.eqNull(placeholder)) { const globalPlaceholder = getConfig().input.placeholder; if (globalPlaceholder) { return getFuncText(globalPlaceholder); } return getI18n('vxe.base.pleaseInput'); } return placeholder; }); const computeInpImmediate = computed(() => { const { type, immediate } = props; return immediate || !(type === 'text' || type === 'number' || type === 'integer' || type === 'float'); }); const computeNumValue = computed(() => { const { type } = props; const { inputValue } = reactData; const isNumType = computeIsNumType.value; if (isNumType) { return type === 'integer' ? XEUtils.toInteger(handleNumber(inputValue)) : XEUtils.toNumber(handleNumber(inputValue)); } return 0; }); const computeIsDisabledSubtractNumber = computed(() => { const { min } = props; const { inputValue } = reactData; const isNumType = computeIsNumType.value; const numValue = computeNumValue.value; // 当有值时再进行判断 if ((inputValue || inputValue === 0) && isNumType && min !== null) { return numValue <= XEUtils.toNumber(min); } return false; }); const computeIsDisabledAddNumber = computed(() => { const { max } = props; const { inputValue } = reactData; const isNumType = computeIsNumType.value; const numValue = computeNumValue.value; // 当有值时再进行判断 if ((inputValue || inputValue === 0) && isNumType && max !== null) { return numValue >= XEUtils.toNumber(max); } return false; }); const getNumberValue = (val) => { const { type, exponential } = props; const inpMaxLength = computeInpMaxLength.value; const digitsValue = computeDigitsValue.value; 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); }; const emitModel = (value) => { emit('update:modelValue', value); }; const triggerEvent = (evnt) => { const { inputValue } = reactData; inputMethods.dispatchEvent(evnt.type, { value: inputValue }, evnt); }; const handleChange = (value, evnt) => { if (props.trim) { value = `${value || ''}`.trim(); } reactData.inputValue = value; emitModel(value); inputMethods.dispatchEvent('input', { value }, evnt); if (XEUtils.toValueString(props.modelValue) !== value) { inputMethods.dispatchEvent('change', { value }, evnt); if (!$xeSelect && !$xeTreeSelect) { // 自动更新校验状态 if ($xeForm && formItemInfo) { $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value); } } } }; const emitInputEvent = (value, evnt) => { const isDatePickerType = computeIsDatePickerType.value; const inpImmediate = computeInpImmediate.value; reactData.inputValue = value; if (!isDatePickerType) { if (inpImmediate) { handleChange(value, evnt); } else { inputMethods.dispatchEvent('input', { value }, evnt); } } }; const inputEvent = (evnt) => { const inputElem = evnt.target; const value = inputElem.value; emitInputEvent(value, evnt); }; const changeEvent = (evnt) => { const inpImmediate = computeInpImmediate.value; if (!inpImmediate) { triggerEvent(evnt); } }; const blurEvent = (evnt) => { const { inputValue } = reactData; const inpImmediate = computeInpImmediate.value; const value = inputValue; if (!inpImmediate) { handleChange(value, evnt); } afterCheckValue(); if (!reactData.visiblePanel) { reactData.isActivated = false; } inputMethods.dispatchEvent('blur', { value }, evnt); if (!$xeSelect && !$xeTreeSelect) { // 自动更新校验状态 if ($xeForm && formItemInfo) { $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value); } } }; const focusEvent = (evnt) => { const { inputValue } = reactData; const isNumType = computeIsNumType.value; const isDatePickerType = computeIsDatePickerType.value; reactData.isActivated = true; if (isNumType) { reactData.inputValue = eqEmptyValue(inputValue) ? '' : `${XEUtils.toNumber(inputValue)}`; } else if (isDatePickerType) { datePickerOpenEvent(evnt); } triggerEvent(evnt); }; const clickPrefixEvent = (evnt) => { const isDisabled = computeIsDisabled.value; if (!isDisabled) { const { inputValue } = reactData; inputMethods.dispatchEvent('prefix-click', { value: inputValue }, evnt); } }; const hidePanel = () => { return new Promise(resolve => { reactData.visiblePanel = false; internalData.hpTimeout = setTimeout(() => { reactData.isAniVisible = false; resolve(); }, 350); }); }; const clearValueEvent = (evnt, value) => { const { type, autoFocus } = props; const isNumType = computeIsNumType.value; const isDatePickerType = computeIsDatePickerType.value; if (isDatePickerType) { hidePanel(); } if (autoFocus || autoFocus === null) { if (isNumType || ['text', 'search', 'password'].indexOf(type) > -1) { focus(); } } handleChange('', evnt); inputMethods.dispatchEvent('clear', { value }, evnt); }; const clickSuffixEvent = (evnt) => { const isDisabled = computeIsDisabled.value; if (!isDisabled) { const { inputValue } = reactData; inputMethods.dispatchEvent('suffix-click', { value: inputValue }, evnt); } }; const dateParseValue = (value) => { const { type } = props; const dateLabelFormat = computeDateLabelFormat.value; const dateValueFormat = computeDateValueFormat.value; const firstDayOfWeek = computeFirstDayOfWeek.value; let dValue = 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) : 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 { type } = props; const { inputValue } = reactData; const isDatePickerType = computeIsDatePickerType.value; const digitsValue = computeDigitsValue.value; if (isDatePickerType) { changeValue(); } else if (type === 'float') { if (inputValue) { const validValue = toFloatValueFixed(inputValue, digitsValue); if (inputValue !== validValue) { handleChange(validValue, { type: 'init' }); } } } }; const validMaxNum = (num) => { return props.max === null || XEUtils.toNumber(num) <= XEUtils.toNumber(props.max); }; const validMinNum = (num) => { return props.min === null || XEUtils.toNumber(num) >= XEUtils.toNumber(props.min); }; const dateRevert = () => { reactData.inputValue = props.multiple ? computeDateMultipleLabel.value : reactData.datePanelLabel; }; const dateCheckMonth = (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) => { 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); date = XEUtils.getWhatWeek(date, 0, sWeek, firstDayOfWeek); } else if (isDateTimeType) { 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 dateMultipleValue = computeDateMultipleValue.value; if (isDateTimeType) { // 如果是datetime特殊类型 const dateListValue = [...computeDateListValue.value]; const datetimeRest = []; const eqIndex = XEUtils.findIndexOf(dateListValue, val => XEUtils.isDateSame(date, val, 'yyyyMMdd')); if (eqIndex === -1) { dateListValue.push(date); } else { dateListValue.splice(eqIndex, 1); } dateListValue.forEach(item => { if (item) { 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 { // 如果是日期类型 if (dateMultipleValue.some(val => XEUtils.isEqual(val, inpVal))) { handleChange(dateMultipleValue.filter(val => !XEUtils.isEqual(val, inpVal)).join(','), { type: 'update' }); } else { handleChange(dateMultipleValue.concat([inpVal]).join(','), { type: 'update' }); } } } else { // 如果为单选 if (!XEUtils.isEqual(modelValue, inpVal)) { handleChange(inpVal, { type: 'update' }); } } }; const afterCheckValue = () => { const { type, min, max, exponential } = props; const { inputValue, datetimePanelValue } = reactData; const isNumType = computeIsNumType.value; const isDatePickerType = computeIsDatePickerType.value; const dateLabelFormat = computeDateLabelFormat.value; const inputReadonly = computeInputReadonly.value; if (!inputReadonly) { if (isNumType) { if (inputValue) { let inpNumVal = type === 'integer' ? XEUtils.toInteger(handleNumber(inputValue)) : XEUtils.toNumber(handleNumber(inputValue)); if (!validMinNum(inpNumVal)) { inpNumVal = min; } else if (!validMaxNum(inpNumVal)) { inpNumVal = max; } if (exponential) { const inpStringVal = XEUtils.toValueString(inputValue).toLowerCase(); if (inpStringVal === XEUtils.toNumber(inpNumVal).toExponential()) { inpNumVal = inpStringVal; } } handleChange(getNumberValue(inpNumVal), { type: 'check' }); } } else if (isDatePickerType) { if (inputValue) { let inpDateVal = parseDate(inputValue, dateLabelFormat); 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; 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 passwordToggleEvent = (evnt) => { const { showPwd } = reactData; const isDisabled = computeIsDisabled.value; const isReadonly = computeIsReadonly.value; if (!isDisabled && !isReadonly) { reactData.showPwd = !showPwd; } inputMethods.dispatchEvent('toggle-visible', { visible: reactData.showPwd }, evnt); }; // 密码 // 搜索 const searchEvent = (evnt) => { inputMethods.dispatchEvent('search-click', {}, evnt); }; // 搜索 // 数值 const numberChange = (isPlus, evnt) => { const { min, max, type } = props; const { inputValue } = reactData; const stepValue = computeStepValue.value; 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 (!validMinNum(newValue)) { restNum = min; } else if (!validMaxNum(newValue)) { restNum = max; } else { restNum = newValue; } emitInputEvent(getNumberValue(restNum), evnt); }; const numberNextEvent = (evnt) => { const isDisabled = computeIsDisabled.value; const isReadonly = computeIsReadonly.value; const isDisabledSubtractNumber = computeIsDisabledSubtractNumber.value; numberStopDown(); if (!isDisabled && !isReadonly && !isDisabledSubtractNumber) { numberChange(false, evnt); } inputMethods.dispatchEvent('next-number', { value: reactData.inputValue }, evnt); }; const numberDownNextEvent = (evnt) => { internalData.dnTimeout = setTimeout(() => { numberNextEvent(evnt); numberDownNextEvent(evnt); }, 60); }; const numberPrevEvent = (evnt) => { const isDisabled = computeIsDisabled.value; const isReadonly = computeIsReadonly.value; const isDisabledAddNumber = computeIsDisabledAddNumber.value; numberStopDown(); if (!isDisabled && !isReadonly && !isDisabledAddNumber) { numberChange(true, evnt); } inputMethods.dispatchEvent('prev-number', { value: reactData.inputValue }, evnt); }; const numberKeydownEvent = (evnt) => { const isUpArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_UP); const isDwArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_DOWN); if (isUpArrow || isDwArrow) { evnt.preventDefault(); if (isUpArrow) { numberPrevEvent(evnt); } else { numberNextEvent(evnt); } } }; const keydownEvent = (evnt) => { const { exponential, controls } = props; const isNumType = computeIsNumType.value; if (isNumType) { const isCtrlKey = evnt.ctrlKey; const isShiftKey = evnt.shiftKey; const isAltKey = evnt.altKey; const isMetaKey = evnt.metaKey; const keyCode = evnt.keyCode; const isEsc = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ESCAPE); const isUpArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_UP); const isDwArrow = globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.ARROW_DOWN); if (!isCtrlKey && !isShiftKey && !isAltKey && !isMetaKey && (globalEvents.hasKey(evnt, GLOBAL_EVENT_KEYS.SPACEBAR) || ((!exponential || keyCode !== 69) && (keyCode >= 65 && keyCode <= 90)) || (keyCode >= 186 && keyCode <= 188) || keyCode >= 191)) { evnt.preventDefault(); } if (isEsc) { afterCheckValue(); } else if (isUpArrow || isDwArrow) { if (controls) { numberKeydownEvent(evnt); } } } triggerEvent(evnt); }; const keyupEvent = (evnt) => { triggerEvent(evnt); }; // 数值 const numberStopDown = () => { const { dnTimeout } = internalData; if (dnTimeout) { clearTimeout(dnTimeout); internalData.dnTimeout = undefined; } }; const numberDownPrevEvent = (evnt) => { internalData.dnTimeout = setTimeout(() => { numberPrevEvent(evnt); numberDownPrevEvent(evnt); }, 60); }; const numberMousedownEvent = (evnt) => { numberStopDown(); if (evnt.button === 0) { const isPrevNumber = hasClass(evnt.currentTarget, 'is--prev'); if (isPrevNumber) { numberPrevEvent(evnt); } else { numberNextEvent(evnt); } internalData.dnTimeout = setTimeout(() => { if (isPrevNumber) { numberDownPrevEvent(evnt); } else { numberDownNextEvent(evnt); } }, 500); } }; const wheelEvent = (evnt) => { const isNumType = computeIsNumType.value; if (isNumType && props.controls) { if (reactData.isActivated) { const delta = evnt.deltaY; if (delta > 0) {