日期范围选择

    1. import { useMemo, useCallback, useEffect } from 'react';
    2. import moment, { Moment, DurationInputArg2 } from 'moment';
    3. import { useSetState } from '../index';
    4. const formatType = 'YYYY-MM-DD HH:mm:ss';
    5. const formatDate = (date: string | Moment | undefined | null, formatString = formatType) =>
    6. moment(date).format(formatString);
    7. export type RangeType = 'none' | 'same' | number | undefined;
    8. export interface RangeDateCfg {
    9. /** 开始 结束时间 只有在 type === 'range' 有用 */
    10. start?: string | null;
    11. end?: string | null;
    12. /** 区间 或 单个 时间 */
    13. type: 'range' | 'date';
    14. /** 范围 */
    15. range?: RangeType;
    16. /** 计算单位 */
    17. unit?: DurationInputArg2;
    18. /** 格式化参数 */
    19. formatStr?: string;
    20. }
    21. export interface RangeDateState<T> {
    22. range: RangeType;
    23. date: T;
    24. }
    25. const getDateByType = (dateStr: string | string[]) => {
    26. if (!Array.isArray(dateStr)) {
    27. return [dateStr, dateStr];
    28. }
    29. return dateStr;
    30. };
    31. const useRangeDate = <T = string | string[]>(state: RangeDateCfg = {} as RangeDateCfg) => {
    32. const { start, end, type = 'range', range } = state;
    33. const initDate = ((type === 'range' ? [] : '') as unknown) as T;
    34. /** none: 表示任何都不选择 */
    35. const [rangeDate, setRangeDate] = useSetState<RangeDateState<T>>({
    36. range,
    37. date: initDate,
    38. });
    39. /** 处理计算格式 && 格式化参数 */
    40. const unit = useMemo(() => state.unit ?? 'days', [state.unit]);
    41. const fmtStr = useMemo(() => state.formatStr ?? 'YYYY-MM-DD', [state.formatStr]);
    42. useEffect(() => {
    43. if (range !== undefined && range !== 'none') {
    44. console.log(unit, ';unit');
    45. const newDate = moment().subtract(range, unit).format(fmtStr);
    46. setRangeDate({ date: (newDate as unknown) as T });
    47. }
    48. }, [range]);
    49. useEffect(() => {
    50. /** same: 表示和 开始 及 结束重叠 */
    51. if (start && end && type === 'range') {
    52. setRangeDate({ range: 'same', date: ([start, end] as unknown) as T });
    53. }
    54. }, [start, end]);
    55. /** setRange: 暂时不支持回调 */
    56. const setRange = useCallback(
    57. (val: RangeType, unitType?: DurationInputArg2, fStr?: string) => {
    58. /** 当 type === 'range', same 回填初始状态 */
    59. if (val === 'same') {
    60. setRangeDate({ range: val, date: ([start, end] as unknown) as T });
    61. return;
    62. }
    63. const u = unitType ?? unit;
    64. const newFstr = fStr ?? fmtStr;
    65. const sDate = formatDate(moment().subtract(val, u), fmtStr);
    66. const eDate = formatDate(moment(), newFstr);
    67. const fillDate = type === 'date' ? sDate : [sDate, eDate];
    68. setRangeDate({ range: val, date: (fillDate as unknown) as T });
    69. },
    70. [setRangeDate, start, end],
    71. );
    72. const changeDate = useCallback(
    73. <R>(_: R, dateStr: string | string[]) => {
    74. const [startStr, endStr] = getDateByType(dateStr);
    75. const isSame =
    76. type === 'range'
    77. ? startStr === start && endStr === end
    78. : startStr === formatDate(moment().subtract(range, unit), fmtStr);
    79. const newDate = type === 'range' ? [startStr, endStr] : startStr;
    80. setRangeDate({
    81. date: newDate as any,
    82. range: isSame ? range ?? 'same' : 'none',
    83. });
    84. },
    85. [setRangeDate, start, end],
    86. );
    87. return [rangeDate, { changeDate, setRange, setRangeDate }] as const;
    88. };
    89. export default useRangeDate;