event.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import { EventFrequency } from '@/constant'
  2. export function isMoreThanOneWeek (timestamp) {
  3. return timestamp >= 604800000
  4. }
  5. export function isOverDay ({ startTime, endTime }) {
  6. if (startTime === endTime) {
  7. return startTime !== '00:00:00'
  8. }
  9. return startTime > endTime
  10. }
  11. export function getNearestHitDate (event, minDate, maxDate) {
  12. switch (event.freq) {
  13. case EventFrequency.ONCE:
  14. return getNearestHitDateForOnce(event, minDate, maxDate)
  15. case EventFrequency.WEEKLY:
  16. return getNearestHitDateForWeekly(event, minDate, maxDate)
  17. default:
  18. return null
  19. }
  20. }
  21. function getNearestHitDateForOnce (event, minDate, maxDate) {
  22. minDate = pickMax(toDate(event.start), toDate(minDate))
  23. maxDate = pickMin(toDate(event.until), toDate(maxDate))
  24. console.log('getNearestHitDateForOnce', minDate, maxDate)
  25. return maxDate && maxDate <= minDate ? null : minDate
  26. }
  27. function getNearestHitDateForWeekly (event, minDate, maxDate) {
  28. console.log('getNearestHitDateForWeekly', event)
  29. minDate = getNearestHitDateForOnce(event, minDate, maxDate)
  30. if (!minDate) {
  31. return null
  32. }
  33. if (isHitWeeklyByDate(event, minDate)) {
  34. return minDate
  35. }
  36. maxDate = pickMin(toDate(event.until), toDate(maxDate))
  37. const byDay = event.byDay
  38. const date = toDate(`${toDateStr(minDate)} ${event.startTime}`)
  39. if (date < minDate) {
  40. date.setDate(date.getDate() + 1)
  41. }
  42. while (canContinue(date, maxDate)) {
  43. if (byDay.includes(date.getDay())) {
  44. return date
  45. }
  46. date.setDate(date.getDate() + 1)
  47. }
  48. return null
  49. }
  50. function offsetWeek (week, offset) {
  51. return (week + offset + 7) % 7
  52. }
  53. export function toDate (val) {
  54. return val && new Date(typeof val === 'string' ? val.replace(/-/g, '/') : val)
  55. }
  56. export function pickMax (a, b) {
  57. return a >= b ? a : b
  58. }
  59. export function pickMin (a, b) {
  60. return a && b
  61. ? a >= b
  62. ? b
  63. : a
  64. : a || b
  65. }
  66. export function isHit (event, date) {
  67. console.log('isHit', event, date)
  68. if (!isIn(toDate(date), toDate(event.start), toDate(event.until))) {
  69. console.log('miss', 'out of range')
  70. return false
  71. }
  72. switch (event.freq) {
  73. case EventFrequency.WEEKLY:
  74. return isHitWeeklyByDate(event, date)
  75. default:
  76. return true
  77. }
  78. }
  79. function isHitWeeklyByDate (event, date) {
  80. date = toDate(date)
  81. const byDay = event.byDay
  82. const week = date.getDay()
  83. if (!isOverDay(event)) {
  84. return byDay.includes(week) && isIn(toTimeStr(date), event.startTime, correctEndTime(event.endTime))
  85. }
  86. if (byDay.includes(week) && isIn(toTimeStr(date), event.startTime, '24:00:00')) {
  87. return true
  88. }
  89. if (byDay.includes(offsetWeek(week, -1)) && isIn(toTimeStr(date), '00:00:00', event.endTime)) {
  90. return true
  91. }
  92. return false
  93. }
  94. function canContinue (startDate, endDate) {
  95. return !endDate || startDate < endDate
  96. }
  97. export function isIn (target, start, end) {
  98. return target >= start && (!end || target < end)
  99. }
  100. export function toDateStr (date, offset = 0) {
  101. date = toDate(date)
  102. if (offset !== 0) {
  103. date.setDate(date.getDate() + offset)
  104. }
  105. return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`
  106. }
  107. export function toTimeStr (date) {
  108. return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`
  109. }
  110. export function toZeroPoint (date) {
  111. return toDate(`${toDateStr(date)} 00:00:00`)
  112. }
  113. export function getStartDate (event, date) {
  114. switch (event.freq) {
  115. case EventFrequency.WEEKLY:
  116. return getWeeklyStartDate(event, date)
  117. default:
  118. return toDate(event.start)
  119. }
  120. }
  121. function getWeeklyStartDate (event, date) {
  122. const time = toTimeStr(date)
  123. return time < event.startTime
  124. ? toDate(`${toDateStr(date, -1)} ${event.startTime}`)
  125. : toDate(`${toDateStr(date)} ${event.startTime}`)
  126. }
  127. export function getFinishDate (event, date) {
  128. switch (event.freq) {
  129. case EventFrequency.WEEKLY:
  130. return getWeeklyFinishDate(event, date)
  131. default:
  132. return event.until && toDate(event.until)
  133. }
  134. }
  135. function getWeeklyFinishDate (event, date) {
  136. const time = toTimeStr(date)
  137. return time < event.startTime
  138. ? toDate(`${toDateStr(date)} ${event.endTime}`)
  139. : toDate(`${toDateStr(date, isOverDay(event) ? 1 : 0)} ${correctEndTime(event.endTime)}`)
  140. }
  141. export function getConflict (a, b) {
  142. console.log('compare', a, b)
  143. if (a.freq !== b.freq) {
  144. return a.freq === EventFrequency.WEEKLY
  145. ? getNearestHitDateForWeekly(a, b.start, b.until)
  146. : getNearestHitDateForWeekly(b, a.start, a.until)
  147. }
  148. if (a.freq === EventFrequency.WEEKLY) {
  149. return getConflictForWeeklyToWeekly(a, b)
  150. }
  151. return getNearestHitDateForOnce(a, b.start, b.until)
  152. }
  153. function getConflictForWeeklyToWeekly (a, b) {
  154. const hitDate = getNearestHitDateForOnce(a, b.start, b.until)
  155. if (hitDate) {
  156. const untilDate = pickMin(toDate(a.until), toDate(b.until))
  157. const isMore = !untilDate || isMoreThanOneWeek(untilDate - hitDate)
  158. const minDate = isMore ? toDate(`${toDateStr(hitDate)} 00:00:00`) : hitDate
  159. const maxDate = isMore ? toDate(`${toDateStr(hitDate, 7)} 00:00:00`) : untilDate
  160. console.log('isConflictForWeeklyToWeekly', minDate, maxDate)
  161. const aTimeSlices = getTimeSlicesInRange(a, minDate, maxDate)
  162. if (aTimeSlices[0].length) {
  163. console.log('isConflictForWeeklyToWeekly', a, aTimeSlices)
  164. const bTimeSlices = getTimeSlicesInRange(b, minDate, maxDate)
  165. if (bTimeSlices[0].length) {
  166. console.log('isConflictForWeeklyToWeekly', b, bTimeSlices)
  167. const fromTimeSlices = [...aTimeSlices[0], ...bTimeSlices[0]].sort(ascSort)
  168. const toTimeSlices = [...aTimeSlices[1], ...bTimeSlices[1]].sort(ascSort)
  169. return getConflictTimeSlice(fromTimeSlices, toTimeSlices)
  170. }
  171. }
  172. }
  173. console.log('miss')
  174. return null
  175. }
  176. function getConflictTimeSlice (fromTimeSlices, toTimeSlices) {
  177. let i = 0
  178. let j = 0
  179. let running = false
  180. while (i < fromTimeSlices.length && j < toTimeSlices.length) {
  181. if (fromTimeSlices[i] < toTimeSlices[j]) {
  182. if (running) {
  183. return fromTimeSlices[i]
  184. }
  185. running = true
  186. i += 1
  187. } else {
  188. running = false
  189. j += 1
  190. }
  191. }
  192. console.log('time slice miss')
  193. return null
  194. }
  195. function ascSort (a, b) {
  196. return a - b
  197. }
  198. function getTimeSlicesInRange (event, minDate, maxDate) {
  199. const { byDay, startTime } = event
  200. const endTime = correctEndTime(event.endTime)
  201. const minDateStr = toDateStr(minDate)
  202. const fromTimeSlices = []
  203. const toTimeSlices = []
  204. if (isHitOverDayTime(event, minDate)) {
  205. fromTimeSlices.push(toDate(minDate))
  206. toTimeSlices.push(pickMin(toDate(`${minDateStr} ${endTime}`), maxDate))
  207. }
  208. const referFromDate = toDate(`${minDateStr} ${startTime}`)
  209. if (referFromDate < maxDate) {
  210. const referToDate = toDate(`${toDateStr(minDate, isOverDay(event) ? 1 : 0)} ${endTime}`)
  211. while (canContinue(referFromDate, maxDate)) {
  212. if (byDay.includes(referFromDate.getDay())) {
  213. fromTimeSlices.push(toDate(pickMax(referFromDate, minDate)))
  214. toTimeSlices.push(toDate(pickMin(referToDate, maxDate)))
  215. }
  216. referFromDate.setDate(referFromDate.getDate() + 1)
  217. referToDate.setDate(referToDate.getDate() + 1)
  218. }
  219. }
  220. return [fromTimeSlices, toTimeSlices]
  221. }
  222. export function isHitOverDayTime (event, date) {
  223. if (!isOverDay(event)) {
  224. return null
  225. }
  226. date = toDate(date)
  227. const { byDay, endTime } = event
  228. return byDay.includes(offsetWeek(date.getDay(), -1)) && toTimeStr(date) < endTime
  229. }
  230. export function correctEndTime (endTime) {
  231. return endTime === '00:00:00' ? '24:00:00' : endTime
  232. }
  233. export function getEventDateDescription (event) {
  234. const { freq, start, until, endTime } = event
  235. if (freq === EventFrequency.WEEKLY) {
  236. return until ? `${toDateStr(start)} - ${toDateStr(until, endTime === '00:00:00' ? -1 : 0)}` : `自${toDateStr(start)}开始`
  237. }
  238. return until ? `${start} - ${until}` : `自${start}开始`
  239. }
  240. const weekEnum = ['日', '一', '二', '三', '四', '五', '六']
  241. export function getEventExtraDescription (event) {
  242. const { freq, start, until, byDay, startTime, endTime, target } = event
  243. switch (freq) {
  244. case EventFrequency.WEEKLY:
  245. if (byDay.split(',').length === 7) {
  246. return `每天 ${startTime} - ${correctEndTime(endTime)}`
  247. }
  248. return `每周${byDay.split(',').sort().map(val => weekEnum[val])
  249. .join('、')} ${startTime} - ${correctEndTime(endTime)}`
  250. default:
  251. return target?.duration
  252. ? `播放${(toDate(until) - toDate(start)) / target.duration / 1000}次`
  253. : ''
  254. }
  255. }
  256. export function getEventDescription (event) {
  257. const extra = getEventExtraDescription(event)
  258. if (extra) {
  259. return `${getEventDateDescription(event)} ${extra}`
  260. }
  261. return getEventDateDescription(event)
  262. }
  263. export function createEmptyEvent () {
  264. return {
  265. freq: EventFrequency.ONCE,
  266. start: `${toDateStr(new Date())} 00:00:00`,
  267. until: `${toDateStr(new Date(), 1)} 00:00:00`,
  268. byDay: '',
  269. startTime: '00:00:00',
  270. endTime: '00:00:00'
  271. }
  272. }