422 lines
9.8 KiB
JavaScript
422 lines
9.8 KiB
JavaScript
class Calendar {
|
||
constructor({
|
||
selected,
|
||
startDate,
|
||
endDate,
|
||
range,
|
||
} = {}) {
|
||
// 当前日期
|
||
this.date = this.getDateObj(new Date()) // 当前初入日期
|
||
// 打点信息
|
||
this.selected = selected || [];
|
||
// 起始时间
|
||
this.startDate = startDate
|
||
// 终止时间
|
||
this.endDate = endDate
|
||
// 是否范围选择
|
||
this.range = range
|
||
// 多选状态
|
||
this.cleanMultipleStatus()
|
||
// 每周日期
|
||
this.weeks = {}
|
||
this.lastHover = false
|
||
}
|
||
/**
|
||
* 设置日期
|
||
* @param {Object} date
|
||
*/
|
||
setDate(date) {
|
||
const selectDate = this.getDateObj(date)
|
||
this.getWeeks(selectDate.fullDate)
|
||
}
|
||
|
||
/**
|
||
* 清理多选状态
|
||
*/
|
||
cleanMultipleStatus() {
|
||
this.multipleStatus = {
|
||
before: '',
|
||
after: '',
|
||
data: []
|
||
}
|
||
}
|
||
|
||
setStartDate(startDate) {
|
||
this.startDate = startDate
|
||
}
|
||
|
||
setEndDate(endDate) {
|
||
this.endDate = endDate
|
||
}
|
||
|
||
getPreMonthObj(date) {
|
||
date = fixIosDateFormat(date)
|
||
date = new Date(date)
|
||
|
||
const oldMonth = date.getMonth()
|
||
date.setMonth(oldMonth - 1)
|
||
const newMonth = date.getMonth()
|
||
if (oldMonth !== 0 && newMonth - oldMonth === 0) {
|
||
date.setMonth(newMonth - 1)
|
||
}
|
||
return this.getDateObj(date)
|
||
}
|
||
getNextMonthObj(date) {
|
||
date = fixIosDateFormat(date)
|
||
date = new Date(date)
|
||
|
||
const oldMonth = date.getMonth()
|
||
date.setMonth(oldMonth + 1)
|
||
const newMonth = date.getMonth()
|
||
if (newMonth - oldMonth > 1) {
|
||
date.setMonth(newMonth - 1)
|
||
}
|
||
return this.getDateObj(date)
|
||
}
|
||
|
||
/**
|
||
* 获取指定格式Date对象
|
||
*/
|
||
getDateObj(date) {
|
||
date = fixIosDateFormat(date)
|
||
date = new Date(date)
|
||
|
||
return {
|
||
fullDate: getDate(date),
|
||
year: date.getFullYear(),
|
||
month: addZero(date.getMonth() + 1),
|
||
date: addZero(date.getDate()),
|
||
day: date.getDay()
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取上一个月日期集合
|
||
*/
|
||
getPreMonthDays(amount, dateObj) {
|
||
const result = []
|
||
for (let i = amount - 1; i >= 0; i--) {
|
||
const month = dateObj.month - 1
|
||
result.push({
|
||
date: new Date(dateObj.year, month, -i).getDate(),
|
||
month,
|
||
disable: true
|
||
})
|
||
}
|
||
return result
|
||
}
|
||
/**
|
||
* 获取本月日期集合
|
||
*/
|
||
getCurrentMonthDays(amount, dateObj) {
|
||
const result = []
|
||
const fullDate = this.date.fullDate
|
||
for (let i = 1; i <= amount; i++) {
|
||
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
|
||
const isToday = fullDate === currentDate
|
||
// 获取打点信息
|
||
const info = this.selected && this.selected.find((item) => {
|
||
if (this.dateEqual(currentDate, item.date)) {
|
||
return item
|
||
}
|
||
})
|
||
|
||
// 日期禁用
|
||
let disableBefore = true
|
||
let disableAfter = true
|
||
if (this.startDate) {
|
||
disableBefore = dateCompare(this.startDate, currentDate)
|
||
}
|
||
|
||
if (this.endDate) {
|
||
disableAfter = dateCompare(currentDate, this.endDate)
|
||
}
|
||
|
||
let multiples = this.multipleStatus.data
|
||
let multiplesStatus = -1
|
||
if (this.range && multiples) {
|
||
multiplesStatus = multiples.findIndex((item) => {
|
||
return this.dateEqual(item, currentDate)
|
||
})
|
||
}
|
||
const checked = multiplesStatus !== -1
|
||
|
||
result.push({
|
||
fullDate: currentDate,
|
||
year: dateObj.year,
|
||
date: i,
|
||
multiple: this.range ? checked : false,
|
||
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||
month: dateObj.month,
|
||
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
|
||
currentDate, this.endDate)),
|
||
isToday,
|
||
userChecked: false,
|
||
extraInfo: info
|
||
})
|
||
}
|
||
return result
|
||
}
|
||
/**
|
||
* 获取下一个月日期集合
|
||
*/
|
||
_getNextMonthDays(amount, dateObj) {
|
||
const result = []
|
||
const month = dateObj.month + 1
|
||
for (let i = 1; i <= amount; i++) {
|
||
result.push({
|
||
date: i,
|
||
month,
|
||
disable: true
|
||
})
|
||
}
|
||
return result
|
||
}
|
||
|
||
/**
|
||
* 获取当前日期详情
|
||
* @param {Object} date
|
||
*/
|
||
getInfo(date) {
|
||
if (!date) {
|
||
date = new Date()
|
||
}
|
||
|
||
return this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
|
||
}
|
||
|
||
/**
|
||
* 比较时间是否相等
|
||
*/
|
||
dateEqual(before, after) {
|
||
before = new Date(fixIosDateFormat(before))
|
||
after = new Date(fixIosDateFormat(after))
|
||
return before.valueOf() === after.valueOf()
|
||
}
|
||
|
||
/**
|
||
* 比较真实起始日期
|
||
*/
|
||
|
||
isLogicBefore(currentDate, before, after) {
|
||
let logicBefore = before
|
||
if (before && after) {
|
||
logicBefore = dateCompare(before, after) ? before : after
|
||
}
|
||
return this.dateEqual(logicBefore, currentDate)
|
||
}
|
||
|
||
isLogicAfter(currentDate, before, after) {
|
||
let logicAfter = after
|
||
if (before && after) {
|
||
logicAfter = dateCompare(before, after) ? after : before
|
||
}
|
||
return this.dateEqual(logicAfter, currentDate)
|
||
}
|
||
|
||
/**
|
||
* 获取日期范围内所有日期
|
||
* @param {Object} begin
|
||
* @param {Object} end
|
||
*/
|
||
geDateAll(begin, end) {
|
||
var arr = []
|
||
var ab = begin.split('-')
|
||
var ae = end.split('-')
|
||
var db = new Date()
|
||
db.setFullYear(ab[0], ab[1] - 1, ab[2])
|
||
var de = new Date()
|
||
de.setFullYear(ae[0], ae[1] - 1, ae[2])
|
||
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
|
||
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||
for (var k = unixDb; k <= unixDe;) {
|
||
k = k + 24 * 60 * 60 * 1000
|
||
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
|
||
}
|
||
return arr
|
||
}
|
||
|
||
/**
|
||
* 获取多选状态
|
||
*/
|
||
setMultiple(fullDate) {
|
||
if (!this.range) return
|
||
|
||
let {
|
||
before,
|
||
after
|
||
} = this.multipleStatus
|
||
if (before && after) {
|
||
if (!this.lastHover) {
|
||
this.lastHover = true
|
||
return
|
||
}
|
||
this.multipleStatus.before = fullDate
|
||
this.multipleStatus.after = ''
|
||
this.multipleStatus.data = []
|
||
this.multipleStatus.fulldate = ''
|
||
this.lastHover = false
|
||
} else {
|
||
if (!before) {
|
||
this.multipleStatus.before = fullDate
|
||
this.multipleStatus.after = undefined;
|
||
this.lastHover = false
|
||
} else {
|
||
this.multipleStatus.after = fullDate
|
||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
|
||
.after);
|
||
} else {
|
||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
|
||
.before);
|
||
}
|
||
this.lastHover = true
|
||
}
|
||
}
|
||
this.getWeeks(fullDate)
|
||
}
|
||
|
||
/**
|
||
* 鼠标 hover 更新多选状态
|
||
*/
|
||
setHoverMultiple(fullDate) {
|
||
//抖音小程序点击会触发hover事件,需要避免一下
|
||
// #ifndef MP-TOUTIAO
|
||
if (!this.range || this.lastHover) return
|
||
const {
|
||
before
|
||
} = this.multipleStatus
|
||
|
||
if (!before) {
|
||
this.multipleStatus.before = fullDate
|
||
} else {
|
||
this.multipleStatus.after = fullDate
|
||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
|
||
} else {
|
||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
|
||
}
|
||
}
|
||
this.getWeeks(fullDate)
|
||
// #endif
|
||
|
||
}
|
||
|
||
/**
|
||
* 更新默认值多选状态
|
||
*/
|
||
setDefaultMultiple(before, after) {
|
||
this.multipleStatus.before = before
|
||
this.multipleStatus.after = after
|
||
if (before && after) {
|
||
if (dateCompare(before, after)) {
|
||
this.multipleStatus.data = this.geDateAll(before, after);
|
||
this.getWeeks(after)
|
||
} else {
|
||
this.multipleStatus.data = this.geDateAll(after, before);
|
||
this.getWeeks(before)
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取每周数据
|
||
* @param {Object} dateData
|
||
*/
|
||
getWeeks(dateData) {
|
||
const {
|
||
year,
|
||
month,
|
||
} = this.getDateObj(dateData)
|
||
|
||
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
|
||
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
|
||
|
||
const currentMonthDayAmount = new Date(year, month, 0).getDate()
|
||
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
|
||
|
||
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
|
||
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
|
||
|
||
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
|
||
|
||
const weeks = new Array(6)
|
||
for (let i = 0; i < calendarDays.length; i++) {
|
||
const index = Math.floor(i / 7)
|
||
if (!weeks[index]) {
|
||
weeks[index] = new Array(7)
|
||
}
|
||
weeks[index][i % 7] = calendarDays[i]
|
||
}
|
||
|
||
this.calendar = calendarDays
|
||
this.weeks = weeks
|
||
}
|
||
}
|
||
|
||
function getDateTime(date, hideSecond) {
|
||
return `${getDate(date)} ${getTime(date, hideSecond)}`
|
||
}
|
||
|
||
function getDate(date) {
|
||
date = fixIosDateFormat(date)
|
||
date = new Date(date)
|
||
const year = date.getFullYear()
|
||
const month = date.getMonth() + 1
|
||
const day = date.getDate()
|
||
return `${year}-${addZero(month)}-${addZero(day)}`
|
||
}
|
||
|
||
function getTime(date, hideSecond) {
|
||
date = fixIosDateFormat(date)
|
||
date = new Date(date)
|
||
const hour = date.getHours()
|
||
const minute = date.getMinutes()
|
||
const second = date.getSeconds()
|
||
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
|
||
}
|
||
|
||
function addZero(num) {
|
||
if (num < 10) {
|
||
num = `0${num}`
|
||
}
|
||
return num
|
||
}
|
||
|
||
function getDefaultSecond(hideSecond) {
|
||
return hideSecond ? '00:00' : '00:00:00'
|
||
}
|
||
|
||
function dateCompare(startDate, endDate) {
|
||
startDate = new Date(fixIosDateFormat(startDate))
|
||
endDate = new Date(fixIosDateFormat(endDate))
|
||
return startDate <= endDate
|
||
}
|
||
|
||
function checkDate(date) {
|
||
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
|
||
return date.match(dateReg)
|
||
}
|
||
//ios低版本15及以下,无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号
|
||
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
|
||
|
||
function fixIosDateFormat(value) {
|
||
if (typeof value === 'string' && dateTimeReg.test(value)) {
|
||
value = value.replace(/-/g, '/')
|
||
}
|
||
return value
|
||
}
|
||
|
||
export {
|
||
Calendar,
|
||
getDateTime,
|
||
getDate,
|
||
getTime,
|
||
addZero,
|
||
getDefaultSecond,
|
||
dateCompare,
|
||
checkDate,
|
||
fixIosDateFormat
|
||
}
|