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.
446 lines
14 KiB
446 lines
14 KiB
/** |
|
* @Author: drfu* |
|
* @Description: 周视图 |
|
* @Date: 2020-10-08 21:22:09* |
|
* @Last Modified by: drfu |
|
* @Last Modified time: 2020-10-12 14:39:45 |
|
*/ |
|
|
|
import { calcJumpData } from '../core' |
|
import { renderCalendar } from '../render' |
|
import { |
|
dateUtil, |
|
getCalendarConfig, |
|
getCalendarData, |
|
logger, |
|
} from '../utils/index' |
|
|
|
/** |
|
* 当月第一周所有日期 |
|
*/ |
|
function firstWeekInMonth( |
|
target = {}, |
|
calendarDates = [], |
|
calendarConfig = {}, |
|
) { |
|
const { firstDayOfWeek } = calendarConfig |
|
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' |
|
const { year, month } = target |
|
let firstDay = dateUtil.getDayOfWeek(year, month, 1) |
|
if (firstDayOfWeekIsMon && firstDay === 0) { |
|
firstDay = 7 |
|
} |
|
const [, end] = [0, 7 - firstDay] |
|
return calendarDates.slice(0, firstDayOfWeekIsMon ? end + 1 : end) |
|
} |
|
|
|
/** |
|
* 当月最后一周所有日期 |
|
*/ |
|
function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) { |
|
const { firstDayOfWeek } = calendarConfig |
|
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' |
|
const { year, month } = target |
|
const lastDay = dateUtil.getDatesCountOfMonth(year, month) |
|
let lastDayWeek = dateUtil.getDayOfWeek(year, month, lastDay) |
|
if (firstDayOfWeekIsMon && lastDayWeek === 0) { |
|
lastDayWeek = 7 |
|
} |
|
const [start, end] = [lastDay - lastDayWeek, lastDay] |
|
return calendarDates.slice(firstDayOfWeekIsMon ? start : start - 1, end) |
|
} |
|
|
|
/** |
|
* 判断目标日期是否在某些指定日历内 |
|
*/ |
|
function dateIsInDatesRange(target, dates) { |
|
if (!target || !dates || !dates.length) |
|
return false |
|
const targetDateStr = dateUtil.toTimeStr(target) |
|
let rst = false |
|
for (const date of dates) { |
|
const dateStr = dateUtil.toTimeStr(date) |
|
if (dateStr === targetDateStr) { |
|
rst = true |
|
return rst |
|
} |
|
rst = false |
|
} |
|
return rst |
|
} |
|
|
|
function getDatesWhenTargetInFirstWeek(target, firstWeekDates) { |
|
const { year, month } = target |
|
const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month }) |
|
let lastMonthDatesCount = dateUtil.getDatesCountOfMonth( |
|
prevMonthInfo.year, |
|
prevMonthInfo.month, |
|
) |
|
const dates = firstWeekDates |
|
const firstWeekCount = firstWeekDates.length |
|
for (let i = 0; i < 7 - firstWeekCount; i++) { |
|
const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount) |
|
dates.unshift({ |
|
year: prevMonthInfo.year, |
|
month: prevMonthInfo.month, |
|
date: lastMonthDatesCount, |
|
week, |
|
}) |
|
lastMonthDatesCount -= 1 |
|
} |
|
return dates |
|
} |
|
|
|
function getDatesWhenTargetInLastWeek(target, lastWeekDates) { |
|
const { year, month } = target |
|
const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month }) |
|
const dates = lastWeekDates |
|
const lastWeekCount = lastWeekDates.length |
|
for (let i = 0; i < 7 - lastWeekCount; i++) { |
|
const week = dateUtil.getDayOfWeek(+year, +month, i + 1) |
|
dates.push({ |
|
year: prevMonthInfo.year, |
|
month: prevMonthInfo.month, |
|
date: i + 1, |
|
week, |
|
}) |
|
} |
|
return dates |
|
} |
|
|
|
function getDates(target, calendarDates = [], calendarConfig = {}) { |
|
const { year, month, date } = target |
|
const targetDay = dateUtil.getDayOfWeek(year, month, date) |
|
const { firstDayOfWeek } = calendarConfig |
|
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' |
|
if (firstDayOfWeekIsMon) { |
|
const startIdx = date - (targetDay || 7) |
|
return calendarDates.splice(startIdx, 7) |
|
} |
|
else { |
|
const startIdx = date - targetDay - 1 |
|
return calendarDates.splice(startIdx, 7) |
|
} |
|
} |
|
|
|
function getTargetWeekDates(target, calendarConfig) { |
|
if (!target) |
|
return |
|
const { year, month } = target |
|
const calendarDates = dateUtil.calcDates(year, month) |
|
const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig) |
|
const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig) |
|
if (dateIsInDatesRange(target, firstWeekDates)) { |
|
return getDatesWhenTargetInFirstWeek(target, firstWeekDates) |
|
} |
|
else if (dateIsInDatesRange(target, lastWeekDates)) { |
|
return getDatesWhenTargetInLastWeek(target, lastWeekDates) |
|
} |
|
else { |
|
return getDates(target, calendarDates, calendarConfig) |
|
} |
|
} |
|
|
|
/** |
|
* 计算周视图下当前这一周最后一天 |
|
*/ |
|
function calculateLastDateOfCurrentWeek(calendarData = {}) { |
|
const { dates = [] } = calendarData |
|
return dates[dates.length - 1] |
|
} |
|
/** |
|
* 计算周视图下当前这一周第一天 |
|
*/ |
|
function calculateFirstDateOfCurrentWeek(calendarData = {}) { |
|
const { dates } = calendarData |
|
return dates[0] |
|
} |
|
|
|
/** |
|
* 计算下一周的日期 |
|
*/ |
|
function calculateNextWeekDates(calendarData = {}) { |
|
let { curYear, curMonth } = calendarData |
|
let calendarDates = [] |
|
const lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData) |
|
const { year: LYear, month: LMonth } = lastDateInThisWeek |
|
if (curYear !== LYear || curMonth !== LMonth) { |
|
calendarDates = dateUtil.calcDates(LYear, LMonth) |
|
curYear = LYear |
|
curMonth = LMonth |
|
} |
|
else { |
|
calendarDates = dateUtil.calcDates(curYear, curMonth) |
|
} |
|
const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth) |
|
const count = lastDateInThisMonth - lastDateInThisWeek.date |
|
const lastDateIdx = calendarDates.findIndex( |
|
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek), |
|
) |
|
const startIdx = lastDateIdx + 1 |
|
if (count >= 7) { |
|
return { |
|
dates: calendarDates.splice(startIdx, 7), |
|
year: curYear, |
|
month: curMonth, |
|
} |
|
} |
|
else { |
|
const nextMonth = dateUtil.getNextMonthInfo({ |
|
year: curYear, |
|
month: curMonth, |
|
}) |
|
const { year, month } = nextMonth || {} |
|
const calendarDatesOfNextMonth = dateUtil.calcDates(year, month) |
|
const remainDatesOfThisMonth = calendarDates.splice(startIdx) |
|
const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice( |
|
0, |
|
7 - remainDatesOfThisMonth.length, |
|
) |
|
return { |
|
dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth], |
|
...nextMonth, |
|
} |
|
} |
|
} |
|
|
|
/** |
|
* 计算上一周的日期 |
|
*/ |
|
function calculatePrevWeekDates(calendarData = {}) { |
|
let { curYear, curMonth } = calendarData |
|
const firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData) |
|
let calendarDates = [] |
|
const { year: FYear, month: FMonth } = firstDateInThisWeek |
|
if (curYear !== FYear || curMonth !== FMonth) { |
|
calendarDates = dateUtil.calcDates(FYear, FMonth) |
|
curYear = FYear |
|
curMonth = FMonth |
|
} |
|
else { |
|
calendarDates = dateUtil.calcDates(curYear, curMonth) |
|
} |
|
const firstDateIdx = calendarDates.findIndex( |
|
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek), |
|
) |
|
if (firstDateIdx - 7 >= 0) { |
|
const startIdx = firstDateIdx - 7 |
|
return { |
|
dates: calendarDates.splice(startIdx, 7), |
|
year: curYear, |
|
month: curMonth, |
|
} |
|
} |
|
else { |
|
const prevMonth = dateUtil.getPrevMonthInfo({ |
|
year: curYear, |
|
month: curMonth, |
|
}) |
|
const { year, month } = prevMonth || {} |
|
const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month) |
|
const remainDatesOfThisMonth = calendarDates.splice( |
|
0, |
|
firstDateInThisWeek.date - 1, |
|
) |
|
const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice( |
|
-(7 - remainDatesOfThisMonth.length), |
|
) |
|
return { |
|
dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth], |
|
...prevMonth, |
|
} |
|
} |
|
} |
|
|
|
export default () => { |
|
return { |
|
name: 'week', |
|
beforeRender(calendarData = {}, calendarConfig = {}, component) { |
|
const { initializedWeekMode, selectedDates } = calendarData |
|
if (calendarConfig.weekMode && !initializedWeekMode) { |
|
const { defaultDate } = calendarConfig |
|
const target |
|
= (selectedDates && selectedDates[0]) |
|
|| (defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) |
|
|| dateUtil.todayFMD() |
|
const waitRenderData = this.methods( |
|
component, |
|
).__calcDatesWhenSwitchView('week', target) |
|
const { data, config } = waitRenderData || {} |
|
const setSelectDates = this.methods( |
|
component, |
|
).__selectTargetDateWhenJump(target, data.dates, config) |
|
return { |
|
calendarData: { |
|
...data, |
|
...setSelectDates, |
|
weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek), |
|
initializedWeekMode: true, |
|
}, |
|
calendarConfig, |
|
} |
|
} |
|
return { |
|
calendarData, |
|
calendarConfig, |
|
} |
|
}, |
|
onSwitchCalendar(target = {}, calendarData = {}, component) { |
|
const { direction } = target |
|
const { curYear, curMonth } = calendarData |
|
const calendarConfig = getCalendarConfig(component) |
|
let waitRenderData = {} |
|
if (calendarConfig.weekMode) { |
|
if (direction === 'left') { |
|
waitRenderData = calculateNextWeekDates(calendarData) |
|
} |
|
else { |
|
waitRenderData = calculatePrevWeekDates(calendarData) |
|
} |
|
const { dates, year, month } = waitRenderData |
|
return { |
|
...calendarData, |
|
dates, |
|
curYear: year || curYear, |
|
curMonth: month || curMonth, |
|
} |
|
} |
|
return calendarData |
|
}, |
|
methods(component) { |
|
return { |
|
__selectTargetDateWhenJump: (target = {}, dates = [], config = {}) => { |
|
let selectedDate = target |
|
const weekDates = dates.map((date, idx) => { |
|
const tmp = { ...date } |
|
tmp.id = idx |
|
const isTarget |
|
= dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp) |
|
if (isTarget && !target.choosed && config.autoChoosedWhenJump) { |
|
tmp.choosed = true |
|
selectedDate = tmp |
|
} |
|
return tmp |
|
}) |
|
return { |
|
dates: weekDates, |
|
selectedDates: [selectedDate], |
|
} |
|
}, |
|
__calcDatesForWeekMode(target, config = {}, calendarData = {}) { |
|
const { year, month } = target || {} |
|
const weekDates = getTargetWeekDates(target, config) |
|
weekDates.forEach((date, idx) => (date.id = idx)) |
|
return { |
|
data: { |
|
...calendarData, |
|
prevMonthGrids: null, |
|
nextMonthGrids: null, |
|
dates: weekDates, |
|
curYear: year, |
|
curMonth: month, |
|
}, |
|
config: { |
|
...config, |
|
weekMode: true, |
|
}, |
|
} |
|
}, |
|
__calcDatesForMonthMode(target, config = {}, calendarData = {}) { |
|
const { year, month } = target || {} |
|
const waitRenderData = calcJumpData({ |
|
dateInfo: target, |
|
config, |
|
}) |
|
return { |
|
data: { |
|
...calendarData, |
|
...waitRenderData, |
|
curYear: year, |
|
curMonth: month, |
|
}, |
|
config: { |
|
...config, |
|
weekMode: false, |
|
}, |
|
} |
|
}, |
|
/** |
|
* 周、月视图切换 |
|
* @param {string} view 视图 [week, month] |
|
* @param {object} target |
|
*/ |
|
__calcDatesWhenSwitchView: (view, target) => { |
|
const calendarConfig = getCalendarConfig(component) |
|
if (calendarConfig.multi) |
|
return logger.warn('多选模式不能切换周月视图') |
|
const existCalendarData = getCalendarData('calendar', component) || {} |
|
const { |
|
selectedDates = [], |
|
dates = [], |
|
curYear, |
|
curMonth, |
|
} = existCalendarData |
|
const currentMonthSelected = selectedDates.filter( |
|
item => curYear === +item.year || curMonth === +item.month, |
|
) |
|
let jumpTarget = {} |
|
if (target) { |
|
jumpTarget = target |
|
} |
|
else { |
|
if (currentMonthSelected.length) { |
|
jumpTarget = currentMonthSelected.pop() |
|
} |
|
else { |
|
jumpTarget = dates[0] |
|
} |
|
} |
|
if (view === 'week') { |
|
return this.methods(component).__calcDatesForWeekMode( |
|
jumpTarget, |
|
calendarConfig, |
|
existCalendarData, |
|
) |
|
} |
|
else { |
|
return this.methods(component).__calcDatesForMonthMode( |
|
jumpTarget, |
|
calendarConfig, |
|
existCalendarData, |
|
) |
|
} |
|
}, |
|
weekModeJump: (dateInfo) => { |
|
const target = dateInfo || dateUtil.todayFMD() |
|
const existCalendarData = getCalendarData('calendar', component) || {} |
|
const waitRenderData = this.methods( |
|
component, |
|
).__calcDatesWhenSwitchView('week', target) |
|
const { data, config } = waitRenderData || {} |
|
const setSelectDates = this.methods( |
|
component, |
|
).__selectTargetDateWhenJump(target, data.dates, config) |
|
return renderCalendar.call( |
|
component, |
|
{ |
|
...existCalendarData, |
|
...data, |
|
...setSelectDates, |
|
}, |
|
config, |
|
) |
|
}, |
|
switchView: (view, target) => { |
|
const waitRenderData = this.methods( |
|
component, |
|
).__calcDatesWhenSwitchView(view, target) |
|
const { data, config } = waitRenderData || {} |
|
if (!data) |
|
return logger.warn('当前状态不能切换为周视图') |
|
return renderCalendar.call(component, data, config) |
|
}, |
|
} |
|
}, |
|
} |
|
}
|
|
|