自定义工作日历fullCalendar组件

发布于:2024-12-06 ⋅ 阅读:(98) ⋅ 点赞:(0)

在这里插入图片描述

<template>
  <div style="height: 100%">
    <el-row>
      <el-col :span="12">
        <el-select
          v-model="year"
          size="mini"
          @change="change_year"
        >
          <el-option
            v-for="item in yearOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <el-select
          v-model="month"
          size="mini"
          style="margin-right: 20px"
          @change="change_mon"
        >
          <el-option
            v-for="item in monthOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
      </el-col>
    </el-row>
    <el-row style="height: 100%">
      <el-col :span="24">
        <el-row style="width: 100%">
          <full-calendar
            ref="fullCalendar"
            style="width: 100%"
            :options="calendarOptions"
            :event-content="renderEventContent"
          />
        </el-row>
      </el-col>
    </el-row>
    <!-- 对话框 -->
    <el-dialog
      title="切换状态"
      :visible.sync="dialogVisible"
    >
      <p>您确定要将选中的日期切换为 {{ selectedStatus }} 吗?</p>
      <span
        slot="footer"
        class="dialog-footer"
      >
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button
          type="primary"
          @click="confirmChange"
          >确 定</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import bootstrapPlugin from '@fullcalendar/bootstrap'
import { formatDate } from '../../../api/basic/util'

import { list, save } from '../../../api/basic/tamapsexample'

