日期范围选择
import { useMemo, useCallback, useEffect } from 'react';
import moment, { Moment, DurationInputArg2 } from 'moment';
import { useSetState } from '../index';
const formatType = 'YYYY-MM-DD HH:mm:ss';
const formatDate = (date: string | Moment | undefined | null, formatString = formatType) =>
moment(date).format(formatString);
export type RangeType = 'none' | 'same' | number | undefined;
export interface RangeDateCfg {
/** 开始 结束时间 只有在 type === 'range' 有用 */
start?: string | null;
end?: string | null;
/** 区间 或 单个 时间 */
type: 'range' | 'date';
/** 范围 */
range?: RangeType;
/** 计算单位 */
unit?: DurationInputArg2;
/** 格式化参数 */
formatStr?: string;
}
export interface RangeDateState<T> {
range: RangeType;
date: T;
}
const getDateByType = (dateStr: string | string[]) => {
if (!Array.isArray(dateStr)) {
return [dateStr, dateStr];
}
return dateStr;
};
const useRangeDate = <T = string | string[]>(state: RangeDateCfg = {} as RangeDateCfg) => {
const { start, end, type = 'range', range } = state;
const initDate = ((type === 'range' ? [] : '') as unknown) as T;
/** none: 表示任何都不选择 */
const [rangeDate, setRangeDate] = useSetState<RangeDateState<T>>({
range,
date: initDate,
});
/** 处理计算格式 && 格式化参数 */
const unit = useMemo(() => state.unit ?? 'days', [state.unit]);
const fmtStr = useMemo(() => state.formatStr ?? 'YYYY-MM-DD', [state.formatStr]);
useEffect(() => {
if (range !== undefined && range !== 'none') {
console.log(unit, ';unit');
const newDate = moment().subtract(range, unit).format(fmtStr);
setRangeDate({ date: (newDate as unknown) as T });
}
}, [range]);
useEffect(() => {
/** same: 表示和 开始 及 结束重叠 */
if (start && end && type === 'range') {
setRangeDate({ range: 'same', date: ([start, end] as unknown) as T });
}
}, [start, end]);
/** setRange: 暂时不支持回调 */
const setRange = useCallback(
(val: RangeType, unitType?: DurationInputArg2, fStr?: string) => {
/** 当 type === 'range', same 回填初始状态 */
if (val === 'same') {
setRangeDate({ range: val, date: ([start, end] as unknown) as T });
return;
}
const u = unitType ?? unit;
const newFstr = fStr ?? fmtStr;
const sDate = formatDate(moment().subtract(val, u), fmtStr);
const eDate = formatDate(moment(), newFstr);
const fillDate = type === 'date' ? sDate : [sDate, eDate];
setRangeDate({ range: val, date: (fillDate as unknown) as T });
},
[setRangeDate, start, end],
);
const changeDate = useCallback(
<R>(_: R, dateStr: string | string[]) => {
const [startStr, endStr] = getDateByType(dateStr);
const isSame =
type === 'range'
? startStr === start && endStr === end
: startStr === formatDate(moment().subtract(range, unit), fmtStr);
const newDate = type === 'range' ? [startStr, endStr] : startStr;
setRangeDate({
date: newDate as any,
range: isSame ? range ?? 'same' : 'none',
});
},
[setRangeDate, start, end],
);
return [rangeDate, { changeDate, setRange, setRangeDate }] as const;
};
export default useRangeDate;