Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
44a75c4
fix: 修复在next.js环境下的报错
Passing-of-A-Dream Jul 29, 2025
3fbe174
refactor(deps): 从 ahooks 的 useIsomorphicLayoutEffect 迁移到 rc-util 的 us…
Passing-of-A-Dream Jul 30, 2025
a71a9dd
Merge branch 'ant-design:master' into master
Passing-of-A-Dream Jul 30, 2025
6a4811f
Merge branch 'ant-design:master' into master
Passing-of-A-Dream Aug 6, 2025
398f75b
Merge branch 'ant-design:master' into master
Passing-of-A-Dream Aug 11, 2025
585573e
Merge branch 'ant-design:master' into master
Passing-of-A-Dream Aug 11, 2025
db7ed93
Merge branch 'ant-design:master' into master
Passing-of-A-Dream Aug 19, 2025
f232314
refactor(DatePicker): 增加columns列,用于控制列显示
Passing-of-A-Dream Sep 2, 2025
9f645e5
test(DatePicker): 增加测试用例
Passing-of-A-Dream Sep 2, 2025
a0d3b28
refactor(DatePicker): 将列常量类型定义为常量,优化导入方式
Passing-of-A-Dream Sep 2, 2025
222386c
feat(DatePicker): 增强日期选择器,支持自定义列和默认值处理
Passing-of-A-Dream Sep 3, 2025
f652cf4
fix(DatePicker): 优化日期选择器列生成逻辑,确保列精度正确过滤
Passing-of-A-Dream Sep 3, 2025
1f737b4
refactor(DatePicker): 优化生成日期选择器列的逻辑,使用映射关系简化代码
Passing-of-A-Dream Sep 8, 2025
6c73792
chore: trigger CI/CD pipeline
Passing-of-A-Dream Sep 8, 2025
687940b
refactor: 优化日期选择器日期转换逻辑
Passing-of-A-Dream Sep 16, 2025
fd37168
fix: 修复日期选择器列生成逻辑
Passing-of-A-Dream Sep 16, 2025
2b131b5
refactor: 优化日期选择器列生成逻辑
Passing-of-A-Dream Sep 16, 2025
3488ea9
refactor: 优化日期选择器工具函数逻辑
Passing-of-A-Dream Sep 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 145 additions & 87 deletions src/components/date-picker/date-picker-date-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import isoWeeksInYear from 'dayjs/plugin/isoWeeksInYear'
import { RenderLabel } from '../date-picker-view/date-picker-view'
import { PickerColumn } from '../picker'
import type { DatePickerFilter } from './date-picker-utils'
import { TILL_NOW } from './util'
import {
DateColumnType,
DAY_COLUMN,
HOUR_COLUMN,
MINUTE_COLUMN,
MONTH_COLUMN,
SECOND_COLUMN,
TILL_NOW,
YEAR_COLUMN,
} from './util'

dayjs.extend(isoWeek)
dayjs.extend(isoWeeksInYear)
Expand All @@ -28,14 +37,31 @@ const precisionRankRecord: Record<DatePrecision, number> = {
second: 5,
}

const columnToPrecisionMap: Record<DateColumnType, DatePrecision> = {
[YEAR_COLUMN]: 'year',
[MONTH_COLUMN]: 'month',
[DAY_COLUMN]: 'day',
[HOUR_COLUMN]: 'hour',
[MINUTE_COLUMN]: 'minute',
[SECOND_COLUMN]: 'second',
}

function getDefaultColumns(precision: DatePrecision): DateColumnType[] {
const rank = precisionRankRecord[precision]
return (Object.keys(columnToPrecisionMap) as DateColumnType[]).filter(
columnType => rank >= precisionRankRecord[columnToPrecisionMap[columnType]]
)
}