export default {
  components: {
    FullCalendar
  },
  data() {
    return {
      year: new Date().getFullYear(), // 默认年份
      month: new Date().getMonth() + 1, // 默认月份
      yearOptions: [],
      monthOptions: [],
      selectedEvent: null, // 当前选中的事件
      selectedDate: null, // 选中的日期
      calendarOptions: {
        dateClick: this.handleDateClick,
        selectable: true, // 启用选择功能
        locale: 'zh-cn',
        plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin, bootstrapPlugin],
        firstDay: '1',
        headerToolbar: true,
        slotLabelFormat: {
          hour: '2-digit',
          minute: '2-digit',
          meridiem: false,
          hour12: false
        },
        eventTimeFormat: {
          hour: 'numeric',
          minute: '2-digit',
          hour12: false
        },
        weekends: true,
        events: [],
        height: 700,
        editable: false,
        selectable: true, // 启用选择日期功能
        navLinks: false,
        handleWindowResize: true,
        initialDate: new Date(),
        initialView: 'dayGridMonth',
        fixedWeekCount: false
      },
      dialogVisible: false, // 对话框是否可见
      selectedStatus: '', // 选中的状态
      calendarData: []
    }
  },
  mounted() {
    this.initYearMonthOptions()
    this.getCalendarData()
  },
  methods: {
    initYearMonthOptions() {
      const now = new Date()
      for (let i = now.getFullYear() - 5; i <= now.getFullYear() + 5; i++) {
        this.yearOptions.push({
          value: i,
          label: `${i}`
        })
      }
      for (let j = 1; j <= 12; j++) {
        this.monthOptions.push({
          value: j,
          label: `${j}`
        })
      }
    },
    async getCalendarData() {
      // 从API获取日历数据
      const response = await list({ year: this.year, month: this.month })
      this.calendarData = response.data.list

      const rawEvents = this.generateFakeData(this.year, this.month, this.calendarData)

      const events = []
      rawEvents.forEach((event) => {
        const { title, start, classNames } = event
        events.push({
          title,
          start,
          allDay: true,
          classNames
        })
      })

      console.log('Events:', events)

      this.calendarOptions.events = events

      const formatData = formatDate(new Date(this.year, this.month - 1, 1), 'yyyy-MM-dd')
      console.log('formatData:', formatData)

      this.$refs.fullCalendar.getApi().gotoDate(formatData)
    },

    generateFakeData(year, month, calendarData) {
      const rawEvents = []
      console.log('rawEvents', rawEvents)

      const daysInMonth = new Date(year, month, 0).getDate() // 获取当月天数

      const calendarMap = new Map(calendarData.map((event) => [event.date, event]))

      for (let day = 1; day <= daysInMonth; day++) {
        const format = 'yyyy-MM-dd'
        const date = new Date(year, month - 1, day)
        // const formattedDate = date.toISOString().split('T')[0]
        const formattedDate = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(
          date.getDate()
        ).padStart(2, '0')}`

        console.log('eventForDay:', formattedDate, 'date:', formatDate(date, format))

        const eventForDay = calendarMap.get(formattedDate)

        let status
        let statusClass

        if (eventForDay) {
          status = eventForDay.status === '0' ? '休' : '班'
          statusClass = eventForDay.status === '0' ? 'restday' : 'workday'

          console.log('eventForDay:', formattedDate, 'status:', status, 'date:', formatDate(date, format))

          rawEvents.push({
            title: status,
            start: date,
            classNames: [statusClass]
          })
        } else {
          const dayOfWeek = date.getDay()
          const isWorkDay = dayOfWeek >= 1 && dayOfWeek <= 5
          status = isWorkDay ? '班' : '休'
          statusClass = isWorkDay ? 'workday' : 'restday'

          const format = 'yyyy-MM-dd'
          console.log('No event for day:', formattedDate, 'status:', status, 'date:', formatDate(date, format))

          rawEvents.push({
            title: status,
            start: date,
            classNames: [statusClass]
          })
        }
      }

      console.log('rawEvents', rawEvents)

      return rawEvents
    },
    change_year() {
      this.getCalendarData()
    },
    change_mon() {
      this.getCalendarData()
    },
    handleDateClick(arg) {
      this.selectedDate = arg.date
      console.log(arg.date)
      const format = 'yyyy-MM-dd'
      const formattedDate = formatDate(this.selectedDate, format)
      const eventForDay = this.calendarData.find((event) => event.date === formattedDate)
      const status = eventForDay
        ? eventForDay.status === '0'
          ? '休'
          : '班'
        : arg.date.getDay() >= 1 && arg.date.getDay() <= 5
        ? '班'
        : '休'
      this.showDialog(status)
    },
    renderEventContent(eventInfo) {
      return {
        html: `<div class="${eventInfo.event.classNames.join(' ')}">
             <span class="event-title">${eventInfo.event.title}</span>
           </div>`
      }
    },
    showDialog(status) {
      const date = this.selectedDate // 获取当前选中的日期

      console.log(status)

      if (date) {
        this.selectedStatus = status === '班' ? '休' : '班' // 设置选中的状态
        this.dialogVisible = true // 显示对话框
      } else {
        this.$message.warning('请先选择一个日期!')
      }
    },
    async confirmChange() {
      const date = this.selectedDate // 获取选中的日期
      const format = 'yyyy-MM-dd'
      console.log('nowdate', formatDate(date, format))
      if (date) {
        const events = this.calendarOptions.events
        const eventIndex = events.findIndex((event) => {
          return event.start.toDateString() === date.toDateString()
        })

        if (eventIndex !== -1) {
          const currentEvent = events[eventIndex]
          if (currentEvent.title === '班') {
            currentEvent.title = '休'
            currentEvent.classNames = ['restday']
          } else {
            currentEvent.title = '班'
            currentEvent.classNames = ['workday']
          }
        } else {
          events.push({
            title: '班',
            start: date,
            allDay: true,
            classNames: ['workday']
          })
        }
        this.calendarOptions.events = [...events]

        const saveData = {
          date: formatDate(date, 'yyyy-MM-dd'),
          year: String(date.getFullYear()),
          month: String(date.getMonth() + 1),
          status: this.selectedStatus === '班' ? 1 : 0
        }

        try {
          await save(saveData)
          this.$message.success('保存成功!')
          // this.getCalendarData()
        } catch (error) {
          this.$message.error('保存失败,请重试!') // 提示保存失败
        }

        this.dialogVisible = false // 关闭对话框
      }
    }
  }
}
</script>

<style>
.workday {
  background-color: blue; /* 班的背景色为蓝色 /
color: white; / 字体颜色为白色 /
padding: 5px; / 内边距 /
border-radius: 5px; / 圆角 /
}
.restday {
background-color: green; / 休的背景色为绿色 /
color: white; / 字体颜色为白色 /
padding: 5px; / 内边距 /
border-radius: 5px; / 圆角 */
}

.event-title {
  font-weight: bold;
}
</style>


网站公告

今日签到

点亮在社区的每一天
去签到