index.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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. // 初始化日历
  106. // console.log(this.list, 323, this.maxDays)
  107. },
  108. methods: {
  109. formatter(date: any) {
  110. const dateStr = dayjs(date.date).format('YYYY-MM-DD')
  111. const dateObj = this.list[dateStr]
  112. date.type = ''
  113. // 判断是否有课程 并且 时间在当前时间之后
  114. if (dateObj && dayjs().subtract(1, 'day').isBefore(dayjs(date.date))) {
  115. // fullCourse当天是否排满 0: 未,1:满 , courseTime 当天没有课程
  116. if (
  117. dateObj.fullCourse ||
  118. !dateObj?.courseTime ||
  119. dateObj?.courseTime?.length <= 0
  120. ) {
  121. date.bottomInfo = '满'
  122. date.className = 'full'
  123. date.type = 'disabled'
  124. }
  125. } else {
  126. date.type = 'disabled'
  127. }
  128. console.log(date)
  129. if(this.$route.name == 'liveCreate' && dayjs(date.date).isToday()) {
  130. date.type = 'disabled'
  131. }
  132. // 是否是节假日
  133. if (dateObj && this.isSkipHolidays && dateObj.holiday) {
  134. // date.bottomInfo = '节假日'
  135. date.type = 'disabled'
  136. }
  137. // date.type = date.type === 'selected' ? 'selected' : date.type
  138. // console.log(date.type)
  139. return date
  140. },
  141. onPrevMonth() {
  142. // 上一月
  143. if (this.arrowStatus) return
  144. const tempDate = dayjs(this.currentDate).subtract(1, 'month')
  145. this._monthChange(tempDate)
  146. this.prevMonth && this.prevMonth(this.minDate)
  147. },
  148. onNextMonth() {
  149. // 下一月
  150. const tempDate = dayjs(this.currentDate).add(1, 'month')
  151. this._monthChange(tempDate)
  152. this.nextMonth && this.nextMonth(this.minDate)
  153. },
  154. _monthChange(date: any) {
  155. // 月份改变
  156. // 需要判断是否是当月,需要单独处理最小时间
  157. const currentMinDate = dayjs().add(1, 'day').toDate()
  158. const monthMinDate = date.startOf('month').toDate()
  159. this.minDate = dayjs(currentMinDate).isAfter(monthMinDate)
  160. ? currentMinDate
  161. : monthMinDate
  162. // this.minDate = date.startOf('month').toDate()
  163. this.maxDate = date.endOf('month').toDate()
  164. this.currentDate = date.toDate()
  165. this.$emit('update:calendarDate', date.toDate())
  166. this.subtitle = date.format('YYYY年MM月')
  167. },
  168. onSelectDay(item: any) {
  169. // 选择某个时间段
  170. const index = this.selectDays.findIndex((days: any) => {
  171. return days.startTime === item.startTime
  172. })
  173. if (this.selectDays.length < this.maxDays || index !== -1) {
  174. const index = this.selectDays.findIndex(
  175. (days: any) => days.startTime === item.startTime
  176. )
  177. item.checked = !item.checked
  178. if (index === -1) {
  179. this.selectDays.push({ ...item })
  180. } else {
  181. this.selectDays.splice(index, 1)
  182. }
  183. } else {
  184. Toast('最多选择' + this.maxDays + '个时间段')
  185. }
  186. },
  187. onPrevDay() {
  188. // 获取上一天的数据
  189. const tempDate = dayjs(this.currentDate).subtract(1, 'day')
  190. this._dayChange(tempDate.toDate())
  191. },
  192. onNextDay() {
  193. // 获取下一天的数据
  194. const tempDate = dayjs(this.currentDate).add(1, 'day')
  195. this._dayChange(tempDate.toDate())
  196. },
  197. onDateSelect(date: any) {
  198. // 选择日历上某一个日期
  199. // console.log([...this.selectList])
  200. this.selectDays = [...this.selectList] // 初始化用户选中的值
  201. this._dayChange(date)
  202. this.onSelect && this.onSelect(date)
  203. },
  204. _dayChange(date: Date) {
  205. const dateStr = dayjs(date).format('YYYY-MM-DD')
  206. let dataList = [] as any
  207. if (this.list[dateStr] && Array.isArray(this.list[dateStr].courseTime)) {
  208. dataList = [...this.list[dateStr].courseTime].filter(n =>
  209. dayjs().isBefore(dayjs(n.startTime))
  210. )
  211. }
  212. dataList.forEach((item: any) => {
  213. item.start = dayjs(item.startTime).format('HH:mm')
  214. item.end = dayjs(item.endTime).format('HH:mm')
  215. const isExist = this.selectDays?.some(
  216. (course: any) => course.startTime === item.startTime
  217. )
  218. item.checked = isExist
  219. })
  220. this.dayList = dataList
  221. this.currentDate = date // 更新当前日期
  222. this.$emit('update:calendarDate', date)
  223. this.show = true
  224. }
  225. },
  226. render() {
  227. return (
  228. <>
  229. <Calendar
  230. class={styles.calendar}
  231. showTitle={false}
  232. poppable={false}
  233. showConfirm={false}
  234. showMark={false}
  235. firstDayOfWeek={1}
  236. rowHeight={56}
  237. minDate={this.minDate}
  238. maxDate={this.maxDate}
  239. color="var(--van-primary)"
  240. formatter={this.formatter}
  241. onSelect={this.onDateSelect}
  242. v-slots={{
  243. subtitle: () => (
  244. <div class={styles.subtitle}>
  245. <Icon
  246. name={IconArrow}
  247. size={22}
  248. class={this.arrowStatus && styles.disabled}
  249. onClick={this.onPrevMonth}
  250. />
  251. <span>{this.subtitle}</span>
  252. <Icon
  253. name={IconArrow}
  254. size={22}
  255. class={styles.right}
  256. onClick={this.onNextMonth}
  257. />
  258. </div>
  259. )
  260. // 'bottom-info': (date: any) => <span>{date.type}</span>
  261. }}
  262. />
  263. <Popup show={this.show} class={styles.calenderPopup}>
  264. <div class={styles.popup}>
  265. <div class={styles.title}>
  266. {/* <Button
  267. type="primary"
  268. plain
  269. style={{ border: 0 }}
  270. size="small"
  271. disabled={this.isPrevDay}
  272. onClick={this.onPrevDay}
  273. >
  274. 上一日
  275. </Button> */}
  276. <span>{this.selectDayTitle}</span>
  277. {/* <Button
  278. type="primary"
  279. plain
  280. style={{ border: 0 }}
  281. size="small"
  282. disabled={this.isNextDay}
  283. onClick={this.onNextDay}
  284. >
  285. 下一日
  286. </Button> */}
  287. </div>
  288. <div class={styles.container}>
  289. {this.dayList.map((item: any) => (
  290. <div>
  291. <Tag
  292. round
  293. class={[styles.tag, item.checked ? styles.active : '']}
  294. size="large"
  295. plain
  296. onClick={() => this.onSelectDay(item)}
  297. >
  298. {item.start}~{item.end}
  299. </Tag>
  300. </div>
  301. ))}
  302. {this.dayList.length <= 0 && (
  303. <div class={styles.noDay}>
  304. <Image src={IconClock} class={styles.clock} fit="cover" />
  305. <span>今日已约满</span>
  306. </div>
  307. )}
  308. </div>
  309. <div class={styles.dayBtn}>
  310. <Button
  311. round
  312. plain
  313. block
  314. style={{ marginRight: '10px' }}
  315. onClick={() => {
  316. this.show = false
  317. this.selectDays = []
  318. }}
  319. >
  320. 取消
  321. </Button>
  322. <Button
  323. type="primary"
  324. block
  325. round
  326. disabled={!(this.selectDays.length > 0)}
  327. onClick={() => {
  328. this.selectDay && this.selectDay(this.selectDays)
  329. this.show = false
  330. }}
  331. >
  332. 确认
  333. </Button>
  334. </div>
  335. </div>
  336. </Popup>
  337. </>
  338. )
  339. }
  340. })