index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. import { Button, Calendar, Dialog, Icon, Image, Popup, Tag, Toast } from 'vant'
  2. import { defineComponent } from 'vue'
  3. import dayjs from 'dayjs'
  4. import styles from './index.module.less'
  5. import IconArrow from '@/common/images/icon_arrow.png'
  6. import IconClock from '@/common/images/icon_clock.png'
  7. import isToday from 'dayjs/plugin/isToday'
  8. dayjs.extend(isToday)
  9. export default defineComponent({
  10. name: 'calendar',
  11. props: {
  12. calendarDate: {
  13. type: Date,
  14. default: () => new Date()
  15. },
  16. // 选中的数据
  17. selectList: {
  18. type: Array,
  19. default: []
  20. },
  21. // 接口数据
  22. list: {
  23. type: Object,
  24. default: {}
  25. },
  26. /**
  27. * 每天选择课程最大数
  28. */
  29. maxDays: {
  30. type: [Number, String],
  31. default: 0
  32. },
  33. /**
  34. * 点击并选中任意日期时触发
  35. */
  36. onSelect: {
  37. type: Function,
  38. default: (date: Date) => {}
  39. },
  40. /**
  41. * 上一月,不能小于当月
  42. */
  43. prevMonth: {
  44. type: Function,
  45. default: (date: Date) => {}
  46. },
  47. /**
  48. * 下一月,暂无限制
  49. */
  50. nextMonth: {
  51. type: Function,
  52. default: (date: Date) => {}
  53. },
  54. /**
  55. * 日期选择结束时触发
  56. */
  57. selectDay: {
  58. type: Function,
  59. default: (obj: any) => {}
  60. },
  61. isSkipHolidays: {
  62. // 是否跳过节假日
  63. type: Boolean,
  64. default: false
  65. }
  66. },
  67. data() {
  68. return {
  69. minDate: new Date(),
  70. maxDate: new Date(),
  71. currentDate: dayjs().add(1, 'day').toDate(), // 当前日历日期
  72. subtitle: '',
  73. show: false,
  74. dayList: [],
  75. selectDays: [] as any
  76. }
  77. },
  78. computed: {
  79. arrowStatus() {
  80. // 上月箭头状态
  81. return !dayjs().add(1, 'day').isBefore(dayjs(this.currentDate), 'month')
  82. },
  83. selectDayTitle() {
  84. // 选中日期标题
  85. return dayjs(this.currentDate).format('YYYY-MM-DD')
  86. },
  87. isPrevDay() {
  88. // 是否可以点击上一天
  89. return dayjs(this.currentDate)
  90. .subtract(1, 'day')
  91. .isBefore(dayjs(this.minDate), 'day')
  92. },
  93. isNextDay() {
  94. // 是否可以点击下一天
  95. return dayjs(this.currentDate)
  96. .add(1, 'day')
  97. .isAfter(dayjs(this.maxDate), 'day')
  98. }
  99. },
  100. mounted() {
  101. // 初始化标题和最大显示日期
  102. this.subtitle = dayjs().add(1, 'day').format('YYYY年MM月')
  103. this.maxDate = dayjs().add(1, 'day').endOf('month').toDate()
  104. this.minDate = dayjs().add(1, 'day').toDate()
  105. // console.log(this.list, "this.list")
  106. // for(const key in this.list) {
  107. // console.log(key, this.list[key])
  108. // let dataList = [] as any
  109. // if (this.list[key] && Array.isArray(this.list[key].courseTime)) {
  110. // dataList = [...this.list[key].courseTime].filter(n =>
  111. // dayjs().isBefore(dayjs(n.startTime))
  112. // )
  113. // }
  114. // this.list[key].courseTime = dataList
  115. // }
  116. // 初始化日历
  117. // console.log(this.list, 323, this.maxDays)
  118. },
  119. methods: {
  120. formatter(date: any) {
  121. const dateStr = dayjs(date.date).format('YYYY-MM-DD')
  122. const dateObj = this.list[dateStr]
  123. // 格式化选择的时间
  124. let courseTime = [] as any
  125. if (dateObj && Array.isArray(dateObj.courseTime)) {
  126. courseTime = [...dateObj.courseTime].filter(n =>
  127. dayjs().isBefore(dayjs(n.startTime))
  128. )
  129. }
  130. date.type = ''
  131. // 判断是否有课程 并且 时间在当前时间之后
  132. if (dateObj && dayjs().subtract(1, 'day').isBefore(dayjs(date.date))) {
  133. // fullCourse当天是否排满 0: 未,1:满 , courseTime 当天没有课程
  134. if (
  135. dateObj.fullCourse ||
  136. !courseTime ||
  137. courseTime?.length <= 0
  138. ) {
  139. date.bottomInfo = '满'
  140. date.className = 'full'
  141. date.type = 'disabled'
  142. }
  143. } else {
  144. date.type = 'disabled'
  145. }
  146. // console.log(date)
  147. if((this.$route.name == 'liveCreate' || this.$route.name == 'groupCreate') && dayjs(date.date).isToday()) {
  148. date.type = 'disabled'
  149. }
  150. // 是否是节假日
  151. if (dateObj && this.isSkipHolidays && dateObj.holiday) {
  152. // date.bottomInfo = '节假日'
  153. date.type = 'disabled'
  154. }
  155. // date.type = date.type === 'selected' ? 'selected' : date.type
  156. // console.log(date.type)
  157. return date
  158. },
  159. onPrevMonth() {
  160. // 上一月
  161. if (this.arrowStatus) return
  162. const tempDate = dayjs(this.currentDate).subtract(1, 'month')
  163. this._monthChange(tempDate)
  164. this.prevMonth && this.prevMonth(this.minDate)
  165. },
  166. onNextMonth() {
  167. // 下一月
  168. const tempDate = dayjs(this.currentDate).add(1, 'month')
  169. this._monthChange(tempDate)
  170. this.nextMonth && this.nextMonth(this.minDate)
  171. },
  172. _monthChange(date: any) {
  173. // 月份改变
  174. // 需要判断是否是当月,需要单独处理最小时间
  175. const currentMinDate = dayjs().add(1, 'day').toDate()
  176. const monthMinDate = date.startOf('month').toDate()
  177. this.minDate = dayjs(currentMinDate).isAfter(monthMinDate)
  178. ? currentMinDate
  179. : monthMinDate
  180. // this.minDate = date.startOf('month').toDate()
  181. this.maxDate = date.endOf('month').toDate()
  182. this.currentDate = date.toDate()
  183. this.$emit('update:calendarDate', date.toDate())
  184. this.subtitle = date.format('YYYY年MM月')
  185. },
  186. onSelectDay(item: any) {
  187. // 选择某个时间段
  188. const index = this.selectDays.findIndex((days: any) => {
  189. return days.startTime === item.startTime
  190. })
  191. if (this.selectDays.length < this.maxDays || index !== -1) {
  192. const index = this.selectDays.findIndex(
  193. (days: any) => days.startTime === item.startTime
  194. )
  195. item.checked = !item.checked
  196. if (index === -1) {
  197. this.selectDays.push({ ...item })
  198. } else {
  199. this.selectDays.splice(index, 1)
  200. }
  201. } else {
  202. Toast('最多选择' + this.maxDays + '个时间段')
  203. }
  204. },
  205. onPrevDay() {
  206. // 获取上一天的数据
  207. const tempDate = dayjs(this.currentDate).subtract(1, 'day')
  208. this._dayChange(tempDate.toDate())
  209. },
  210. onNextDay() {
  211. // 获取下一天的数据
  212. const tempDate = dayjs(this.currentDate).add(1, 'day')
  213. this._dayChange(tempDate.toDate())
  214. },
  215. onDateSelect(date: any) {
  216. // 选择日历上某一个日期
  217. // console.log([...this.selectList])
  218. this.selectDays = [...this.selectList] // 初始化用户选中的值
  219. this._dayChange(date)
  220. this.onSelect && this.onSelect(date)
  221. },
  222. _dayChange(date: Date) {
  223. const dateStr = dayjs(date).format('YYYY-MM-DD')
  224. let dataList = [] as any
  225. if (this.list[dateStr] && Array.isArray(this.list[dateStr].courseTime)) {
  226. dataList = [...this.list[dateStr].courseTime].filter(n =>
  227. dayjs().isBefore(dayjs(n.startTime))
  228. )
  229. }
  230. dataList.forEach((item: any) => {
  231. item.start = dayjs(item.startTime).format('HH:mm')
  232. item.end = dayjs(item.endTime).format('HH:mm')
  233. const isExist = this.selectDays?.some(
  234. (course: any) => course.startTime === item.startTime
  235. )
  236. item.checked = isExist
  237. })
  238. this.dayList = dataList
  239. this.currentDate = date // 更新当前日期
  240. this.$emit('update:calendarDate', date)
  241. this.show = true
  242. }
  243. },
  244. render() {
  245. return (
  246. <>
  247. <Calendar
  248. class={styles.calendar}
  249. showTitle={false}
  250. poppable={false}
  251. showConfirm={false}
  252. showMark={false}
  253. firstDayOfWeek={1}
  254. rowHeight={56}
  255. minDate={this.minDate}
  256. maxDate={this.maxDate}
  257. color="var(--van-primary)"
  258. formatter={this.formatter}
  259. onSelect={this.onDateSelect}
  260. v-slots={{
  261. subtitle: () => (
  262. <div class={styles.subtitle}>
  263. <Icon
  264. name={IconArrow}
  265. size={22}
  266. class={this.arrowStatus && styles.disabled}
  267. onClick={this.onPrevMonth}
  268. />
  269. <span>{this.subtitle}</span>
  270. <Icon
  271. name={IconArrow}
  272. size={22}
  273. class={styles.right}
  274. onClick={this.onNextMonth}
  275. />
  276. </div>
  277. )
  278. // 'bottom-info': (date: any) => <span>{date.type}</span>
  279. }}
  280. />
  281. <Popup show={this.show} class={styles.calenderPopup}>
  282. <div class={styles.popup}>
  283. <div class={styles.title}>
  284. {/* <Button
  285. type="primary"
  286. plain
  287. style={{ border: 0 }}
  288. size="small"
  289. disabled={this.isPrevDay}
  290. onClick={this.onPrevDay}
  291. >
  292. 上一日
  293. </Button> */}
  294. <span>{this.selectDayTitle}</span>
  295. {/* <Button
  296. type="primary"
  297. plain
  298. style={{ border: 0 }}
  299. size="small"
  300. disabled={this.isNextDay}
  301. onClick={this.onNextDay}
  302. >
  303. 下一日
  304. </Button> */}
  305. </div>
  306. <div class={styles.container}>
  307. {this.dayList.map((item: any) => (
  308. <div>
  309. <Tag
  310. round
  311. class={[styles.tag, item.checked ? styles.active : '']}
  312. size="large"
  313. plain
  314. onClick={() => this.onSelectDay(item)}
  315. >
  316. {item.start}~{item.end}
  317. </Tag>
  318. </div>
  319. ))}
  320. {this.dayList.length <= 0 && (
  321. <div class={styles.noDay}>
  322. <Image src={IconClock} class={styles.clock} fit="cover" />
  323. <span>今日已约满</span>
  324. </div>
  325. )}
  326. </div>
  327. <div class={styles.dayBtn}>
  328. <Button
  329. round
  330. plain
  331. block
  332. style={{ marginRight: '10px' }}
  333. onClick={() => {
  334. this.show = false
  335. this.selectDays = []
  336. }}
  337. >
  338. 取消
  339. </Button>
  340. <Button
  341. type="primary"
  342. block
  343. round
  344. disabled={!(this.selectDays.length > 0)}
  345. onClick={() => {
  346. this.selectDay && this.selectDay(this.selectDays)
  347. this.show = false
  348. }}
  349. >
  350. 确认
  351. </Button>
  352. </div>
  353. </div>
  354. </Popup>
  355. </>
  356. )
  357. }
  358. })