同步1.2版本的时间范围选择改动 (#2183)

This commit is contained in:
xuzhendong666 2021-06-30 23:37:10 +08:00 committed by GitHub
parent fc2f792bbd
commit 927e8107b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 57 deletions

View File

@ -45,6 +45,7 @@ export interface DateRangePickerProps extends ThemeProps, LocaleProps {
popOverContainer?: any;
dateFormat?: string;
embed?: boolean;
viewMode?: 'days' | 'months' | 'years' | 'time' | 'quarters';
}
export interface DateRangePickerState {
@ -54,7 +55,7 @@ export interface DateRangePickerState {
endDate?: moment.Moment;
}
const availableRanges: {[propName: string]: any} = {
export const availableRanges: {[propName: string]: any} = {
'today': {
label: 'Date.today',
startDate: (now: moment.Moment) => {
@ -262,6 +263,7 @@ export class DateRangePicker extends React.Component<
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handlePopOverClick = this.handlePopOverClick.bind(this);
this.renderDay = this.renderDay.bind(this);
this.renderQuarter = this.renderQuarter.bind(this);
const {format, joinValues, delimiter, value} = this.props;
this.state = {
@ -271,11 +273,11 @@ export class DateRangePicker extends React.Component<
};
}
componentWillReceiveProps(nextProps: DateRangePickerProps) {
componentDidUpdate(prevProps: DateRangePickerProps) {
const props = this.props;
const {value, format, joinValues, delimiter} = nextProps;
const {value, format, joinValues, delimiter} = props;
if (props.value !== value) {
if (prevProps.value !== value) {
this.setState({
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter)
});
@ -384,6 +386,8 @@ export class DateRangePicker extends React.Component<
value = value[type === 'start' ? 'startOf' : 'endOf']('minute');
} else if (typeof timeFormat === 'string' && /HH/i.test(timeFormat)) {
value = value[type === 'start' ? 'startOf' : 'endOf']('hour');
} else if (typeof timeFormat === 'string' && /Q/i.test(timeFormat)) {
value = value[type === 'start' ? 'startOf' : 'endOf']('quarter');
} else {
value = value[type === 'start' ? 'startOf' : 'endOf']('day');
}
@ -527,8 +531,8 @@ export class DateRangePicker extends React.Component<
checkStartIsValidDate(currentDate: moment.Moment) {
let {endDate, startDate} = this.state;
let {minDate, maxDate, minDuration, maxDuration} = this.props;
let {minDate, maxDate, minDuration, maxDuration, viewMode} = this.props;
const precision = viewMode === 'time' ? 'hours' : viewMode || 'day';
maxDate =
maxDate && endDate
@ -537,9 +541,9 @@ export class DateRangePicker extends React.Component<
: endDate
: maxDate || endDate;
if (minDate && currentDate.isBefore(minDate, 'day')) {
if (minDate && currentDate.isBefore(minDate, precision)) {
return false;
} else if (maxDate && currentDate.isAfter(maxDate, 'day')) {
} else if (maxDate && currentDate.isAfter(maxDate, precision)) {
return false;
} else if (
// 如果配置了 minDuration 那么 EndDate - minDuration 之后的天数也不能选
@ -561,8 +565,8 @@ export class DateRangePicker extends React.Component<
checkEndIsValidDate(currentDate: moment.Moment) {
let {startDate} = this.state;
let {minDate, maxDate, minDuration, maxDuration} = this.props;
let {minDate, maxDate, minDuration, maxDuration, viewMode} = this.props;
const precision = viewMode === 'time' ? 'hours' : viewMode || 'day';
minDate =
minDate && startDate
@ -571,9 +575,9 @@ export class DateRangePicker extends React.Component<
: startDate
: minDate || startDate;
if (minDate && currentDate.isBefore(minDate, 'day')) {
if (minDate && currentDate.isBefore(minDate, precision)) {
return false;
} else if (maxDate && currentDate.isAfter(maxDate, 'day')) {
} else if (maxDate && currentDate.isAfter(maxDate, precision)) {
return false;
} else if (
startDate &&
@ -606,18 +610,38 @@ export class DateRangePicker extends React.Component<
return <td {...props}>{currentDate.date()}</td>;
}
renderQuarter(props: any, quarter: number, year: number) {
const currentDate = moment().year(year).quarter(quarter);
const {startDate, endDate} = this.state;
if (
startDate &&
endDate &&
currentDate.isBetween(startDate, endDate, 'quarter', '[]')
) {
props.className += ' rdtBetween';
}
return (
<td {...props}>
<span>Q{quarter}</span>
</td>
);
}
renderCalendar() {
const {
classPrefix: ns,
classnames: cx,
dateFormat,
timeFormat,
inputFormat,
ranges,
locale,
embed
embed,
viewMode = 'days'
} = this.props;
const __ = this.props.translate;
let viewMode: 'days' | 'months' | 'years' | 'time' = 'days';
const {startDate, endDate} = this.state;
return (
@ -630,12 +654,14 @@ export class DateRangePicker extends React.Component<
onChange={this.handleStartChange}
requiredConfirm={false}
dateFormat={dateFormat}
inputFormat={inputFormat}
timeFormat={timeFormat}
isValidDate={this.checkStartIsValidDate}
viewMode={viewMode}
input={false}
onClose={this.close}
renderDay={this.renderDay}
renderQuarter={this.renderQuarter}
locale={locale}
/>
@ -645,6 +671,7 @@ export class DateRangePicker extends React.Component<
onChange={this.handleEndChange}
requiredConfirm={false}
dateFormat={dateFormat}
inputFormat={inputFormat}
timeFormat={timeFormat}
viewDate={this.nextMonth}
isEndDate
@ -653,6 +680,7 @@ export class DateRangePicker extends React.Component<
input={false}
onClose={this.close}
renderDay={this.renderDay}
renderQuarter={this.renderQuarter}
locale={locale}
/>

View File

@ -18,6 +18,8 @@ import {noop} from '../utils/helper';
import {LocaleProps, localeable} from '../locale';
import {DateRangePicker} from './DateRangePicker';
import capitalize from 'lodash/capitalize';
import {ShortCuts, ShortCutDateRange} from './DatePicker';
import {availableRanges} from './DateRangePicker';
export interface MonthRangePickerProps extends ThemeProps, LocaleProps {
className?: string;
@ -27,7 +29,8 @@ export interface MonthRangePickerProps extends ThemeProps, LocaleProps {
format: string;
utc?: boolean;
inputFormat?: string;
// ranges?: string | Array<ShortCuts>;
timeFormat?: string;
ranges?: string | Array<ShortCuts>;
clearable?: boolean;
minDate?: moment.Moment;
maxDate?: moment.Moment;
@ -103,11 +106,11 @@ export class MonthRangePicker extends React.Component<
};
}
componentWillReceiveProps(nextProps: MonthRangePickerProps) {
componentDidUpdate(prevProps: MonthRangePickerProps) {
const props = this.props;
const {value, format, joinValues, delimiter} = nextProps;
const {value, format, joinValues, delimiter} = props;
if (props.value !== value) {
if (prevProps.value !== value) {
this.setState({
...DateRangePicker.unFormatValue(value, format, joinValues, delimiter)
});
@ -275,6 +278,68 @@ export class MonthRangePicker extends React.Component<
);
}
selectRannge(range: PlainObject) {
const {closeOnSelect, minDate, maxDate} = this.props;
this.setState(
{
startDate: minDate
? moment.max(range.startDate(moment()), minDate)
: range.startDate(moment()),
endDate: maxDate
? moment.min(maxDate, range.endDate(moment()))
: range.endDate(moment())
},
closeOnSelect ? this.confirm : noop
);
}
renderRanges(ranges: string | Array<ShortCuts> | undefined) {
if (!ranges) {
return null;
}
const {classPrefix: ns} = this.props;
let rangeArr: Array<string | ShortCuts>;
if (typeof ranges === 'string') {
rangeArr = ranges.split(',');
} else {
rangeArr = ranges;
}
const __ = this.props.translate;
return (
<ul className={`${ns}DateRangePicker-rangers`}>
{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 (
<li
className={`${ns}DateRangePicker-ranger`}
onClick={() => this.selectRannge(range)}
key={range.key || range.label}
>
<a>{__(range.label)}</a>
</li>
);
})}
</ul>
);
}
clearValue(e: React.MouseEvent<any>) {
e.preventDefault();
e.stopPropagation();
@ -375,7 +440,7 @@ export class MonthRangePicker extends React.Component<
}
renderCalendar() {
const {classPrefix: ns, classnames: cx, locale, embed} = this.props;
const {classPrefix: ns, classnames: cx, locale, embed, ranges, inputFormat, timeFormat} = this.props;
const __ = this.props.translate;
const viewMode: 'months' = 'months';
const dateFormat = 'YYYY-MM';
@ -383,12 +448,15 @@ export class MonthRangePicker extends React.Component<
return (
<div className={`${ns}DateRangePicker-wrap`}>
{this.renderRanges(ranges)}
<Calendar
className={`${ns}DateRangePicker-start`}
value={startDate}
onChange={this.handleStartChange}
requiredConfirm={false}
dateFormat={dateFormat}
inputFormat={inputFormat}
timeFormat={timeFormat}
isValidDate={this.checkStartIsValidDate}
viewMode={viewMode}
input={false}
@ -406,6 +474,8 @@ export class MonthRangePicker extends React.Component<
onChange={this.handleEndChange}
requiredConfirm={false}
dateFormat={dateFormat}
inputFormat={inputFormat}
timeFormat={timeFormat}
viewDate={this.nextMonth}
isEndDate
isValidDate={this.checkEndIsValidDate}

View File

@ -21,6 +21,12 @@ interface BaseDatePickerProps
currentDate: moment.Moment,
selectedDate: moment.Moment
) => JSX.Element;
renderQuarter?: (
props: any,
quartar: number,
year?: number,
date?: moment.Moment
) => JSX.Element;
}
class BaseDatePicker extends ReactDatePicker {
@ -106,7 +112,7 @@ class BaseDatePicker extends ReactDatePicker {
.startOf(type),
currentView: nextViews[type]
});
this.props.onViewModeChange!(nextViews[type]);
this.props.onViewModeChange?.(nextViews[type]);
};
};
@ -135,6 +141,7 @@ class BaseDatePicker extends ReactDatePicker {
date = viewDate
.clone()
.quarter(parseInt(target.getAttribute('data-value')!, 10))
.startOf('quarter')
.date(currentDate.date());
} else if (target.className.indexOf('rdtYear') !== -1) {
date = viewDate
@ -173,12 +180,18 @@ class BaseDatePicker extends ReactDatePicker {
render() {
const Component = CustomCalendarContainer as any;
const viewProps = this.getComponentProps();
if (this.props.viewMode === 'quarters') {
[viewProps.updateOn, viewProps.renderQuarter] = ['quarters', this.props.renderQuarter];
}
return (
<div className={cx('rdt rdtStatic rdtOpen', this.props.className)}>
<div key="dt" className="rdtPicker">
<Component
view={this.state.currentView}
viewProps={this.getComponentProps()}
viewProps={viewProps}
/>
</div>
</div>

View File

@ -1,3 +1,4 @@
import moment from 'moment';
import React from 'react';
import {localeable, LocaleProps} from '../../locale';
import {ThemeProps} from '../../theme';
@ -21,12 +22,10 @@ export interface QuarterViewProps extends LocaleProps, ThemeProps {
showView: (view: string) => () => void;
updateSelectedDate: (e: any, close?: boolean) => void;
renderQuarter: any;
isValidDate: any;
isValidDate: (date: moment.Moment) => boolean;
}
export class QuarterView extends React.Component<QuarterViewProps> {
alwaysValidDate: any;
renderYear() {
const __ = this.props.translate;
const showYearHead = !/^mm$/i.test(this.props.inputFormat || '');
@ -67,47 +66,24 @@ export class QuarterView extends React.Component<QuarterViewProps> {
}
renderQuarters() {
let date = this.props.selectedDate,
month = this.props.viewDate.month(),
quarter = this.props.viewDate.quarter(),
year = this.props.viewDate.year(),
rows = [],
i = 1,
months = [],
quarters = [],
renderer = this.props.renderQuarter || this.renderQuarter,
isValid = this.props.isValidDate || this.alwaysValidDate,
classes,
props: any,
currentMonth: moment.Moment,
isDisabled,
noOfDaysInMonth,
daysInMonth,
validDay,
// Date is irrelevant because we're only interested in month
irrelevantDate = 1;
isDisabled;
while (i < 5) {
classes = 'rdtQuarter';
currentMonth = this.props.viewDate
.clone()
.set({year: year, quarter: i, date: irrelevantDate});
noOfDaysInMonth = currentMonth.endOf('quarter').format('Q');
daysInMonth = Array.from(
{length: parseInt(noOfDaysInMonth, 10)},
function (e, i) {
return i + 1;
}
);
validDay = daysInMonth.find(function (d) {
var day = currentMonth.clone().set('date', d);
return isValid(day);
});
isDisabled = validDay === undefined;
isDisabled = !isValid(moment(`${year}-${i}`, 'YYYY-Q'));
if (isDisabled) classes += ' rdtDisabled';
if (date && i === date.quarter() && year === date.year())
classes += ' rdtActive';
if (date && i === date.quarter() && year === date.year()) classes += ' rdtActive';
props = {
'key': i,
@ -122,13 +98,13 @@ export class QuarterView extends React.Component<QuarterViewProps> {
: this.props.setDate('quarter');
}
months.push(renderer(props, i, year, date && date.clone()));
quarters.push(renderer(props, i, year, date && date.clone()));
if (months.length === 2) {
if (quarters.length === 2) {
rows.push(
React.createElement('tr', {key: month + '_' + rows.length}, months)
React.createElement('tr', {key: quarter + '_' + rows.length}, quarters)
);
months = [];
quarters = [];
}
i++;
@ -154,6 +130,10 @@ export class QuarterView extends React.Component<QuarterViewProps> {
this.props.updateSelectedDate(event);
};
alwaysValidDate() {
return true;
}
render() {
const {classnames: cx} = this.props;