示例:
相关包安装
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,
},
];