export function generateDatePickerColumns(
selected: string[],
min: Date,
max: Date,
precision: DatePrecision,
renderLabel: RenderLabel,
filter: DatePickerFilter | undefined,
tillNow?: boolean
tillNow?: boolean,
columns?: DateColumnType[]
) {
const ret: PickerColumn[] = []

Expand All @@ -54,16 +80,30 @@ export function generateDatePickerColumns(
const maxSecond = max.getSeconds()

const rank = precisionRankRecord[precision]
const defaultColumns = getDefaultColumns(precision)
const finalColumns = columns?.length ? columns : defaultColumns
const renderedColumns = finalColumns.filter(columnType => {
const columnPrecision = columnToPrecisionMap[columnType]
return rank >= precisionRankRecord[columnPrecision]
})
function getValue(type: DateColumnType): number | null {
const index = renderedColumns.indexOf(type)
if (index >= 0 && index < selected.length) {
const val = parseInt(selected[index], 10)
return isNaN(val) ? null : val
}
return null
}

const selectedYear = parseInt(selected[0])
const selectedYear = getValue(YEAR_COLUMN) ?? min.getFullYear()
const selectedMonth = getValue(MONTH_COLUMN) ?? 1
const selectedDay = getValue(DAY_COLUMN) ?? 1
const selectedHour = getValue(HOUR_COLUMN) ?? 0
const selectedMinute = getValue(MINUTE_COLUMN) ?? 0
const selectedSecond = getValue(SECOND_COLUMN) ?? 0
const firstDayInSelectedMonth = dayjs(
convertStringArrayToDate([selected[0], selected[1], '1'])
new Date(selectedYear, selectedMonth - 1, 1)
)
const selectedMonth = parseInt(selected[1])
const selectedDay = parseInt(selected[2])
const selectedHour = parseInt(selected[3])
const selectedMinute = parseInt(selected[4])
const selectedSecond = parseInt(selected[5])

const isInMinYear = selectedYear === minYear
const isInMaxYear = selectedYear === maxYear
Expand All @@ -79,99 +119,97 @@ export function generateDatePickerColumns(
const generateColumn = (
from: number,
to: number,
precision: DatePrecision
precision: DatePrecision,
columnType: DateColumnType
) => {
let column: number[] = []
for (let i = from; i <= to; i++) {
column.push(i)
}
const prefix = selected.slice(0, precisionRankRecord[precision])
const pos = Math.max(0, renderedColumns.indexOf(columnType))
const prefix = selected.slice(0, pos)
const partialColumns = renderedColumns.slice(0, pos).concat(columnType)
const currentFilter = filter?.[precision]
if (currentFilter && typeof currentFilter === 'function') {
column = column.filter(i =>
currentFilter(i, {
get date() {
const stringArray = [...prefix, i.toString()]
return convertStringArrayToDate(stringArray)
return convertStringArrayToDate(
stringArray,
partialColumns,
precision
)
},
})
)
}
return column
}

if (rank >= precisionRankRecord.year) {
const lower = minYear
const upper = maxYear
const years = generateColumn(lower, upper, 'year')
ret.push(
years.map(v => ({
label: renderLabel('year', v, { selected: selectedYear === v }),
value: v.toString(),
}))
)
const columnConfigs = {
[YEAR_COLUMN]: {
lower: minYear,
upper: maxYear,
selected: selectedYear,
precision: 'year' as DatePrecision,
},
[MONTH_COLUMN]: {
lower: isInMinYear ? minMonth : 1,
upper: isInMaxYear ? maxMonth : 12,
selected: selectedMonth,
precision: 'month' as DatePrecision,
},
[DAY_COLUMN]: {
lower: isInMinMonth ? minDay : 1,
upper: isInMaxMonth ? maxDay : firstDayInSelectedMonth.daysInMonth(),
selected: selectedDay,
precision: 'day' as DatePrecision,
},
[HOUR_COLUMN]: {
lower: isInMinDay ? minHour : 0,
upper: isInMaxDay ? maxHour : 23,
selected: selectedHour,
precision: 'hour' as DatePrecision,
},
[MINUTE_COLUMN]: {
lower: isInMinHour ? minMinute : 0,
upper: isInMaxHour ? maxMinute : 59,
selected: selectedMinute,
precision: 'minute' as DatePrecision,
},
[SECOND_COLUMN]: {
lower: isInMinMinute ? minSecond : 0,
upper: isInMaxMinute ? maxSecond : 59,
selected: selectedSecond,
precision: 'second' as DatePrecision,
},
}

if (rank >= precisionRankRecord.month) {
const lower = isInMinYear ? minMonth : 1
const upper = isInMaxYear ? maxMonth : 12
const months = generateColumn(lower, upper, 'month')
ret.push(
months.map(v => ({
label: renderLabel('month', v, { selected: selectedMonth === v }),
value: v.toString(),
}))
)
}
if (rank >= precisionRankRecord.day) {
const lower = isInMinMonth ? minDay : 1
const upper = isInMaxMonth ? maxDay : firstDayInSelectedMonth.daysInMonth()
const days = generateColumn(lower, upper, 'day')
ret.push(
days.map(v => ({
label: renderLabel('day', v, { selected: selectedDay === v }),
value: v.toString(),
}))
)
}
if (rank >= precisionRankRecord.hour) {
const lower = isInMinDay ? minHour : 0
const upper = isInMaxDay ? maxHour : 23
const hours = generateColumn(lower, upper, 'hour')
ret.push(
hours.map(v => ({
label: renderLabel('hour', v, { selected: selectedHour === v }),
value: v.toString(),
}))
)
}
if (rank >= precisionRankRecord.minute) {
const lower = isInMinHour ? minMinute : 0
const upper = isInMaxHour ? maxMinute : 59
const minutes = generateColumn(lower, upper, 'minute')
ret.push(
minutes.map(v => ({
label: renderLabel('minute', v, { selected: selectedMinute === v }),
value: v.toString(),
}))
renderedColumns.forEach(columnType => {
const config = columnConfigs[columnType]
if (!config) return

const column = generateColumn(
config.lower,
config.upper,
config.precision,
columnType
)
}
if (rank >= precisionRankRecord.second) {
const lower = isInMinMinute ? minSecond : 0
const upper = isInMaxMinute ? maxSecond : 59
const seconds = generateColumn(lower, upper, 'second')
ret.push(
seconds.map(v => ({
label: renderLabel('second', v, { selected: selectedSecond === v }),
column.map(v => ({
label: renderLabel(config.precision, v, {
selected: config.selected === v,
}),
value: v.toString(),
}))
)
}
})

// Till Now
if (tillNow) {
if (tillNow && ret.length > 0) {
ret[0].push({
label: renderLabel('now', null!, { selected: selected[0] === TILL_NOW }),
label: renderLabel('now', 0, { selected: selected[0] === TILL_NOW }),
value: TILL_NOW,
})

Expand Down Expand Up @@ -201,19 +239,39 @@ export function convertDateToStringArray(

export function convertStringArrayToDate<
T extends string | number | null | undefined,
>(value: T[]): Date {
const yearString = value[0] ?? '1900'
const monthString = value[1] ?? '1'
const dateString = value[2] ?? '1'
const hourString = value[3] ?? '0'
const minuteString = value[4] ?? '0'
const secondString = value[5] ?? '0'
>(
value: T[],
columns: DateColumnType[] | undefined,
precision: DatePrecision
): Date {
let finalColumns = columns
if (!finalColumns || finalColumns.length === 0) {
finalColumns = getDefaultColumns(precision)
}

const now = new Date()
const dateParts = {
[YEAR_COLUMN]: now.getFullYear().toString(),
[MONTH_COLUMN]: (now.getMonth() + 1).toString(),
[DAY_COLUMN]: now.getDate().toString(),
[HOUR_COLUMN]: now.getHours().toString(),
[MINUTE_COLUMN]: now.getMinutes().toString(),
[SECOND_COLUMN]: now.getSeconds().toString(),
}

finalColumns.forEach((columnType, index) => {
const val = value[index]
if (val !== null && val !== undefined) {
dateParts[columnType] = val.toString()
}
})

return new Date(
parseInt(yearString as string),
parseInt(monthString as string) - 1,
parseInt(dateString as string),
parseInt(hourString as string),
parseInt(minuteString as string),
parseInt(secondString as string)
parseInt(dateParts[YEAR_COLUMN]),
parseInt(dateParts[MONTH_COLUMN]) - 1,
parseInt(dateParts[DAY_COLUMN]),
parseInt(dateParts[HOUR_COLUMN]),
parseInt(dateParts[MINUTE_COLUMN]),
parseInt(dateParts[SECOND_COLUMN])
)
}
Loading
Loading