UNPKG

zarm-web

Version:
454 lines (385 loc) 11.8 kB
import React, { Component } from 'react'; import classnames from 'classnames'; import Events from '../utils/events'; import Format from '../utils/format'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import Dropdown from '../dropdown/index'; import RangeCalendar from '../calendar/Calendar'; import Icon from '../icon/index'; // 比较时间大小 const compareTime = (v1, v2) => new Date(v1) > new Date(v2); // 获取当前时间 Date 对象 const now = () => new Date(); // 获取原生 Date 对象 const getDate = v => v ? new Date(v) : now(); // 获取下月 1 号 const nextMonthFirstDay = v => { let date = `${v.getFullYear()}/${v.getMonth() + 2}/1`; if (v.getMonth() + 2 > 12) { date = `${v.getFullYear() + 1}/1/1`; } return getDate(date); }; // 获取日期的年、月、日 const getYearMonthDay = v => [v.getFullYear(), v.getMonth(), v.getDate()]; // 判断是否为空对象 const isEmptyArray = arr => Array.isArray(arr) && (arr.length === 0 || arr.every(i => !i)); // const getValueFromSelectedValue = (v = []) => { if (isEmptyArray(v)) { return [now(), nextMonthFirstDay(now())]; } const [start, end] = v.map(getDate); const newEnd = start.getMonth() === end.getMonth() && start.getFullYear() === end.getFullYear() ? nextMonthFirstDay(end) : end; return [start, newEnd]; }; // 空方法 const fn = () => {}; class RangeDatePicker extends Component { constructor(props) { super(props); this.unmounted = void 0; this.onSelectClick = e => { e.preventDefault(); const disabled = 'disabled' in this.props || this.props.isDisabled; if (!disabled) { this.setDropdown(!this.state.isShowDropdown); } }; this.getStartDate = () => { const { current } = this.state; return getDate(current[0]); }; this.getEndDate = () => { const { current } = this.state; const [start, end] = current.map(getDate); // 当结束时间不存在时,结束时间初始值为开始时间月份加 1 return getDate(end || nextMonthFirstDay(start)); }; this.disabledStartMonth = month => { const { current, selectedValue } = this.state; const end = getDate(current[1] || selectedValue[1] || nextMonthFirstDay(now())); const [endYear, endMonth] = getYearMonthDay(end); const [_year, _month] = getYearMonthDay(getDate(month)); if (_year < endYear) { return true; } if (_year === endYear) { return _month < endMonth; } return false; }; this.disabledEndMonth = month => { const { current, selectedValue } = this.state; const start = getDate(current[0] || selectedValue[0]); const [startYear, startMonth] = getYearMonthDay(start); const [_year, _month] = getYearMonthDay(getDate(month)); if (_year > startYear) { return true; } if (_year === startYear) { return _month > startMonth; } return false; }; this.handleLeftPanelChange = v => { const { current: stateCurrent } = this.state; const current = [...stateCurrent]; current[0] = v; this.setState({ current }); }; this.handleRightPanelChange = v => { const { current: stateCurrent } = this.state; const current = [...stateCurrent]; current[1] = v; this.setState({ current }); }; this.handleLeftDateChange = (v, _dropdown, isTime) => { const { selectedValue } = this.state; const start = getDate(v); const end = getDate(selectedValue[1]); // 同年同月,表示一个月选了两个日期 if (!(start.getMonth() === end.getMonth() && start.getFullYear() === end.getFullYear())) { this.handleLeftPanelChange(v); } this.handleDateChange(v, isTime, true); }; this.handleRightDateChange = (v, _dropdown, isTime) => { const { selectedValue } = this.state; const start = getDate(selectedValue[0]); const end = getDate(v); // 同年同月,表示一个月选了两个日期 if (!(start.getMonth() === end.getMonth() && start.getFullYear() === end.getFullYear())) { this.handleRightPanelChange(v); } this.handleDateChange(v, isTime, false); }; this.handleDateChange = (v, isTime, isLeft) => { const { selectedValue } = this.state; if (isTime) { if (isLeft) { this.setState({ selectedValue: [v, selectedValue[1]] }); } else { this.setState({ selectedValue: [selectedValue[0], v] }); } return; } if (selectedValue.length === 1) { if (compareTime(selectedValue[0], v)) { this.setState({ selectedValue: [v, selectedValue[0]] }, () => this.handleCloseDropDownAndChangeDate()); } else { this.setState({ selectedValue: [selectedValue[0], v] }, () => this.handleCloseDropDownAndChangeDate()); } } else { this.setState({ selectedValue: [v] }); } }; this.handleCloseDropDown = () => { this.setDropdown(false); this.props.onChange([]); }; this.handleConfirm = () => { this.handleCloseDropDownAndChangeDate(true); }; this.handleCloseDropDownAndChangeDate = isConfirm => { const { showTime, onChange, format } = this.props; const { selectedValue } = this.state; if (isConfirm || !showTime) { this.setDropdown(false, () => onChange(selectedValue.map(v => Format.date(v, format)))); } }; this.handleKeyup = e => { if (e.keyCode === 27) { this.setDropdown(false); } }; this.handleDropDownVisibleChange = visible => { const { isDisabled } = this.props; const disabled = 'disabled' in this.props || isDisabled; if (disabled) { return; } this.setState({ isShowDropdown: visible }); }; this.renderPlaceholder = () => { const { placeholder, isDisabled, isRadius, size, style, value = [], locale } = this.props; const { isShowDropdown } = this.state; let valueText = placeholder || locale.placeholder; let hasValue = false; if (value.length) { if (typeof value !== 'string') { valueText = value.join(' —— '); } hasValue = true; } const disabled = 'disabled' in this.props || isDisabled; const radius = 'radius' in this.props || isRadius; const cls = classnames('za-select', { 'za-select--open': isShowDropdown, disabled, radius, [`size-${size}`]: !!size }); const textCls = classnames('za-select__text', { 'za-select__text-placeholder': !hasValue }); return React.createElement("span", { className: cls, style: style }, React.createElement("span", { className: "za-select__selection", "aria-autocomplete": "list", "aria-haspopup": "true", "aria-expanded": "false", onClick: this.onSelectClick }, React.createElement("span", { className: textCls }, valueText), React.createElement(Icon, { className: "za-select__icon", type: "date" }))); }; this.unmounted = false; this.state = { selectedValue: props.value.map(getDate), current: getValueFromSelectedValue(props.value), isShowDropdown: false }; } componentDidMount() { this.unmounted = true; } componentWillReceiveProps(nextProps) { if ('value' in nextProps) { this.setState({ selectedValue: nextProps.value.map(getDate), current: getValueFromSelectedValue(nextProps.value) }); } } componentWillUnmount() { this.unmounted = false; this.unbindOuterHandlers(); } setDropdown(isOpen, callback) { if (!this.unmounted) { return; } if (isOpen) { this.bindOuterHandlers(); } else { this.unbindOuterHandlers(); } this.setState({ isShowDropdown: isOpen }, () => { if (callback) { callback(); } }); } bindOuterHandlers() { Events.on(document, 'keyup', this.handleKeyup); } unbindOuterHandlers() { Events.off(document, 'keyup', this.handleKeyup); } render() { const { defaultValue, isRadius, format, min, max, showTime, locale } = this.props; const { selectedValue, current, isShowDropdown } = this.state; const radius = 'radius' in this.props || isRadius; const startDate = this.getStartDate(); const endDate = this.getEndDate(); // 开始时间月份加 1 且 年份与结束时间相同时,不允许点击左日历月份加 1,不允许右日历月份减 1 const isAllowJumpMonth = !(startDate.getMonth() + 1 === endDate.getMonth() && startDate.getFullYear() === endDate.getFullYear()); const compRangeCalendar = React.createElement(React.Fragment, null, React.createElement("div", { style: { float: 'left', width: '50%' } }, React.createElement(RangeCalendar, { isLeftCalendar: true, defaultValue: defaultValue, selectedValue: selectedValue, current: current[0] || startDate, value: selectedValue[0] || current[0], format: format, min: min, max: max, showTime: showTime, isShowPrev: true, isShowNext: isAllowJumpMonth, disabledMonth: this.disabledStartMonth, onPanelChange: this.handleLeftPanelChange, onChange: this.handleLeftDateChange })), React.createElement("div", { style: { float: 'right', width: '50%' } }, React.createElement(RangeCalendar, { isRightCalendar: true, defaultValue: defaultValue, selectedValue: selectedValue, current: current[1] || endDate, value: selectedValue[1] || current[1], format: format, min: min, max: max, showTime: showTime, isShowPrev: isAllowJumpMonth, isShowNext: true, disabledMonth: this.disabledEndMonth, onPanelChange: this.handleRightPanelChange, onChange: this.handleRightDateChange }))); const timeFooter = React.createElement("div", { className: "za-range__date-picker-footer" }, React.createElement("span", { className: "za-range__date-picker-footer-btn", onClick: this.handleCloseDropDown }, locale.clear), React.createElement("span", { onClick: this.handleConfirm }, locale.confirm)); const rangeDatePickerStyle = classnames('za-range__date-picker', { 'za-range__date-time-picker': showTime }); const rangeDatePicker = React.createElement("div", { className: rangeDatePickerStyle }, React.createElement("div", { className: "za-range__date-picker-table" }, compRangeCalendar), showTime && timeFooter); return React.createElement(Dropdown, { onVisibleChange: this.handleDropDownVisibleChange, overlay: rangeDatePicker, isRadius: radius, visible: isShowDropdown, hideOnClick: !showTime }, this.renderPlaceholder()); } } RangeDatePicker.defaultProps = { isRange: false, isDisabled: false, format: 'yyyy-MM-dd', min: '', max: '', value: [], onChange: fn }; export default LocaleReceiver('Calendar')(RangeDatePicker);