Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(DatePicker2): should support prohibit minutes and seconds close … #4745

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions components/date-picker2/__docs__/demo/disabledDate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ const disabledDate = function (date, mode) {
}
};

const disabledCurrentTime = function (date) {
return (
date.valueOf() < Number(dayjs().valueOf()) ||
date.valueOf() > Number(dayjs().add(6, 'day').valueOf())
);
};

ReactDOM.render(
<div>
<DatePicker2 disabledDate={disabledDate} onChange={val => console.log(val)} />
Expand All @@ -36,6 +43,13 @@ ReactDOM.render(
<RangePicker disabledDate={disabledDate} onChange={val => console.log(val)} />
<br />
<br />
<RangePicker
showTime
disabledDate={disabledCurrentTime}
onChange={val => console.log(val)}
/>
<br />
<br />
</div>,
mountNode
);
46 changes: 46 additions & 0 deletions components/date-picker2/__tests__/index-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,52 @@ describe('Picker', () => {
wrapper = mount(<DatePicker state="loading" />);
assert(wrapper.find('.next-icon-loading').length === 1);
});

it('should support prohibit minutes and seconds', () => {
const div = document.createElement('div');
document.body.appendChild(div);
const disabledDate = date => {
return (
date.valueOf() < Number(moment('2024-01-22 13:30:12').valueOf()) ||
date.valueOf() > Number(moment('2024-01-28 18:30:12').valueOf())
);
};
wrapper = mount(
<RangePicker
showTime
disabledDate={disabledDate}
visible={true}
followTrigger
onChange={val => console.log(val)}
defaultPanelValue={dayjs('2024-01-22 14:30:10')}
/>,
{ attachTo: div }
);
const isDisabledNode = name => {
return div.querySelector(name).classList.contains('next-disabled');
};

let startHour = isDisabledNode('.next-time-picker2-menu-hour > li[title="12"]');
let startMinute = isDisabledNode('.next-time-picker2-menu-minute > li[title="29"]');
let startSecond = isDisabledNode('.next-time-picker2-menu-second > li[title="11"]');
assert(startHour && startMinute && startSecond);

ReactTestUtils.Simulate.click(div.querySelector('td[title="2024-01-28"]'));

let endHour = isDisabledNode('.next-time-picker2-menu-hour > li[title="19"]');
ReactTestUtils.Simulate.click(
div.querySelector('.next-time-picker2-menu-hour > li[title="18"]')
);

let endMinute = isDisabledNode('.next-time-picker2-menu-minute > li[title="31"]');
ReactTestUtils.Simulate.click(
div.querySelector('.next-time-picker2-menu-minute > li[title="30"]')
);

let endSecond = isDisabledNode('.next-time-picker2-menu-second > li[title="13"]');

assert(endHour && endMinute && endSecond);
});
});
});

Expand Down
17 changes: 16 additions & 1 deletion components/date-picker2/panels/date-panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ class DatePanel extends React.Component {
func.invoke(this.props, 'onPanelChange', [v, mode]);
};

checkValueDisabled = (v, mode) => {
const { showTime, disabledDate, panelMode } = this.props;

if (showTime && mode === panelMode) {
return (
disabledDate(v.hour(0).minute(0).second(0), mode) &&
disabledDate(v.hour(23).minute(59).second(59), mode)
);
}

return disabledDate && disabledDate(v, mode);
};

