From 38b9e505cc7ab44b392cec29e295011fcd08ae8b Mon Sep 17 00:00:00 2001 From: 2betop <2betop.cn@gmail.com> Date: Mon, 7 Dec 2020 18:09:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E6=9C=9F=E8=8C=83?= =?UTF-8?q?=E5=9B=B4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DateRangePicker.tsx | 1021 +++++++++++++++------------- 1 file changed, 530 insertions(+), 491 deletions(-) diff --git a/src/components/DateRangePicker.tsx b/src/components/DateRangePicker.tsx index 11848c582..7b4a47de3 100644 --- a/src/components/DateRangePicker.tsx +++ b/src/components/DateRangePicker.tsx @@ -154,559 +154,598 @@ const availableRanges: {[propName: string]: any} = { }; export class DateRangePicker extends React.Component< - DateRangePickerProps, - DateRangePickerState - > { - static defaultProps = { - placeholder: '请选择日期范围', - format: 'X', - inputFormat: 'YYYY-MM-DD', - joinValues: true, - clearable: true, - delimiter: ',', - ranges: - 'yesterday,7daysago,prevweek,thismonth,prevmonth,prevquarter', - resetValue: '', - closeOnSelect: true, - overlayPlacement: 'auto' - }; + DateRangePickerProps, + DateRangePickerState +> { + static defaultProps = { + placeholder: '请选择日期范围', + format: 'X', + inputFormat: 'YYYY-MM-DD', + joinValues: true, + clearable: true, + delimiter: ',', + ranges: 'yesterday,7daysago,prevweek,thismonth,prevmonth,prevquarter', + resetValue: '', + closeOnSelect: true, + overlayPlacement: 'auto' + }; - innerDom: any; - popover: any; - input?: HTMLInputElement; + innerDom: any; + popover: any; + input?: HTMLInputElement; - static formatValue( - newValue: any, - format: string, - joinValues: boolean, - delimiter: string, - utc = false - ) { - newValue = [ - (utc ? moment.utc(newValue.startDate) : newValue.startDate).format( - format - ), - (utc ? moment.utc(newValue.endDate) : newValue.endDate).format( - format - ) - ]; + static formatValue( + newValue: any, + format: string, + joinValues: boolean, + delimiter: string, + utc = false + ) { + newValue = [ + (utc ? moment.utc(newValue.startDate) : newValue.startDate).format( + format + ), + (utc ? moment.utc(newValue.endDate) : newValue.endDate).format(format) + ]; - if (joinValues) { - newValue = newValue.join(delimiter); - } + if (joinValues) { + newValue = newValue.join(delimiter); + } - return newValue; - } + return newValue; + } - static unFormatValue( - value: any, - format: string, - joinValues: boolean, - delimiter: string - ) { - if (!value) { - return { - startDate: undefined, - endDate: undefined - }; - } + static unFormatValue( + value: any, + format: string, + joinValues: boolean, + delimiter: string + ) { + if (!value) { + return { + startDate: undefined, + endDate: undefined + }; + } - if (joinValues && typeof value === 'string') { - value = value.split(delimiter); - } + if (joinValues && typeof value === 'string') { + value = value.split(delimiter); + } - return { - startDate: value[0] ? moment(value[0], format) : undefined, - endDate: value[1] ? moment(value[1], format) : undefined - }; - } + return { + startDate: value[0] ? moment(value[0], format) : undefined, + endDate: value[1] ? moment(value[1], format) : undefined + }; + } - dom: React.RefObject; - nextMonth = moment().add(1, 'months'); + dom: React.RefObject; + nextMonth = moment().add(1, 'months'); - constructor(props: DateRangePickerProps) { - super(props); + constructor(props: DateRangePickerProps) { + super(props); - this.open = this.open.bind(this); - this.close = this.close.bind(this); - this.handleStartChange = this.handleStartChange.bind(this); - this.handleEndChange = this.handleEndChange.bind(this); - this.handleFocus = this.handleFocus.bind(this); - this.handleBlur = this.handleBlur.bind(this); - this.checkStartIsValidDate = this.checkStartIsValidDate.bind(this); - this.checkEndIsValidDate = this.checkEndIsValidDate.bind(this); - this.confirm = this.confirm.bind(this); - this.clearValue = this.clearValue.bind(this); - this.dom = React.createRef(); - this.handleClick = this.handleClick.bind(this); - this.handleKeyPress = this.handleKeyPress.bind(this); - this.handlePopOverClick = this.handlePopOverClick.bind(this); - this.renderDay = this.renderDay.bind(this); - const {format, joinValues, delimiter, value} = this.props; + this.open = this.open.bind(this); + this.close = this.close.bind(this); + this.handleStartChange = this.handleStartChange.bind(this); + this.handleEndChange = this.handleEndChange.bind(this); + this.handleFocus = this.handleFocus.bind(this); + this.handleBlur = this.handleBlur.bind(this); + this.checkStartIsValidDate = this.checkStartIsValidDate.bind(this); + this.checkEndIsValidDate = this.checkEndIsValidDate.bind(this); + this.confirm = this.confirm.bind(this); + this.clearValue = this.clearValue.bind(this); + this.dom = React.createRef(); + this.handleClick = this.handleClick.bind(this); + this.handleKeyPress = this.handleKeyPress.bind(this); + this.handlePopOverClick = this.handlePopOverClick.bind(this); + this.renderDay = this.renderDay.bind(this); + const {format, joinValues, delimiter, value} = this.props; - this.state = { - isOpened: false, - isFocused: false, - ...DateRangePicker.unFormatValue( - value, - format, - joinValues, - delimiter - ) - }; - } + this.state = { + isOpened: false, + isFocused: false, + ...DateRangePicker.unFormatValue(value, format, joinValues, delimiter) + }; + } - componentWillReceiveProps(nextProps: DateRangePickerProps) { - const props = this.props; - const {value, format, joinValues, delimiter} = nextProps; + componentWillReceiveProps(nextProps: DateRangePickerProps) { + const props = this.props; + const {value, format, joinValues, delimiter} = nextProps; - if (props.value !== value) { - this.setState({ - ...DateRangePicker.unFormatValue( - value, - format, - joinValues, - delimiter - ) - }); - } - } + if (props.value !== value) { + this.setState({ + ...DateRangePicker.unFormatValue(value, format, joinValues, delimiter) + }); + } + } - focus() { - if (!this.dom.current || this.props.disabled) { - return; - } + focus() { + if (!this.dom.current || this.props.disabled) { + return; + } - this.dom.current.focus(); - } + this.dom.current.focus(); + } - blur() { - if (!this.dom.current || this.props.disabled) { - return; - } + blur() { + if (!this.dom.current || this.props.disabled) { + return; + } - this.dom.current.blur(); - } + this.dom.current.blur(); + } - handleFocus() { - this.setState({ - isFocused: true - }); - } + handleFocus() { + this.setState({ + isFocused: true + }); + } - handleBlur() { - this.setState({ - isFocused: false - }); - } + handleBlur() { + this.setState({ + isFocused: false + }); + } - open() { - if (this.props.disabled) { - return; - } + open() { + if (this.props.disabled) { + return; + } - this.setState({ - isOpened: true - }); - } + this.setState({ + isOpened: true + }); + } - close() { - this.setState( - { - isOpened: false - }, - this.blur - ); - } + close() { + this.setState( + { + isOpened: false + }, + this.blur + ); + } - handleClick() { - this.state.isOpened ? this.close() : this.open(); - } + handleClick() { + this.state.isOpened ? this.close() : this.open(); + } - handlePopOverClick(e: React.MouseEvent) { - e.stopPropagation(); - e.preventDefault(); - } + handlePopOverClick(e: React.MouseEvent) { + e.stopPropagation(); + e.preventDefault(); + } - handleKeyPress(e: React.KeyboardEvent) { - if (e.key === ' ') { - this.handleClick(); - e.preventDefault(); - } - } + handleKeyPress(e: React.KeyboardEvent) { + if (e.key === ' ') { + this.handleClick(); + e.preventDefault(); + } + } - confirm() { - if (!this.state.startDate || !this.state.endDate) { - return; - } else if (this.state.startDate.isAfter(this.state.endDate)) { - return; - } + confirm() { + if (!this.state.startDate || !this.state.endDate) { + return; + } else if (this.state.startDate.isAfter(this.state.endDate)) { + return; + } - this.props.onChange( - DateRangePicker.formatValue( - { - startDate: this.state.startDate, - endDate: this.state.endDate - }, - this.props.format, - this.props.joinValues, - this.props.delimiter, - this.props.utc - ) - ); - this.close(); - } + this.props.onChange( + DateRangePicker.formatValue( + { + startDate: this.state.startDate, + endDate: this.state.endDate + }, + this.props.format, + this.props.joinValues, + this.props.delimiter, + this.props.utc + ) + ); + this.close(); + } - handleStartChange(newValue: moment.Moment) { - if ( - this.state.startDate && - !this.state.endDate && - newValue.isAfter(this.state.startDate) - ) { - return this.setState({ - endDate: newValue.clone() - }); - } + filterDate( + date: moment.Moment, + originValue?: moment.Moment, + timeFormat?: string, + type: 'start' | 'end' = 'start' + ): moment.Moment { + let value = date.clone(); - this.setState({ - startDate: newValue.clone() - }); - } + // 没有初始值 + if (!originValue) { + value = value[type === 'start' ? 'startOf' : 'endOf']('day'); + } else if (typeof timeFormat === 'string' && /ss/.test(timeFormat)) { + value = value[type === 'start' ? 'startOf' : 'endOf']('second'); + } else if (typeof timeFormat === 'string' && /mm/.test(timeFormat)) { + value = value[type === 'start' ? 'startOf' : 'endOf']('minute'); + } else if (typeof timeFormat === 'string' && /HH/i.test(timeFormat)) { + value = value[type === 'start' ? 'startOf' : 'endOf']('hour'); + } else { + value = value[type === 'start' ? 'startOf' : 'endOf']('day'); + } - handleEndChange(newValue: moment.Moment) { - newValue = - !this.state.endDate && !this.props.timeFormat - ? newValue.endOf('day') - : newValue; + return value; + } - if ( - this.state.endDate && - !this.state.startDate && - newValue.isBefore(this.state.endDate) - ) { - return this.setState({ - startDate: newValue.clone() - }); - } + handleStartChange(newValue: moment.Moment) { + if ( + this.state.startDate && + !this.state.endDate && + newValue.isSameOrAfter(this.state.startDate) + ) { + return this.setState( + { + endDate: this.filterDate( + newValue, + this.state.endDate, + this.props.timeFormat, + 'end' + ) + }, + () => { + this.props.embed && this.confirm(); + } + ); + } - this.setState({ - endDate: newValue.clone() - }, () => { - this.props.embed && this.confirm(); - }); - } + this.setState( + { + startDate: this.filterDate( + newValue, + this.state.startDate, + this.props.timeFormat, + 'start' + ) + }, + () => { + this.props.embed && this.confirm(); + } + ); + } - selectRannge(range: PlainObject) { - const {closeOnSelect, minDate, maxDate} = this.props; - const now = moment(); - this.setState( - { - startDate: minDate - ? moment.max(range.startDate(now.clone()), minDate) - : range.startDate(now.clone()), - endDate: maxDate - ? moment.min(maxDate, range.endDate(now.clone())) - : range.endDate(now.clone()) - }, - closeOnSelect ? this.confirm : noop - ); - } + handleEndChange(newValue: moment.Moment) { + if ( + this.state.endDate && + !this.state.startDate && + newValue.isSameOrBefore(this.state.endDate) + ) { + return this.setState( + { + startDate: this.filterDate( + newValue, + this.state.startDate, + this.props.timeFormat, + 'start' + ) + }, + () => { + this.props.embed && this.confirm(); + } + ); + } - renderRanges(ranges: string | Array | undefined) { - if (!ranges) { - return null; - } - const {classPrefix: ns} = this.props; - let rangeArr: Array; - if (typeof ranges === 'string') { - rangeArr = ranges.split(','); - } else { - rangeArr = ranges; - } - const __ = this.props.translate; + this.setState( + { + endDate: this.filterDate( + newValue, + this.state.endDate, + this.props.timeFormat, + 'end' + ) + }, + () => { + this.props.embed && this.confirm(); + } + ); + } - return ( -
    - {rangeArr.map(item => { - if (!item) { - return null; - } - let range: PlainObject = {}; - if (typeof item === 'string') { - range = availableRanges[item]; - range.key = item; - } else if ( - (item as ShortCutDateRange).startDate && - (item as ShortCutDateRange).endDate - ) { - range = { - ...item, - startDate: () => (item as ShortCutDateRange).startDate, - endDate: () => (item as ShortCutDateRange).endDate - }; - } - return ( -
  • this.selectRannge(range)} - key={range.key || range.label} - > - {__(range.label)} -
  • - ); - })} -
- ); - } + selectRannge(range: PlainObject) { + const {closeOnSelect, minDate, maxDate} = this.props; + const now = moment(); + this.setState( + { + startDate: minDate + ? moment.max(range.startDate(now.clone()), minDate) + : range.startDate(now.clone()), + endDate: maxDate + ? moment.min(maxDate, range.endDate(now.clone())) + : range.endDate(now.clone()) + }, + closeOnSelect ? this.confirm : noop + ); + } - clearValue(e: React.MouseEvent) { - e.preventDefault(); - e.stopPropagation(); - const {resetValue, onChange} = this.props; + renderRanges(ranges: string | Array | undefined) { + if (!ranges) { + return null; + } + const {classPrefix: ns} = this.props; + let rangeArr: Array; + if (typeof ranges === 'string') { + rangeArr = ranges.split(','); + } else { + rangeArr = ranges; + } + const __ = this.props.translate; - onChange(resetValue); - } + return ( +
    + {rangeArr.map(item => { + if (!item) { + return null; + } + let range: PlainObject = {}; + if (typeof item === 'string') { + range = availableRanges[item]; + range.key = item; + } else if ( + (item as ShortCutDateRange).startDate && + (item as ShortCutDateRange).endDate + ) { + range = { + ...item, + startDate: () => (item as ShortCutDateRange).startDate, + endDate: () => (item as ShortCutDateRange).endDate + }; + } + return ( +
  • this.selectRannge(range)} + key={range.key || range.label} + > + {__(range.label)} +
  • + ); + })} +
+ ); + } - checkStartIsValidDate(currentDate: moment.Moment) { - let {endDate} = this.state; + clearValue(e: React.MouseEvent) { + e.preventDefault(); + e.stopPropagation(); + const {resetValue, onChange} = this.props; - let {minDate, maxDate} = this.props; + onChange(resetValue); + } - maxDate = - maxDate && endDate - ? maxDate.isBefore(endDate) - ? maxDate - : endDate - : maxDate || endDate; + checkStartIsValidDate(currentDate: moment.Moment) { + let {endDate} = this.state; - if (minDate && currentDate.isBefore(minDate, 'day')) { - return false; - } else if (maxDate && currentDate.isAfter(maxDate, 'day')) { - return false; - } + let {minDate, maxDate} = this.props; - return true; - } + maxDate = + maxDate && endDate + ? maxDate.isBefore(endDate) + ? maxDate + : endDate + : maxDate || endDate; - checkEndIsValidDate(currentDate: moment.Moment) { - let {startDate} = this.state; + if (minDate && currentDate.isBefore(minDate, 'day')) { + return false; + } else if (maxDate && currentDate.isAfter(maxDate, 'day')) { + return false; + } - let {minDate, maxDate} = this.props; + return true; + } - minDate = - minDate && startDate - ? minDate.isAfter(startDate) - ? minDate - : startDate - : minDate || startDate; + checkEndIsValidDate(currentDate: moment.Moment) { + let {startDate} = this.state; - if (minDate && currentDate.isBefore(minDate, 'day')) { - return false; - } else if (maxDate && currentDate.isAfter(maxDate, 'day')) { - return false; - } + let {minDate, maxDate} = this.props; - return true; - } + minDate = + minDate && startDate + ? minDate.isAfter(startDate) + ? minDate + : startDate + : minDate || startDate; - renderDay(props: any, currentDate: moment.Moment) { - let {startDate, endDate} = this.state; + if (minDate && currentDate.isBefore(minDate, 'day')) { + return false; + } else if (maxDate && currentDate.isAfter(maxDate, 'day')) { + return false; + } - if ( - startDate && - endDate && - currentDate.isBetween(startDate, endDate, 'day', '[]') - ) { - props.className += ' rdtBetween'; - } + return true; + } - return {currentDate.date()}; - } + renderDay(props: any, currentDate: moment.Moment) { + let {startDate, endDate} = this.state; - renderCalendar() { - const { - classPrefix: ns, - dateFormat, - timeFormat, - ranges, - locale, - embed - } = this.props; - const __ = this.props.translate; + if ( + startDate && + endDate && + currentDate.isBetween(startDate, endDate, 'day', '[]') + ) { + props.className += ' rdtBetween'; + } - const {startDate, endDate} = this.state; - return ( -
- {this.renderRanges(ranges)} + return {currentDate.date()}; + } - + renderCalendar() { + const { + classPrefix: ns, + dateFormat, + timeFormat, + ranges, + locale, + embed + } = this.props; + const __ = this.props.translate; - + const {startDate, endDate} = this.state; + return ( +
+ {this.renderRanges(ranges)} - {embed ? null : ( - - )} -
- ); - } + - render() { - const { - className, - classPrefix: ns, - value, - placeholder, - popOverContainer, - inputFormat, - format, - joinValues, - delimiter, - clearable, - disabled, - embed, - overlayPlacement - } = this.props; + - const {isOpened, isFocused} = this.state; + {embed ? null : ( + + )} +
+ ); + } - 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; + render() { + const { + className, + classPrefix: ns, + value, + placeholder, + popOverContainer, + inputFormat, + format, + joinValues, + delimiter, + clearable, + disabled, + embed, + overlayPlacement + } = this.props; - if (embed) { - return ( -
- {this.renderCalendar()} -
- ); - } + const {isOpened, isFocused} = this.state; - return ( -
- {arr.length ? ( - - {arr.join(__(' 至 '))} - - ) : ( - - {__(placeholder)} - - )} + 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; - {clearable && !disabled && value ? ( - - - - ) : null} + if (embed) { + return ( +
+ {this.renderCalendar()} +
+ ); + } - - - + return ( +
+ {arr.length ? ( + + {arr.join(__(' 至 '))} + + ) : ( + + {__(placeholder)} + + )} - {isOpened ? ( - this.dom.current} - onHide={this.close} - container={popOverContainer || (() => findDOMNode(this))} - rootClose={false} - placement={overlayPlacement} - show - > - - {this.renderCalendar()} - - - ) : null} -
- ); - } - } + {clearable && !disabled && value ? ( + + + + ) : null} + + + + + + {isOpened ? ( + this.dom.current} + onHide={this.close} + container={popOverContainer || (() => findDOMNode(this))} + rootClose={false} + placement={overlayPlacement} + show + > + + {this.renderCalendar()} + + + ) : null} +
+ ); + } +} export default themeable(localeable(DateRangePicker));