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