antd封装多态时间选择器(包含日,可选近7日,近30日,周,月)react+moment+antd+ts

示例:

相关包安装

npm i antd --S

npm i moment --S

代码文件 

模块date-pickers
import React, { useState } from 'react';
import { DatePicker, } from 'antd';
import moment from 'moment';
import { cycleList } from './cycleList';
import './index.less';

/**
 * 使用示例
 * <DatePickers
      timingChange={(time) => {
      // console.log(time, 'timingChange');
      // time:{ start:string ,endTime: string, timeInfo: 1 | 7 | 30 | 'week' | 'month' }
      }}
      defaultValue={defaultValue}
    />
 */

/* --------------------------- 类型定义  --------------------------- */
interface TimingPropsType {
  /**
   * 日期变换的change
   * - {startTime,endTime,timeInfo}
   *  */
  timingChange?: (params: any) => void;
  /** 当前不支持区间选择,默认统一使用昨天的时间 */
  defaultValue?: {
    /** 结束时间 */
    endTime: string,
    /** 默认时间类型 */
    timeInfo?: CycleStateType | any,
  }
};
type CycleStateType = 1 | 7 | 30 | 'week' | 'month';

// * ****************************** 通用方法 ****************************** * //
// ? ------------------------------ 时间选择器,默认时间获取态 ------------------------------ ? //

/** 获取上周日 */
export const getLastSundayOfPreviousWeek = () => {
  const today = moment();
  // 先移动到本周周一
  const thisMonday = today.startOf('isoWeek');
  // 然后回退一周得到上周周一
  const lastMonday = thisMonday.clone().subtract(1, 'weeks');
  // 最后移动到上周周日
  const lastSunday = lastMonday.clone().add(6, 'days');
  return lastSunday;
};

/** 昨天 */
const TODAY = moment();
/** 移动到上个月第一天 */
const firstDayOfPrevMonth = TODAY.clone().subtract(1, 'months').startOf('month');

/** 获取上个月最后一天 */
const getLastDayOfPreviousMonth = () => {
  // 然后移动到最后一天
  const lastDayOfPrevMonth = firstDayOfPrevMonth.clone().endOf('month');
  return lastDayOfPrevMonth;
};

/** 获取某个月的第一天 */
function getFirstDayOfMonth(day: any) {
  // 注意:moment构造函数中的月份是从0开始计数的,所以需要减1
  return moment(day).startOf('month').format('YYYY-MM-DD');
};

// ? ------------------------------ 时间选择器,周选择change获取 ------------------------------ ? //

const getLastDayOfWeek = (day: any) => {
  return moment(day).endOf('isoWeek');
};

// ! ------------------------------ 时间选择器,统一计算开始时间 ------------------------------ ! //

/** 获取开始时间 */
const getStartTime = (obj: {
  endTime: string,
  interval: CycleStateType,
}) => {
  const { endTime, interval } = obj || {};

  let NEW_interval = interval;
  if (NEW_interval !== 'month') {
    if (NEW_interval === 'week') {
      NEW_interval = 7
    }
    return moment(endTime).subtract(NEW_interval - 1, 'days').format('YYYY-MM-DD');
  } else {
    /** 月份选择时不可以天数为计算,要以xx月1号作为标点 */
    return getFirstDayOfMonth(endTime);
  }
};


/** 昨天-字符串 */
const YESTERDAY = TODAY.subtract(1, 'days').format('YYYY-MM-DD');

