time-range.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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-11 13:56:32
  7. * */
  8. import { renderCalendar } from '../render'
  9. import {
  10. logger,
  11. dateUtil,
  12. getCalendarConfig,
  13. getCalendarData
  14. } from '../utils/index'
  15. function pusheNextMonthDateArea(
  16. dateInfo = {},
  17. startTimestamp,
  18. endTimestamp,
  19. selectedDates = []
  20. ) {
  21. let tempOfSelectedDate = [...selectedDates]
  22. const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month)
  23. let datesLen = dates.length
  24. for (let i = 0; i < datesLen; i++) {
  25. const date = dates[i]
  26. const timeStamp = dateUtil.getTimeStamp(date)
  27. if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) {
  28. tempOfSelectedDate.push({
  29. ...date,
  30. choosed: true
  31. })
  32. }
  33. if (i === datesLen - 1 && timeStamp < endTimestamp) {
  34. pusheNextMonthDateArea(
  35. dateUtil.getNextMonthInfo(date),
  36. startTimestamp,
  37. endTimestamp,
  38. tempOfSelectedDate
  39. )
  40. }
  41. }
  42. return tempOfSelectedDate
  43. }
  44. function pushPrevMonthDateArea(
  45. dateInfo = {},
  46. startTimestamp,
  47. endTimestamp,
  48. selectedDates = []
  49. ) {
  50. let tempOfSelectedDate = [...selectedDates]
  51. const dates = dateUtil.sortDatesByTime(
  52. dateUtil.calcDates(dateInfo.year, dateInfo.month),
  53. 'desc'
  54. )
  55. let datesLen = dates.length
  56. let firstDate = dateUtil.getTimeStamp(dates[0])
  57. for (let i = 0; i < datesLen; i++) {
  58. const date = dates[i]
  59. const timeStamp = dateUtil.getTimeStamp(date)
  60. if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) {
  61. tempOfSelectedDate.push({
  62. ...date,
  63. choosed: true
  64. })
  65. }
  66. if (i === datesLen - 1 && firstDate > startTimestamp) {
  67. pushPrevMonthDateArea(
  68. dateUtil.getPrevMonthInfo(date),
  69. startTimestamp,
  70. endTimestamp,
  71. tempOfSelectedDate
  72. )
  73. }
  74. }
  75. return tempOfSelectedDate
  76. }
  77. /**
  78. * 当设置日期区域非当前时保存其他月份的日期至已选日期数组
  79. * @param {object} info
  80. */
  81. function calcDateWhenNotInOneMonth(info) {
  82. const { firstDate, lastDate, startTimestamp, endTimestamp } = info
  83. let { selectedDate } = info
  84. if (dateUtil.getTimeStamp(firstDate) > startTimestamp) {
  85. selectedDate = pushPrevMonthDateArea(
  86. dateUtil.getPrevMonthInfo(firstDate),
  87. startTimestamp,
  88. endTimestamp,
  89. selectedDate
  90. )
  91. }
  92. if (dateUtil.getTimeStamp(lastDate) < endTimestamp) {
  93. selectedDate = pusheNextMonthDateArea(
  94. dateUtil.getNextMonthInfo(lastDate),
  95. startTimestamp,
  96. endTimestamp,
  97. selectedDate
  98. )
  99. }
  100. return [...selectedDate]
  101. }
  102. /**
  103. * 指定日期区域转时间戳
  104. * @param {array} timearea 时间区域
  105. */
  106. export function convertTimeRangeToTimestamp(timearea = []) {
  107. const start = timearea[0].split('-')
  108. const end = timearea[1].split('-')
  109. if (start.length !== 3 || end.length !== 3) {
  110. logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]')
  111. return {}
  112. }
  113. const startTimestamp = dateUtil
  114. .newDate(start[0], start[1], start[2])
  115. .getTime()
  116. const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime()
  117. return {
  118. start,
  119. end,
  120. startTimestamp,
  121. endTimestamp
  122. }
  123. }
  124. /**
  125. * 校验时间区域是否合法
  126. * @param {array} dateArea 时间区域
  127. */
  128. function validateTimeRange(dateArea) {
  129. const {
  130. start,
  131. end,
  132. startTimestamp,
  133. endTimestamp
  134. } = convertTimeRangeToTimestamp(dateArea)
  135. if (!start || !end) return
  136. const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1])
  137. const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1])
  138. if (start[2] > startMonthDays || start[2] < 1) {
  139. logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内')
  140. return false
  141. } else if (start[1] > 12 || start[1] < 1) {
  142. logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
  143. return false
  144. } else if (end[2] > endMonthDays || end[2] < 1) {
  145. logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内')
  146. return false
  147. } else if (end[1] > 12 || end[1] < 1) {
  148. logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
  149. return false
  150. } else if (startTimestamp > endTimestamp) {
  151. logger.warn('enableArea()参数最小日期大于了最大日期')
  152. return false
  153. } else {
  154. return true
  155. }
  156. }
  157. export default () => {
  158. return {
  159. name: 'timeRange',
  160. beforeRender(calendarData = {}, calendarConfig = {}) {
  161. const {
  162. chooseAreaTimestamp = [],
  163. dates = [],
  164. selectedDates = []
  165. } = calendarData
  166. let __dates = dates
  167. let __selectedDates = selectedDates
  168. const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp
  169. if (chooseAreaTimestamp.length === 2) {
  170. __selectedDates = []
  171. __dates = dates.map(d => {
  172. const date = { ...d }
  173. const dateTimeStamp = dateUtil.getTimeStamp(date)
  174. if (
  175. dateTimeStamp >= startDateTimestamp &&
  176. endDateTimestamp >= dateTimeStamp
  177. ) {
  178. date.choosed = true
  179. __selectedDates.push(date)
  180. } else {
  181. date.choosed = false
  182. __selectedDates = __selectedDates.filter(
  183. item => dateUtil.getTimeStamp(item) !== dateTimeStamp
  184. )
  185. }
  186. return date
  187. })
  188. const monthOfStartDate = new Date(startDateTimestamp).getMonth()
  189. const monthOfEndDate = new Date(endDateTimestamp).getMonth()
  190. if (monthOfStartDate !== monthOfEndDate) {
  191. __selectedDates = calcDateWhenNotInOneMonth({
  192. firstDate: __dates[0],
  193. lastDate: __dates[__dates.length - 1],
  194. startTimestamp: startDateTimestamp,
  195. endTimestamp: endDateTimestamp,
  196. selectedDate: __selectedDates
  197. })
  198. }
  199. }
  200. return {
  201. calendarData: {
  202. ...calendarData,
  203. dates: __dates,
  204. selectedDates: dateUtil.sortDatesByTime(
  205. dateUtil.uniqueArrayByDate(__selectedDates)
  206. )
  207. },
  208. calendarConfig
  209. }
  210. },
  211. onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
  212. if (!calendarConfig.chooseAreaMode) {
  213. return {
  214. calendarData,
  215. calendarConfig
  216. }
  217. }
  218. let {
  219. tempChooseAreaTimestamp = [],
  220. chooseAreaTimestamp: existChooseAreaTimestamp = [],
  221. selectedDates = [],
  222. dates = []
  223. } = calendarData
  224. const timestamp = dateUtil.getTimeStamp(tapedDate)
  225. let __dates = [...dates]
  226. let __selectedDates = [...selectedDates]
  227. if (
  228. tempChooseAreaTimestamp.length === 2 ||
  229. existChooseAreaTimestamp.length === 2
  230. ) {
  231. tempChooseAreaTimestamp = [tapedDate]
  232. __selectedDates = []
  233. __dates.forEach(d => (d.choosed = false))
  234. } else if (tempChooseAreaTimestamp.length === 1) {
  235. const preChoosedDate = tempChooseAreaTimestamp[0]
  236. const preTimestamp = dateUtil.getTimeStamp(preChoosedDate)
  237. if (preTimestamp <= timestamp) {
  238. tempChooseAreaTimestamp.push(tapedDate)
  239. } else if (preTimestamp > timestamp) {
  240. tempChooseAreaTimestamp.unshift(tapedDate)
  241. }
  242. } else {
  243. tempChooseAreaTimestamp = [tapedDate]
  244. }
  245. let chooseAreaTimestamp = []
  246. if (tempChooseAreaTimestamp.length === 2) {
  247. const [startDate, endDate] = tempChooseAreaTimestamp
  248. const startDateTimestamp = dateUtil.getTimeStamp(startDate)
  249. const endDateTimestamp = dateUtil.getTimeStamp(endDate)
  250. chooseAreaTimestamp = [startDateTimestamp, endDateTimestamp]
  251. }
  252. return {
  253. calendarData: {
  254. ...calendarData,
  255. chooseAreaTimestamp,
  256. tempChooseAreaTimestamp,
  257. dates: __dates,
  258. selectedDates: __selectedDates
  259. },
  260. calendarConfig: {
  261. ...calendarConfig,
  262. multi: true
  263. }
  264. }
  265. },
  266. methods(component) {
  267. return {
  268. /**
  269. * 设置连续日期选择区域
  270. * @param {array} dateArea 区域开始结束日期数组
  271. */
  272. chooseDateArea: (dateArea = []) => {
  273. if (dateArea.length === 1) {
  274. dateArea = dateArea.concat(dateArea)
  275. }
  276. if (dateArea.length !== 2) return
  277. const isRight = validateTimeRange(dateArea)
  278. if (!isRight) return
  279. const config = getCalendarConfig(component) || {}
  280. const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp(
  281. dateArea
  282. )
  283. const existCalendarData = getCalendarData('calendar', component)
  284. return renderCalendar.call(
  285. component,
  286. {
  287. ...existCalendarData,
  288. chooseAreaTimestamp: [startTimestamp, endTimestamp]
  289. },
  290. {
  291. ...config,
  292. multi: true,
  293. chooseAreaMode: true
  294. }
  295. )
  296. }
  297. }
  298. }
  299. }
  300. }