需求说明:
某个查询条件的时间选择需要限定是一个月内。即如果开始时间为2021-11-17 11:11:11,则结束时间最晚只能选2021-12-17 11:11:11
开始时间和结束时间相互限制
本来是用RangePicker的,但是看了网上的一些方法,感觉RangePicker不能完美实现,所以这里采用两个DatePicker时间框实现
最终效果:
开始时间根据结束时间,日期和时刻都都有限制。因为结束时间是2021-12-17 02:02:02,所以开始时间最早不能早于2021-11-17 02:02:02
开始时间最晚不能晚于2021-12-17 02:02:02
结束时间根据开始时间同理动态限制。最早不能早于开始时间,最晚不能晚于开始时间的后30天的时刻。
此处的天数也可动态修改
代码如下:
state = {
limitBeginDate: '', // 记录开始时间
limitEndDate: '', // 记录结束时间
}
render里的代码:
const time = type => {
if (this.state[type]) {
return moment(this.state[type]).format('HH:mm:ss');
}
return '00:00:00';
};
<Col span={5}>
<Form.Item label="处理时限" labelCol={{ span: 13 }} wrapperCol={{ span: 11 }}>
{getFieldDecorator('limitBeginDate')(
<DatePicker
showTime={{ defaultValue: moment(time('limitEndDate'), 'HH:mm:ss') }} // 此处必须设置,否则可能出现添加了时间限制但是由于时间框继承之前的时刻导致时刻超出的情况
placeholder="Select Time"
allowClear={false}
onChange={(data, value) => { this.onChangeBeginTime(data, value, 'limitBeginDate', 'limitEndDate'); }}
disabledDate={this.disabledLimitBeginDate}
disabledTime={this.disabledLimitBeginTime}
/>
)}
</Form.Item>
</Col>
<Col span={3}>
<Form.Item wrapperCol={{ span: 21 }} style={{ marginLeft: 20 }}>
{getFieldDecorator('limitEndDate')(
<DatePicker
showTime={{ defaultValue: moment(time('limitBeginDate'), 'HH:mm:ss') }}
placeholder="Select Time"
allowClear={false}
onChange={(data, value) => { this.onChangeEndTime(data, value, 'limitBeginDate', 'limitEndDate'); }}
disabledDate={this.disabledLimitEndDate}
disabledTime={this.disabledLimitEndTime}
/>
)}
</Form.Item>
</Col>
真正实现方法:
1、开始时间选择触发方法。注:此处把修改的数据做了抽离,当有多个类似查询条件时,只需要一个change方法即可实现,避免重复方法
onChangeBeginTime = (data, value, beginType, endType) => {
this.setState({
[beginType]: value,
});
// 倘若结束时间为空,默认给结束时间赋值为一个月后的时候,防止只有开始时间有值,结束时间没值的情况
if (!this.state[endType]) {
// 获取30天后的时间
const afterDate = this.getTheDate(value, 'after');
this.setState({
[endType]: afterDate,
});
this.props.form.setFieldsValue({
[endType]: moment(afterDate),
});
}
}
2、结束时间选择触发方法,作用与上述1的作用类似
onChangeEndTime = (data, value, beginType, endType) => {
this.setState({
[endType]: value,
});
if (!this.state[beginType]) {
// 获取30天前的时间
const beforeDate = this.getTheDate(value, 'before');
this.setState({
[beginType]: beforeDate,
});
this.props.form.setFieldsValue({
[beginType]: moment(beforeDate),
});
}
}
3、开始时间的日期限制方法
disabledLimitBeginDate = current => {
const { limitEndDate } = this.state;
if (limitEndDate) {
// 限制前部分时间时,需多减1天
const beforeTime = this.getTheDate(limitEndDate, 'before', 31);
return current > moment(limitEndDate).endOf('day') || current < moment(beforeTime).endOf('day');
}
return null;
}
4、开始时间的时刻限制方法。antd的DatePicker把时间和时刻的限制分成了两个方法参数,所以必须写2个限制方法
disabledLimitBeginTime = data => {
const { limitEndDate } = this.state;
if (limitEndDate) {
const endBeforeDate = moment(this.getTheDate(limitEndDate, 'before')).format('YYYY-MM-DD');
const endDate = moment(limitEndDate).format('YYYY-MM-DD');
const endHour = moment(limitEndDate).format('HH');
const endMinute = moment(limitEndDate).format('mm');
const endSecond = moment(limitEndDate).format('ss');
if (data && data.format('YYYY-MM-DD') === endBeforeDate) {
return {
disabledHours: () => this.range(0, endHour),
disabledMinutes: () => this.range(0, endMinute),
disabledSeconds: () => this.range(0, endSecond),
};
}
if (data && data.format('YYYY-MM-DD') === endDate) {
return {
disabledHours: () => this.range(endHour, 24),
disabledMinutes: () => this.range(endMinute, 60),
disabledSeconds: () => this.range(endSecond, 60),
};
}
}
return null;
}
5、结束时间的日期限制方法。
disabledLimitEndDate = current => {
const { limitBeginDate } = this.state;
if (limitBeginDate) {
const afterTime = this.getTheDate(limitBeginDate, 'after');
// 限制前部分时间时,需多减1天
const beforeTime = this.getTheDate(limitBeginDate, 'before', 1);
return current < moment(beforeTime).endOf('day') || current > moment(afterTime).endOf('day');
}
return null;
}
6、结束时间的时刻限制方法。
disabledLimitEndTime = data => {
const { limitBeginDate } = this.state;
if (limitBeginDate) {
const beginAfterDate = moment(this.getTheDate(limitBeginDate, 'after')).format('YYYY-MM-DD');
const beginDate = moment(limitBeginDate).format('YYYY-MM-DD');
const beginHour = moment(limitBeginDate).format('HH');
const beginMinute = moment(limitBeginDate).format('mm');
const beginSecond = moment(limitBeginDate).format('ss');
if (data && data.format('YYYY-MM-DD') === beginAfterDate) {
return {
disabledHours: () => this.range(beginHour, 24),
disabledMinutes: () => this.range(beginMinute, 60),
disabledSeconds: () => this.range(beginSecond, 60),
};
}
if (data && data.format('YYYY-MM-DD') === beginDate) {
return {
disabledHours: () => this.range(0, beginHour),
disabledMinutes: () => this.range(0, beginMinute),
disabledSeconds: () => this.range(0, beginSecond),
};
}
}
return null;
}
7、上面使用到的.已知指定时间,获取30天前或30天后的时间,此处天数可根据情况修改。参数和返回格式都是yyyy-mm-dd HH:mm:ss
getTheDate = (date, type, time = 30) => {
const date1 = new Date(date); // yyyy-mm-dd转中国标准日期
const date2 = new Date(date1);
if (type === 'after') { // 获取30天后的日期
date2.setDate(date1.getDate() + time);
}
if (type === 'before') { // 获取30天前的日期
date2.setDate(date1.getDate() - time);
}
return `${date2.getFullYear()}-${date2.getMonth() + 1}-${date2.getDate()} ${date2.getHours()}:${date2.getMinutes()}:${date2.getSeconds()}`;
}
8、遍历两个值中的所有值
range = (start, end) => {
const result = [];
// eslint-disable-next-line no-plusplus
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
以上,可完美实现限制功能。
但是有缺陷。
1、使用了两个DatePicker,美观度来说肯定是不如RangePicker的
2、个人觉得代码量过多,而且只有onChange方法可进行抽离参数重复使用,限制时间和限制时刻的方法我试过不能进行抽取,只能每个时间框都加两个方法。这就导致如果页面有多个这种时间限制的情况的时候,代码量会很冗余
下方附带在本次研究时间限制过程中弄明白的一些时间关系的切换方式
1、yyyy-mm-dd hh:mm:ss转中国标准时间格式
new Date(‘yyyy-mm-dd hh:mm:ss’)
2、中国标准时间格式转yyyy-mm-dd hh:mm:ss
console.log(${date2.getFullYear()}-${date2.getMonth()+1}-${date2.getDate()} ${date2.getHours()}:${date2.getMinutes()}:${date2.getSeconds()}
);
3、 moment转yyyy…
testMoment.format(‘YYYY-MM-DD HH:mm:ss’)
4、 yyyy转moment
moment(‘yyyy’)
5、 获取指定日期三十天后的日期(中国标准格式)
const date1 = new Date(‘yyyy-mm-dd’); // yyyy-mm-dd转中国标准日期
const date2 = new Date(date1);
date2.setDate(date1.getDate() + 30);
date2即为结果