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.
 

623 lines
20 KiB

import Day from './day'
import WxData from './wxData'
import Render from './render'
import CalendarConfig from './config'
import convertSolarLunar from './convertSolarLunar'
import {GetDate, Logger, getDateTimeStamp} from './utils'
const getDate = new GetDate()
const logger = new Logger()
class WeekMode extends WxData {
constructor(component) {
super(component)
this.Component = component
this.getCalendarConfig = CalendarConfig(this.Component).getCalendarConfig
}
/**
* 周、月视图切换
* @param {string} view 视图 [week, month]
* @param {object} date {year: 2017, month: 11, day: 1}
*/
switchWeek(view, date) {
return new Promise((resolve, reject) => {
const config = CalendarConfig(this.Component).getCalendarConfig()
if (config.multi) return logger.warn('多选模式不能切换周月视图')
const {selectedDay = [], curYear, curMonth} = this.getData('calendar')
let currentDate = []
let disableSelected = false
if (!selectedDay.length) {
currentDate = getDate.todayDate()
currentDate.day = currentDate.date
disableSelected = true
// return this.__tipsWhenCanNotSwtich();
} else {
currentDate = selectedDay[0]
}
let selectedDate = date || currentDate
const {year, month} = selectedDate
const notInCurrentMonth = curYear !== year || curMonth !== month
if (view === 'week') {
if (this.Component.weekMode) return
if ((selectedDay.length && notInCurrentMonth) || !selectedDay.length) {
// return this.__tipsWhenCanNotSwtich();
disableSelected = true
selectedDate = {
year: curYear,
month: curMonth,
day: selectedDate.day
}
}
this.Component.weekMode = true
this.setData({
'calendarConfig.weekMode': true
})
this.jump(selectedDate, disableSelected)
.then(resolve)
.catch(reject)
} else {
this.Component.weekMode = false
this.setData({
'calendarConfig.weekMode': false
})
const disableSelected =
(selectedDay.length && notInCurrentMonth) || !selectedDay.length
Render(this.Component)
.renderCalendar(curYear, curMonth, selectedDate.day, disableSelected)
.then(resolve)
.catch(reject)
}
})
}
/**
* 更新当前年月
*/
updateCurrYearAndMonth(type) {
let {days, curYear, curMonth} = this.getData('calendar')
const {month: firstMonth} = days[0]
const {month: lastMonth} = days[days.length - 1]
const lastDayOfThisMonth = getDate.thisMonthDays(curYear, curMonth)
const lastDayOfThisWeek = days[days.length - 1]
const firstDayOfThisWeek = days[0]
if (
(lastDayOfThisWeek.day + 7 > lastDayOfThisMonth ||
(curMonth === firstMonth && firstMonth !== lastMonth)) &&
type === 'next'
) {
curMonth = curMonth + 1
if (curMonth > 12) {
curYear = curYear + 1
curMonth = 1
}
} else if (
(+firstDayOfThisWeek.day <= 7 ||
(curMonth === lastMonth && firstMonth !== lastMonth)) &&
type === 'prev'
) {
curMonth = curMonth - 1
if (curMonth <= 0) {
curYear = curYear - 1
curMonth = 12
}
}
return {
Uyear: curYear,
Umonth: curMonth
}
}
/**
* 计算周视图下当前这一周和当月的最后一天
*/
calculateLastDay() {
const {days = [], curYear, curMonth} = this.getData('calendar')
const lastDayInThisWeek = days[days.length - 1].day
const lastDayInThisMonth = getDate.thisMonthDays(curYear, curMonth)
return {lastDayInThisWeek, lastDayInThisMonth}
}
/**
* 计算周视图下当前这一周第一天
*/
calculateFirstDay() {
const {days} = this.getData('calendar')
const firstDayInThisWeek = days[0].day
return {firstDayInThisWeek}
}
/**
* 当月第一周所有日期范围
* @param {number} year
* @param {number} month
* @param {boolean} firstDayOfWeekIsMon 每周是否配置为以周一开始
*/
firstWeekInMonth(year, month, firstDayOfWeekIsMon) {
let firstDay = getDate.dayOfWeek(year, month, 1)
if (firstDayOfWeekIsMon && firstDay === 0) {
firstDay = 7
}
const [, end] = [0, 7 - firstDay]
let days = this.getData('calendar.days') || []
if (this.Component.weekMode) {
days = Day(this.Component).buildDate(year, month)
}
const daysCut = days.slice(0, firstDayOfWeekIsMon ? end + 1 : end)
return daysCut
}
/**
* 当月最后一周所有日期范围
* @param {number} year
* @param {number} month
* @param {boolean} firstDayOfWeekIsMon 每周是否配置为以周一开始
*/
lastWeekInMonth(year, month, firstDayOfWeekIsMon) {
const lastDay = getDate.thisMonthDays(year, month)
const lastDayWeek = getDate.dayOfWeek(year, month, lastDay)
const [start, end] = [lastDay - lastDayWeek, lastDay]
let days = this.getData('calendar.days') || []
if (this.Component.weekMode) {
days = Day(this.Component).buildDate(year, month)
}
const daysCut = days.slice(firstDayOfWeekIsMon ? start : start - 1, end)
return daysCut
}
__getDisableDateTimestamp(config) {
const {date, type} = config.disableMode || {}
let disableDateTimestamp
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
}
}
/**
* 渲染日期之前初始化已选日期
* @param {array} dates 当前日期数组
*/
initSelectedDay(dates) {
let datesCopy = [...dates]
const {selectedDay = []} = this.getData('calendar')
const selectedDayStr = selectedDay.map(
item => `${+item.year}-${+item.month}-${+item.day}`
)
const config = this.getCalendarConfig()
const {
disableDateTimestamp,
disableType
} = this.__getDisableDateTimestamp(config)
datesCopy = datesCopy.map(item => {
if (!item) return {}
const dateTimestamp = getDateTimeStamp(item)
let date = {...item}
if (
selectedDayStr.includes(`${+date.year}-${+date.month}-${+date.day}`)
) {
date.choosed = true
} else {
date.choosed = false
}
if (
(disableType === 'after' && dateTimestamp > disableDateTimestamp) ||
(disableType === 'before' && dateTimestamp < disableDateTimestamp)
) {
date.disable = true
}
date = this.__setTodoWhenJump(date, config)
if (config.showLunar) {
date = this.__setSolarLunar(date)
}
if (config.highlightToday) {
date = this.__highlightToday(date)
}
return date
})
return datesCopy
}
/**
* 周视图下设置可选日期范围
* @param {object} days 当前展示的日期
*/
setEnableAreaOnWeekMode(dates = []) {
let {enableAreaTimestamp = [], enableDaysTimestamp = []} = this.getData(
'calendar'
)
dates.forEach(item => {
const timestamp = getDate
.newDate(item.year, item.month, item.day)
.getTime()
let setDisable = false
if (enableAreaTimestamp.length) {
if (
(+enableAreaTimestamp[0] > +timestamp ||
+timestamp > +enableAreaTimestamp[1]) &&
!enableDaysTimestamp.includes(+timestamp)
) {
setDisable = true
}
} else if (
enableDaysTimestamp.length &&
!enableDaysTimestamp.includes(+timestamp)
) {
setDisable = true
}
if (setDisable) {
item.disable = true
item.choosed = false
}
const config = CalendarConfig(this.Component).getCalendarConfig()
const {
disableDateTimestamp,
disableType
} = this.__getDisableDateTimestamp(config)
if (
(disableType === 'before' && timestamp < disableDateTimestamp) ||
(disableType === 'after' && timestamp > disableDateTimestamp)
) {
item.disable = true
}
})
}
updateYMWhenSwipeCalendarHasSelected(dates) {
const hasSelectedDate = dates.filter(date => date.choosed)
if (hasSelectedDate && hasSelectedDate.length) {
const {year, month} = hasSelectedDate[0]
return {
year,
month
}
}
return {}
}
/**
* 计算下一周的日期
*/
calculateNextWeekDays() {
let {lastDayInThisWeek, lastDayInThisMonth} = this.calculateLastDay()
let {curYear, curMonth} = this.getData('calendar')
let days = []
if (lastDayInThisMonth - lastDayInThisWeek >= 7) {
const {Uyear, Umonth} = this.updateCurrYearAndMonth('next')
curYear = Uyear
curMonth = Umonth
for (let i = lastDayInThisWeek + 1; i <= lastDayInThisWeek + 7; i++) {
days.push({
year: curYear,
month: curMonth,
day: i,
week: getDate.dayOfWeek(curYear, curMonth, i)
})
}
} else {
for (let i = lastDayInThisWeek + 1; i <= lastDayInThisMonth; i++) {
days.push({
year: curYear,
month: curMonth,
day: i,
week: getDate.dayOfWeek(curYear, curMonth, i)
})
}
const {Uyear, Umonth} = this.updateCurrYearAndMonth('next')
curYear = Uyear
curMonth = Umonth
for (let i = 1; i <= 7 - (lastDayInThisMonth - lastDayInThisWeek); i++) {
days.push({
year: curYear,
month: curMonth,
day: i,
week: getDate.dayOfWeek(curYear, curMonth, i)
})
}
}
days = this.initSelectedDay(days)
const {
year: updateYear,
month: updateMonth
} = this.updateYMWhenSwipeCalendarHasSelected(days)
if (updateYear && updateMonth) {
curYear = updateYear
curMonth = updateMonth
}
this.setEnableAreaOnWeekMode(days)
this.setData(
{
'calendar.curYear': curYear,
'calendar.curMonth': curMonth,
'calendar.days': days
},
() => {
Day(this.Component).setDateStyle()
}
)
}
/**
* 计算上一周的日期
*/
calculatePrevWeekDays() {
let {firstDayInThisWeek} = this.calculateFirstDay()
let {curYear, curMonth} = this.getData('calendar')
let days = []
if (firstDayInThisWeek - 7 > 0) {
const {Uyear, Umonth} = this.updateCurrYearAndMonth('prev')
curYear = Uyear
curMonth = Umonth
for (let i = firstDayInThisWeek - 7; i < firstDayInThisWeek; i++) {
days.push({
year: curYear,
month: curMonth,
day: i,
week: getDate.dayOfWeek(curYear, curMonth, i)
})
}
} else {
let temp = []
for (let i = 1; i < firstDayInThisWeek; i++) {
temp.push({
year: curYear,
month: curMonth,
day: i,
week: getDate.dayOfWeek(curYear, curMonth, i)
})
}
const {Uyear, Umonth} = this.updateCurrYearAndMonth('prev')
curYear = Uyear
curMonth = Umonth
const prevMonthDays = getDate.thisMonthDays(curYear, curMonth)
for (
let i = prevMonthDays - Math.abs(firstDayInThisWeek - 7);
i <= prevMonthDays;
i++
) {
days.push({
year: curYear,
month: curMonth,
day: i,
week: getDate.dayOfWeek(curYear, curMonth, i)
})
}
days = days.concat(temp)
}
days = this.initSelectedDay(days)
const {
year: updateYear,
month: updateMonth
} = this.updateYMWhenSwipeCalendarHasSelected(days)
if (updateYear && updateMonth) {
curYear = updateYear
curMonth = updateMonth
}
this.setEnableAreaOnWeekMode(days)
this.setData(
{
'calendar.curYear': curYear,
'calendar.curMonth': curMonth,
'calendar.days': days
},
() => {
Day(this.Component).setDateStyle()
}
)
}
calculateDatesWhenJump(
{year, month, day},
{firstWeekDays, lastWeekDays},
firstDayOfWeekIsMon
) {
const inFirstWeek = this.__dateIsInWeek({year, month, day}, firstWeekDays)
const inLastWeek = this.__dateIsInWeek({year, month, day}, lastWeekDays)
let dates = []
if (inFirstWeek) {
dates = this.__calculateDatesWhenInFirstWeek(
firstWeekDays,
firstDayOfWeekIsMon
)
} else if (inLastWeek) {
dates = this.__calculateDatesWhenInLastWeek(
lastWeekDays,
firstDayOfWeekIsMon
)
} else {
dates = this.__calculateDates({year, month, day}, firstDayOfWeekIsMon)
}
return dates
}
jump({year, month, day}, disableSelected) {
return new Promise(resolve => {
if (!day) return
const config = this.getCalendarConfig()
const firstDayOfWeekIsMon = config.firstDayOfWeek === 'Mon'
const firstWeekDays = this.firstWeekInMonth(
year,
month,
firstDayOfWeekIsMon
)
let lastWeekDays = this.lastWeekInMonth(year, month, firstDayOfWeekIsMon)
let dates = this.calculateDatesWhenJump(
{year, month, day},
{
firstWeekDays,
lastWeekDays
},
firstDayOfWeekIsMon
)
dates = dates.map(d => {
let date = {...d}
if (
+date.year === +year &&
+date.month === +month &&
+date.day === +day &&
!disableSelected
) {
date.choosed = true
}
date = this.__setTodoWhenJump(date, config)
if (config.showLunar) {
date = this.__setSolarLunar(date)
}
if (config.highlightToday) {
date = this.__highlightToday(date)
}
return date
})
this.setEnableAreaOnWeekMode(dates)
const tmpData = {
'calendar.days': dates,
'calendar.curYear': year,
'calendar.curMonth': month,
'calendar.empytGrids': [],
'calendar.lastEmptyGrids': []
}
if (!disableSelected) {
tmpData['calendar.selectedDay'] = dates.filter(item => item.choosed)
}
this.setData(tmpData, () => {
Day(this.Component).setDateStyle()
resolve({year, month, date: day})
})
})
}
__setTodoWhenJump(dateInfo) {
const date = {...dateInfo}
const {todoLabels = [], showLabelAlways} = this.getData('calendar')
const todosStr = todoLabels.map(d => `${+d.year}-${+d.month}-${+d.day}`)
const idx = todosStr.indexOf(`${+date.year}-${+date.month}-${+date.day}`)
if (idx !== -1) {
if (showLabelAlways) {
date.showTodoLabel = true
} else {
date.showTodoLabel = !date.choosed
}
const todo = todoLabels[idx] || {}
if (date.showTodoLabel && todo.todoText) date.todoText = todo.todoText
if (todo.color) date.color = todo.color
}
return date
}
__setSolarLunar(dateInfo) {
const date = {...dateInfo}
date.lunar = convertSolarLunar.solar2lunar(
+date.year,
+date.month,
+date.day
)
return date
}
__highlightToday(dateInfo) {
const date = {...dateInfo}
const today = getDate.todayDate()
const isToday =
+today.year === +date.year &&
+today.month === +date.month &&
+date.day === +today.date
date.isToday = isToday
return date
}
__calculateDatesWhenInFirstWeek(firstWeekDays) {
const dates = [...firstWeekDays]
if (dates.length < 7) {
let {year, month} = dates[0]
let len = 7 - dates.length
let lastDate
if (month > 1) {
month -= 1
lastDate = getDate.thisMonthDays(year, month)
} else {
month = 12
year -= 1
lastDate = getDate.thisMonthDays(year, month)
}
while (len) {
dates.unshift({
year,
month,
day: lastDate,
week: getDate.dayOfWeek(year, month, lastDate)
})
lastDate -= 1
len -= 1
}
}
return dates
}
__calculateDatesWhenInLastWeek(lastWeekDays) {
const dates = [...lastWeekDays]
if (dates.length < 7) {
let {year, month} = dates[0]
let len = 7 - dates.length
let firstDate = 1
if (month > 11) {
month = 1
year += 1
} else {
month += 1
}
while (len) {
dates.push({
year,
month,
day: firstDate,
week: getDate.dayOfWeek(year, month, firstDate)
})
firstDate += 1
len -= 1
}
}
return dates
}
__calculateDates({year, month, day}, firstDayOfWeekIsMon) {
const week = getDate.dayOfWeek(year, month, day)
let range = [day - week, day + (6 - week)]
if (firstDayOfWeekIsMon) {
range = [day + 1 - week, day + (7 - week)]
}
const dates = Day(this.Component).buildDate(year, month)
const weekDates = dates.slice(range[0] - 1, range[1])
return weekDates
}
__dateIsInWeek(date, week) {
return week.find(
item =>
+item.year === +date.year &&
+item.month === +date.month &&
+item.day === +date.day
)
}
__tipsWhenCanNotSwtich() {
logger.info(
'当前月份未选中日期下切换为周视图,不能明确该展示哪一周的日期,故此情况不允许切换'
)
}
}
export default component => new WeekMode(component)