From 1f43e8f371dbe6fc31bff89f038c70c34988191f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?w=C5=AB=20y=C4=81ng?= Date: Thu, 20 Jun 2024 16:10:22 +0800 Subject: [PATCH] feat(DatePicker): optimize range picker panel header click logic (#3207) * feat(DatePicker): optimize range picker panel header click logic * feat(DatePicker): optimize range picker panel header click logic --- src/date-picker/DateRangePicker.tsx | 79 ++++++++++++------------ src/date-picker/DateRangePickerPanel.tsx | 66 ++++++++++++-------- src/date-picker/utils.ts | 49 +++++++++++++++ 3 files changed, 131 insertions(+), 63 deletions(-) create mode 100644 src/date-picker/utils.ts diff --git a/src/date-picker/DateRangePicker.tsx b/src/date-picker/DateRangePicker.tsx index 871504520..e2e727943 100644 --- a/src/date-picker/DateRangePicker.tsx +++ b/src/date-picker/DateRangePicker.tsx @@ -22,6 +22,7 @@ import { } from '../_common/js/date-picker/format'; import { subtractMonth, addMonth, extractTimeObj } from '../_common/js/date-picker/utils'; import useFormDisabled from '../hooks/useFormDisabled'; +import { dateCorrection } from './utils'; export default defineComponent({ name: 'TDateRangePicker', @@ -132,7 +133,7 @@ export default defineComponent({ } // 日期点击 - function onCellClick(nextDate: Date, { e, partial }: { e: MouseEvent; partial: DateRangePickerPartial }) { + function onCellClick(nextDate: Date, { e }: { e: MouseEvent; partial: DateRangePickerPartial }) { const date = nextDate; // 不开启时间选择时 结束时间默认重置为 23:59:59 if (activeIndex.value && !props.enableTimePicker) date.setHours(23, 59, 59); @@ -150,18 +151,6 @@ export default defineComponent({ cacheValue.value = nextValue; inputValue.value = nextValue; - // date 模式自动切换年月 - if (props.mode === 'date') { - // 选择了不属于面板中展示月份的日期 - const partialIndex = partial === 'start' ? 0 : 1; - const isAdditional = dayjs(date).month() !== month.value[partialIndex]; - if (isAdditional) { - // 保证左侧时间小于右侧 - if (activeIndex.value === 0) month.value = [dayjs(date).month(), Math.min(dayjs(date).month() + 1, 11)]; - if (activeIndex.value === 1) month.value = [Math.max(dayjs(date).month() - 1, 0), dayjs(date).month()]; - } - } - // 有时间选择器走 confirm 逻辑 if (props.enableTimePicker) return; @@ -227,28 +216,16 @@ export default defineComponent({ next = addMonth(current, monthCount); } - const nextYear = [...year.value]; + let nextYear = [...year.value]; nextYear[partialIndex] = next.getFullYear(); - const nextMonth = [...month.value]; + let nextMonth = [...month.value]; nextMonth[partialIndex] = next.getMonth(); + const onlyYearSelect = ['year', 'quarter', 'month'].includes(props.mode); - // 保证左侧时间不大于右侧 - if (partialIndex === 0) { - nextYear[1] = Math.max(nextYear[0], nextYear[1]); - - if (nextYear[0] === nextYear[1]) { - nextMonth[1] = Math.max(nextMonth[0], nextMonth[1]); - } - } - - // 保证左侧时间不大于右侧 - if (partialIndex === 1) { - nextYear[0] = Math.min(nextYear[0], nextYear[1]); - - if (nextYear[0] === nextYear[1]) { - nextMonth[0] = Math.min(nextMonth[0], nextMonth[1]); - } - } + // 头部日期切换修正 + const correctedDate = dateCorrection(partialIndex, nextYear, nextMonth, onlyYearSelect); + nextYear = correctedDate.nextYear; + nextMonth = correctedDate.nextMonth; year.value = nextYear; month.value = nextMonth; @@ -364,13 +341,18 @@ export default defineComponent({ let partialIndex = partial === 'start' ? 0 : 1; if (props.enableTimePicker) partialIndex = activeIndex.value; - const nextYear = [...year.value]; + let nextYear = [...year.value]; + let nextMonth = [...month.value]; nextYear[partialIndex] = nextVal; - // 保证左侧时间不大于右侧 - if (partialIndex === 0) nextYear[1] = Math.max(nextYear[0], nextYear[1]); - if (partialIndex === 1) nextYear[0] = Math.min(nextYear[0], nextYear[1]); + const onlyYearSelect = ['year', 'quarter', 'month'].includes(props.mode); + + // 头部日期切换修正 + const correctedDate = dateCorrection(partialIndex, nextYear, nextMonth, onlyYearSelect); + nextYear = correctedDate.nextYear; + nextMonth = correctedDate.nextMonth; year.value = nextYear; + if (!onlyYearSelect) month.value = nextMonth; } function onMonthChange(nextVal: number, { partial }: { partial: DateRangePickerPartial }) { @@ -381,8 +363,29 @@ export default defineComponent({ nextMonth[partialIndex] = nextVal; // 保证左侧时间不大于右侧 if (year.value[0] === year.value[1]) { - if (partialIndex === 0) nextMonth[1] = Math.max(nextMonth[0], nextMonth[1]); - if (partialIndex === 1) nextMonth[0] = Math.min(nextMonth[0], nextMonth[1]); + if (partialIndex === 0) { + // 操作了左侧区间, 处理右侧区间小于或等于左侧区间的场景,交互上始终报错右侧比左侧大 1 + if (nextMonth[1] <= nextMonth[0]) { + nextMonth[1] = nextMonth[0] + 1; + if (nextMonth[1] === 12) { + // 处理跨年的边界场景 + nextMonth[1] = 0; + year.value = [year.value?.[0], year.value?.[1] + 1]; + } + } + } + if (partialIndex === 1) { + // 操作了右侧区间, 处理右侧区间小于或等于左侧区间的场景,交互上始终报错左侧比右侧小 1 + nextMonth[0] = Math.min(nextMonth[0], nextMonth[1]); + if (nextMonth[0] >= nextMonth[1]) { + nextMonth[0] -= 1; + if (nextMonth[0] === -1) { + // 处理跨年的边界场景 + nextMonth[0] = 11; + year.value = [year.value?.[0] - 1, year.value?.[1]]; + } + } + } } month.value = nextMonth; diff --git a/src/date-picker/DateRangePickerPanel.tsx b/src/date-picker/DateRangePickerPanel.tsx index 592363b4d..486e00c50 100644 --- a/src/date-picker/DateRangePickerPanel.tsx +++ b/src/date-picker/DateRangePickerPanel.tsx @@ -17,6 +17,7 @@ import TRangePanel from './panel/RangePanel'; import useRangeValue from './hooks/useRangeValue'; import { formatDate, getDefaultFormat, parseToDayjs } from '../_common/js/date-picker/format'; import { subtractMonth, addMonth, extractTimeObj } from '../_common/js/date-picker/utils'; +import { dateCorrection } from './utils'; export default defineComponent({ name: 'TDateRangePickerPanel', @@ -147,28 +148,16 @@ export default defineComponent({ next = addMonth(current, monthCount); } - const nextYear = [...year.value]; + let nextYear = [...year.value]; nextYear[partialIndex] = next.getFullYear(); - const nextMonth = [...month.value]; + let nextMonth = [...month.value]; nextMonth[partialIndex] = next.getMonth(); + const onlyYearSelect = ['year', 'quarter', 'month'].includes(props.mode); - // 保证左侧时间不大于右侧 - if (partialIndex === 0) { - nextYear[1] = Math.max(nextYear[0], nextYear[1]); - - if (nextYear[0] === nextYear[1]) { - nextMonth[1] = Math.max(nextMonth[0], nextMonth[1]); - } - } - - // 保证左侧时间不大于右侧 - if (partialIndex === 1) { - nextYear[0] = Math.min(nextYear[0], nextYear[1]); - - if (nextYear[0] === nextYear[1]) { - nextMonth[0] = Math.min(nextMonth[0], nextMonth[1]); - } - } + // 头部日期切换修正 + const correctedDate = dateCorrection(partialIndex, nextYear, nextMonth, onlyYearSelect); + nextYear = correctedDate.nextYear; + nextMonth = correctedDate.nextMonth; if (year.value.some((y) => !nextYear.includes(y))) { props.onYearChange?.({ @@ -301,13 +290,19 @@ export default defineComponent({ let partialIndex = partial === 'start' ? 0 : 1; if (props.enableTimePicker) partialIndex = activeIndex.value; - const nextYear = [...year.value]; + let nextYear = [...year.value]; nextYear[partialIndex] = nextVal; - // 保证左侧时间不大于右侧 - if (partialIndex === 0) nextYear[1] = Math.max(nextYear[0], nextYear[1]); - if (partialIndex === 1) nextYear[0] = Math.min(nextYear[0], nextYear[1]); + let nextMonth = [...month.value]; + // 年/季度/月份场景下,头部只有年选择器 + const onlyYearSelect = ['year', 'quarter', 'month'].includes(props.mode); + + // 头部日期切换修正 + const correctedDate = dateCorrection(partialIndex, nextYear, nextMonth, onlyYearSelect); + nextYear = correctedDate.nextYear; + nextMonth = correctedDate.nextMonth; year.value = nextYear; + if (!onlyYearSelect) month.value = nextMonth; props.onYearChange?.({ partial, @@ -331,8 +326,29 @@ export default defineComponent({ nextMonth[partialIndex] = nextVal; // 保证左侧时间不大于右侧 if (year[0] === year[1]) { - if (partialIndex === 0) nextMonth[1] = Math.max(nextMonth[0], nextMonth[1]); - if (partialIndex === 1) nextMonth[0] = Math.min(nextMonth[0], nextMonth[1]); + if (partialIndex === 0) { + // 操作了左侧区间, 处理右侧区间小于或等于左侧区间的场景,交互上始终报错右侧比左侧大 1 + if (nextMonth[1] <= nextMonth[0]) { + nextMonth[1] = nextMonth[0] + 1; + if (nextMonth[1] === 12) { + // 处理跨年的边界场景 + nextMonth[1] = 0; + year.value = [year.value?.[0], year.value?.[1] + 1]; + } + } + } + if (partialIndex === 1) { + // 操作了右侧区间, 处理右侧区间小于或等于左侧区间的场景,交互上始终报错左侧比右侧小 1 + nextMonth[0] = Math.min(nextMonth[0], nextMonth[1]); + if (nextMonth[0] >= nextMonth[1]) { + nextMonth[0] -= 1; + if (nextMonth[0] === -1) { + // 处理跨年的边界场景 + nextMonth[0] = 11; + year.value = [year.value?.[0] - 1, year.value?.[1]]; + } + } + } } month.value = nextMonth; diff --git a/src/date-picker/utils.ts b/src/date-picker/utils.ts new file mode 100644 index 000000000..44c3ce2cb --- /dev/null +++ b/src/date-picker/utils.ts @@ -0,0 +1,49 @@ +// 用于头部日期切换修正 +// eslint-disable-next-line import/prefer-default-export +export function dateCorrection( + partialIndex: number, + preYear: Array, + preMonth: Array, + onlyYearSelect: boolean, +) { + let nextYear = preYear; + const nextMonth = preMonth; + if (partialIndex === 0) { + if (nextYear[1] <= nextYear[0]) { + if (onlyYearSelect) nextYear[1] = nextYear[0] + 1; + else { + // eslint-disable-next-line prefer-destructuring + nextYear[1] = nextYear[0]; + if (nextMonth[1] <= nextMonth[0]) { + nextMonth[1] = nextMonth[0] + 1; + if (nextMonth[1] === 12) { + // 处理跨年的边界场景 + nextMonth[1] = 0; + nextYear = [nextYear[0], nextYear[1] + 1]; + } + } + } + } + } + + // 保证左侧时间不大于右侧 + if (partialIndex === 1) { + if (nextYear[0] >= nextYear[1]) { + // 年/季度/月份场景下,头部只有年选择器,直接 - 1 + if (onlyYearSelect) nextYear[0] = nextYear[1] - 1; + else { + // eslint-disable-next-line prefer-destructuring + nextYear[0] = nextYear[1]; + if (nextMonth[0] >= nextMonth[1]) { + nextMonth[0] = nextMonth[1] - 1; + if (nextMonth[0] === -1) { + // 处理跨年的边界场景 + nextMonth[0] = 11; + nextYear = [nextYear[0] - 1, nextYear[1]]; + } + } + } + } + } + return { nextYear, nextMonth }; +}