mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
* fix: TreeSelect组件单选模式开启searchable绑定值后输入框仍然存在问题 * fix: 日期时间范围选择器的时间选择点击无效问题 (#8149)
This commit is contained in:
parent
eb8949f54e
commit
e39264f302
@ -11,6 +11,7 @@ import {themeable, ThemeProps} from 'amis-core';
|
||||
import {LocaleProps, localeable} from 'amis-core';
|
||||
import {autobind} from 'amis-core';
|
||||
import {ShortCuts} from './DatePicker';
|
||||
import type {ViewMode} from './calendar/Calendar';
|
||||
|
||||
export interface CalendarMobileProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
@ -25,7 +26,7 @@ export interface CalendarMobileProps extends ThemeProps, LocaleProps {
|
||||
maxDuration?: moment.Duration;
|
||||
dateFormat?: string;
|
||||
embed?: boolean;
|
||||
viewMode?: 'days' | 'months' | 'years' | 'time' | 'quarters';
|
||||
viewMode?: ViewMode;
|
||||
close?: () => void;
|
||||
confirm?: (startDate?: any, endTime?: any) => void;
|
||||
onChange?: (data: any, callback?: () => void) => void;
|
||||
|
@ -30,6 +30,7 @@ import Input from './Input';
|
||||
import Button from './Button';
|
||||
|
||||
import type {PlainObject, ThemeProps, LocaleProps} from 'amis-core';
|
||||
import type {ViewMode} from './calendar/Calendar';
|
||||
|
||||
export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
||||
className?: string;
|
||||
@ -67,7 +68,7 @@ export interface DateRangePickerProps extends ThemeProps, LocaleProps {
|
||||
popOverContainer?: any;
|
||||
dateFormat?: string;
|
||||
embed?: boolean;
|
||||
viewMode?: 'days' | 'months' | 'years' | 'time' | 'quarters';
|
||||
viewMode?: ViewMode;
|
||||
borderMode?: 'full' | 'half' | 'none';
|
||||
onFocus?: Function;
|
||||
onBlur?: Function;
|
||||
@ -882,12 +883,23 @@ export class DateRangePicker extends React.Component<
|
||||
|
||||
filterDate(
|
||||
date: moment.Moment,
|
||||
originValue?: moment.Moment,
|
||||
timeFormat?: string,
|
||||
type: 'start' | 'end' = 'start'
|
||||
options: {
|
||||
type: 'start' | 'end';
|
||||
originValue?: moment.Moment;
|
||||
timeFormat?: string;
|
||||
subControlViewMode?: 'time';
|
||||
} = {type: 'start'}
|
||||
): moment.Moment {
|
||||
const {type, originValue, timeFormat, subControlViewMode} = options || {
|
||||
type: 'start'
|
||||
};
|
||||
let value = date.clone();
|
||||
|
||||
/** 日期时间选择器组件支持用户选择时间,如果用户手动选择了时间,则不需要走默认处理 */
|
||||
if (subControlViewMode && subControlViewMode === 'time') {
|
||||
return value;
|
||||
}
|
||||
|
||||
// 没有初始值
|
||||
if (!originValue) {
|
||||
value = value[type === 'start' ? 'startOf' : 'endOf']('day');
|
||||
@ -915,18 +927,26 @@ export class DateRangePicker extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
handleStartDateChange(newValue: moment.Moment) {
|
||||
const {timeFormat, minDate, inputFormat, displayFormat, type} = this.props;
|
||||
let {startDate, endDateOpenedFirst} = this.state;
|
||||
/**
|
||||
* @param {Moment} newValue 当前选择的日期时间值
|
||||
* @param {ViewMode=} subControlViewMode 子选择控件的类型,可选参数('time'),用于区分datetime选择器的触发控件
|
||||
*/
|
||||
handleStartDateChange(
|
||||
newValue: moment.Moment,
|
||||
subControlViewMode?: Extract<ViewMode, 'time'>
|
||||
) {
|
||||
const {minDate, inputFormat, displayFormat, type} = this.props;
|
||||
let {startDate, endDateOpenedFirst, curTimeFormat: timeFormat} = this.state;
|
||||
if (minDate && newValue.isBefore(minDate)) {
|
||||
newValue = minDate;
|
||||
}
|
||||
const date = this.filterDate(
|
||||
newValue,
|
||||
startDate || minDate,
|
||||
|
||||
const date = this.filterDate(newValue, {
|
||||
type: 'start',
|
||||
originValue: startDate || minDate,
|
||||
timeFormat,
|
||||
'start'
|
||||
);
|
||||
subControlViewMode
|
||||
});
|
||||
const newState = {
|
||||
startDate: date,
|
||||
startInputValue: date.format(displayFormat || inputFormat)
|
||||
@ -944,13 +964,29 @@ export class DateRangePicker extends React.Component<
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
handelEndDateChange(newValue: moment.Moment) {
|
||||
const {embed, timeFormat, inputFormat, displayFormat, type} = this.props;
|
||||
let {startDate, endDate, endDateOpenedFirst} = this.state;
|
||||
/**
|
||||
* @param {Moment} newValue 当前选择的日期时间值
|
||||
* @param {string=} subControlViewMode 子选择控件的类型的类型,可选参数('time'),用于区分datetime选择器的触发控件
|
||||
*/
|
||||
handelEndDateChange(
|
||||
newValue: moment.Moment,
|
||||
subControlViewMode?: Extract<ViewMode, 'time'>
|
||||
) {
|
||||
const {embed, inputFormat, displayFormat, type} = this.props;
|
||||
let {
|
||||
startDate,
|
||||
endDate,
|
||||
endDateOpenedFirst,
|
||||
curTimeFormat: timeFormat
|
||||
} = this.state;
|
||||
newValue = this.getEndDateByDuration(newValue);
|
||||
const editState = endDateOpenedFirst ? 'start' : 'end';
|
||||
|
||||
const date = this.filterDate(newValue, endDate, timeFormat, 'end');
|
||||
const date = this.filterDate(newValue, {
|
||||
type: 'end',
|
||||
originValue: endDate,
|
||||
timeFormat,
|
||||
subControlViewMode
|
||||
});
|
||||
this.setState(
|
||||
{
|
||||
endDate: date,
|
||||
|
@ -16,6 +16,9 @@ import 'moment/locale/zh-cn';
|
||||
import 'moment/locale/de';
|
||||
import type {RendererEnv} from 'amis-core';
|
||||
|
||||
/** 视图模式 */
|
||||
export type ViewMode = 'days' | 'months' | 'years' | 'time' | 'quarters';
|
||||
|
||||
export type DateType =
|
||||
| 'year'
|
||||
| 'month'
|
||||
@ -48,7 +51,7 @@ interface BaseDatePickerProps {
|
||||
className?: string;
|
||||
value?: any;
|
||||
defaultValue?: any;
|
||||
viewMode?: 'years' | 'months' | 'days' | 'time' | 'quarters';
|
||||
viewMode?: ViewMode;
|
||||
dateFormat?: boolean | string;
|
||||
inputFormat?: boolean | string;
|
||||
displayForamt?: boolean | string;
|
||||
@ -63,7 +66,7 @@ interface BaseDatePickerProps {
|
||||
onViewModeChange?: (type: string) => void;
|
||||
requiredConfirm?: boolean;
|
||||
onClose?: () => void;
|
||||
onChange?: (value: any) => void;
|
||||
onChange?: (value: any, viewMode?: Extract<ViewMode, 'time'>) => void;
|
||||
isEndDate?: boolean;
|
||||
minDate?: moment.Moment;
|
||||
maxDate?: moment.Moment;
|
||||
@ -480,7 +483,7 @@ class BaseDatePicker extends React.Component<
|
||||
inputValue: date.format(state.displayForamt as string)
|
||||
});
|
||||
}
|
||||
this.props.onChange && this.props.onChange(date);
|
||||
this.props.onChange && this.props.onChange(date, 'time');
|
||||
};
|
||||
|
||||
setDate = (type: 'month' | 'year' | 'quarters') => {
|
||||
|
@ -19,9 +19,11 @@ import type {RendererEnv} from 'amis-core';
|
||||
import Picker from '../Picker';
|
||||
import {PickerOption} from '../PickerColumn';
|
||||
import {DateType} from './Calendar';
|
||||
import type {TimeScale} from './TimeView';
|
||||
import {Icon} from '../icons';
|
||||
|
||||
import type {TimeScale} from './TimeView';
|
||||
import type {ViewMode} from './Calendar';
|
||||
|
||||
interface CustomDaysViewProps extends LocaleProps {
|
||||
classPrefix?: string;
|
||||
prevIcon?: string;
|
||||
@ -37,7 +39,10 @@ interface CustomDaysViewProps extends LocaleProps {
|
||||
isEndDate?: boolean;
|
||||
renderDay?: Function;
|
||||
onClose?: () => void;
|
||||
onChange: (value: moment.Moment) => void;
|
||||
onChange: (
|
||||
value: moment.Moment,
|
||||
viewMode?: Extract<ViewMode, 'time'>
|
||||
) => void;
|
||||
onConfirm?: (value: number[], types: DateType[]) => void;
|
||||
setDateTimeState: (state: any) => void;
|
||||
showTime: () => void;
|
||||
@ -294,6 +299,7 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
|
||||
showTime = () => {
|
||||
const {selectedDate, viewDate, timeFormat} = this.props;
|
||||
|
||||
return (
|
||||
<div key="stb" className="rdtShowTime">
|
||||
{(selectedDate || viewDate || moment()).format(timeFormat)}
|
||||
@ -306,15 +312,16 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
value: number
|
||||
) => {
|
||||
const date = (this.props.selectedDate || this.props.viewDate).clone();
|
||||
date[type](value);
|
||||
|
||||
date[type](value);
|
||||
const updatedDate = date.clone();
|
||||
this.props.setDateTimeState({
|
||||
viewDate: date.clone(),
|
||||
selectedDate: date.clone()
|
||||
viewDate: updatedDate,
|
||||
selectedDate: updatedDate
|
||||
});
|
||||
|
||||
if (!this.props.requiredConfirm) {
|
||||
this.props.onChange(date);
|
||||
this.props.onChange(date, 'time');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -530,3 +530,76 @@ test('Tree: item disabled', async () => {
|
||||
transfer: ''
|
||||
});
|
||||
});
|
||||
|
||||
test('Tree: single value mode should not render input when searchable enabled and default value settled', async () => {
|
||||
const {container} = render(
|
||||
amisRender({
|
||||
type: 'container',
|
||||
body: [
|
||||
{
|
||||
"type": "tree-select",
|
||||
"name": "tree",
|
||||
"label": "Tree",
|
||||
"searchable": true,
|
||||
"value": 2,
|
||||
"inputClassName": "single",
|
||||
"options": [
|
||||
{
|
||||
"label": "Folder A",
|
||||
"value": 1,
|
||||
"children": [
|
||||
{
|
||||
"label": "file A",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "file B",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "tree-select",
|
||||
"name": "tree2",
|
||||
"label": "Tree2",
|
||||
"searchable": true,
|
||||
"value": "2,4",
|
||||
"multiple": true,
|
||||
"inputClassName": "multiple",
|
||||
"options": [
|
||||
{
|
||||
"label": "Folder A",
|
||||
"value": 1,
|
||||
"children": [
|
||||
{
|
||||
"label": "file A",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "file B",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "file C",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
));
|
||||
|
||||
const singleModeInput = container.querySelector('.single .cxd-ResultBox-value-input');
|
||||
const multipleModeInput = container.querySelector('.multiple .cxd-ResultBox-value-input');
|
||||
|
||||
/** 单选模式且已选值,不应该再有 input */
|
||||
expect(singleModeInput).not.toBeInTheDocument();
|
||||
/** 多选模式始终都有 input */
|
||||
expect(multipleModeInput).toBeInTheDocument();
|
||||
})
|
||||
|
@ -695,8 +695,13 @@ export default class TreeSelectControl extends React.Component<
|
||||
env,
|
||||
loadingConfig
|
||||
} = this.props;
|
||||
|
||||
const {isOpened} = this.state;
|
||||
const resultValue = multiple
|
||||
? selectedOptions
|
||||
: selectedOptions.length
|
||||
? this.renderItem(selectedOptions[0])
|
||||
: '';
|
||||
|
||||
return (
|
||||
<div ref={this.container} className={cx(`TreeSelectControl`, className)}>
|
||||
<ResultBox
|
||||
@ -716,13 +721,7 @@ export default class TreeSelectControl extends React.Component<
|
||||
'is-opened': this.state.isOpened,
|
||||
'is-disabled': disabled
|
||||
})}
|
||||
result={
|
||||
multiple
|
||||
? selectedOptions
|
||||
: selectedOptions.length
|
||||
? this.renderItem(selectedOptions[0])
|
||||
: ''
|
||||
}
|
||||
result={resultValue}
|
||||
onResultClick={this.handleOutClick}
|
||||
value={this.state.inputValue}
|
||||
onChange={this.handleInputChange}
|
||||
@ -733,7 +732,11 @@ export default class TreeSelectControl extends React.Component<
|
||||
onBlur={this.handleBlur}
|
||||
onKeyDown={this.handleInputKeyDown}
|
||||
clearable={clearable}
|
||||
allowInput={!mobileUI && (searchable || isEffectiveApi(autoComplete))}
|
||||
allowInput={
|
||||
!mobileUI &&
|
||||
(searchable || isEffectiveApi(autoComplete)) &&
|
||||
(multiple || !resultValue)
|
||||
}
|
||||
hasDropDownArrow
|
||||
readOnly={mobileUI}
|
||||
mobileUI={mobileUI}
|
||||
|
Loading…
Reference in New Issue
Block a user