| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- <template>
- <div class="l-flex--col c-week-calendar">
- <div class="l-flex__none l-flex c-week-calendar__header">
- <div class="l-flex__none o-time header" />
- <div class="l-flex__fill l-flex">
- <div
- v-for="item in headers"
- :key="item.info"
- class="l-flex__auto u-readonly"
- >
- <div class="c-week-calendar__week">{{ item.day }}</div>
- <div class="c-week-calendar__info">{{ item.info }}</div>
- </div>
- </div>
- </div>
- <div class="l-flex__auto u-overflow-y--auto">
- <div class="l-flex">
- <div
- v-once
- class="l-flex__none l-flex--col c-week-calendar__time"
- >
- <div
- v-for="(val, hour) in 24"
- :key="hour"
- class="l-flex__none o-time"
- >
- {{ hour.toString().padStart(2, '0') }}:00
- </div>
- </div>
- <div class="l-flex__fill l-flex c-week-calendar__right">
- <div
- v-for="day in week"
- :key="day.value"
- class="l-flex__fill l-flex--col c-week-calendar__day"
- :class="day.status"
- >
- <template v-for="item in day.items">
- <div
- v-if="item.event"
- :key="item.key"
- class="l-flex__none c-week-calendar__item"
- :class="item.status"
- :style="item.style"
- @click="onClick(item.event)"
- >
- <event-item
- :item="item"
- :editable="editable"
- @remove="$listeners.remove"
- />
- </div>
- <div
- v-if="!item.event"
- :key="item.key"
- class="l-flex__none c-week-calendar__item"
- :class="item.status"
- :style="item.style"
- @dblclick="onAdd(item)"
- />
- </template>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import { EventFreq } from '@/constant'
- import {
- ONE_DAY,
- toDate,
- toDateStr,
- toTimeStr,
- pickMin,
- pickMax,
- isOverDay,
- isHitOverDayTime,
- correctEndTime
- } from '@/utils/event'
- import EventItem from './EventItemWeek'
- const Week = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
- export default {
- name: 'ScheduleCalendarWeek',
- components: {
- EventItem
- },
- props: {
- editable: {
- type: [Boolean, String],
- default: false
- },
- weeks: {
- type: Array,
- default: null
- },
- cursor: {
- type: Number,
- default: 0
- }
- },
- computed: {
- currWeek () {
- return this.weeks[this.cursor]
- },
- headers () {
- return this.currWeek.map(({ value }, i) => {
- return { day: value, info: Week[i] }
- })
- },
- week () {
- return this.currWeek.map(this.transform)
- }
- },
- methods: {
- transform (day) {
- return { ...day, items: this.createItems(day) }
- },
- createItems ({ date, events }) {
- const maxDate = new Date(date.getTime() + ONE_DAY)
- const week = date.getDay()
- const arr = []
- for (let i = 0; i < events.length; i++) {
- const eventProxy = events[i]
- switch (eventProxy.origin.freq) {
- case EventFreq.ONCE:
- arr.push(this.createOnceItem(eventProxy, date, maxDate))
- break
- case EventFreq.WEEKLY:
- if (isHitOverDayTime(eventProxy.origin, date)) {
- arr.push(this.createRemainderWeeklyItem(eventProxy, date, maxDate))
- }
- if (eventProxy.origin.byDay.includes(week)) {
- arr.push(this.createWeeklyItem(eventProxy, date, maxDate))
- }
- break
- default:
- break
- }
- }
- const items = []
- let minDate = toDate(date)
- if (arr.length) {
- arr.sort((a, b) => a.minDate - b.minDate)
- for (let i = 0; i < arr.length; i++) {
- if (arr[i].minDate > minDate) {
- this.createPlaceholdeItem(items, minDate, arr[i].minDate)
- }
- items.push(arr[i])
- minDate = arr[i].maxDate
- }
- }
- if (this.editable && minDate < maxDate) {
- this.createPlaceholdeItem(items, minDate, maxDate)
- }
- return items
- },
- createPlaceholdeItem (items, minDate, maxDate) {
- const now = new Date()
- if (maxDate > now && minDate < now) {
- items.push(this.createItem(null, minDate, now))
- minDate = now
- }
- items.push(this.createItem(null, minDate, maxDate))
- },
- createItem (eventProxy, minDate, maxDate) {
- const duration = (maxDate - minDate) / 1000
- return {
- key: Math.random().toString(16).slice(2),
- event: eventProxy,
- status: eventProxy
- ? duration <= 7200 ? 'hold hidden' : 'hold'
- : maxDate > Date.now()
- ? this.editable ? 'free' : 'empty'
- : 'disabled',
- placement: duration <= 7200 ? 'right-start' : 'right-end',
- minDate,
- maxDate,
- startTime: toTimeStr(minDate),
- endTime: toTimeStr(maxDate),
- duration,
- style: { height: `${duration * 0.02}px` }
- }
- },
- createOnceItem (eventProxy, minDate, maxDate) {
- const { start, until } = eventProxy.origin
- minDate = pickMax(toDate(start), minDate)
- maxDate = pickMin(toDate(until), maxDate)
- return this.createItem(eventProxy, minDate, maxDate)
- },
- createRemainderWeeklyItem (eventProxy, minDate, maxDate) {
- const { until, endTime } = eventProxy.origin
- maxDate = pickMin(toDate(`${toDateStr(minDate)} ${correctEndTime(endTime)}`), pickMin(toDate(until), maxDate))
- return this.createItem(eventProxy, minDate, maxDate)
- },
- createWeeklyItem (eventProxy, minDate, maxDate) {
- const { start, until, startTime, endTime } = eventProxy.origin
- minDate = pickMax(toDate(`${toDateStr(minDate)} ${startTime}`), pickMax(toDate(start), minDate))
- maxDate = pickMin(toDate(`${toDateStr(minDate, isOverDay(eventProxy.origin) ? 1 : 0)} ${correctEndTime(endTime)}`), pickMin(toDate(until), maxDate))
- return this.createItem(eventProxy, minDate, maxDate)
- },
- onClick (event) {
- this.$emit('edit', event)
- },
- onAdd ({ minDate, maxDate }) {
- this.$emit('add', {
- freq: EventFreq.ONCE,
- start: `${toDateStr(minDate)} ${toTimeStr(minDate)}`,
- until: `${toDateStr(maxDate)} 00:00:00`
- })
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .c-week-calendar {
- position: relative;
- color: $black;
- font-size: 16px;
- border: 1px solid $info;
- &__header {
- padding: 10px 0;
- text-align: center;
- border-bottom: 1px solid $info;
- }
- &__week {
- font-size: 20px;
- font-weight: bold;
- }
- &__info {
- color: $info;
- }
- &__time {
- align-self: flex-start;
- border-right: 1px solid $info;
- }
- &__right {
- background-size: 100% 72px;
- background-image: linear-gradient(
- to bottom,
- transparent 0,
- transparent 71px,
- $info 71px
- );
- }
- &__day {
- user-select: none;
- &.enabled {
- .c-week-calendar__item.disabled {
- background-color: rgba($gray, 0.5);
- cursor: not-allowed;
- }
- }
- &.invalid {
- background-color: lighten($gray--light, 4%);
- cursor: not-allowed;
- }
- & + & {
- border-left: 1px solid $info;
- }
- }
- .c-week-calendar__item {
- &.hidden {
- overflow: hidden;
- }
- &.hold {
- margin: 0 6px;
- color: #fff;
- text-align: center;
- border-radius: 4px;
- background-color: $blue;
- transition: background-color 0.4s;
- }
- &.hold,
- &.free {
- cursor: pointer;
- }
- &.free:hover {
- margin: 0 6px;
- border-radius: 4px;
- background-color: rgba($blue, 0.5);
- }
- }
- }
- .o-time {
- display: inline-block;
- width: 70px;
- height: 72px;
- text-align: center;
- &.header {
- height: auto;
- }
- }
- </style>
|