/** 时间选择器模块 */
export default function DatePickers(
  props: TimingPropsType
) {
  const {
    timingChange,
    defaultValue
  } = props;
  const {
    timeInfo,
  } = defaultValue || {};
  const [cycleState, setCycleState] = useState<CycleStateType>(timeInfo || 7);// 时间区间
  const [showCycle, set_showCycle] = useState({
    startTime: getStartTime({ endTime: defaultValue?.endTime || YESTERDAY, interval: defaultValue?.timeInfo || 7 }),
    endTime: defaultValue?.endTime || YESTERDAY,
  });// 时间
  const { endTime } = showCycle;


  /** 统一处理选择器:修改当前模块,修改上层模块 */
  const cycleListRadioChange = (e: {
    endTime: string;
    timeInfo: CycleStateType;
  }) => {
    const { endTime, timeInfo, } = e || {};
    const START_TIME = getStartTime({ endTime, interval: timeInfo });
    const showCycle = {
      startTime: START_TIME,
      endTime,
      timeInfo: timeInfo
    };
    // ! 通知上层日期修改完成
    if (timingChange) {
      timingChange(showCycle);
    }
    // ? 修改当前组建状态
    set_showCycle(showCycle);
    // ? 修改当前组建区间
    setCycleState(timeInfo);
  };

  /** 禁用日期 */
  const disabledDate = (obj: any) => {
    const {
      current,
      cycleListItem,
    } = obj;
    if (cycleListItem?.value === 'week') {
      return current.valueOf() > getLastSundayOfPreviousWeek();
    } else if (cycleListItem?.value === 'month') {
      return current.valueOf() > getLastDayOfPreviousMonth();
    } else {
      return current.valueOf() >= moment().startOf('day').valueOf();
    }
  };

  return (
    <div className='date_detail_search_DatePicker_box'>
      <div className='time-interval'>
        时间:
        {showCycle?.startTime !== showCycle?.endTime && `${showCycle?.startTime} 至 `}
        {showCycle?.endTime}
      </div>
      <div className="DatePicker_list_box">
        {cycleList.map((item: { value: any; label: any; interval: number; }) => {
          return (
            <DatePicker
              id={`date_detail_search_ljn_DatePicker_${item?.value}`}
              placement="bottomRight"
              className={cycleState === item?.value ? "ant-radio-button-wrapper-checked" : ""}
              allowClear={false}
              suffixIcon={null}
              showToday={false}
              picker={
                item?.value === 'week' || item?.value === 'month'
                  ? item?.value
                  : 'date'}
              format={item?.label}
              value={moment(showCycle?.endTime)}

              disabledDate={(current) => disabledDate({ current, cycleListItem: item })}
              dateRender={current => {
                const style: React.CSSProperties = {};
                let DIV_CLASS = "";
                /** 指定日-近7天-近30天的高亮 */
                if (item?.value === 7 || item?.value === 30) {
                  // 周期
                  const START_TIME = moment(endTime).subtract(item?.interval, 'days');
                  // 渲染时间
                  const CURRENT_DATE = moment(current);
                  if (
                    // 日期收否包含在周期内
                    CURRENT_DATE.isBetween(START_TIME, moment(endTime)) ||
                    // 渲染时间是否等于结束时间
                    CURRENT_DATE.format('YYYY-MM-DD') === moment(endTime).format('YYYY-MM-DD')
                  ) {
                    style.color = '#fff';
                    style.background = '#1890ff';
                    DIV_CLASS = "ljn-data-detail-cycle";
                  };
                }
                return (
                  <div className={`${DIV_CLASS} ant-picker-cell-inner`}>
                    {current.date()}
                  </div>
                );
              }}
              onChange={(date, dateString: string) => {
                let END_TIME = moment(date).format('YYYY-MM-DD');
                // ** 周和月计算方式特殊,需要特殊处理 ** //
                if (item?.value === 'week') {
                  END_TIME = getLastDayOfWeek(END_TIME).format('YYYY-MM-DD');
                }
                // 月份选择器在onchange时自动获取结束时间
                const showCycle = {
                  endTime: END_TIME,
                  timeInfo: item?.value,
                  interval: item?.interval,
                };
                cycleListRadioChange(showCycle)
              }}
              onClick={() => {
                if (cycleState !== item?.value) {
                  let END_TIME = YESTERDAY;
                  // ** 周和月计算方式特殊,需要特殊处理 ** //
                  if (item?.value === 'week') {
                    END_TIME = getLastSundayOfPreviousWeek().format('YYYY-MM-DD');
                  } else if (item?.value === 'month') {
                    END_TIME = getLastDayOfPreviousMonth().format('YYYY-MM-DD');
                  }
                  const showCycle = {
                    endTime: END_TIME,
                    timeInfo: item?.value,
                    interval: item?.interval,
                  };
                  cycleListRadioChange(showCycle);
                }
              }}
            />
          );
        })}
      </div>
    </div>
  );
}
less文件
.date_detail_search_DatePicker_box {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  .time-interval{
    font-size: 12px;
    line-height: 12px;
    color: #999999;
    margin-right: 10px;
  }
  .date_detail_search_ljn_DatePicker-cell-inner {
    margin-left: 10px;
  }
  .show-time-box {
    margin-right: 10px;

    >span {
      color: #999;
    }
  }

  .DatePicker_list_box {

    #date_detail_search_ljn_DatePicker_1,
    #date_detail_search_ljn_DatePicker_7,
    #date_detail_search_ljn_DatePicker_30,
    #date_detail_search_ljn_DatePicker_week,
    #date_detail_search_ljn_DatePicker_month {
      caret-color: transparent;
      cursor: pointer;
      color: #333;
    }

    .ant-radio-button-wrapper-checked {

      #date_detail_search_ljn_DatePicker_1,
      #date_detail_search_ljn_DatePicker_7,
      #date_detail_search_ljn_DatePicker_30,
      #date_detail_search_ljn_DatePicker_week,
      #date_detail_search_ljn_DatePicker_month {
        color: #1890ff;
      }
    }

    .ant-picker {
      margin-right: 10px;
      width: auto;
      padding: 0 10px;
      height: 30px;
      border-radius: 6px;
      #date_detail_search_ljn_DatePicker_1 {
        width: 14px;
      }

      #date_detail_search_ljn_DatePicker_7{
        width: 35px;
      }

      #date_detail_search_ljn_DatePicker_30 {
        width: 42px;
      }
      #date_detail_search_ljn_DatePicker_week {
        width: 14px;
      }
      #date_detail_search_ljn_DatePicker_month {
        width: 14px;
      }
    }

    .ant-picker:last-child{
      margin: 0;
    }
  }
}

.ant-picker-dropdown {
  .ant-picker-panel-container {
    .ant-picker-content {
      tbody {
        .ant-picker-cell {
          .ljn-data-detail-cycle {
            color: #fff;
            background: #1890ff;
          }

          .ljn-data-detail-cycle:hover {
            color: #000;
          }
        }
      }
    }
  }
}

ts文件
export const cycleList = [
  {
    label: '日',
    value: 1,
    interval: 1,
  },
  {
    label: '近7天',
    value: 7,
    interval: 7,
  },
  {
    label: '近30天',
    value: 30,
    interval: 30,
  },
  {
    label: '周',
    value: 'week',
    interval: 7,
  },
  {
    label: '月',
    value: 'month',
    interval: 30,
  },
];

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值