// @ts-nocheck import React, { createRef, PureComponent } from 'react' import PropTypes from 'prop-types' import dayjs from 'dayjs' import { throttle, formatMonthData, formatWeekData } from './util' import './calendar.less' import arrow from './static/arrow.svg' import doubleArrow from './static/double-arrow.svg' const head = ['日', '一', '二', '三', '四', '五', '六'] class MonthView extends PureComponent { static defaultProps: { currentDate: string; showType: string; transitionDuration: number; onDateClick: () => void; onTouchStart: () => void; onTouchMove: () => void; onTouchEnd: () => void; onToggleShowType: () => void; markType: string; markDates: never[]; disableWeekView: boolean } isTouching: boolean calendarRef: React.RefObject constructor(props:any) { super(props) this.state = { currentMonthFirstDay: null, monthDates: [], // 月日历需要展示的日期 包括前一月 当月 下一月 currenWeekFirstDay: null, weekDates: [], // 周日李需要展示的日期 包括前一周 当周 下一周 currentDate: '', touch: { x: 0, y: 0 }, translateIndex: 0, calendarY: 0, // 于Y轴的位置 showType: props.showType, } this.isTouching = false this.calendarRef = createRef() } static getDerivedStateFromProps(nextProps: { currentDate: any }, prevState: { currentDate: any }) { const { currentDate } = nextProps if (currentDate !== prevState.currentDate) { const dayjsDate:any = dayjs(currentDate) return { ...formatMonthData(dayjsDate), ...formatWeekData(dayjsDate), currentDate, } } return null } handleTouchMove = throttle((e: { stopPropagation: () => void; touches: { clientY: number }[] }) => { e.stopPropagation() const { disableWeekView } = this.props const moveX = e.touches[0].clientX - this.touchStartPositionX const moveY = e.touches[0].clientY - this.touchStartPositionY const calendarWidth = this.calendarRef.current.offsetWidth const calendarHeight = this.calendarRef.current.offsetHeight if (Math.abs(moveX) > Math.abs(moveY)) { // 左右滑动 this.setState({ touch: { x: moveX / calendarWidth, y: 0 } }) } else if (!disableWeekView) { this.setState({ touch: { x: 0, y: moveY / calendarHeight } }) } this.props.onTouchMove(e) }, 25) handleTouchStart = (e: { stopPropagation: () => void; touches: { clientY: any }[] }) => { e.stopPropagation() this.touchStartPositionX = e.touches[0].clientX this.touchStartPositionY = e.touches[0].clientY this.isTouching = true this.props.onTouchStart(e) } handleTouchEnd = (e: { stopPropagation: () => void }) => { e.stopPropagation() const { showType } = this.state const { disableWeekView } = this.props const calendarHeight = this.calendarRef.current.offsetHeight const { touch, translateIndex, currentMonthFirstDay, currenWeekFirstDay } = this.state this.f = false this.isTouching = false const absTouchX = Math.abs(touch.x) const absTouchY = Math.abs(touch.y) if (absTouchX > absTouchY && absTouchX > 0.15) { const isMonthView = showType === 'month' const newTranslateIndex = touch.x > 0 ? translateIndex + 1 : translateIndex - 1 if (isMonthView) { // 月视图 const nextMonthFirstDay = currentMonthFirstDay[touch.x > 0 ? 'subtract' : 'add'](1, 'month') const nextMonthStartDay = nextMonthFirstDay.startOf('week') const nextMonthEndDay = nextMonthStartDay.add(42, 'day') this.setState( { translateIndex: newTranslateIndex, ...formatMonthData(nextMonthFirstDay), }, this.props.onTouchEnd(nextMonthStartDay.valueOf(), nextMonthEndDay.valueOf()), ) } else { // 周视图 const nextWeekFirstDay = currenWeekFirstDay[touch.x > 0 ? 'subtract' : 'add'](1, 'week') const nextWeekLastDay = nextWeekFirstDay.add(7, 'day') this.setState( { translateIndex: newTranslateIndex, ...formatWeekData(nextWeekFirstDay), }, this.props.onTouchEnd(nextWeekFirstDay.valueOf(), nextWeekLastDay.valueOf()), ) } } else if (absTouchY > absTouchX && Math.abs(touch.y * calendarHeight) > 50) { if (disableWeekView) { // 禁用周视图 } else if (touch.y > 0 && showType === 'week') { this.setState({ showType: 'month' }, () => { const dataArray = this.state.monthDates[1] this.props.onToggleShowType({ showType: this.state.showType, startTime: dataArray[0].valueOf(), endTime: dataArray[dataArray.length - 1].add(1, 'day').valueOf(), }) }) } else if (touch.y < 0 && showType === 'month') { this.setState({ showType: 'week' }, () => { const dataArray = this.state.weekDates[1] this.props.onToggleShowType({ showType: this.state.showType, startTime: dataArray[0].valueOf(), endTime: dataArray[dataArray.length - 1].add(1, 'day').valueOf(), }) }) } } this.setState({ touch: { x: 0, y: 0 } }) } handleMonthToggle = (type: string) => { const { currentMonthFirstDay, currenWeekFirstDay, showType } = this.state const isMonthView = showType === 'month' const isPrev = type === 'prev' const formatFun = isMonthView ? formatMonthData : formatWeekData const operateDate = isMonthView ? currentMonthFirstDay : currenWeekFirstDay const updateStateData = formatFun( operateDate[isPrev ? 'subtract' : 'add'](1, isMonthView ? 'month' : 'week'), ) this.setState(updateStateData, () => { const dataArray = updateStateData[isMonthView ? 'monthDates' : 'weekDates'][1] this.props.onTouchEnd( dataArray[0].valueOf(), dataArray[dataArray.length - 1].add(1, 'day').valueOf(), ) }) } handleDayClick = (date: any) => { this.props.onDateClick(date) } handleBottomOperate() {} render() { const { monthDates, weekDates, touch, translateIndex, calendarY, currentMonthFirstDay, currenWeekFirstDay, showType, } = this.state const { currentDate, transitionDuration, markDates, markType, disableWeekView } = this.props const isMonthView = showType === 'month' return (
{(isMonthView ? currentMonthFirstDay : currenWeekFirstDay).format('YYYY-MM')}
{head.map(i => (
{i}
))}
{(isMonthView ? monthDates : weekDates).map((item: any[], index: number) => { return (
{item.map((date: { isSame: (arg0: any, arg1: string) => any; format: (arg0: string) => boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined }, itemIndex: React.Key | null | undefined) => { const isCurrentDay = date.isSame(currentDate, 'day') const isOtherMonthDay = showType === 'week' ? false : !date.isSame(currentMonthFirstDay, 'month') const isMarkDate = markDates.find((i: { date: any }) => date.isSame(i.date, 'day')) const resetMarkType = (isMarkDate && isMarkDate.markType) || markType const showDotMark = isCurrentDay ? false : isMarkDate && resetMarkType === 'dot' const showCircleMark = isCurrentDay ? false : isMarkDate && resetMarkType === 'circle' return (
{date.format('DD')}
{showDotMark && (
)}
) })}
) })}
{disableWeekView ? null : (
)}
) } } MonthView.propTypes = { currentDate: PropTypes.string, showType: PropTypes.oneOf(['week', 'month']), transitionDuration: PropTypes.number, onDateClick: PropTypes.func, onTouchStart: PropTypes.func, onTouchMove: PropTypes.func, onTouchEnd: PropTypes.func, onToggleShowType: PropTypes.func, markType: PropTypes.oneOf(['dot', 'circle']), markDates: PropTypes.array, disableWeekView: PropTypes.bool, } MonthView.defaultProps = { currentDate: dayjs().format('YYYY-MM-DD'), showType: 'month', transitionDuration: 0.3, onDateClick: () => {}, onTouchStart: () => {}, onTouchMove: () => {}, onTouchEnd: () => {}, onToggleShowType: () => {}, markType: 'dot', markDates: [], disableWeekView: false, } export default MonthView as any