render() {
const {
mode,
Expand Down Expand Up @@ -109,7 +122,7 @@ class DatePanel extends React.Component {
colNum={showTime ? 6 : undefined}
onSelect={this.handleSelect}
onPanelChange={this.handlePanelChange}
disabledDate={disabledDate}
disabledDate={this.checkValueDisabled}
dateCellRender={dateCellRender}
/>
{showTime && mode === panelMode ? (
Expand All @@ -119,6 +132,8 @@ class DatePanel extends React.Component {
value={value || this.state.defaultTime}
onSelect={this.onTimeSelect}
disabledTime={disabledTime}
disabledDate={disabledDate}
panelMode={mode}
timePanelProps={{ ..._disabledTime, ...timePanelProps }}
/>
) : null}
Expand Down
16 changes: 14 additions & 2 deletions components/date-picker2/panels/range-panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class RangePanel extends React.Component {
disabledDate,
value: [begin, end],
} = this.props;

const unit = mode2unit(mode);

return (
Expand Down Expand Up @@ -328,8 +328,17 @@ class RangePanel extends React.Component {
});
};

checkValueDisabled = (v, mode) => {
const disabledDate = this.props.justBeginInput ? this.props.disabledDate : this.disabledDate;
return (
disabledDate(v.hour(0).minute(0).second(0), mode) &&
disabledDate(v.hour(23).minute(59).second(59), mode)
);
};


renderRangeTime = sharedProps => {
const { value, prefix, showTime, inputType, timePanelProps = {}, disabledTime } = this.props;
const { value, prefix, showTime, inputType, timePanelProps = {}, disabledTime, mode } = this.props;

const className = classnames(`${prefix}range-picker2-panel`, {
[`${prefix}range-picker2-panel-single`]: this.hasModeChanged,
Expand All @@ -346,6 +355,7 @@ class RangePanel extends React.Component {
<Calendar
panelValue={this.state.panelValue}
{...sharedProps}
disabledDate={this.checkValueDisabled}
value={value[inputType]}
onPanelChange={this.handlePanelChange}
/>
Expand All @@ -356,6 +366,8 @@ class RangePanel extends React.Component {
value={value[inputType] || this.state.defaultTime[inputType]}
onSelect={this.onTimeSelect}
disabledTime={disabledTime}
disabledDate={sharedProps.disabledDate}
panelMode={mode}
timePanelProps={{ ..._disabledTime, ...timePanelProps }}
/>
) : null}
Expand Down
55 changes: 52 additions & 3 deletions components/date-picker2/panels/time-panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,53 @@ import PT from 'prop-types';
import TimePickerPanel from '../../time-picker2/panel';
import SharedPT from '../prop-types';
import { func } from '../../util';
import { getDisabledTime } from '../util'

const DECADE_TIME_FORMAT = 'HH:mm:ss';

const WithTimePanel = function (WrappedComponent) {
return class extends React.Component {
static propTypes = {
...WrappedComponent.propTypes,
disabledDate: PT.func,
panelMode: PT.string,
};

getDisabledStatus = () => {
const { value, timePanelProps, disabledDate } = this.props;

// 直接禁用时间选择,权重最高
if (timePanelProps.disabled) {
return true;
}

// 开启自定义禁用日期
if (typeof disabledDate === 'function') {
// 如果“今天”是属于禁用时间的话,先选时分秒可能导致回填数据与预期不符合,所以未选择值时,提前警用时间选择
return !value;
}

return false;
}

render() {
const { timePanelProps, ...rest } = this.props;

// 开启 disabledDate 属性时,需要提前禁用时分秒
// 如果“今天”是属于禁用时间的话,先选时分秒可能导致回填数据与预期不符合
const disabled = this.getDisabledStatus();
const disabledTime = getDisabledTime(this.props);

return (
<WrappedComponent
{...rest}
timePanelProps={{ ...timePanelProps, disabled, ...disabledTime }}
/>
);
}
};
};

class TimePanel extends React.PureComponent {
static propTypes = {
rtl: PT.bool,
Expand Down Expand Up @@ -68,9 +112,14 @@ class TimePanel extends React.PureComponent {
const { showHour, showMinute, showSecond } = this.getShow();

return (
<div dir={rtl ? 'rtl' : undefined} className={`${prefix}date-time-picker-wrapper ${prefix}calendar2-panel`}>
<div
dir={rtl ? 'rtl' : undefined}
className={`${prefix}date-time-picker-wrapper ${prefix}calendar2-panel`}
>
<div className={`${prefix}calendar2-header`}>
<div className={`${prefix}calendar2-header-text-field`}>{value ? this.formater(value) : null}</div>
<div className={`${prefix}calendar2-header-text-field`}>
{value ? this.formater(value) : null}
</div>
</div>
<TimePickerPanel
prefix={prefix}
Expand All @@ -87,4 +136,4 @@ class TimePanel extends React.PureComponent {
}
}

export default polyfill(TimePanel);
export default polyfill(WithTimePanel(TimePanel));
92 changes: 90 additions & 2 deletions components/date-picker2/util.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { datejs } from '../util';
import { datejs, func } from '../util';
import { DATE_INPUT_TYPE } from './constant';

export function setTime(targetVal, sourceVal) {
Expand Down Expand Up @@ -49,6 +49,94 @@ export function fmtValue(value, fmt) {
*/
export function isValueChanged(newValue, oldValue) {
return Array.isArray(newValue)
? isValueChanged(newValue[0], oldValue && oldValue[0]) || isValueChanged(newValue[1], oldValue && oldValue[1])
? isValueChanged(newValue[0], oldValue && oldValue[0]) ||
isValueChanged(newValue[1], oldValue && oldValue[1])
: newValue !== oldValue && !datejs(newValue).isSame(oldValue);
}

export function getDisabledTime(props) {
const { timePanelProps, value, disabledDate, panelMode } = props;
const { disabledHours, disabledMinutes, disabledSeconds } = timePanelProps;

const disabledItems = list => index => {
return list.indexOf(index) >= 0;
};

if (disabledHours || disabledMinutes || disabledSeconds) {
return {
disabledHours,
disabledMinutes,
disabledSeconds,
};
}

if (value && typeof disabledDate === 'function') {
let newDate = value.clone();
const hours = 24;
const minutesAndSeconds = 60;
const _disabledHours = [];
const _disabledMinutes = [];
const _disabledSeconds = [];
let currentHour = value.get('hour');
let currentMinute = value.get('minute');

for (let i = 0; i < hours; i++) {
// 禁用小时
if (
disabledDate(newDate.hour(i).minute(0).second(0), panelMode) &&
disabledDate(newDate.hour(i).minute(59).second(59), panelMode)
) {
_disabledHours.push(i);
}
}

if (_disabledHours.length && _disabledHours.length < hours) {
// 边界处理
while (_disabledHours.indexOf(currentHour) > -1) {
currentHour = (currentHour + 1) % hours;
}
for (let i = 0; i < minutesAndSeconds; i++) {
// 从当前小时开始遍历
if (
disabledDate(newDate.hour(currentHour).minute(i).second(0), panelMode) &&
disabledDate(newDate.hour(currentHour).minute(i).second(59), panelMode)
) {
_disabledMinutes.push(i);
}
}
}

if (_disabledMinutes.length && _disabledMinutes.length < minutesAndSeconds) {
// 边界处理
while (_disabledMinutes.indexOf(currentMinute) > -1) {
currentMinute = (currentMinute + 1) % minutesAndSeconds;
}
for (let i = 0; i < minutesAndSeconds; i++) {
// 从当前时分开始遍历
newDate = newDate.hour(currentHour).minute(currentMinute).second(i);
if (disabledDate(newDate, panelMode)) {
_disabledSeconds.push(i);
}
}
}

// 当前选中时间落在禁用区
if (disabledDate(value, panelMode)) {
// 边界处理
let currentSecond = value.get('second');
while (_disabledSeconds.indexOf(currentSecond) > -1) {
currentSecond = (currentSecond + 1) % minutesAndSeconds;
}
newDate = newDate.hour(currentHour).minute(currentMinute).second(currentSecond);
func.invoke(props, 'onSelect', [newDate]);
}

return {
disabledHours: disabledItems(_disabledHours),
disabledMinutes: disabledItems(_disabledMinutes),
disabledSeconds: disabledItems(_disabledSeconds),
};
}

return null;
}
Loading