import { EventFrequency } from '@/constant' export function isMoreThanOneWeek (timestamp) { return timestamp >= 604800000 } export function isOverDay ({ startTime, endTime }) { if (startTime === endTime) { return startTime !== '00:00:00' } return startTime > endTime } export function getNearestHitDate (event, minDate, maxDate) { switch (event.freq) { case EventFrequency.ONCE: return getNearestHitDateForOnce(event, minDate, maxDate) case EventFrequency.WEEKLY: return getNearestHitDateForWeekly(event, minDate, maxDate) default: return null } } function getNearestHitDateForOnce (event, minDate, maxDate) { minDate = pickMax(toDate(event.start), toDate(minDate)) maxDate = pickMin(toDate(event.until), toDate(maxDate)) console.log('getNearestHitDateForOnce', minDate, maxDate) return maxDate && maxDate <= minDate ? null : minDate } function getNearestHitDateForWeekly (event, minDate, maxDate) { console.log('getNearestHitDateForWeekly', event) minDate = getNearestHitDateForOnce(event, minDate, maxDate) if (!minDate) { return null } if (isHitWeeklyByDate(event, minDate)) { return minDate } maxDate = pickMin(toDate(event.until), toDate(maxDate)) const byDay = event.byDay const date = toDate(`${toDateStr(minDate)} ${event.startTime}`) if (date < minDate) { date.setDate(date.getDate() + 1) } while (canContinue(date, maxDate)) { if (byDay.includes(date.getDay())) { return date } date.setDate(date.getDate() + 1) } return null } function offsetWeek (week, offset) { return (week + offset + 7) % 7 } export function toDate (val) { return val && new Date(typeof val === 'string' ? val.replace(/-/g, '/') : val) } export function pickMax (a, b) { return a >= b ? a : b } export function pickMin (a, b) { return a && b ? a >= b ? b : a : a || b } export function isHit (event, date) { console.log('isHit', event, date) if (!isIn(toDate(date), toDate(event.start), toDate(event.until))) { console.log('miss', 'out of range') return false } switch (event.freq) { case EventFrequency.WEEKLY: return isHitWeeklyByDate(event, date) default: return true } } function isHitWeeklyByDate (event, date) { date = toDate(date) const byDay = event.byDay const week = date.getDay() if (!isOverDay(event)) { return byDay.includes(week) && isIn(toTimeStr(date), event.startTime, correctEndTime(event.endTime)) } if (byDay.includes(week) && isIn(toTimeStr(date), event.startTime, '24:00:00')) { return true } if (byDay.includes(offsetWeek(week, -1)) && isIn(toTimeStr(date), '00:00:00', event.endTime)) { return true } return false } function canContinue (startDate, endDate) { return !endDate || startDate < endDate } export function isIn (target, start, end) { return target >= start && (!end || target < end) } export function toDateStr (date, offset = 0) { date = toDate(date) if (offset !== 0) { date.setDate(date.getDate() + offset) } return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}` } export function toTimeStr (date) { return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}` } export function toZeroPoint (date) { return toDate(`${toDateStr(date)} 00:00:00`) } export function getStartDate (event, date) { switch (event.freq) { case EventFrequency.WEEKLY: return getWeeklyStartDate(event, date) default: return toDate(event.start) } } function getWeeklyStartDate (event, date) { const time = toTimeStr(date) return time < event.startTime ? toDate(`${toDateStr(date, -1)} ${event.startTime}`) : toDate(`${toDateStr(date)} ${event.startTime}`) } export function getFinishDate (event, date) { switch (event.freq) { case EventFrequency.WEEKLY: return getWeeklyFinishDate(event, date) default: return event.until && toDate(event.until) } } function getWeeklyFinishDate (event, date) { const time = toTimeStr(date) return time < event.startTime ? toDate(`${toDateStr(date)} ${event.endTime}`) : toDate(`${toDateStr(date, isOverDay(event) ? 1 : 0)} ${correctEndTime(event.endTime)}`) } export function getConflict (a, b) { console.log('compare', a, b) if (a.freq !== b.freq) { return a.freq === EventFrequency.WEEKLY ? getNearestHitDateForWeekly(a, b.start, b.until) : getNearestHitDateForWeekly(b, a.start, a.until) } if (a.freq === EventFrequency.WEEKLY) { return getConflictForWeeklyToWeekly(a, b) } return getNearestHitDateForOnce(a, b.start, b.until) } function getConflictForWeeklyToWeekly (a, b) { const hitDate = getNearestHitDateForOnce(a, b.start, b.until) if (hitDate) { const untilDate = pickMin(toDate(a.until), toDate(b.until)) const isMore = !untilDate || isMoreThanOneWeek(untilDate - hitDate) const minDate = isMore ? toDate(`${toDateStr(hitDate)} 00:00:00`) : hitDate const maxDate = isMore ? toDate(`${toDateStr(hitDate, 7)} 00:00:00`) : untilDate console.log('isConflictForWeeklyToWeekly', minDate, maxDate) const aTimeSlices = getTimeSlicesInRange(a, minDate, maxDate) if (aTimeSlices[0].length) { console.log('isConflictForWeeklyToWeekly', a, aTimeSlices) const bTimeSlices = getTimeSlicesInRange(b, minDate, maxDate) if (bTimeSlices[0].length) { console.log('isConflictForWeeklyToWeekly', b, bTimeSlices) const fromTimeSlices = [...aTimeSlices[0], ...bTimeSlices[0]].sort(ascSort) const toTimeSlices = [...aTimeSlices[1], ...bTimeSlices[1]].sort(ascSort) return getConflictTimeSlice(fromTimeSlices, toTimeSlices) } } } console.log('miss') return null } function getConflictTimeSlice (fromTimeSlices, toTimeSlices) { let i = 0 let j = 0 let running = false while (i < fromTimeSlices.length && j < toTimeSlices.length) { if (fromTimeSlices[i] < toTimeSlices[j]) { if (running) { return fromTimeSlices[i] } running = true i += 1 } else { running = false j += 1 } } console.log('time slice miss') return null } function ascSort (a, b) { return a - b } function getTimeSlicesInRange (event, minDate, maxDate) { const { byDay, startTime } = event const endTime = correctEndTime(event.endTime) const minDateStr = toDateStr(minDate) const fromTimeSlices = [] const toTimeSlices = [] if (isHitOverDayTime(event, minDate)) { fromTimeSlices.push(toDate(minDate)) toTimeSlices.push(pickMin(toDate(`${minDateStr} ${endTime}`), maxDate)) } const referFromDate = toDate(`${minDateStr} ${startTime}`) if (referFromDate < maxDate) { const referToDate = toDate(`${toDateStr(minDate, isOverDay(event) ? 1 : 0)} ${endTime}`) while (canContinue(referFromDate, maxDate)) { if (byDay.includes(referFromDate.getDay())) { fromTimeSlices.push(toDate(pickMax(referFromDate, minDate))) toTimeSlices.push(toDate(pickMin(referToDate, maxDate))) } referFromDate.setDate(referFromDate.getDate() + 1) referToDate.setDate(referToDate.getDate() + 1) } } return [fromTimeSlices, toTimeSlices] } export function isHitOverDayTime (event, date) { if (!isOverDay(event)) { return null } date = toDate(date) const { byDay, endTime } = event return byDay.includes(offsetWeek(date.getDay(), -1)) && toTimeStr(date) < endTime } export function correctEndTime (endTime) { return endTime === '00:00:00' ? '24:00:00' : endTime } export function getEventDateDescription (event) { const { freq, start, until, endTime } = event if (freq === EventFrequency.WEEKLY) { return until ? `${toDateStr(start)} - ${toDateStr(until, endTime === '00:00:00' ? -1 : 0)}` : `自${toDateStr(start)}开始` } return until ? `${start} - ${until}` : `自${start}开始` } const weekEnum = ['日', '一', '二', '三', '四', '五', '六'] export function getEventExtraDescription (event) { const { freq, start, until, byDay, startTime, endTime, target } = event switch (freq) { case EventFrequency.WEEKLY: if (byDay.split(',').length === 7) { return `每天 ${startTime} - ${correctEndTime(endTime)}` } return `每周${byDay.split(',').sort().map(val => weekEnum[val]) .join('、')} ${startTime} - ${correctEndTime(endTime)}` default: return target?.duration ? `播放${(toDate(until) - toDate(start)) / target.duration / 1000}次` : '' } } export function getEventDescription (event) { const extra = getEventExtraDescription(event) if (extra) { return `${getEventDateDescription(event)} ${extra}` } return getEventDateDescription(event) } export function createEmptyEvent () { return { freq: EventFrequency.ONCE, start: `${toDateStr(new Date())} 00:00:00`, until: `${toDateStr(new Date(), 1)} 00:00:00`, byDay: '', startTime: '00:00:00', endTime: '00:00:00' } }