diff --git a/packages/amis-ui/scss/components/form/_date-range.scss b/packages/amis-ui/scss/components/form/_date-range.scss index 923ae9406..0d5efcdc1 100644 --- a/packages/amis-ui/scss/components/form/_date-range.scss +++ b/packages/amis-ui/scss/components/form/_date-range.scss @@ -17,8 +17,6 @@ } &:not(.is-disabled) { - cursor: pointer; - &:hover { background: var(--DatePicker-onHover-bg); border-color: var(--DatePicker-onHover-borderColor); @@ -40,7 +38,7 @@ .#{$ns}DateRangePicker-input { border: none; - border-bottom: 1px solid transparent; + border-bottom: 2px solid transparent; outline: none; padding: 0; background: 0; @@ -49,7 +47,7 @@ } .#{$ns}DateRangePicker-input.isActive { - border-bottom: 1px solid var(--DatePicker-onFocused-borderColor); + border-bottom: 2px solid var(--Form-input-onHover-borderColor); } .#{$ns}DateRangePicker-input-separator { diff --git a/packages/amis-ui/scss/components/form/_date.scss b/packages/amis-ui/scss/components/form/_date.scss index dcf3cfe3b..8f722fcce 100644 --- a/packages/amis-ui/scss/components/form/_date.scss +++ b/packages/amis-ui/scss/components/form/_date.scss @@ -289,7 +289,6 @@ .rdtActive.rdtToday { color: #151b26; > span { - background: transparent; border-color: #144bcc; } } @@ -334,12 +333,21 @@ } } +.#{$ns}CalendarTimesWrapper { + display: flex; + flex-direction: column; + height: 100%; + .#{$ns}CalendarInputsWrapper { + height: #{px2rem(248px)}; + } +} + .#{$ns}CalendarInputWrapper { display: inline-block; position: relative; // padding-top: #{px2rem(4px)}; width: #{px2rem(64px)}; - height: #{px2rem(224px)}; + height: #{px2rem(248px)}; overflow: auto; .#{$ns}CalendarInput-sugs { list-style: none; @@ -350,10 +358,10 @@ top: 100%; z-index: 10; &Hours { - height: #{px2rem(868px)}; + height: #{px2rem(892px)}; } &Times { - height: #{px2rem(1876px)}; + height: #{px2rem(1900px)}; border-left: 1px solid var(--Calendar-input-borderColor); } &Item { @@ -610,28 +618,39 @@ td.rdtQuarter { } } -.#{$ns}DateRangePicker-start { - .rdtPicker .rdtActive.rdtBetween { - background: linear-gradient( - to right, - transparent 0%, - transparent 50%, - var(--Calendar-cell-onBetween-bg) 51%, - var(--Calendar-cell-onBetween-bg) 100% - ); +.rdtPicker .rdtActive.rdtBetween.rdtStartDay { + background: linear-gradient( + to right, + transparent 0%, + transparent 50%, + var(--Calendar-cell-onBetween-bg) 51%, + var(--Calendar-cell-onBetween-bg) 100% + ); +} + +.rdt .rdtPicker td.is-disabled { + cursor: not-allowed !important; + background: var(--Calendar-cell-onDisabled-bg); + color: var(--text--muted-color); + + &:hover { + background: var(--Calendar-cell-onDisabled-bg); + color: var(--text--muted-color); + & > span { + background: inherit !important; + color: inherit !important; + } } } -.#{$ns}DateRangePicker-end { - .rdtPicker .rdtActive.rdtBetween { - background: linear-gradient( - to right, - var(--Calendar-cell-onBetween-bg) 0%, - var(--Calendar-cell-onBetween-bg) 50%, - transparent 51%, - transparent 100% - ); - } +.rdtPicker .rdtActive.rdtBetween.rdtEndDay { + background: linear-gradient( + to right, + var(--Calendar-cell-onBetween-bg) 0%, + var(--Calendar-cell-onBetween-bg) 50%, + transparent 51%, + transparent 100% + ); } .#{$ns}DateCalendar { diff --git a/packages/amis-ui/src/components/DatePicker.tsx b/packages/amis-ui/src/components/DatePicker.tsx index 93df422eb..9ebadb599 100644 --- a/packages/amis-ui/src/components/DatePicker.tsx +++ b/packages/amis-ui/src/components/DatePicker.tsx @@ -356,11 +356,14 @@ export class DatePicker extends React.Component { this.handlePopOverClick = this.handlePopOverClick.bind(this); this.renderShortCuts = this.renderShortCuts.bind(this); this.inputChange = this.inputChange.bind(this); + this.onInputBlur = this.onInputBlur.bind(this); } dom: HTMLDivElement; inputRef: React.RefObject; + // 缓存上一次的input值 + inputValueCache: string; componentDidMount() { this.props?.onRef?.(this); @@ -378,7 +381,7 @@ export class DatePicker extends React.Component { newState.inputValue = newState.value?.format(this.props.inputFormat) || ''; - + this.inputValueCache = newState.inputValue; this.setState(newState); } } @@ -533,6 +536,12 @@ export class DatePicker extends React.Component { } } + onInputBlur() { + this.setState({ + inputValue: this.inputValueCache + }); + } + selectRannge(item: any) { const {closeOnSelect} = this.props; const now = moment(); @@ -775,6 +784,7 @@ export class DatePicker extends React.Component { ; calendarRef: React.RefObject; - nextMonth = moment().add(1, 'months'); + nextMonth = moment().add(1, 'months').startOf('day'); + currentMonth = moment().startOf('day'); startInputRef: React.RefObject; endInputRef: React.RefObject; @@ -505,7 +508,7 @@ export class DateRangePicker extends React.Component< this.endInputChange = this.endInputChange.bind(this); this.handleDateChange = this.handleDateChange.bind(this); this.handleStartDateChange = this.handleStartDateChange.bind(this); - this.handeleEndDateChange = this.handeleEndDateChange.bind(this); + this.handelEndDateChange = this.handelEndDateChange.bind(this); this.handleTimeStartChange = this.handleTimeStartChange.bind(this); this.handleTimeEndChange = this.handleTimeEndChange.bind(this); this.handleFocus = this.handleFocus.bind(this); @@ -540,7 +543,8 @@ export class DateRangePicker extends React.Component< oldStartDate: startDate, oldEndDate: endDate, startInputValue: startDate?.format(inputFormat), - endInputValue: endDate?.format(inputFormat) + endInputValue: endDate?.format(inputFormat), + endDateOpenedFirst: false }; } componentDidMount() { @@ -646,7 +650,8 @@ export class DateRangePicker extends React.Component< } this.setState({ isOpened: true, - editState: 'end' + editState: 'end', + endDateOpenedFirst: true }); } @@ -660,11 +665,17 @@ export class DateRangePicker extends React.Component< startDate: oldStartDate, startInputValue: oldStartDate ? oldStartDate.format(inputFormat) : '' }); + } else { + this.setState({ + oldStartDate: this.state.startDate, + oldEndDate: this.state.endDate + }); } this.setState( { isOpened: false, - editState: undefined + editState: undefined, + endDateOpenedFirst: false }, this.blur ); @@ -689,7 +700,10 @@ export class DateRangePicker extends React.Component< confirm() { if (!this.state.startDate && !this.state.endDate) { return; - } else if (this.state.startDate?.isAfter(this.state.endDate)) { + } else if ( + this.state.endDate && + this.state.startDate?.isAfter(this.state.endDate) + ) { return; } @@ -706,7 +720,7 @@ export class DateRangePicker extends React.Component< ) ); if (this.state.startDate && !this.state.endDate) { - this.setState({editState: 'end'}); + this.setState({editState: 'end', endDateOpenedFirst: false}); } else { this.close(true); } @@ -743,13 +757,13 @@ export class DateRangePicker extends React.Component< if (editState === 'start') { this.handleStartDateChange(newValue); } else if (editState === 'end') { - this.handeleEndDateChange(newValue); + this.handelEndDateChange(newValue); } } handleStartDateChange(newValue: moment.Moment) { const {timeFormat, minDate, inputFormat, type} = this.props; - let {startDate} = this.state; + let {startDate, endDateOpenedFirst} = this.state; if (minDate && newValue.isBefore(minDate)) { newValue = minDate; } @@ -761,46 +775,41 @@ export class DateRangePicker extends React.Component< ); const newState = { startDate: date, - oldStartDate: startDate, startInputValue: date.format(inputFormat) } as any; // 这些没有时间的选择点第一次后第二次就是选结束时间 if ( - type === 'input-date-range' || - type === 'input-year-range' || - type === 'input-quarter-range' || - type === 'input-month-range' + !endDateOpenedFirst && + (type === 'input-date-range' || + type === 'input-year-range' || + type === 'input-quarter-range' || + type === 'input-month-range') ) { newState.editState = 'end'; } this.setState(newState); } - handeleEndDateChange(newValue: moment.Moment) { - const {embed, timeFormat, inputFormat} = this.props; - let {startDate, endDate} = this.state; + handelEndDateChange(newValue: moment.Moment) { + const {embed, timeFormat, inputFormat, type} = this.props; + let {startDate, endDate, endDateOpenedFirst} = this.state; newValue = this.getEndDateByDuration(newValue); - - // 如果结束时间在前面,需要清空开始时间 - if (newValue.isBefore(startDate)) { - this.setState({ - startDate: undefined, - oldStartDate: startDate, - startInputValue: '' - }); - } + const editState = endDateOpenedFirst ? 'start' : 'end'; const date = this.filterDate(newValue, endDate, timeFormat, 'end'); this.setState( { endDate: date, - oldEndDate: endDate, endInputValue: date.format(inputFormat) }, () => { embed && this.confirm(); } ); + + if (type !== 'input-datetime-range') { + this.setState({editState}); + } } // 手动控制输入时间 @@ -1155,7 +1164,7 @@ export class DateRangePicker extends React.Component< } renderDay(props: any, currentDate: moment.Moment) { - let {startDate, endDate} = this.state; + let {startDate, endDate, endDateOpenedFirst, editState} = this.state; if ( startDate && @@ -1165,8 +1174,19 @@ export class DateRangePicker extends React.Component< props.className += ' rdtBetween'; } + if (startDate && currentDate.isSame(startDate, 'day')) { + props.className += ' rdtActive rdtStartDay'; + } + + if (endDate && currentDate.isSame(endDate, 'day')) { + props.className += ' rdtActive rdtEndDay'; + } + + const {className, ...others} = this.getDisabledElementProps(currentDate); + props.className += className; + return ( - + {currentDate.date()} ); @@ -1189,8 +1209,11 @@ export class DateRangePicker extends React.Component< props.className += ' rdtBetween'; } + const {className, ...others} = this.getDisabledElementProps(currentDate); + props.className += className; + return ( - + {monthStrFixedLength} ); @@ -1208,8 +1231,11 @@ export class DateRangePicker extends React.Component< props.className += ' rdtBetween'; } + const {className, ...others} = this.getDisabledElementProps(currentDate); + props.className += className; + return ( - + Q{quarter} ); @@ -1226,8 +1252,11 @@ export class DateRangePicker extends React.Component< props.className += ' rdtBetween'; } + const {className, ...others} = this.getDisabledElementProps(currentDate); + props.className += className; + return ( - + {year} ); @@ -1251,8 +1280,9 @@ export class DateRangePicker extends React.Component< const {startDate, endDate, editState} = this.state; + const isDateTimeRange = type === 'input-datetime-range'; // timeRange需要单独选择范围 - const isTimeRange = type === 'input-datetime-range' || viewMode === 'time'; + const isTimeRange = isDateTimeRange || viewMode === 'time'; return (
@@ -1264,7 +1294,7 @@ export class DateRangePicker extends React.Component< // 区分的原因是 time-range 左侧就只能选起始时间,而其它都能在左侧同时同时选择起始和结束 // TODO: 后续得把 time-range 代码拆分出来 onChange={ - type === 'input-datetime-range' + isDateTimeRange ? this.handleStartDateChange : viewMode === 'time' ? this.handleTimeStartChange @@ -1291,8 +1321,8 @@ export class DateRangePicker extends React.Component< className={`${ns}DateRangePicker-end`} value={endDate} onChange={ - type === 'input-datetime-range' - ? this.handeleEndDateChange + isDateTimeRange + ? this.handelEndDateChange : viewMode === 'time' ? this.handleTimeEndChange : this.handleDateChange @@ -1301,8 +1331,8 @@ export class DateRangePicker extends React.Component< dateFormat={dateFormat} inputFormat={inputFormat} timeFormat={timeFormat} - viewDate={this.nextMonth} - isEndDate + viewDate={isDateTimeRange ? this.currentMonth : this.nextMonth} + // isEndDate isValidDate={this.checkEndIsValidDate} viewMode={viewMode} input={false} @@ -1320,7 +1350,7 @@ export class DateRangePicker extends React.Component<
this.close} + onClick={() => this.close()} > {__('cancel')} @@ -1331,7 +1361,8 @@ export class DateRangePicker extends React.Component< isTimeRange && editState === 'start') || (!this.state.endDate && isTimeRange && editState === 'end') || - this.state.endDate?.isBefore(this.state.startDate) + (this.state.startDate && + this.state.endDate?.isBefore(this.state.startDate)) })} onClick={this.confirm} > @@ -1343,6 +1374,23 @@ export class DateRangePicker extends React.Component< ); } + getDisabledElementProps(currentDate: moment.Moment) { + const {endDateOpenedFirst, endDate, startDate, editState} = this.state; + const afterEndDate = editState === 'start' && currentDate > endDate!; + const beforeStartDate = editState === 'end' && currentDate < startDate!; + + if (afterEndDate || beforeStartDate) { + return { + className: ' is-disabled', + onClick: undefined + }; + } + + return { + className: '' + }; + } + render() { const { className, diff --git a/packages/amis-ui/src/components/calendar/DaysView.tsx b/packages/amis-ui/src/components/calendar/DaysView.tsx index c532d38b9..af0d74f42 100644 --- a/packages/amis-ui/src/components/calendar/DaysView.tsx +++ b/packages/amis-ui/src/components/calendar/DaysView.tsx @@ -531,8 +531,6 @@ export class CustomDaysView extends React.Component { const inputs: Array = []; const timeConstraints = this.timeConstraints; - inputs.push(this.showTime()); - timeFormat.split(':').forEach((format, i) => { const type = /h/i.test(format) ? 'hours' @@ -631,7 +629,12 @@ export class CustomDaysView extends React.Component { } }); inputs.length && inputs.pop(); - return
{inputs}
; + return ( +
+ {this.showTime()} +
{inputs}
+
+ ); }; renderFooter = () => {