import { createNamespace, addUnit } from '../../utils'; import { setScrollTop } from '../../utils/dom/scroll'; import { t, bem, compareDay, ROW_HEIGHT, getPrevDay, getNextDay, formatMonthTitle, } from '../utils'; import { getMonthEndDay } from '../../datetime-picker/utils'; const [createComponent] = createNamespace('calendar-month'); export default createComponent({ props: { date: Date, type: String, color: String, minDate: Date, maxDate: Date, showMark: Boolean, rowHeight: [Number, String], formatter: Function, lazyRender: Boolean, currentDate: [Date, Array], allowSameDay: Boolean, showSubtitle: Boolean, showMonthTitle: Boolean, firstDayOfWeek: Number, }, emits: ['click'], data() { return { visible: false, }; }, computed: { title() { return formatMonthTitle(this.date); }, rowHeightWithUnit() { if (this.rowHeight !== ROW_HEIGHT) { return addUnit(this.rowHeight); } }, offset() { const { firstDayOfWeek } = this; const realDay = this.date.getDay(); if (!firstDayOfWeek) { return realDay; } return (realDay + 7 - this.firstDayOfWeek) % 7; }, totalDay() { return getMonthEndDay(this.date.getFullYear(), this.date.getMonth() + 1); }, shouldRender() { return this.visible || !this.lazyRender; }, monthStyle() { if (!this.shouldRender) { const padding = Math.ceil((this.totalDay + this.offset) / 7) * this.rowHeight; return { paddingBottom: `${padding}px`, }; } }, days() { const days = []; const year = this.date.getFullYear(); const month = this.date.getMonth(); for (let day = 1; day <= this.totalDay; day++) { const date = new Date(year, month, day); const type = this.getDayType(date); let config = { date, type, text: day, bottomInfo: this.getBottomInfo(type), }; if (this.formatter) { config = this.formatter(config); } days.push(config); } return days; }, }, methods: { getHeight() { if (!this.height) { this.height = this.$el.getBoundingClientRect().height; } return this.height; }, scrollIntoView(body) { const { days, month } = this.$refs; const el = this.showSubtitle ? days : month; const scrollTop = el.getBoundingClientRect().top - body.getBoundingClientRect().top + body.scrollTop; setScrollTop(body, scrollTop); }, getMultipleDayType(day) { const isSelected = (date) => this.currentDate.some((item) => compareDay(item, date) === 0); if (isSelected(day)) { const prevDay = getPrevDay(day); const nextDay = getNextDay(day); const prevSelected = isSelected(prevDay); const nextSelected = isSelected(nextDay); if (prevSelected && nextSelected) { return 'multiple-middle'; } if (prevSelected) { return 'end'; } return nextSelected ? 'start' : 'multiple-selected'; } return ''; }, getRangeDayType(day) { const [startDay, endDay] = this.currentDate; if (!startDay) { return ''; } const compareToStart = compareDay(day, startDay); if (!endDay) { return compareToStart === 0 ? 'start' : ''; } const compareToEnd = compareDay(day, endDay); if (compareToStart === 0 && compareToEnd === 0 && this.allowSameDay) { return 'start-end'; } if (compareToStart === 0) { return 'start'; } if (compareToEnd === 0) { return 'end'; } if (compareToStart > 0 && compareToEnd < 0) { return 'middle'; } }, getDayType(day) { const { type, minDate, maxDate, currentDate } = this; if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) { return 'disabled'; } if (Array.isArray(currentDate)) { if (type === 'multiple') { return this.getMultipleDayType(day); } if (type === 'range') { return this.getRangeDayType(day); } } else if (type === 'single') { return compareDay(day, currentDate) === 0 ? 'selected' : ''; } }, getBottomInfo(type) { if (this.type === 'range') { if (type === 'start' || type === 'end') { return t(type); } if (type === 'start-end') { return t('startEnd'); } } }, getDayStyle(type, index) { const style = { height: this.rowHeightWithUnit, }; if (index === 0) { style.marginLeft = `${(100 * this.offset) / 7}%`; } if (this.color) { if ( type === 'start' || type === 'end' || type === 'start-end' || type === 'multiple-selected' || type === 'multiple-middle' ) { style.background = this.color; } else if (type === 'middle') { style.color = this.color; } } return style; }, genTitle() { if (this.showMonthTitle) { return