week.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /**
  2. * @Author: drfu*
  3. * @Description: 周视图
  4. * @Date: 2020-10-08 21:22:09*
  5. * @Last Modified by: drfu
  6. * @Last Modified time: 2020-10-12 14:39:45
  7. * */
  8. import { renderCalendar } from '../render'
  9. import {
  10. getCalendarConfig,
  11. getCalendarData,
  12. logger,
  13. dateUtil
  14. } from '../utils/index'
  15. import { calcJumpData } from '../core'
  16. /**
  17. * 当月第一周所有日期
  18. */
  19. function firstWeekInMonth(
  20. target = {},
  21. calendarDates = [],
  22. calendarConfig = {}
  23. ) {
  24. const { firstDayOfWeek } = calendarConfig
  25. const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
  26. const { year, month } = target
  27. let firstDay = dateUtil.getDayOfWeek(year, month, 1)
  28. if (firstDayOfWeekIsMon && firstDay === 0) {
  29. firstDay = 7
  30. }
  31. const [, end] = [0, 7 - firstDay]
  32. return calendarDates.slice(0, firstDayOfWeekIsMon ? end + 1 : end)
  33. }
  34. /**
  35. * 当月最后一周所有日期
  36. */
  37. function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) {
  38. const { firstDayOfWeek } = calendarConfig
  39. const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
  40. const { year, month } = target
  41. const lastDay = dateUtil.getDatesCountOfMonth(year, month)
  42. let lastDayWeek = dateUtil.getDayOfWeek(year, month, lastDay)
  43. if (firstDayOfWeekIsMon && lastDayWeek === 0) {
  44. lastDayWeek = 7
  45. }
  46. const [start, end] = [lastDay - lastDayWeek, lastDay]
  47. return calendarDates.slice(firstDayOfWeekIsMon ? start : start - 1, end)
  48. }
  49. /**
  50. * 判断目标日期是否在某些指定日历内
  51. */
  52. function dateIsInDatesRange(target, dates) {
  53. if (!target || !dates || !dates.length) return false
  54. const targetDateStr = dateUtil.toTimeStr(target)
  55. let rst = false
  56. for (let date of dates) {
  57. const dateStr = dateUtil.toTimeStr(date)
  58. if (dateStr === targetDateStr) {
  59. rst = true
  60. return rst
  61. }
  62. rst = false
  63. }
  64. return rst
  65. }
  66. function getDatesWhenTargetInFirstWeek(target, firstWeekDates) {
  67. const { year, month } = target
  68. const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month })
  69. let lastMonthDatesCount = dateUtil.getDatesCountOfMonth(
  70. prevMonthInfo.year,
  71. prevMonthInfo.month
  72. )
  73. let dates = firstWeekDates
  74. let firstWeekCount = firstWeekDates.length
  75. for (let i = 0; i < 7 - firstWeekCount; i++) {
  76. const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount)
  77. dates.unshift({
  78. year: prevMonthInfo.year,
  79. month: prevMonthInfo.month,
  80. date: lastMonthDatesCount,
  81. week
  82. })
  83. lastMonthDatesCount -= 1
  84. }
  85. return dates
  86. }
  87. function getDatesWhenTargetInLastWeek(target, lastWeekDates) {
  88. const { year, month } = target
  89. const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month })
  90. let dates = lastWeekDates
  91. let lastWeekCount = lastWeekDates.length
  92. for (let i = 0; i < 7 - lastWeekCount; i++) {
  93. const week = dateUtil.getDayOfWeek(+year, +month, i + 1)
  94. dates.push({
  95. year: prevMonthInfo.year,
  96. month: prevMonthInfo.month,
  97. date: i + 1,
  98. week
  99. })
  100. }
  101. return dates
  102. }
  103. function getDates(target, calendarDates = [], calendarConfig = {}) {
  104. const { year, month, date } = target
  105. const targetDay = dateUtil.getDayOfWeek(year, month, date)
  106. const { firstDayOfWeek } = calendarConfig
  107. const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
  108. if (firstDayOfWeekIsMon) {
  109. const startIdx = date - targetDay
  110. return calendarDates.splice(startIdx, 7)
  111. } else {
  112. const startIdx = date - targetDay - 1
  113. return calendarDates.splice(startIdx, 7)
  114. }
  115. }
  116. function getTargetWeekDates(target, calendarConfig) {
  117. if (!target) return
  118. const { year, month } = target
  119. const calendarDates = dateUtil.calcDates(year, month)
  120. const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig)
  121. const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig)
  122. if (dateIsInDatesRange(target, firstWeekDates)) {
  123. return getDatesWhenTargetInFirstWeek(target, firstWeekDates)
  124. } else if (dateIsInDatesRange(target, lastWeekDates)) {
  125. return getDatesWhenTargetInLastWeek(target, lastWeekDates)
  126. } else {
  127. return getDates(target, calendarDates, calendarConfig)
  128. }
  129. }
  130. /**
  131. * 计算周视图下当前这一周最后一天
  132. */
  133. function calculateLastDateOfCurrentWeek(calendarData = {}) {
  134. const { dates = [] } = calendarData
  135. return dates[dates.length - 1]
  136. }
  137. /**
  138. * 计算周视图下当前这一周第一天
  139. */
  140. function calculateFirstDateOfCurrentWeek(calendarData = {}) {
  141. const { dates } = calendarData
  142. return dates[0]
  143. }
  144. /**
  145. * 计算下一周的日期
  146. */
  147. function calculateNextWeekDates(calendarData = {}) {
  148. let { curYear, curMonth } = calendarData
  149. let calendarDates = []
  150. let lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData)
  151. const { year: LYear, month: LMonth } = lastDateInThisWeek
  152. if (curYear !== LYear || curMonth !== LMonth) {
  153. calendarDates = dateUtil.calcDates(LYear, LMonth)
  154. curYear = LYear
  155. curMonth = LMonth
  156. } else {
  157. calendarDates = dateUtil.calcDates(curYear, curMonth)
  158. }
  159. const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth)
  160. const count = lastDateInThisMonth - lastDateInThisWeek.date
  161. const lastDateIdx = calendarDates.findIndex(
  162. date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek)
  163. )
  164. const startIdx = lastDateIdx + 1
  165. if (count >= 7) {
  166. return {
  167. dates: calendarDates.splice(startIdx, 7),
  168. year: curYear,
  169. month: curMonth
  170. }
  171. } else {
  172. const nextMonth = dateUtil.getNextMonthInfo({
  173. year: curYear,
  174. month: curMonth
  175. })
  176. const { year, month } = nextMonth || {}
  177. const calendarDatesOfNextMonth = dateUtil.calcDates(year, month)
  178. const remainDatesOfThisMonth = calendarDates.splice(startIdx)
  179. const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice(
  180. 0,
  181. 7 - remainDatesOfThisMonth.length
  182. )
  183. return {
  184. dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth],
  185. ...nextMonth
  186. }
  187. }
  188. }
  189. /**
  190. * 计算上一周的日期
  191. */
  192. function calculatePrevWeekDates(calendarData = {}) {
  193. let { curYear, curMonth } = calendarData
  194. let firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData)
  195. let calendarDates = []
  196. const { year: FYear, month: FMonth } = firstDateInThisWeek
  197. if (curYear !== FYear || curMonth !== FMonth) {
  198. calendarDates = dateUtil.calcDates(FYear, FMonth)
  199. curYear = FYear
  200. curMonth = FMonth
  201. } else {
  202. calendarDates = dateUtil.calcDates(curYear, curMonth)
  203. }
  204. const firstDateIdx = calendarDates.findIndex(
  205. date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek)
  206. )
  207. if (firstDateIdx - 7 >= 0) {
  208. const startIdx = firstDateIdx - 7
  209. return {
  210. dates: calendarDates.splice(startIdx, 7),
  211. year: curYear,
  212. month: curMonth
  213. }
  214. } else {
  215. const prevMonth = dateUtil.getPrevMonthInfo({
  216. year: curYear,
  217. month: curMonth
  218. })
  219. const { year, month } = prevMonth || {}
  220. const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month)
  221. const remainDatesOfThisMonth = calendarDates.splice(
  222. 0,
  223. firstDateInThisWeek.date - 1
  224. )
  225. const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice(
  226. -(7 - remainDatesOfThisMonth.length)
  227. )
  228. return {
  229. dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth],
  230. ...prevMonth
  231. }
  232. }
  233. }
  234. export default () => {
  235. return {
  236. name: 'week',
  237. beforeRender(calendarData = {}, calendarConfig = {}, component) {
  238. const { initializedWeekMode, selectedDates } = calendarData
  239. if (calendarConfig.weekMode && !initializedWeekMode) {
  240. const { defaultDate } = calendarConfig
  241. const target =
  242. (selectedDates && selectedDates[0]) ||
  243. (defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) ||
  244. dateUtil.todayFMD()
  245. const waitRenderData = this.methods(
  246. component
  247. ).__calcDatesWhenSwitchView('week', target)
  248. const { data, config } = waitRenderData || {}
  249. const setSelectDates = this.methods(
  250. component
  251. ).__selectTargetDateWhenJump(target, data.dates, config)
  252. return {
  253. calendarData: {
  254. ...data,
  255. ...setSelectDates,
  256. weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek),
  257. initializedWeekMode: true
  258. },
  259. calendarConfig
  260. }
  261. }
  262. return {
  263. calendarData,
  264. calendarConfig
  265. }
  266. },
  267. onSwitchCalendar(target = {}, calendarData = {}, component) {
  268. const { direction } = target
  269. const { curYear, curMonth } = calendarData
  270. const calendarConfig = getCalendarConfig(component)
  271. let waitRenderData = {}
  272. if (calendarConfig.weekMode) {
  273. if (direction === 'left') {
  274. waitRenderData = calculateNextWeekDates(calendarData)
  275. } else {
  276. waitRenderData = calculatePrevWeekDates(calendarData)
  277. }
  278. const { dates, year, month } = waitRenderData
  279. return {
  280. ...calendarData,
  281. dates,
  282. curYear: year || curYear,
  283. curMonth: month || curMonth
  284. }
  285. }
  286. return calendarData
  287. },
  288. methods(component) {
  289. return {
  290. __selectTargetDateWhenJump: (target = {}, dates = [], config = {}) => {
  291. let selectedDate = target
  292. const weekDates = dates.map((date, idx) => {
  293. const tmp = { ...date }
  294. tmp.id = idx
  295. const isTarget =
  296. dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp)
  297. if (isTarget && !target.choosed && config.autoChoosedWhenJump) {
  298. tmp.choosed = true
  299. selectedDate = tmp
  300. }
  301. return tmp
  302. })
  303. return {
  304. dates: weekDates,
  305. selectedDates: [selectedDate]
  306. }
  307. },
  308. __calcDatesForWeekMode(target, config = {}, calendarData = {}) {
  309. const { year, month } = target || {}
  310. const weekDates = getTargetWeekDates(target, config)
  311. weekDates.forEach((date, idx) => (date.id = idx))
  312. return {
  313. data: {
  314. ...calendarData,
  315. prevMonthGrids: null,
  316. nextMonthGrids: null,
  317. dates: weekDates,
  318. curYear: year,
  319. curMonth: month
  320. },
  321. config: {
  322. ...config,
  323. weekMode: true
  324. }
  325. }
  326. },
  327. __calcDatesForMonthMode(target, config = {}, calendarData = {}) {
  328. const { year, month } = target || {}
  329. const waitRenderData = calcJumpData({
  330. dateInfo: target,
  331. config
  332. })
  333. return {
  334. data: {
  335. ...calendarData,
  336. ...waitRenderData,
  337. curYear: year,
  338. curMonth: month
  339. },
  340. config: {
  341. ...config,
  342. weekMode: false
  343. }
  344. }
  345. },
  346. /**
  347. * 周、月视图切换
  348. * @param {string} view 视图 [week, month]
  349. * @param {object} target
  350. */
  351. __calcDatesWhenSwitchView: (view, target) => {
  352. const calendarConfig = getCalendarConfig(component)
  353. if (calendarConfig.multi)
  354. return logger.warn('多选模式不能切换周月视图')
  355. const existCalendarData = getCalendarData('calendar', component) || {}
  356. const {
  357. selectedDates = [],
  358. dates = [],
  359. curYear,
  360. curMonth
  361. } = existCalendarData
  362. const currentMonthSelected = selectedDates.filter(
  363. item => curYear === +item.year || curMonth === +item.month
  364. )
  365. let jumpTarget = {}
  366. if (target) {
  367. jumpTarget = target
  368. } else {
  369. if (currentMonthSelected.length) {
  370. jumpTarget = currentMonthSelected.pop()
  371. } else {
  372. jumpTarget = dates[0]
  373. }
  374. }
  375. if (view === 'week') {
  376. return this.methods(component).__calcDatesForWeekMode(
  377. jumpTarget,
  378. calendarConfig,
  379. existCalendarData
  380. )
  381. } else {
  382. return this.methods(component).__calcDatesForMonthMode(
  383. jumpTarget,
  384. calendarConfig,
  385. existCalendarData
  386. )
  387. }
  388. },
  389. weekModeJump: dateInfo => {
  390. const target = dateInfo || dateUtil.todayFMD()
  391. const existCalendarData = getCalendarData('calendar', component) || {}
  392. const waitRenderData = this.methods(
  393. component
  394. ).__calcDatesWhenSwitchView('week', target)
  395. const { data, config } = waitRenderData || {}
  396. const setSelectDates = this.methods(
  397. component
  398. ).__selectTargetDateWhenJump(target, data.dates, config)
  399. return renderCalendar.call(
  400. component,
  401. {
  402. ...existCalendarData,
  403. ...data,
  404. ...setSelectDates
  405. },
  406. config
  407. )
  408. },
  409. switchView: (view, target) => {
  410. const waitRenderData = this.methods(
  411. component
  412. ).__calcDatesWhenSwitchView(view, target)
  413. const { data, config } = waitRenderData || {}
  414. if (!data) return logger.warn('当前状态不能切换为周视图')
  415. return renderCalendar.call(component, data, config)
  416. }
  417. }
  418. }
  419. }
  420. }