import Day from './day' import Todo from './todo' import WxData from './wxData' import convertSolarLunar from './convertSolarLunar' import { Logger, GetDate, delRepeatedEnableDay, getDateTimeStamp, converEnableDaysToTimestamp } from './utils' const getDate = new GetDate() const logger = new Logger() class Calendar extends WxData { constructor(component) { super(component) this.Component = component } getCalendarConfig() { return this.Component.config } /** * 渲染日历 * @param {number} curYear 年份 * @param {number} curMonth 月份 * @param {number} curDate 日期 * @param {boolean} disableSelect 是否禁用选中 */ renderCalendar(curYear, curMonth, curDate, disableSelect) { return new Promise(resolve => { const config = this.getCalendarConfig() this.calculateEmptyGrids(curYear, curMonth) this.calculateDays(curYear, curMonth, curDate, disableSelect).then(() => { const { todoLabels, specialStyleDates, enableDays, selectedDay } = this.getData('calendar') || {} if ( todoLabels && todoLabels.find( item => +item.month === +curMonth && +item.year === +curYear ) ) { Todo(this.Component).setTodoLabels() } if ( specialStyleDates && specialStyleDates.length && specialStyleDates.find( item => +item.month === +curMonth && +item.year === +curYear ) ) { Day(this.Component).setDateStyle(specialStyleDates) } if ( enableDays && enableDays.length && enableDays.find(item => { let ymd = item.split('-') return +ymd[1] === +curMonth && +ymd[0] === +curYear }) ) { Day(this.Component).enableDays(enableDays) } if ( selectedDay && selectedDay.length && selectedDay.find( item => +item.month === +curMonth && +item.year === +curYear ) && config.mulit ) { Day(this.Component).setSelectedDays(selectedDay) } if (!this.Component.firstRender) { resolve({ firstRender: true }) } else { resolve({ firstRender: false }) } }) }) } /** * 计算当前月份前后两月应占的格子 * @param {number} year 年份 * @param {number} month 月份 */ calculateEmptyGrids(year, month) { this.calculatePrevMonthGrids(year, month) this.calculateNextMonthGrids(year, month) } /** * 计算上月应占的格子 * @param {number} year 年份 * @param {number} month 月份 */ calculatePrevMonthGrids(year, month) { let empytGrids = [] const prevMonthDays = getDate.thisMonthDays(year, month - 1) let firstDayOfWeek = getDate.firstDayOfWeek(year, month) const config = this.getCalendarConfig() || {} if (config.firstDayOfWeek === 'Mon') { if (firstDayOfWeek === 0) { firstDayOfWeek = 6 } else { firstDayOfWeek -= 1 } } if (firstDayOfWeek > 0) { const len = prevMonthDays - firstDayOfWeek const { onlyShowCurrentMonth } = config const { showLunar } = this.getCalendarConfig() for (let i = prevMonthDays; i > len; i--) { if (onlyShowCurrentMonth) { empytGrids.push('') } else { empytGrids.push({ day: i, lunar: showLunar ? convertSolarLunar.solar2lunar(year, month - 1, i) : null }) } } this.setData({ 'calendar.empytGrids': empytGrids.reverse() }) } else { this.setData({ 'calendar.empytGrids': null }) } } /** * 计算下一月日期是否需要多展示的日期 * 某些月份日期为5排,某些月份6排,统一为6排 * @param {number} year * @param {number} month * @param {object} config */ calculateExtraEmptyDate(year, month, config) { let extDate = 0 if (+month === 2) { extDate += 7 let firstDayofMonth = getDate.dayOfWeek(year, month, 1) if (config.firstDayOfWeek === 'Mon') { if (+firstDayofMonth === 1) extDate += 7 } else { if (+firstDayofMonth === 0) extDate += 7 } } else { let firstDayofMonth = getDate.dayOfWeek(year, month, 1) if (config.firstDayOfWeek === 'Mon') { if (firstDayofMonth !== 0 && firstDayofMonth < 6) { extDate += 7 } } else { if (firstDayofMonth <= 5) { extDate += 7 } } } return extDate } /** * 计算下月应占的格子 * @param {number} year 年份 * @param {number} month 月份 */ calculateNextMonthGrids(year, month) { let lastEmptyGrids = [] const thisMonthDays = getDate.thisMonthDays(year, month) let lastDayWeek = getDate.dayOfWeek(year, month, thisMonthDays) const config = this.getCalendarConfig() || {} if (config.firstDayOfWeek === 'Mon') { if (lastDayWeek === 0) { lastDayWeek = 6 } else { lastDayWeek -= 1 } } let len = 7 - (lastDayWeek + 1) const { onlyShowCurrentMonth, showLunar } = config if (!onlyShowCurrentMonth) { len = len + this.calculateExtraEmptyDate(year, month, config) } for (let i = 1; i <= len; i++) { if (onlyShowCurrentMonth) { lastEmptyGrids.push('') } else { lastEmptyGrids.push({ day: i, lunar: showLunar ? convertSolarLunar.solar2lunar(year, month + 1, i) : null }) } } this.setData({ 'calendar.lastEmptyGrids': lastEmptyGrids }) } /** * 日历初始化将默认值写入 selectDay * @param {number} year * @param {number} month * @param {number} curDate */ setSelectedDay(year, month, curDate) { let selectedDay = [] const config = this.getCalendarConfig() if (config.noDefault) { selectedDay = [] config.noDefault = false } else { const data = this.getData('calendar') || {} const { showLunar } = this.getCalendarConfig() selectedDay = curDate ? [ { year, month, day: curDate, choosed: true, week: getDate.dayOfWeek(year, month, curDate), lunar: showLunar ? convertSolarLunar.solar2lunar(year, month, curDate) : null } ] : data.selectedDay } return selectedDay } __getDisableDateTimestamp() { let disableDateTimestamp const { date, type } = this.getCalendarConfig().disableMode || {} if (date) { const t = date.split('-') if (t.length < 3) { logger.warn('配置 disableMode.date 格式错误') return {} } disableDateTimestamp = getDateTimeStamp({ year: +t[0], month: +t[1], day: +t[2] }) } return { disableDateTimestamp, disableType: type } } resetDates() { this.setData({ 'calendar.days': [] }) } /** * 设置日历面板数据 * @param {number} year 年份 * @param {number} month 月份 * @param {number} curDate 日期 * @param {boolean} disableSelect 是否禁用选中 */ calculateDays(year, month, curDate, disableSelect) { return new Promise(resolve => { // 避免切换日期时样式残影 this.resetDates() let days = [] const { disableDays = [], chooseAreaTimestamp = [], selectedDay: selectedDates = [] } = this.getData('calendar') days = Day(this.Component).buildDate(year, month) let selectedDay = selectedDates if (!disableSelect) { selectedDay = this.setSelectedDay(year, month, curDate) } const selectedDayStr = selectedDay.map(d => getDate.toTimeStr(d)) const disableDaysStr = disableDays.map(d => getDate.toTimeStr(d)) const [areaStart, areaEnd] = chooseAreaTimestamp days.forEach(item => { const cur = getDate.toTimeStr(item) const timestamp = getDateTimeStamp(item) if (selectedDayStr.includes(cur) && !disableSelect) { item.choosed = true if (timestamp > areaEnd || timestamp < areaStart) { const idx = selectedDay.findIndex( selectedDate => getDate.toTimeStr(selectedDate) === getDate.toTimeStr(item) ) selectedDay.splice(idx, 1) } } else if ( areaStart && areaEnd && timestamp >= areaStart && timestamp <= areaEnd && !disableSelect ) { item.choosed = true selectedDay.push(item) } if (disableDaysStr.includes(cur)) item.disable = true const { disableDateTimestamp, disableType } = this.__getDisableDateTimestamp() let disabelByConfig = false if (disableDateTimestamp) { if ( (disableType === 'before' && timestamp < disableDateTimestamp) || (disableType === 'after' && timestamp > disableDateTimestamp) ) { disabelByConfig = true } } const isDisable = disabelByConfig || this.__isDisable(timestamp) if (isDisable) { item.disable = true item.choosed = false } }) this.setData( { 'calendar.days': days, 'calendar.selectedDay': [...selectedDay] || [] }, () => { resolve() } ) }) } __isDisable(timestamp) { const { enableArea = [], enableDays = [], enableAreaTimestamp = [] } = this.getData('calendar') let setDisable = false let expectEnableDaysTimestamp = converEnableDaysToTimestamp(enableDays) if (enableArea.length) { expectEnableDaysTimestamp = delRepeatedEnableDay(enableDays, enableArea) } if (enableAreaTimestamp.length) { if ( (+enableAreaTimestamp[0] > +timestamp || +timestamp > +enableAreaTimestamp[1]) && !expectEnableDaysTimestamp.includes(+timestamp) ) { setDisable = true } } else if ( expectEnableDaysTimestamp.length && !expectEnableDaysTimestamp.includes(+timestamp) ) { setDisable = true } return setDisable } } export default component => new Calendar(component)