diff --git a/packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx b/packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx index 91ae3d6953..dc750ad1db 100644 --- a/packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx +++ b/packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx @@ -461,6 +461,24 @@ describe('DatePickerPanel', () => { '6', ]) }) + + it('should handle array value without errors', async () => { + const value = ref(['2025-09-01']) + const wrapper = mount(() => ( + + )) + await nextTick() + + const dateInput = wrapper.find( + '.el-date-picker__time-header > span:nth-child(1) input' + ).element as HTMLInputElement + expect(dateInput.value).toBe('2025-09-01') + + const timeInput = wrapper.find( + '.el-date-picker__time-header > span:nth-child(2) input' + ).element as HTMLInputElement + expect(timeInput.value).toBe('00:00:00') + }) }) describe(':type="datetimerange"', () => { diff --git a/packages/components/date-picker-panel/src/date-picker-com/panel-date-pick.vue b/packages/components/date-picker-panel/src/date-picker-com/panel-date-pick.vue index 8ed9e36be8..8c8848e947 100644 --- a/packages/components/date-picker-panel/src/date-picker-com/panel-date-pick.vue +++ b/packages/components/date-picker-panel/src/date-picker-com/panel-date-pick.vue @@ -236,7 +236,7 @@ import { extractTimeFormat, } from '@element-plus/components/time-picker' import { ElIcon } from '@element-plus/components/icon' -import { isArray, isFunction } from '@element-plus/utils' +import { extractFirst, isArray, isFunction } from '@element-plus/utils' import { EVENT_CODE } from '@element-plus/constants' import { ArrowLeft, @@ -347,8 +347,9 @@ const emit = (value: Dayjs | Dayjs[], ...args: any[]) => { const handleDatePick = async (value: DateTableEmits, keepOpen?: boolean) => { if (selectionMode.value === 'date') { value = value as Dayjs - let newDate = props.parsedValue - ? (props.parsedValue as Dayjs) + const parsedDateValue = extractFirst(props.parsedValue) + let newDate = parsedDateValue + ? parsedDateValue .year(value.year()) .month(value.month()) .date(value.date()) @@ -547,7 +548,7 @@ const onConfirm = () => { emit(props.parsedValue as Dayjs[]) } else { // deal with the scenario where: user opens the date time picker, then confirm without doing anything - let result = props.parsedValue as Dayjs + let result = extractFirst(props.parsedValue) if (!result) { const defaultTimeD = dayjs(defaultTime).locale(lang.value) const defaultValueD = getDefaultValue() @@ -595,17 +596,15 @@ const dateFormat = computed(() => { const visibleTime = computed(() => { if (userInputTime.value) return userInputTime.value if (!props.parsedValue && !defaultValue.value) return - return ((props.parsedValue || innerDate.value) as Dayjs).format( - timeFormat.value - ) + const dateValue = extractFirst(props.parsedValue) || innerDate.value + return dateValue.format(timeFormat.value) }) const visibleDate = computed(() => { if (userInputDate.value) return userInputDate.value if (!props.parsedValue && !defaultValue.value) return - return ((props.parsedValue || innerDate.value) as Dayjs).format( - dateFormat.value - ) + const dateValue = extractFirst(props.parsedValue) || innerDate.value + return dateValue.format(dateFormat.value) }) const timePickerVisible = ref(false) @@ -629,8 +628,9 @@ const getUnits = (date: Dayjs) => { const handleTimePick = (value: Dayjs, visible: boolean, first: boolean) => { const { hour, minute, second } = getUnits(value) - const newDate = props.parsedValue - ? (props.parsedValue as Dayjs).hour(hour).minute(minute).second(second) + const parsedDateValue = extractFirst(props.parsedValue) + const newDate = parsedDateValue + ? parsedDateValue.hour(hour).minute(minute).second(second) : value innerDate.value = newDate emit(innerDate.value, true) diff --git a/packages/components/date-picker/__tests__/date-picker.test.ts b/packages/components/date-picker/__tests__/date-picker.test.ts index e4d0211676..69196255a0 100644 --- a/packages/components/date-picker/__tests__/date-picker.test.ts +++ b/packages/components/date-picker/__tests__/date-picker.test.ts @@ -1096,6 +1096,54 @@ describe('DatePicker', () => { expect(changeHandler).toHaveBeenCalledTimes(1) }) }) + + it('should handle array value for datetime type without errors', async () => { + const wrapper = _mount( + ``, + () => ({ value: ['2025-09-01'] }) + ) + + await nextTick() + const input = wrapper.find('input') + expect(input.element.value).toBe('2025-09-01 00:00:00') + + await input.trigger('focus') + await nextTick() + + const dateInput = document.querySelector( + '.el-date-picker__time-header > span:nth-child(1) input' + ) as HTMLInputElement + const timeInput = document.querySelector( + '.el-date-picker__time-header > span:nth-child(2) input' + ) as HTMLInputElement + + expect(dateInput?.value).toBe('2025-09-01') + expect(timeInput?.value).toBe('00:00:00') + }) + + it('should convert array value to proper format when changed', async () => { + const wrapper = _mount( + ``, + () => ({ value: ['2025-09-04'] }) + ) + + const originalValue = wrapper.vm.value + expect(originalValue).toEqual(['2025-09-04']) + + const input = wrapper.find('input') + await input.trigger('focus') + await nextTick() + + const dateCell = document.querySelector('.el-date-table td.available') + await (dateCell as HTMLElement)?.click() + await nextTick() + + expect(wrapper.vm.value).not.toEqual(['2025-09-04']) + expect(Array.isArray(wrapper.vm.value)).toBe(false) + }) }) describe('DatePicker Navigation', () => { diff --git a/packages/utils/__tests__/arrays.test.ts b/packages/utils/__tests__/arrays.test.ts index e18dd8f527..d51d0dd743 100644 --- a/packages/utils/__tests__/arrays.test.ts +++ b/packages/utils/__tests__/arrays.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import { castArray as lodashCastArray } from 'lodash-unified' -import { castArray, ensureArray, unique } from '..' +import { castArray, ensureArray, extractFirst, unique } from '..' describe('arrays', () => { it('unique should work', () => { @@ -17,4 +17,14 @@ describe('arrays', () => { it('re-export ensureArray', () => { expect(ensureArray).toBe(lodashCastArray) }) + + it('extractFirst should work', () => { + expect(extractFirst([1, 2, 3])).toBe(1) + expect(extractFirst(['a', 'b', 'c'])).toBe('a') + expect(extractFirst(42)).toBe(42) + expect(extractFirst('hello')).toBe('hello') + expect(extractFirst(null)).toBe(null) + expect(extractFirst(undefined)).toBe(undefined) + expect(extractFirst([])).toBe(undefined) + }) }) diff --git a/packages/utils/arrays.ts b/packages/utils/arrays.ts index 892096434f..6eeddfa4c3 100644 --- a/packages/utils/arrays.ts +++ b/packages/utils/arrays.ts @@ -2,6 +2,10 @@ import { isArray } from './types' export const unique = (arr: T[]) => [...new Set(arr)] +export const extractFirst = (arr: T | T[]): T => { + return isArray(arr) ? arr[0] : arr +} + type Many = T | ReadonlyArray // TODO: rename to `ensureArray` /** like `_.castArray`, except falsy value returns empty array. */