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.
543 lines
16 KiB
543 lines
16 KiB
import WxData from './wxData' |
|
import CalendarConfig from './config' |
|
import convertSolarLunar from './convertSolarLunar' |
|
import { |
|
Logger, |
|
GetDate, |
|
getDateTimeStamp, |
|
uniqueArrayByDate, |
|
delRepeatedEnableDay, |
|
convertEnableAreaToTimestamp, |
|
converEnableDaysToTimestamp |
|
} from './utils' |
|
|
|
const logger = new Logger() |
|
const getDate = new GetDate() |
|
const toString = Object.prototype.toString |
|
|
|
class Day extends WxData { |
|
constructor(component) { |
|
super(component) |
|
this.Component = component |
|
} |
|
getCalendarConfig() { |
|
return this.Component.config |
|
} |
|
/** |
|
* |
|
* @param {number} year |
|
* @param {number} month |
|
*/ |
|
buildDate(year, month) { |
|
const today = getDate.todayDate() |
|
const thisMonthDays = getDate.thisMonthDays(year, month) |
|
const dates = [] |
|
for (let i = 1; i <= thisMonthDays; i++) { |
|
const isToday = |
|
+today.year === +year && +today.month === +month && i === +today.date |
|
const config = this.getCalendarConfig() |
|
const date = { |
|
year, |
|
month, |
|
day: i, |
|
choosed: false, |
|
week: getDate.dayOfWeek(year, month, i), |
|
isToday: isToday && config.highlightToday, |
|
lunar: convertSolarLunar.solar2lunar(+year, +month, +i) |
|
} |
|
dates.push(date) |
|
} |
|
return dates |
|
} |
|
/** |
|
* 指定可选日期范围 |
|
* @param {array} area 日期访问数组 |
|
*/ |
|
enableArea(dateArea = []) { |
|
if (dateArea.length === 2) { |
|
const isRight = this.__judgeParam(dateArea) |
|
if (isRight) { |
|
let { days = [], selectedDay = [] } = this.getData('calendar') |
|
const { startTimestamp, endTimestamp } = convertEnableAreaToTimestamp( |
|
dateArea |
|
) |
|
const dataAfterHandle = this.__handleEnableArea( |
|
{ |
|
dateArea, |
|
days, |
|
startTimestamp, |
|
endTimestamp |
|
}, |
|
selectedDay |
|
) |
|
this.setData({ |
|
'calendar.enableArea': dateArea, |
|
'calendar.days': dataAfterHandle.dates, |
|
'calendar.selectedDay': dataAfterHandle.selectedDay, |
|
'calendar.enableAreaTimestamp': [startTimestamp, endTimestamp] |
|
}) |
|
} |
|
} else { |
|
logger.warn( |
|
'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]' |
|
) |
|
} |
|
} |
|
/** |
|
* 指定特定日期可选 |
|
* @param {array} days 指定日期数组 |
|
*/ |
|
enableDays(dates = []) { |
|
const { enableArea = [] } = this.getData('calendar') |
|
let expectEnableDaysTimestamp = [] |
|
if (enableArea.length) { |
|
expectEnableDaysTimestamp = delRepeatedEnableDay(dates, enableArea) |
|
} else { |
|
expectEnableDaysTimestamp = converEnableDaysToTimestamp(dates) |
|
} |
|
let { days = [], selectedDay = [] } = this.getData('calendar') |
|
const dataAfterHandle = this.__handleEnableDays( |
|
{ |
|
days, |
|
expectEnableDaysTimestamp |
|
}, |
|
selectedDay |
|
) |
|
this.setData({ |
|
'calendar.days': dataAfterHandle.dates, |
|
'calendar.selectedDay': dataAfterHandle.selectedDay, |
|
'calendar.enableDays': dates, |
|
'calendar.enableDaysTimestamp': expectEnableDaysTimestamp |
|
}) |
|
} |
|
/** |
|
* 设置多个日期选中 |
|
* @param {array} selected 需选中日期 |
|
*/ |
|
setSelectedDays(selected) { |
|
const config = CalendarConfig(this.Component).getCalendarConfig() |
|
if (!config.multi) { |
|
return logger.warn('单选模式下不能设置多日期选中,请配置 multi') |
|
} |
|
let { days } = this.getData('calendar') |
|
let newSelectedDay = [] |
|
if (!selected) { |
|
days.map(item => { |
|
item.choosed = true |
|
item.showTodoLabel = false |
|
}) |
|
newSelectedDay = days |
|
} else if (selected && selected.length) { |
|
const { dates, selectedDates } = this.__handleSelectedDays( |
|
days, |
|
newSelectedDay, |
|
selected |
|
) |
|
days = dates |
|
newSelectedDay = selectedDates |
|
} |
|
CalendarConfig(this.Component).setCalendarConfig('multi', true) |
|
this.setData({ |
|
'calendar.days': days, |
|
'calendar.selectedDay': newSelectedDay |
|
}) |
|
} |
|
/** |
|
* 禁用指定日期 |
|
* @param {array} dates 禁用 |
|
*/ |
|
disableDays(dates) { |
|
const { disableDays = [], days } = this.getData('calendar') |
|
if (Object.prototype.toString.call(dates) !== '[object Array]') { |
|
return logger.warn('disableDays 参数为数组') |
|
} |
|
let _disableDays = [] |
|
if (dates.length) { |
|
_disableDays = uniqueArrayByDate(dates.concat(disableDays)) |
|
const disableDaysCol = _disableDays.map(d => getDate.toTimeStr(d)) |
|
days.forEach(item => { |
|
const cur = getDate.toTimeStr(item) |
|
if (disableDaysCol.includes(cur)) item.disable = true |
|
}) |
|
} else { |
|
days.forEach(item => { |
|
item.disable = false |
|
}) |
|
} |
|
this.setData({ |
|
'calendar.days': days, |
|
'calendar.disableDays': _disableDays |
|
}) |
|
} |
|
/** |
|
* 设置连续日期选择区域 |
|
* @param {array} dateArea 区域开始结束日期数组 |
|
*/ |
|
chooseArea(dateArea = []) { |
|
return new Promise((resolve, reject) => { |
|
if (dateArea.length === 1) { |
|
dateArea = dateArea.concat(dateArea) |
|
} |
|
if (dateArea.length === 2) { |
|
const isRight = this.__judgeParam(dateArea) |
|
if (isRight) { |
|
const config = CalendarConfig(this.Component).getCalendarConfig() |
|
const { startTimestamp, endTimestamp } = convertEnableAreaToTimestamp( |
|
dateArea |
|
) |
|
this.setData( |
|
{ |
|
calendarConfig: { |
|
...config, |
|
chooseAreaMode: true, |
|
mulit: true |
|
}, |
|
'calendar.chooseAreaTimestamp': [startTimestamp, endTimestamp] |
|
}, |
|
() => { |
|
this.__chooseContinuousDates(startTimestamp, endTimestamp) |
|
.then(resolve) |
|
.catch(reject) |
|
} |
|
) |
|
} |
|
} |
|
}) |
|
} |
|
__pusheNextMonthDateArea(item, startTimestamp, endTimestamp, selectedDates) { |
|
const days = this.buildDate(item.year, item.month) |
|
let daysLen = days.length |
|
for (let i = 0; i < daysLen; i++) { |
|
const item = days[i] |
|
const timeStamp = getDateTimeStamp(item) |
|
if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) { |
|
selectedDates.push({ |
|
...item, |
|
choosed: true |
|
}) |
|
} |
|
if (i === daysLen - 1 && timeStamp < endTimestamp) { |
|
this.__pusheNextMonthDateArea( |
|
getDate.nextMonth(item), |
|
startTimestamp, |
|
endTimestamp, |
|
selectedDates |
|
) |
|
} |
|
} |
|
} |
|
__pushPrevMonthDateArea(item, startTimestamp, endTimestamp, selectedDates) { |
|
const days = getDate.sortDates( |
|
this.buildDate(item.year, item.month), |
|
'desc' |
|
) |
|
let daysLen = days.length |
|
let firstDate = getDateTimeStamp(days[0]) |
|
for (let i = 0; i < daysLen; i++) { |
|
const item = days[i] |
|
const timeStamp = getDateTimeStamp(item) |
|
if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) { |
|
selectedDates.push({ |
|
...item, |
|
choosed: true |
|
}) |
|
} |
|
if (i === daysLen - 1 && firstDate > startTimestamp) { |
|
this.__pushPrevMonthDateArea( |
|
getDate.prevMonth(item), |
|
startTimestamp, |
|
endTimestamp, |
|
selectedDates |
|
) |
|
} |
|
} |
|
} |
|
/** |
|
* 当设置日期区域非当前时保存其他月份的日期至已选日期数组 |
|
* @param {object} info |
|
*/ |
|
__calcDateWhenNotInOneMonth(info) { |
|
const { |
|
firstDate, |
|
lastDate, |
|
startTimestamp, |
|
endTimestamp, |
|
filterSelectedDate |
|
} = info |
|
if (getDateTimeStamp(firstDate) > startTimestamp) { |
|
this.__pushPrevMonthDateArea( |
|
getDate.prevMonth(firstDate), |
|
startTimestamp, |
|
endTimestamp, |
|
filterSelectedDate |
|
) |
|
} |
|
if (getDateTimeStamp(lastDate) < endTimestamp) { |
|
this.__pusheNextMonthDateArea( |
|
getDate.nextMonth(lastDate), |
|
startTimestamp, |
|
endTimestamp, |
|
filterSelectedDate |
|
) |
|
} |
|
const newSelectedDates = [...getDate.sortDates(filterSelectedDate)] |
|
return newSelectedDates |
|
} |
|
/** |
|
* 设置连续日期段 |
|
* @param {number} startTimestamp 连续日期段开始日期时间戳 |
|
* @param {number} endTimestamp 连续日期段结束日期时间戳 |
|
*/ |
|
__chooseContinuousDates(startTimestamp, endTimestamp) { |
|
return new Promise((resolve, reject) => { |
|
const { days, selectedDay = [] } = this.getData('calendar') |
|
const selectedDateStr = [] |
|
let filterSelectedDate = [] |
|
selectedDay.forEach(item => { |
|
const timeStamp = getDateTimeStamp(item) |
|
if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) { |
|
filterSelectedDate.push(item) |
|
selectedDateStr.push(getDate.toTimeStr(item)) |
|
} |
|
}) |
|
days.forEach(item => { |
|
const timeStamp = getDateTimeStamp(item) |
|
const dateInSelecedArray = selectedDateStr.includes( |
|
getDate.toTimeStr(item) |
|
) |
|
if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) { |
|
if (dateInSelecedArray) { |
|
return |
|
} |
|
item.choosed = true |
|
filterSelectedDate.push(item) |
|
} else { |
|
item.choosed = false |
|
if (dateInSelecedArray) { |
|
const idx = filterSelectedDate.findIndex( |
|
selectedDate => |
|
getDate.toTimeStr(selectedDate) === getDate.toTimeStr(item) |
|
) |
|
if (idx > -1) { |
|
filterSelectedDate.splice(idx, 1) |
|
} |
|
} |
|
} |
|
}) |
|
const firstDate = days[0] |
|
const lastDate = days[days.length - 1] |
|
const newSelectedDates = this.__calcDateWhenNotInOneMonth({ |
|
firstDate, |
|
lastDate, |
|
startTimestamp, |
|
endTimestamp, |
|
filterSelectedDate |
|
}) |
|
try { |
|
this.setData( |
|
{ |
|
'calendar.days': [...days], |
|
'calendar.selectedDay': newSelectedDates |
|
}, |
|
() => { |
|
resolve(newSelectedDates) |
|
} |
|
) |
|
} catch (err) { |
|
reject(err) |
|
} |
|
}) |
|
} |
|
/** |
|
* 设置指定日期样式 |
|
* @param {array} dates 待设置特殊样式的日期 |
|
*/ |
|
setDateStyle(dates) { |
|
if (toString.call(dates) !== '[object Array]') return |
|
const { days, specialStyleDates } = this.getData('calendar') |
|
if (toString.call(specialStyleDates) === '[object Array]') { |
|
dates = uniqueArrayByDate([...specialStyleDates, ...dates]) |
|
} |
|
const _specialStyleDates = dates.map( |
|
item => `${item.year}_${item.month}_${item.day}` |
|
) |
|
const _days = days.map(item => { |
|
const idx = _specialStyleDates.indexOf( |
|
`${item.year}_${item.month}_${item.day}` |
|
) |
|
if (idx > -1) { |
|
return { |
|
...item, |
|
class: dates[idx].class |
|
} |
|
} else { |
|
return { ...item } |
|
} |
|
}) |
|
this.setData({ |
|
'calendar.days': _days, |
|
'calendar.specialStyleDates': dates |
|
}) |
|
} |
|
__judgeParam(dateArea) { |
|
const { |
|
start, |
|
end, |
|
startTimestamp, |
|
endTimestamp |
|
} = convertEnableAreaToTimestamp(dateArea) |
|
if (!start || !end) return |
|
const startMonthDays = getDate.thisMonthDays(start[0], start[1]) |
|
const endMonthDays = getDate.thisMonthDays(end[0], end[1]) |
|
if (start[2] > startMonthDays || start[2] < 1) { |
|
logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内') |
|
return false |
|
} else if (start[1] > 12 || start[1] < 1) { |
|
logger.warn('enableArea() 开始日期错误,月份超出1-12月份') |
|
return false |
|
} else if (end[2] > endMonthDays || end[2] < 1) { |
|
logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内') |
|
return false |
|
} else if (end[1] > 12 || end[1] < 1) { |
|
logger.warn('enableArea() 截止日期错误,月份超出1-12月份') |
|
return false |
|
} else if (startTimestamp > endTimestamp) { |
|
logger.warn('enableArea()参数最小日期大于了最大日期') |
|
return false |
|
} else { |
|
return true |
|
} |
|
} |
|
__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 |
|
} |
|
} |
|
__handleEnableArea(data = {}, selectedDay = []) { |
|
const { area, days, startTimestamp, endTimestamp } = data |
|
const enableDays = this.getData('calendar.enableDays') || [] |
|
let expectEnableDaysTimestamp = [] |
|
if (enableDays.length) { |
|
expectEnableDaysTimestamp = delRepeatedEnableDay(enableDays, area) |
|
} |
|
const { |
|
disableDateTimestamp, |
|
disableType |
|
} = this.__getDisableDateTimestamp() |
|
const dates = [...days] |
|
dates.forEach(item => { |
|
const timestamp = +getDate |
|
.newDate(item.year, item.month, item.day) |
|
.getTime() |
|
const ifOutofArea = |
|
(+startTimestamp > timestamp || timestamp > +endTimestamp) && |
|
!expectEnableDaysTimestamp.includes(timestamp) |
|
if ( |
|
ifOutofArea || |
|
(disableType === 'before' && |
|
disableDateTimestamp && |
|
timestamp < disableDateTimestamp) || |
|
(disableType === 'after' && |
|
disableDateTimestamp && |
|
timestamp > disableDateTimestamp) |
|
) { |
|
item.disable = true |
|
if (item.choosed) { |
|
item.choosed = false |
|
selectedDay = selectedDay.filter( |
|
d => getDate.toTimeStr(item) !== getDate.toTimeStr(d) |
|
) |
|
} |
|
} else if (item.disable) { |
|
item.disable = false |
|
} |
|
}) |
|
return { |
|
dates, |
|
selectedDay |
|
} |
|
} |
|
__handleEnableDays(data = {}, selectedDay = []) { |
|
const { days, expectEnableDaysTimestamp } = data |
|
const { enableAreaTimestamp = [] } = this.getData('calendar') |
|
const dates = [...days] |
|
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]) && |
|
!expectEnableDaysTimestamp.includes(+timestamp) |
|
) { |
|
setDisable = true |
|
} |
|
} else if (!expectEnableDaysTimestamp.includes(+timestamp)) { |
|
setDisable = true |
|
} |
|
if (setDisable) { |
|
item.disable = true |
|
if (item.choosed) { |
|
item.choosed = false |
|
selectedDay = selectedDay.filter( |
|
d => getDate.toTimeStr(item) !== getDate.toTimeStr(d) |
|
) |
|
} |
|
} else { |
|
item.disable = false |
|
} |
|
}) |
|
return { |
|
dates, |
|
selectedDay |
|
} |
|
} |
|
__handleSelectedDays(days = [], newSelectedDay = [], selected) { |
|
const { selectedDay, showLabelAlways } = this.getData('calendar') |
|
if (selectedDay && selectedDay.length) { |
|
newSelectedDay = uniqueArrayByDate(selectedDay.concat(selected)) |
|
} else { |
|
newSelectedDay = selected |
|
} |
|
const { year: curYear, month: curMonth } = days[0] |
|
const currentSelectedDays = [] |
|
newSelectedDay.forEach(item => { |
|
if (+item.year === +curYear && +item.month === +curMonth) { |
|
currentSelectedDays.push(getDate.toTimeStr(item)) |
|
} |
|
}) |
|
;[...days].map(item => { |
|
if (currentSelectedDays.includes(getDate.toTimeStr(item))) { |
|
item.choosed = true |
|
if (showLabelAlways && item.showTodoLabel) { |
|
item.showTodoLabel = true |
|
} else { |
|
item.showTodoLabel = false |
|
} |
|
} |
|
}) |
|
return { |
|
dates: days, |
|
selectedDates: newSelectedDay |
|
} |
|
} |
|
} |
|
|
|
export default component => new Day(component)
|
|
|