import React from "react"; import moment, { Moment } from "moment"; import Table, { CellStatus } from "./BaseTable"; import { useTranslation } from "../../i18n"; import { RangeDateType, CalendarTableType, DateChangeContext, } from "../DateProps"; import { useConfig } from "../../_util/config-context"; import { noop } from "../../_util/noop"; import { getNow, isAfter, isBefore, isSame } from "../../datepicker/util"; export interface DateTableProps { /** * 当前展示日期 */ current: Moment; /** * 当前选中的日期 */ value: Moment; /** * 允许选择的时间范围限制 */ range?: RangeDateType; /** * 可选的日期范围 */ disabledDate?: (date: Moment) => boolean; /** * Cell 渲染状态 */ cellStatus?: (date: Moment) => CellStatus; /** * 选中回调 */ onSelect?: (value: Moment, context: DateChangeContext) => void; /** * type 变更回调 */ onTypeChange?: (type: CalendarTableType) => void; /** * 当前展示日期变更回调 */ onCurrentChange?: ( current: Moment, context?: { from?: "jumper" | "outside-date" } ) => void; /** * 当前展示日期变更回调 */ onHoveredChange?: (hovered: Moment) => void; /** * 范围选择中日期的范围 * 解决范围选择中相邻月间交错日期不可点的问题 */ dateRangeInRangePicker?: RangeDateType; } export function DateTable({ current, onCurrentChange = noop, onHoveredChange = noop, range, disabledDate, onSelect = noop, onTypeChange = noop, cellStatus = () => CellStatus.Common, dateRangeInRangePicker, }: DateTableProps) { const t = useTranslation(); const { classPrefix } = useConfig(); const month = current.month(); const now = getNow(current); function genTable(): Moment[][] { const table = []; // 本月第一天 // 从 current clone 保持 value 的时区等信息 const first = moment(current).set({ date: 1, hour: 0, minute: 0, second: 0, millisecond: 0, }); const firstDay = first.day(); // 第一周 const firstWeek = Array(7) .fill(null) .map((_, i) => first.clone().add(i - firstDay, "d")); table.push(firstWeek); let nextWeekFirst = firstWeek[6].clone().add(1, "d"); while (nextWeekFirst.month() === month) { const week = Array(7) .fill(null) .map((_, i) => nextWeekFirst.clone().add(i, "d")); // eslint-disable-line no-loop-func table.push(week); nextWeekFirst = week[6].clone().add(1, "d"); } return table; } function renderYear() { return ( onTypeChange("year")}> {current.format(t.yearFormat)} ); } function renderMonth() { return ( onTypeChange("month")}> {moment.monthsShort(month)} ); } const [rangeMin, rangeMax] = range || [null, null]; function isValidDate(date) { // 非 RangePicker if (typeof dateRangeInRangePicker === "undefined") { if (moment.isMoment(rangeMin) && isAfter(rangeMin, date, "day")) { return false; } if (moment.isMoment(rangeMax) && isBefore(rangeMax, date, "day")) { return false; } } else { // RangePicker const [aRangeMin, aRangeMax] = dateRangeInRangePicker; if (moment.isMoment(aRangeMin) && isAfter(aRangeMin, date, "day")) { return false; } if (moment.isMoment(aRangeMax) && isBefore(aRangeMax, date, "day")) { return false; } } return disabledDate(date); } return ( {renderMonth()} {renderYear()} ) : ( <> {renderYear()} {renderMonth()} ) } jumperOptions={{ onNext: () => onCurrentChange(moment(current).add(1, "month"), { from: "jumper" }), onPrev: () => onCurrentChange(moment(current).subtract(1, "month"), { from: "jumper", }), onCurrent: () => onCurrentChange(now, { from: "jumper" }), isCurrent: isSame(current, now, "month"), nextDisabled: moment.isMoment(rangeMax) && isBefore( rangeMax, moment(current) .set({ date: 1, }) .add(1, "month"), "day" ), prevDisabled: moment.isMoment(rangeMin) && isAfter( rangeMin, moment(current) .set({ date: 1, }) .subtract(1, "day"), "day" ), nextTitle: t.nextMonth, prevTitle: t.prevMonth, curTitle: t.curMonth, }} > {/* 周 */}
{moment.weekdaysMin().map(name => ( ))}
{genTable().map((week, i) => ( {week.map((date, j) => ( onCurrentChange(date.clone(), { from: "outside-date" }) } onHoveredChange={onHoveredChange} /> ))} ))}
); } DateTable.displayName = "DateTable";