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
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)
|
|
|