You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

386 lines
13 KiB

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)