mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
feat: 日期范围支持手动输入 (#3835)
* feat: 日期范围支持手动输入 * 更新单元测试 * 修复 minDuration 和 maxDuration 错误 * 避免通过 input 绕过时间限制 * 优化时间范围编辑体验
This commit is contained in:
parent
c721d22ab6
commit
11cd80a33f
@ -56,11 +56,25 @@ exports[`Renderer:dateRange 1`] = `
|
|||||||
class="cxd-DateRangePicker"
|
class="cxd-DateRangePicker"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
|
<input
|
||||||
|
autocomplete="off"
|
||||||
|
class="cxd-DateRangePicker-input"
|
||||||
|
placeholder="选择开始时间"
|
||||||
|
type="text"
|
||||||
|
value="2019-06-06"
|
||||||
|
/>
|
||||||
<span
|
<span
|
||||||
class="cxd-DateRangePicker-value"
|
class="cxd-DateRangePicker-input-separator"
|
||||||
>
|
>
|
||||||
2019-06-06 至 2019-06-26
|
~
|
||||||
</span>
|
</span>
|
||||||
|
<input
|
||||||
|
autocomplete="off"
|
||||||
|
class="cxd-DateRangePicker-input"
|
||||||
|
placeholder="选择结束时间"
|
||||||
|
type="text"
|
||||||
|
value="2019-06-26"
|
||||||
|
/>
|
||||||
<a
|
<a
|
||||||
class="cxd-DateRangePicker-clear"
|
class="cxd-DateRangePicker-clear"
|
||||||
>
|
>
|
@ -31,12 +31,12 @@ test('Renderer:dateRange', async () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const input = container.querySelector('.cxd-DateRangePicker-value');
|
const input = container.querySelectorAll('.cxd-DateRangePicker-input');
|
||||||
expect(input?.innerHTML).toEqual(
|
expect(input[0].value).toEqual(
|
||||||
`${moment(1559750400, 'X').format('YYYY-MM-DD')} 至 ${moment(
|
`${moment(1559750400, 'X').format('YYYY-MM-DD')}`
|
||||||
1561564799,
|
);
|
||||||
'X'
|
expect(input[1].value).toEqual(
|
||||||
).format('YYYY-MM-DD')}`
|
`${moment(1561564799, 'X').format('YYYY-MM-DD')}`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
@ -8,7 +8,7 @@ import {makeEnv} from '../../helper';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
test('Renderer:inputYearRange click', async () => {
|
test('Renderer:inputYearRange click', async () => {
|
||||||
const {container, findByText, getByText} = render(
|
const {container, findByPlaceholderText, getByText} = render(
|
||||||
amisRender(
|
amisRender(
|
||||||
{
|
{
|
||||||
type: 'form',
|
type: 'form',
|
||||||
@ -28,7 +28,7 @@ test('Renderer:inputYearRange click', async () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const inputDate = await findByText('请选择年份范围');
|
const inputDate = await findByPlaceholderText('选择开始时间');
|
||||||
|
|
||||||
fireEvent.click(inputDate);
|
fireEvent.click(inputDate);
|
||||||
|
|
||||||
@ -51,9 +51,8 @@ test('Renderer:inputYearRange click', async () => {
|
|||||||
|
|
||||||
fireEvent.click(confirm);
|
fireEvent.click(confirm);
|
||||||
|
|
||||||
const value = document.querySelector(
|
const value = document.querySelectorAll('.cxd-DateRangePicker-input')!;
|
||||||
'.cxd-DateRangePicker-value'
|
|
||||||
) as HTMLSpanElement;
|
|
||||||
|
|
||||||
expect(value.innerHTML).toEqual(thisYearText + ' 至 ' + nextYearText);
|
expect((value[0] as HTMLInputElement).value).toEqual(thisYearText);
|
||||||
|
expect((value[1] as HTMLInputElement).value).toEqual(nextYearText);
|
||||||
});
|
});
|
||||||
|
@ -31,6 +31,22 @@
|
|||||||
box-shadow: var(--Form-input-boxShadow);
|
box-shadow: var(--Form-input-boxShadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.#{$ns}DateRangePicker-input {
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
background: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$ns}DateRangePicker-input.isActive {
|
||||||
|
border-bottom: 1px solid var(--DatePicker-onFocused-borderColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$ns}DateRangePicker-input-separator {
|
||||||
|
margin: 0 var(--gap-sm);
|
||||||
|
}
|
||||||
|
|
||||||
&.is-disabled {
|
&.is-disabled {
|
||||||
background: $gray200;
|
background: $gray200;
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import {findDOMNode} from 'react-dom';
|
import {findDOMNode} from 'react-dom';
|
||||||
import cx from 'classnames';
|
|
||||||
import {Icon} from './icons';
|
import {Icon} from './icons';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
import {ShortCuts, ShortCutDateRange} from './DatePicker';
|
import {ShortCuts, ShortCutDateRange} from './DatePicker';
|
||||||
@ -19,11 +18,13 @@ import {PlainObject} from '../types';
|
|||||||
import {isMobile, noop, ucFirst} from '../utils/helper';
|
import {isMobile, noop, ucFirst} from '../utils/helper';
|
||||||
import {LocaleProps, localeable} from '../locale';
|
import {LocaleProps, localeable} from '../locale';
|
||||||
import CalendarMobile from './CalendarMobile';
|
import CalendarMobile from './CalendarMobile';
|
||||||
|
import Input from './Input';
|
||||||
|
|
||||||
export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
popoverClassName?: string;
|
popoverClassName?: string;
|
||||||
placeholder?: string;
|
startPlaceholder?: string;
|
||||||
|
endPlaceholder?: string;
|
||||||
theme?: any;
|
theme?: any;
|
||||||
format: string;
|
format: string;
|
||||||
utc?: boolean;
|
utc?: boolean;
|
||||||
@ -52,6 +53,7 @@ export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
|||||||
useMobileUI?: boolean;
|
useMobileUI?: boolean;
|
||||||
onFocus?: Function;
|
onFocus?: Function;
|
||||||
onBlur?: Function;
|
onBlur?: Function;
|
||||||
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DateRangePickerState {
|
export interface DateRangePickerState {
|
||||||
@ -59,6 +61,9 @@ export interface DateRangePickerState {
|
|||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
startDate?: moment.Moment;
|
startDate?: moment.Moment;
|
||||||
endDate?: moment.Moment;
|
endDate?: moment.Moment;
|
||||||
|
editState?: 'start' | 'end'; // 编辑开始时间还是结束时间
|
||||||
|
startInputValue?: string;
|
||||||
|
endInputValue?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const availableRanges: {[propName: string]: any} = {
|
export const availableRanges: {[propName: string]: any} = {
|
||||||
@ -390,7 +395,8 @@ export class DateRangePicker extends React.Component<
|
|||||||
DateRangePickerState
|
DateRangePickerState
|
||||||
> {
|
> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
placeholder: 'DateRange.placeholder',
|
startPlaceholder: 'Calendar.startPick',
|
||||||
|
endPlaceholder: 'Calendar.endPick',
|
||||||
format: 'X',
|
format: 'X',
|
||||||
inputFormat: 'YYYY-MM-DD',
|
inputFormat: 'YYYY-MM-DD',
|
||||||
joinValues: true,
|
joinValues: true,
|
||||||
@ -456,12 +462,21 @@ export class DateRangePicker extends React.Component<
|
|||||||
dom: React.RefObject<HTMLDivElement>;
|
dom: React.RefObject<HTMLDivElement>;
|
||||||
nextMonth = moment().add(1, 'months');
|
nextMonth = moment().add(1, 'months');
|
||||||
|
|
||||||
|
startInputRef: React.RefObject<HTMLInputElement>;
|
||||||
|
endInputRef: React.RefObject<HTMLInputElement>;
|
||||||
|
|
||||||
constructor(props: DateRangePickerProps) {
|
constructor(props: DateRangePickerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
|
this.startInputRef = React.createRef();
|
||||||
|
this.endInputRef = React.createRef();
|
||||||
this.open = this.open.bind(this);
|
this.open = this.open.bind(this);
|
||||||
|
this.openStart = this.openStart.bind(this);
|
||||||
|
this.openEnd = this.openEnd.bind(this);
|
||||||
this.close = this.close.bind(this);
|
this.close = this.close.bind(this);
|
||||||
this.handleSelectChange = this.handleSelectChange.bind(this);
|
this.startInputChange = this.startInputChange.bind(this);
|
||||||
|
this.endInputChange = this.endInputChange.bind(this);
|
||||||
|
this.handleDateChange = this.handleDateChange.bind(this);
|
||||||
this.handleTimeStartChange = this.handleTimeStartChange.bind(this);
|
this.handleTimeStartChange = this.handleTimeStartChange.bind(this);
|
||||||
this.handleTimeEndChange = this.handleTimeEndChange.bind(this);
|
this.handleTimeEndChange = this.handleTimeEndChange.bind(this);
|
||||||
this.handleFocus = this.handleFocus.bind(this);
|
this.handleFocus = this.handleFocus.bind(this);
|
||||||
@ -477,22 +492,61 @@ export class DateRangePicker extends React.Component<
|
|||||||
this.renderDay = this.renderDay.bind(this);
|
this.renderDay = this.renderDay.bind(this);
|
||||||
this.renderQuarter = this.renderQuarter.bind(this);
|
this.renderQuarter = this.renderQuarter.bind(this);
|
||||||
this.handleMobileChange = this.handleMobileChange.bind(this);
|
this.handleMobileChange = this.handleMobileChange.bind(this);
|
||||||
const {format, joinValues, delimiter, value} = this.props;
|
this.handleOutClick = this.handleOutClick.bind(this);
|
||||||
|
const {format, joinValues, delimiter, value, inputFormat} = this.props;
|
||||||
|
const {startDate, endDate} = DateRangePicker.unFormatValue(
|
||||||
|
value,
|
||||||
|
format,
|
||||||
|
joinValues,
|
||||||
|
delimiter
|
||||||
|
);
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpened: false,
|
isOpened: false,
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter)
|
startDate,
|
||||||
|
endDate,
|
||||||
|
startInputValue: startDate?.format(inputFormat),
|
||||||
|
endInputValue: endDate?.format(inputFormat)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
document.body.addEventListener('click', this.handleOutClick, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
document.body.removeEventListener('click', this.handleOutClick, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOutClick(e: Event) {
|
||||||
|
if (
|
||||||
|
!e.target ||
|
||||||
|
!this.dom.current ||
|
||||||
|
this.dom.current.contains(e.target as HTMLElement)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.state.isOpened) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: DateRangePickerProps) {
|
componentDidUpdate(prevProps: DateRangePickerProps) {
|
||||||
const props = this.props;
|
const props = this.props;
|
||||||
const {value, format, joinValues, delimiter} = props;
|
const {value, format, joinValues, inputFormat, delimiter} = props;
|
||||||
|
|
||||||
if (prevProps.value !== value) {
|
if (prevProps.value !== value) {
|
||||||
|
const {startDate, endDate} = DateRangePicker.unFormatValue(
|
||||||
|
value,
|
||||||
|
format,
|
||||||
|
joinValues,
|
||||||
|
delimiter
|
||||||
|
);
|
||||||
this.setState({
|
this.setState({
|
||||||
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter)
|
startDate,
|
||||||
|
endDate,
|
||||||
|
startInputValue: startDate?.format(inputFormat),
|
||||||
|
endInputValue: endDate?.format(inputFormat)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -539,10 +593,31 @@ export class DateRangePicker extends React.Component<
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openStart() {
|
||||||
|
if (this.props.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
isOpened: true,
|
||||||
|
editState: 'start'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openEnd() {
|
||||||
|
if (this.props.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
isOpened: true,
|
||||||
|
editState: 'end'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
isOpened: false
|
isOpened: false,
|
||||||
|
editState: undefined
|
||||||
},
|
},
|
||||||
this.blur
|
this.blur
|
||||||
);
|
);
|
||||||
@ -612,77 +687,163 @@ export class DateRangePicker extends React.Component<
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSelectChange(newValue: moment.Moment) {
|
handleDateChange(newValue: moment.Moment) {
|
||||||
const {embed, timeFormat, minDuration, maxDuration, minDate} = this.props;
|
const {
|
||||||
let {startDate, endDate} = this.state;
|
embed,
|
||||||
|
timeFormat,
|
||||||
// 第一次点击只标记起始时间,或者点击了开始时间前面的时间
|
minDuration,
|
||||||
if (this.isFirstClick || newValue.isBefore(startDate)) {
|
maxDuration,
|
||||||
// 这种情况说明第二次点击点击了前面的时间,这时要标记为第二次点击
|
minDate,
|
||||||
if (newValue.isBefore(startDate)) {
|
inputFormat,
|
||||||
this.isFirstClick = true;
|
type
|
||||||
}
|
} = this.props;
|
||||||
|
let {startDate, endDate, editState} = this.state;
|
||||||
|
if (editState === 'start') {
|
||||||
if (minDate && newValue.isBefore(minDate)) {
|
if (minDate && newValue.isBefore(minDate)) {
|
||||||
newValue = minDate;
|
newValue = minDate;
|
||||||
}
|
}
|
||||||
this.setState({
|
const date = this.filterDate(
|
||||||
startDate: this.filterDate(
|
newValue,
|
||||||
newValue,
|
startDate || minDate,
|
||||||
startDate || minDate,
|
timeFormat,
|
||||||
timeFormat,
|
'start'
|
||||||
'start'
|
);
|
||||||
),
|
const newState = {
|
||||||
endDate: undefined
|
startDate: date,
|
||||||
});
|
startInputValue: date.format(inputFormat)
|
||||||
} else {
|
} as any;
|
||||||
// 第二次点击作为结束时间
|
// 这些没有时间的选择点第一次后第二次就是选结束时间
|
||||||
if (!startDate) {
|
if (
|
||||||
// 不大可能,但只能作为开始时间了
|
type === 'input-date-range' ||
|
||||||
startDate = newValue;
|
type === 'input-year-range' ||
|
||||||
|
type === 'input-quarter-range'
|
||||||
|
) {
|
||||||
|
newState.editState = 'end';
|
||||||
|
}
|
||||||
|
this.setState(newState);
|
||||||
|
} else if (editState === 'end') {
|
||||||
|
newValue = this.getEndDateByDuration(newValue);
|
||||||
|
|
||||||
|
// 如果结束时间在前面,需要清空开始时间
|
||||||
|
if (newValue.isBefore(startDate)) {
|
||||||
|
this.setState({
|
||||||
|
startDate: undefined,
|
||||||
|
startInputValue: ''
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minDuration && newValue.isAfter(startDate.clone().add(minDuration))) {
|
const date = this.filterDate(newValue, endDate, timeFormat, 'end');
|
||||||
newValue = startDate.clone().add(minDuration);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
maxDuration &&
|
|
||||||
newValue.isBefore(startDate.clone().add(maxDuration))
|
|
||||||
) {
|
|
||||||
newValue = startDate.clone().add(maxDuration);
|
|
||||||
}
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
endDate: this.filterDate(newValue, endDate, timeFormat, 'end')
|
endDate: date,
|
||||||
|
endInputValue: date.format(inputFormat)
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
embed && this.confirm();
|
embed && this.confirm();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.isFirstClick = !this.isFirstClick;
|
// 手动控制输入时间
|
||||||
|
startInputChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
|
const {onChange, inputFormat, format, utc} = this.props;
|
||||||
|
const value = e.currentTarget.value;
|
||||||
|
this.setState({startInputValue: value});
|
||||||
|
if (value === '') {
|
||||||
|
onChange('');
|
||||||
|
} else {
|
||||||
|
let newDate = this.getStartDateByDuration(moment(value, inputFormat));
|
||||||
|
this.setState({startDate: newDate});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endInputChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
|
const {onChange, inputFormat, format, utc} = this.props;
|
||||||
|
const value = e.currentTarget.value;
|
||||||
|
this.setState({endInputValue: value});
|
||||||
|
if (value === '') {
|
||||||
|
onChange('');
|
||||||
|
} else {
|
||||||
|
let newDate = this.getEndDateByDuration(moment(value, inputFormat));
|
||||||
|
this.setState({endDate: newDate});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 duration 修复结束时间
|
||||||
|
getEndDateByDuration(newValue: moment.Moment) {
|
||||||
|
const {minDuration, maxDuration, type} = this.props;
|
||||||
|
let {startDate, endDate, editState} = this.state;
|
||||||
|
if (!startDate) {
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间范围必须统一成同一天,不然会不一致
|
||||||
|
if (type === 'input-time-range' && startDate) {
|
||||||
|
newValue.set({
|
||||||
|
year: startDate.year(),
|
||||||
|
month: startDate.month(),
|
||||||
|
date: startDate.date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minDuration && newValue.isBefore(startDate.clone().add(minDuration))) {
|
||||||
|
newValue = startDate.clone().add(minDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxDuration && newValue.isAfter(startDate.clone().add(maxDuration))) {
|
||||||
|
newValue = startDate.clone().add(maxDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 duration 修复起始时间
|
||||||
|
getStartDateByDuration(newValue: moment.Moment) {
|
||||||
|
const {minDuration, maxDuration, type} = this.props;
|
||||||
|
let {endDate, editState} = this.state;
|
||||||
|
if (!endDate) {
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
// 时间范围必须统一成同一天,不然会不一致
|
||||||
|
if (type === 'input-time-range' && endDate) {
|
||||||
|
newValue.set({
|
||||||
|
year: endDate.year(),
|
||||||
|
month: endDate.month(),
|
||||||
|
date: endDate.date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
minDuration &&
|
||||||
|
newValue.isBefore(endDate.clone().subtract(minDuration))
|
||||||
|
) {
|
||||||
|
newValue = endDate.clone().subtract(minDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
maxDuration &&
|
||||||
|
newValue.isAfter(endDate.clone().subtract(maxDuration))
|
||||||
|
) {
|
||||||
|
newValue = endDate.clone().subtract(maxDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主要用于处理时间的情况
|
// 主要用于处理时间的情况
|
||||||
handleTimeStartChange(newValue: moment.Moment) {
|
handleTimeStartChange(newValue: moment.Moment) {
|
||||||
const {embed, timeFormat, minDuration, maxDuration, minDate} = this.props;
|
const {embed, timeFormat, inputFormat, minDuration, maxDuration, minDate} =
|
||||||
|
this.props;
|
||||||
const {startDate, endDate} = this.state;
|
const {startDate, endDate} = this.state;
|
||||||
|
|
||||||
if (
|
// 时间范围必须统一成同一天,不然会不一致
|
||||||
startDate &&
|
if (endDate) {
|
||||||
(!endDate || (endDate && newValue.isSame(startDate))) && // 没有结束时间,或者新的时间也是开始时间,这时都会将新值当成结束时间
|
newValue.set({
|
||||||
newValue.isSameOrAfter(startDate) &&
|
year: endDate.year(),
|
||||||
(!minDuration || newValue.isAfter(startDate.clone().add(minDuration))) &&
|
month: endDate.month(),
|
||||||
(!maxDuration || newValue.isBefore(startDate.clone().add(maxDuration)))
|
date: endDate.date()
|
||||||
) {
|
});
|
||||||
return this.setState(
|
|
||||||
{
|
|
||||||
endDate: this.filterDate(newValue, endDate, timeFormat, 'end')
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
embed && this.confirm();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minDate && newValue && newValue.isBefore(minDate, 'second')) {
|
if (minDate && newValue && newValue.isBefore(minDate, 'second')) {
|
||||||
@ -691,12 +852,8 @@ export class DateRangePicker extends React.Component<
|
|||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
startDate: this.filterDate(
|
startDate: newValue,
|
||||||
newValue,
|
startInputValue: newValue.format(inputFormat)
|
||||||
startDate || minDate,
|
|
||||||
timeFormat,
|
|
||||||
'start'
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
embed && this.confirm();
|
embed && this.confirm();
|
||||||
@ -705,39 +862,40 @@ export class DateRangePicker extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleTimeEndChange(newValue: moment.Moment) {
|
handleTimeEndChange(newValue: moment.Moment) {
|
||||||
const {embed, timeFormat, minDuration, maxDuration, maxDate} = this.props;
|
const {embed, timeFormat, inputFormat, minDuration, maxDuration, maxDate} =
|
||||||
|
this.props;
|
||||||
const {startDate, endDate} = this.state;
|
const {startDate, endDate} = this.state;
|
||||||
|
if (startDate) {
|
||||||
if (
|
newValue.set({
|
||||||
endDate &&
|
year: startDate.year(),
|
||||||
!startDate &&
|
month: startDate.month(),
|
||||||
newValue.isSameOrBefore(endDate) &&
|
date: startDate.date()
|
||||||
(!minDuration ||
|
});
|
||||||
newValue.isBefore(endDate.clone().subtract(minDuration))) &&
|
|
||||||
(!maxDuration || newValue.isAfter(endDate.clone().subtract(maxDuration)))
|
|
||||||
) {
|
|
||||||
return this.setState(
|
|
||||||
{
|
|
||||||
startDate: this.filterDate(newValue, startDate, timeFormat, 'start')
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
embed && this.confirm();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxDate && newValue && newValue.isAfter(maxDate, 'second')) {
|
if (maxDate && newValue && newValue.isAfter(maxDate, 'second')) {
|
||||||
newValue = maxDate;
|
newValue = maxDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
startDate &&
|
||||||
|
minDuration &&
|
||||||
|
newValue.isAfter(startDate.clone().add(minDuration))
|
||||||
|
) {
|
||||||
|
newValue = startDate.clone().add(minDuration);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
startDate &&
|
||||||
|
maxDuration &&
|
||||||
|
newValue.isBefore(startDate.clone().add(maxDuration))
|
||||||
|
) {
|
||||||
|
newValue = startDate.clone().add(maxDuration);
|
||||||
|
}
|
||||||
|
|
||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
endDate: this.filterDate(
|
endDate: newValue,
|
||||||
newValue,
|
endInputValue: newValue.format(inputFormat)
|
||||||
endDate || maxDate,
|
|
||||||
timeFormat,
|
|
||||||
'end'
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
embed && this.confirm();
|
embed && this.confirm();
|
||||||
@ -836,7 +994,7 @@ export class DateRangePicker extends React.Component<
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const {resetValue, onChange} = this.props;
|
const {resetValue, onChange} = this.props;
|
||||||
|
this.setState({startInputValue: '', endInputValue: ''});
|
||||||
onChange(resetValue);
|
onChange(resetValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -950,6 +1108,7 @@ export class DateRangePicker extends React.Component<
|
|||||||
ranges,
|
ranges,
|
||||||
locale,
|
locale,
|
||||||
embed,
|
embed,
|
||||||
|
type,
|
||||||
viewMode = 'days'
|
viewMode = 'days'
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const __ = this.props.translate;
|
const __ = this.props.translate;
|
||||||
@ -959,7 +1118,6 @@ export class DateRangePicker extends React.Component<
|
|||||||
return (
|
return (
|
||||||
<div className={`${ns}DateRangePicker-wrap`}>
|
<div className={`${ns}DateRangePicker-wrap`}>
|
||||||
{this.renderRanges(ranges)}
|
{this.renderRanges(ranges)}
|
||||||
|
|
||||||
<Calendar
|
<Calendar
|
||||||
className={`${ns}DateRangePicker-start`}
|
className={`${ns}DateRangePicker-start`}
|
||||||
value={startDate}
|
value={startDate}
|
||||||
@ -968,7 +1126,7 @@ export class DateRangePicker extends React.Component<
|
|||||||
onChange={
|
onChange={
|
||||||
viewMode === 'time'
|
viewMode === 'time'
|
||||||
? this.handleTimeStartChange
|
? this.handleTimeStartChange
|
||||||
: this.handleSelectChange
|
: this.handleDateChange
|
||||||
}
|
}
|
||||||
requiredConfirm={false}
|
requiredConfirm={false}
|
||||||
dateFormat={dateFormat}
|
dateFormat={dateFormat}
|
||||||
@ -982,14 +1140,13 @@ export class DateRangePicker extends React.Component<
|
|||||||
renderQuarter={this.renderQuarter}
|
renderQuarter={this.renderQuarter}
|
||||||
locale={locale}
|
locale={locale}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Calendar
|
<Calendar
|
||||||
className={`${ns}DateRangePicker-end`}
|
className={`${ns}DateRangePicker-end`}
|
||||||
value={endDate}
|
value={endDate}
|
||||||
onChange={
|
onChange={
|
||||||
viewMode === 'time'
|
viewMode === 'time'
|
||||||
? this.handleTimeEndChange
|
? this.handleTimeEndChange
|
||||||
: this.handleSelectChange
|
: this.handleDateChange
|
||||||
}
|
}
|
||||||
requiredConfirm={false}
|
requiredConfirm={false}
|
||||||
dateFormat={dateFormat}
|
dateFormat={dateFormat}
|
||||||
@ -1013,7 +1170,10 @@ export class DateRangePicker extends React.Component<
|
|||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
className={cx('Button', 'Button--primary', 'm-l-sm', {
|
className={cx('Button', 'Button--primary', 'm-l-sm', {
|
||||||
'is-disabled': !this.state.startDate || !this.state.endDate
|
'is-disabled':
|
||||||
|
!this.state.startDate ||
|
||||||
|
!this.state.endDate ||
|
||||||
|
this.state.endDate?.isBefore(this.state.startDate)
|
||||||
})}
|
})}
|
||||||
onClick={this.confirm}
|
onClick={this.confirm}
|
||||||
>
|
>
|
||||||
@ -1030,8 +1190,10 @@ export class DateRangePicker extends React.Component<
|
|||||||
className,
|
className,
|
||||||
popoverClassName,
|
popoverClassName,
|
||||||
classPrefix: ns,
|
classPrefix: ns,
|
||||||
|
classnames: cx,
|
||||||
value,
|
value,
|
||||||
placeholder,
|
startPlaceholder,
|
||||||
|
endPlaceholder,
|
||||||
popOverContainer,
|
popOverContainer,
|
||||||
inputFormat,
|
inputFormat,
|
||||||
format,
|
format,
|
||||||
@ -1059,21 +1221,6 @@ export class DateRangePicker extends React.Component<
|
|||||||
|
|
||||||
const {isOpened, isFocused, startDate, endDate} = this.state;
|
const {isOpened, isFocused, startDate, endDate} = this.state;
|
||||||
|
|
||||||
const selectedDate = DateRangePicker.unFormatValue(
|
|
||||||
value,
|
|
||||||
format,
|
|
||||||
joinValues,
|
|
||||||
delimiter
|
|
||||||
);
|
|
||||||
const startViewValue = selectedDate.startDate
|
|
||||||
? selectedDate.startDate.format(inputFormat)
|
|
||||||
: '';
|
|
||||||
const endViewValue = selectedDate.endDate
|
|
||||||
? selectedDate.endDate.format(inputFormat)
|
|
||||||
: '';
|
|
||||||
const arr = [];
|
|
||||||
startViewValue && arr.push(startViewValue);
|
|
||||||
endViewValue && arr.push(endViewValue);
|
|
||||||
const __ = this.props.translate;
|
const __ = this.props.translate;
|
||||||
|
|
||||||
const calendarMobile = (
|
const calendarMobile = (
|
||||||
@ -1138,17 +1285,32 @@ export class DateRangePicker extends React.Component<
|
|||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
ref={this.dom}
|
ref={this.dom}
|
||||||
onClick={this.handleClick}
|
|
||||||
>
|
>
|
||||||
{arr.length ? (
|
<Input
|
||||||
<span className={`${ns}DateRangePicker-value`}>
|
className={cx('DateRangePicker-input', {
|
||||||
{arr.join(__('DateRange.valueConcat'))}
|
isActive: this.state.editState === 'start'
|
||||||
</span>
|
})}
|
||||||
) : (
|
onChange={this.startInputChange}
|
||||||
<span className={`${ns}DateRangePicker-placeholder`}>
|
onClick={this.openStart}
|
||||||
{__(placeholder)}
|
ref={this.startInputRef}
|
||||||
</span>
|
placeholder={__(startPlaceholder)}
|
||||||
)}
|
autoComplete="off"
|
||||||
|
value={this.state.startInputValue || ''}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<span className={cx('DateRangePicker-input-separator')}>~</span>
|
||||||
|
<Input
|
||||||
|
className={cx('DateRangePicker-input', {
|
||||||
|
isActive: this.state.editState === 'end'
|
||||||
|
})}
|
||||||
|
onChange={this.endInputChange}
|
||||||
|
onClick={this.openEnd}
|
||||||
|
ref={this.endInputRef}
|
||||||
|
placeholder={__(endPlaceholder)}
|
||||||
|
autoComplete="off"
|
||||||
|
value={this.state.endInputValue || ''}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
{clearable && !disabled && value ? (
|
{clearable && !disabled && value ? (
|
||||||
<a className={`${ns}DateRangePicker-clear`} onClick={this.clearValue}>
|
<a className={`${ns}DateRangePicker-clear`} onClick={this.clearValue}>
|
||||||
@ -1185,7 +1347,6 @@ export class DateRangePicker extends React.Component<
|
|||||||
className={cx(`${ns}DateRangePicker-popover`, popoverClassName)}
|
className={cx(`${ns}DateRangePicker-popover`, popoverClassName)}
|
||||||
onHide={this.close}
|
onHide={this.close}
|
||||||
onClick={this.handlePopOverClick}
|
onClick={this.handlePopOverClick}
|
||||||
overlay
|
|
||||||
>
|
>
|
||||||
{this.renderCalendar()}
|
{this.renderCalendar()}
|
||||||
</PopOver>
|
</PopOver>
|
||||||
|
@ -223,8 +223,7 @@ class BaseDatePicker extends React.Component<
|
|||||||
updatedState.viewDate = moment(props.viewDate);
|
updatedState.viewDate = moment(props.viewDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// time-range 下会有问题,先不支持
|
if (Object.keys(updatedState).length) {
|
||||||
if (Object.keys(updatedState).length && props.viewMode !== 'time') {
|
|
||||||
this.setState(updatedState);
|
this.setState(updatedState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user