From 776ae477fee79d0321db9c49dae0039627f29dd1 Mon Sep 17 00:00:00 2001 From: DDDDD12138 <43703884+DDDDD12138@users.noreply.github.com> Date: Sat, 23 Nov 2024 17:44:43 +0800 Subject: [PATCH] fix(components): [date-picker] resolve v-model type inconsistency (#18888) * fix(components): [date-picker] resolve v-model type inconsistency * test: add unit test form CommonPicker --- .../date-picker/src/date-picker.tsx | 4 ++- .../__tests__/time-picker.test.tsx | 35 +++++++++++++++++++ .../time-picker/src/common/picker.vue | 23 ++++-------- packages/components/time-picker/src/utils.ts | 7 ++++ 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/packages/components/date-picker/src/date-picker.tsx b/packages/components/date-picker/src/date-picker.tsx index 34cd218d4a..b4d6aa1629 100644 --- a/packages/components/date-picker/src/date-picker.tsx +++ b/packages/components/date-picker/src/date-picker.tsx @@ -13,6 +13,8 @@ import { CommonPicker, DEFAULT_FORMATS_DATE, DEFAULT_FORMATS_DATEPICKER, + type DateModelType, + type SingleOrRange, } from '@element-plus/components/time-picker' import { ROOT_PICKER_INJECTION_KEY } from './constants' @@ -61,7 +63,7 @@ export default defineComponent({ expose(refProps) - const onModelValueUpdated = (val: any) => { + const onModelValueUpdated = (val: SingleOrRange | null) => { emit('update:modelValue', val) } diff --git a/packages/components/time-picker/__tests__/time-picker.test.tsx b/packages/components/time-picker/__tests__/time-picker.test.tsx index 0380ddea4c..2d7f909a26 100644 --- a/packages/components/time-picker/__tests__/time-picker.test.tsx +++ b/packages/components/time-picker/__tests__/time-picker.test.tsx @@ -385,6 +385,41 @@ describe('TimePicker', () => { expect(value.value).toEqual('2000-01-01 09:00:00') }) + it('when a time is input, the type of modelValue should be Date by default', async () => { + const value = ref('2024-11-18 12:00:00') + const wrapper = mount(() => ) + + const input = wrapper.find('input') + input.trigger('focus') + + await input.setValue('10:00:00') + + input.trigger('blur') + expect(value.value).toBeInstanceOf(Date) + }) + + it('when a time is input, the type of modelValue should be Date by default (is-range)', async () => { + const value = ref([ + new Date('2024-11-18 10:00:00'), + new Date('2024-11-18 12:00:00'), + ]) + const wrapper = mount(() => ) + + const [startTimeInput, endTimeInput] = wrapper.findAll('input') + + // Input start time + startTimeInput.trigger('focus') + await startTimeInput.setValue('10:00:10') + startTimeInput.trigger('blur') + expect(value.value[0]).toBeInstanceOf(Date) + + // Input end time + endTimeInput.trigger('focus') + await endTimeInput.setValue('12:00:10') + endTimeInput.trigger('blur') + expect(value.value[1]).toBeInstanceOf(Date) + }) + it('picker-panel should not pop up when readonly', async () => { const wrapper = mount(() => ) diff --git a/packages/components/time-picker/src/common/picker.vue b/packages/components/time-picker/src/common/picker.vue index 05f6d0ea5a..7b0b28d200 100644 --- a/packages/components/time-picker/src/common/picker.vue +++ b/packages/components/time-picker/src/common/picker.vue @@ -180,7 +180,7 @@ import ElTooltip from '@element-plus/components/tooltip' import { NOOP, debugWarn, isArray } from '@element-plus/utils' import { EVENT_CODE } from '@element-plus/constants' import { Calendar, Clock } from '@element-plus/icons-vue' -import { formatter, parseDate, valueEquals } from '../utils' +import { dayOrDaysToDate, formatter, parseDate, valueEquals } from '../utils' import { timePickerDefaultProps } from './props' import PickerRangeTrigger from './picker-range-trigger.vue' import type { InputInstance } from '@element-plus/components/input' @@ -190,7 +190,6 @@ import type { ComponentPublicInstance, Ref } from 'vue' import type { Options } from '@popperjs/core' import type { DateModelType, - DateOrDates, DayOrDays, PickerOptions, SingleOrRange, @@ -199,8 +198,6 @@ import type { } from './props' import type { TooltipInstance } from '@element-plus/components/tooltip' -// Date object and string - defineOptions({ name: 'Picker', }) @@ -299,7 +296,7 @@ const emitChange = ( formItem?.validate('change').catch((err) => debugWarn(err)) } } -const emitInput = (input: SingleOrRange | null) => { +const emitInput = (input: SingleOrRange | null) => { if (!valueEquals(props.modelValue, input)) { let formatted if (isArray(input)) { @@ -402,11 +399,7 @@ const parsedValue = computed(() => { // The result is corrected only when model-value exists if (!valueIsEmpty.value) { - emitInput( - (isArray(dayOrDays) - ? dayOrDays.map((_) => _.toDate()) - : dayOrDays.toDate()) as SingleOrRange - ) + emitInput(dayOrDaysToDate(dayOrDays)) } } } @@ -540,11 +533,7 @@ const handleChange = () => { const value = parseUserInputToDayjs(displayValue.value) if (value) { if (isValidValue(value)) { - emitInput( - (isArray(value) - ? value.map((_) => _.toDate()) - : value.toDate()) as DateOrDates - ) + emitInput(dayOrDaysToDate(value)) userInput.value = null } } @@ -664,7 +653,7 @@ const handleStartChange = () => { ] const newValue = [value, parsedVal && (parsedVal[1] || null)] as DayOrDays if (isValidValue(newValue)) { - emitInput(newValue) + emitInput(dayOrDaysToDate(newValue)) userInput.value = null } } @@ -681,7 +670,7 @@ const handleEndChange = () => { ] const newValue = [parsedVal && parsedVal[0], value] as DayOrDays if (isValidValue(newValue)) { - emitInput(newValue) + emitInput(dayOrDaysToDate(newValue)) userInput.value = null } } diff --git a/packages/components/time-picker/src/utils.ts b/packages/components/time-picker/src/utils.ts index 0a8b86b563..0bffcf3e13 100644 --- a/packages/components/time-picker/src/utils.ts +++ b/packages/components/time-picker/src/utils.ts @@ -2,6 +2,7 @@ import dayjs from 'dayjs' import { isArray, isDate, isEmpty } from '@element-plus/utils' import type { Dayjs } from 'dayjs' +import type { DateOrDates, DayOrDays } from './common/props' export type TimeList = [number | undefined, number, undefined | number] export const buildTimeList = (value: number, bound: number): TimeList => { @@ -88,3 +89,9 @@ export const makeList = (total: number, method?: () => number[]) => { } return arr } + +export const dayOrDaysToDate = (dayOrDays: DayOrDays): DateOrDates => { + return isArray(dayOrDays) + ? (dayOrDays.map((d) => d.toDate()) as [Date, Date]) + : dayOrDays.toDate() +}