vue3 Fullcalendar 实现动态创建、编辑(拖拽)计划-----详细版

前情介绍:vue3 fullcalendar实现日历视图创建事项
考虑到很多人找我要demo代码,但我又不一定能及时回复,所以我决定再详细的列一下我的代码:

<template>
  <ListLayout
    v-loading="loading"
    :has-page-header="false"
    :has-search-panel="false"
    :has-quick-query="false"
    class="plan_management"
  >
  <!-- 这里是自定义头部,切换视图类型和切换日期 -->
    <div class="calendarHeader">
      <div class="header_left">
        <h1>{{ type ==='3' ? '计划列表' : calendarTitle }}</h1>
      </div>
      <div class="header_right">
        <span v-if="type!=='3'&&isShowBack" class="blue-color backToday" @click="getToday()">{{ type==='1'?'返回本月':'返回本周' }}</span>
        <el-select v-model="type" placeholder="视图类型" style="width: 80px" size="small" class="header_select" @change="handleChangeType">
          <el-option label="" value="1" />
          <el-option label="" value="2" />
          <el-option label="" value="3" />
        </el-select>
        <!-- 选择月份的日期框 -->
        <el-date-picker v-if="type === '1'" v-model="showMonth" type="month" size="small" :clearable="false" placeholder="请选择日期" style="margin-left: 10px; vertical-align: middle;" @change="changeDate" />
        <el-button-group v-if="type === '2'" style="margin-left: 10px;">
          <el-button size="small" class="el-icon-arrow-left" @click="getPrev()">上一周</el-button>
          <el-button size="small" @click="getNext()">下一周<i class="el-icon-arrow-right" /></el-button>
        </el-button-group>
        <el-select v-model="planCategoryId" placeholder="计划分类" style="width: 120px" class="header_select" size="small" @change="handleChangePlanId">
          <el-option label="全部" value="" />
          <el-option v-for="item in categoryList" :key="item.id" :label="item.name" :value="item.id" />
        </el-select>
        <div v-if="categoryList.length" class="separator" />
        <el-tooltip content="类目维护" placement="top" effect="light">
          <el-button size="small" class="el-icon-setting setting_btn" @click="handleSetting()" />
        </el-tooltip>
        <el-button v-if="categoryList.length" size="small" type="primary" class="el-icon-plus" @click="handleAddPlan()"> 新增计划</el-button>
      </div>
    </div>
    <!-- 月视图和周视图显示,列视图显示表格形式 -->
    <div v-show="type !== '3'" ref="fullcalendar" class="card" />
    <el-table
      v-show="type === '3'"
      ref="tableRef"
      v-loading="loading"
      :data="infoList"
      fit
      border
      height="auto"
      size="medium"
      class="dark-table base-table format-height-table"
      @header-dragend="drageHeader"
    >
      <el-table-column label="标题" prop="title " :min-width="colWidth.name" show-overflow-tooltip>
        <template #default="{ row }">
          <span class="nowrap blue-color" @click="handleClickList(row)">{{ row.title || '--' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="类型" prop="planCategoryName" :minwidth="colWidth.typeGroup" show-overflow-tooltip>
        <template #default="{ row }">
          <span>{{ row.planCategoryName || '--' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="负责人/协作者" prop="managerId " :min-width="colWidth.name" show-overflow-tooltip>
        <template #default="{ row }">
          <UserTag v-for="(item, index) in row.managerId.split(',')" :key="index" :name="getNameByid(item) || item || '--'" />
        </template>
      </el-table-column>
      <el-table-column label="开始时间" prop="startDate " :minwidth="colWidth.datetime" show-overflow-tooltip>
        <template #default="{ row }">
          <span>{{ row.startDate }} {{ row.startDateMinute }}</span>
        </template>
      </el-table-column>
      <el-table-column label="结束时间" prop="endDate " :minwidth="colWidth.datetime" show-overflow-tooltip>
        <template #default="{ row }">
          <span>{{ row.endDate }} {{ row.endDateMinute }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" :width="colWidth.operation" fixed="right" class-name="fixed-right">
        <template #default="{ row }">
          <span v-if="categoryList.length" class="blue-color" @click="handleEdit(row)">编辑</span>
          <span v-if="getPermissionBtn('CalendarDelete')" class="blue-color" @click="handleDelete(row)">删除</span>
        </template>
      </el-table-column>
    </el-table>
    <!-- 新建编辑日程 -->
    <DrawerAddPlan :drawer="drawerVisiable" :drawer-type="drawerType" :category-list="categoryAllList" :detail-data="detailData" @closeDrawer="closeDrawer" />
    <!-- 类目维护 -->
    <DialogCategory :dialog-show="dialogCategory" :detail-list="categoryAllList" @closeDialog="closeDialogCategory" />
    <!-- 查看计划 -->
    <DialogCalendar :dialog-show="dialogCalendar" :detail-info="detailInfo" :category-json="categoryJSON" @closeDialog="closeDialogCalendar" />
  </ListLayout>
</template>

<script>
import { reactive, toRefs, ref, onMounted, getCurrentInstance } from 'vue'
import ListLayout from '@/components/ListLayout'
import { drageHeader } from '@/utils/formatTable'
import { colWidth } from '@/data/tableStyle'
import { formatDateFilter, formatDateDay, formatDate, formatCalendar, formatYM, getWeekNumber } from '@/utils/formatTime'
import DrawerAddPlan from './components/drawer-add-plan.vue'
import DialogCategory from './components/dialog-category.vue'
import DialogCalendar from './components/dialog-calendar.vue'
import { Calendar } from '@fullcalendar/core'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import listPlugin from '@fullcalendar/list'
import interactionPlugin from '@fullcalendar/interaction'
import { getNameByid, getPermissionBtn } from '@/utils/common'
import UserTag from '@/components/UserTag'
import { getLoginInfo } from '@/utils/auth'
import { documentPlanCategoryList, plandetailList, plandetailId, deletePlanDetail, savePlanDetail } from '@/api/planManagement'

export default {
  name: 'PlanManagement',
  components: { ListLayout, DrawerAddPlan, DialogCategory, DialogCalendar, UserTag },
  setup() {
    const { proxy } = getCurrentInstance()
    const state = reactive({
      calendarTitle: new Date().getFullYear() + '年' + Number(new Date().getMonth() + 1) + '月', // 日历头部显示文字
      dialogVisiable: false,
      showMonth: formatYM(new Date()), // 显示月份
      loading: false,
      isShowBack: false, // 是否显示回到当月或当周
      planCategoryId: '', // 计划分类Id
      type: '1',
      dialogType: '',
      detailInfo: {},
      Tcalendar: null,
      drawerVisiable: false,
      drawerType: '',
      colorJSON: { // 我这里有类别的概念,不同的类别又有不同的颜色
        'green': { title: '#00B578', class: 'green' },
        'red': { title: '#FA5151', class: 'red' },
        'orange': { title: '#FF8F1F', class: 'orange' },
        'yellow': { title: '#FFC300', class: 'yellow' },
        'cyan': { title: '#07B9B9', class: 'cyan' },
        'blue': { title: '#3662EC', class: 'blue' },
        'purple': { title: '#8A38F5', class: 'purple' },
        'magenta': { title: '#EB2F96', class: 'magenta' }
      },
      fullcalendar: ref(),
      detailData: {},
      calendarList: [],
      calendarViewType: {
        1: 'dayGridMonth',
        2: 'timeGridWeek',
        3: 'listMonth'
      },
      nowDate: new Date(),
      dialogCategory: false, // 计划分类弹出窗
      dialogCalendar: false, // 计划详情弹出窗
      infoList: [], // 日历显示的列信息
      categoryJSON: {}, // 计划分类json
      categoryAllList: [], // 全部计划分类
      categoryList: [] // 已启用计划分类
    })
    onMounted(() => {
      initCalendar()
      getPlanCategoryList()
    })
    const initCalendar = () => {
      state.Tcalendar = new Calendar(state.fullcalendar, {
        plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
        initialView: 'dayGridMonth',
        aspectRatio: 2.2,
        locale: 'zh-cn',
        handleWindowResize: true,
        editable: true, // 允许编辑表格
        droppable: true,
        eventDurationEditable: true,
        eventResizableFromStart: true,
        selectable: true, // 允许用户通过单击和拖动来突出显示多个日期或时间段
        firstDay: 1, // 设置一周中显示的第一天是哪天,周日是0,周一是1,类推。
        unselectAuto: true, // 当点击页面日历以外的位置时,是否自动取消当前的选中状态
        unselectCancel: '.el-drawer',
        dayMaxEvents: true,
        // eventLimit: true,
        headerToolbar: false,
        buttonText: {
          today: '回到今天',
          month: '月',
          week: '周',
          list: '列',
          day: '日'
        },
        allDayText: '全天',
        events: state.infoList,
        eventClassNames: function(arg) { // 添加自定义class
          return [arg.event.extendedProps.class]
        },
        eventContent: function(arg) {
          const italicEl = document.createElement('div')
          if (arg.event.extendedProps.startDateMinute && state.type === '1') {
            const childEl = document.createElement('span')
            childEl.innerHTML = arg.event.extendedProps.startDateMinute
            italicEl.append(childEl)
          }
          italicEl.append(arg.event.title)
          italicEl.setAttribute('class', `plan_title ${arg.event.extendedProps.class}`)
          return { domNodes: [italicEl] }
        },
        eventDrop: function(info) {
          // 拖拽停止时触发
          handleDrap(info)
        },
        eventClick: function(info) {
          // 点击查看时触发
          handleClick(info)
        },
        select: function(info) {
          // 视图选择日期触发
          if (getPermissionBtn('CalendarPlanAdd')) {
            handleSelectDate(info)
          }
        },
        eventResize: function(info) {
          handleEventResize(info)
        }
      })
      state.Tcalendar.render()
    }
    // 上一月、周、日
    const getPrev = () => {
      state.Tcalendar.prev()
      state.calendarTitle = state.Tcalendar.view.title
      const nowDate = formatDateFilter(state.calendarTitle)
      // 判断已经是当前周隐藏返回当前周按钮
      if ((getWeekNumber(nowDate) === getWeekNumber(new Date())) && (new Date(nowDate).getFullYear() === new Date().getFullYear())) {
        state.isShowBack = false
      } else {
        state.isShowBack = true
      }
      getCalendarList()
    }
    // 下一月、周、日
    const getNext = () => {
      state.Tcalendar.next()
      state.calendarTitle = state.Tcalendar.view.title
      const nowDate = formatDateFilter(state.calendarTitle)
      // 判断已经是当前周隐藏返回当前周按钮
      if ((getWeekNumber(nowDate) === getWeekNumber(new Date())) && (new Date(nowDate).getFullYear() === new Date().getFullYear())) {
        state.isShowBack = false
      } else {
        state.isShowBack = true
      }
      getCalendarList()
    }
    // 回到今天
    const getToday = () => {
      state.Tcalendar.today()
      state.calendarTitle = state.Tcalendar.view.title
      state.isShowBack = false
      state.showMonth = formatYM(new Date())
      getCalendarList()
    }
    // 计划分类列表
    const getPlanCategoryList = () => {
      state.loading = true
      state.categoryList = []
      state.categoryAllList = []
      state.categoryJSON = {}
      documentPlanCategoryList({ page: '1', limit: '-1' }).then(res => {
        state.loading = false
        if (res) {
          res.data.data.forEach(item => {
            state.categoryJSON[item.id] = { lable: item.name, color: item.color, status: item.status }
            state.categoryAllList.push(item)
            if (item.status) {
              state.categoryList.push(item)
            }
          })
          getCalendarList()
        }
      })
    }
    const handleSetting = () => {
      state.dialogCategory = true
    }
    const getCalendarList = () => {
      const params = {
        planCategoryId: state.planCategoryId,
        startDate: state.type === '3' ? '' : formatDateFilter(state.calendarTitle),
        type: state.type
      }
      state.loading = true
      state.Tcalendar.getEventSources().forEach(item => {
        item.remove()
      })
      plandetailList(params).then(res => {
        state.loading = false
        if (res) {
          state.infoList = res.data.data
          state.infoList.forEach(item => {
            item.class = state.colorJSON[state.categoryJSON[item.planCategoryId]?.color]?.class
            item.start = item.startDateMinute ? item.startDate + ' ' + item.startDateMinute : item.startDate
            if ((item.startDate !== item.endDate) || item.isAllDay) {
              item.end = item.endDateMinute ? formatDate(new Date(item.endDate).getTime()) + ' ' + item.endDateMinute : formatDate(new Date(item.endDate).getTime() + 1000 * 60 * 60 * 24)
            } else {
              item.end = item.endDateMinute ? item.endDate + ' ' + item.endDateMinute : item.endDate
            }
          })
          state.Tcalendar.addEventSource(state.infoList)
        }
      })
    }
    // 点击计划查看
    const handleClick = (info) => {
      const detail = info.event._def
      plandetailId(detail.publicId).then(res => {
        if (res) {
          state.detailInfo = res.data.data
          state.dialogCalendar = true
        }
      })
    }
    // 列视图点击查看
    const handleClickList = (row) => {
      plandetailId(row.id).then(res => {
        if (res) {
          state.detailInfo = res.data.data
          state.dialogCalendar = true
        }
      })
    }
    // 删除
    const handleDelete = (row) => {
      proxy.$confirm('是否确认删除', '删除确认', {
        confirmButtonText: '确认删除',
        cancelButtonText: '取消',
        showCancelButton: true,
        closeOnClickModal: false,
        type: 'warning'
      }).then(() => {
        state.loading = true
        deletePlanDetail(row.id).then(function(res) {
          state.loading = false
          if (res) {
            proxy.$message.success('删除成功!')
            getCalendarList()
          }
        })
      }).catch(() => {})
    }
    // 编辑
    const handleEdit = (row) => {
      state.loading = true
      plandetailId(row.id).then(res => {
        state.loading = false
        if (res) {
          state.detailData = res.data.data
          state.drawerType = 'edit'
          state.drawerVisiable = true
        }
      })
    }
    const closeDialog = () => {
      state.dialogVisiable = false
    }
    const closeDialogCategory = (val) => {
      state.dialogCategory = false
      if (val) {
        getPlanCategoryList()
      }
    }
    const closeDialogCalendar = (val) => {
      state.dialogCalendar = false
      if (val?.isRefresh) {
        getCalendarList()
      }
      if (val?.isEdit) {
        // 编辑计量计划
        state.detailData = val.info
        state.drawerType = 'edit'
        state.drawerVisiable = true
      }
    }
    const closeDrawer = (val) => {
      state.drawerVisiable = false
      if (val) {
        getCalendarList()
      }
    }
    // 切换视图类型
    const handleChangeType = (val) => {
      if (val === '1') {
        state.Tcalendar.changeView('dayGridMonth')
        state.showMonth = formatYM(new Date())
      } else if (val === '2') {
        state.Tcalendar.changeView('timeGridWeek')
      } else {
        state.Tcalendar.changeView('listMonth')
      }
      state.isShowBack = false
      state.calendarTitle = state.Tcalendar.view.title
      getToday()
    }
    // 切换类型
    const handleChangePlanId = () => {
      getCalendarList()
    }
    // 新增计划
    const handleAddPlan = () => {
      state.drawerVisiable = true
      state.drawerType = 'add'
      state.detailData = {
        managerIds: [getLoginInfo()?.accountId],
        fileList: [],
        isAllDay: 0,
        startDate: formatDate(new Date()),
        endDate: formatDate(new Date()),
        startDateMinute: new Date().getHours() < 23 ? new Date().getHours() + 1 + ':00' : '23:00',
        endDateMinute: new Date().getHours() < 22 ? new Date().getHours() + 2 + ':00' : '23:00'
      }
    }
    // 拖拽计划时触发
    const handleDrap = (info) => {
      const params = { ...info.event.extendedProps, id: info.event.id }
      params.startDate = formatCalendar(info.event.start)
      if (info.event.allDay) {
        // 全天
        params.startDateMinute = ''
        params.endDateMinute = ''
        params.isAllDay = 1
        params.endDate = info.event.end ? formatCalendar(new Date(info.event.end).getTime() - 24 * 3600 * 1000) : formatCalendar(info.event.start)
      } else {
        // 非全天
        params.startDateMinute = formatCalendar(info.event.start, 'hour')
        params.endDateMinute = formatCalendar(new Date(info.event.end), 'hour')
        params.endDate = info.event.end ? formatCalendar(new Date(info.event.end)) : formatCalendar(info.event.start)
        params.isAllDay = 0
      }
      state.loading = true
      savePlanDetail(params).then(res => {
        state.loading = false
        if (res) {
          proxy.$message.success('修改成功!')
          getCalendarList()
        }
      })
    }
    // 调整大小时触发
    const handleEventResize = (info) => {
      const params = { ...info.event.extendedProps, id: info.event.id }
      params.startDate = formatCalendar(info.event.start)
      if (info.event.allDay) {
        // 全天
        params.startDateMinute = ''
        params.endDateMinute = ''
        params.isAllDay = 1
        params.endDate = info.event.end ? formatCalendar(new Date(info.event.end).getTime() - 24 * 3600 * 1000) : formatCalendar(info.event.start)
      } else {
        // 非全天
        params.startDateMinute = formatCalendar(info.event.start, 'hour')
        params.endDateMinute = formatCalendar(new Date(info.event.end), 'hour')
        params.endDate = info.event.end ? formatCalendar(new Date(info.event.end)) : formatCalendar(info.event.start)
        params.isAllDay = 0
      }
      state.loading = true
      savePlanDetail(params).then(res => {
        state.loading = false
        if (res) {
          proxy.$message.success('修改成功!')
          getCalendarList()
        }
      })
    }
    // 拖拽触发
    const handleSelectDate = (info) => {
      if (info.view.type === 'timeGridWeek') {
        // 周视图
        if (info.allDay) {
          state.detailData = {
            startDate: formatCalendar(info.startStr),
            endDate: formatCalendar(new Date(info.endStr).getTime() - 24 * 3600 * 1000),
            managerIds: [getLoginInfo()?.accountId],
            fileList: [],
            startDateMinute: '',
            endDateMinute: '',
            isAllDay: 1
          }
        } else {
          state.detailData = {
            startDate: formatCalendar(info.startStr),
            endDate: formatCalendar(info.endStr),
            managerIds: [getLoginInfo()?.accountId],
            fileList: [],
            startDateMinute: formatCalendar(info.startStr, 'hour'),
            endDateMinute: formatCalendar(info.endStr, 'hour'),
            isAllDay: 0
          }
        }
      } else {
        // 月视图
        if (info.startStr === formatDate(new Date(info.endStr).getTime() - 24 * 3600 * 1000)) {
          // 只选择一天,默认非全天
          state.detailData = {
            startDate: info.startStr,
            endDate: formatDate(new Date(info.endStr).getTime() - 24 * 3600 * 1000),
            managerIds: [getLoginInfo()?.accountId],
            fileList: [],
            startDateMinute: new Date().getHours() < 23 ? new Date().getHours() + 1 + ':00' : '23:00',
            endDateMinute: new Date().getHours() < 22 ? new Date().getHours() + 2 + ':00' : '23:00',
            isAllDay: 0
          }
        } else {
          // 跨天,默认全天
          state.detailData = {
            startDate: info.startStr,
            endDate: formatDate(new Date(info.endStr).getTime() - 24 * 3600 * 1000),
            managerIds: [getLoginInfo()?.accountId],
            fileList: [],
            startDateMinute: '',
            endDateMinute: '',
            isAllDay: 1
          }
        }
      }
      state.drawerVisiable = true
      state.drawerType = 'add'
    }
    // 切换月份和日期
    const changeDate = (date) => {
      state.Tcalendar.gotoDate(formatDate(date))
      // 判断不是当前月份,显示返回当前月
      if (date.getMonth() !== new Date().getMonth() || (new Date().getFullYear() !== new Date(date).getFullYear())) {
        state.isShowBack = true
      } else {
        state.isShowBack = false
      }
      state.calendarTitle = state.Tcalendar.view.title
      getCalendarList()
    }
    return {
      ...toRefs(state),
      formatDateFilter,
      changeDate,
      getPrev,
      getPermissionBtn,
      handleDrap,
      handleAddPlan,
      handleClickList,
      handleDelete,
      handleEdit,
      getNameByid,
      handleEventResize,
      handleChangePlanId,
      getNext,
      getToday,
      closeDrawer,
      getCalendarList,
      handleSetting,
      handleChangeType,
      closeDialog,
      handleClick,
      closeDialogCategory,
      closeDialogCalendar,
      handleSelectDate,
      formatDateDay,
      formatDate,
      drageHeader,
      colWidth
    }
  }
}
</script>
<style lang="scss" scoped>
.calendarHeader {
  margin: 0 0 20px 0;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  .header_select {
    margin: 0 0 0 10px;
    display: inline-block;
    vertical-align: middle;
  }
  .separator {
    display: inline-block;
    position: relative;
    margin: 0 12px;
    &:after {
      content: '';
      position: absolute;
      top: -16px;
      left: 0;
      height: 24px;
      width: 1px;
      background: #DCDFE6;
    }
  }
}
h1 {
  font-size: 20px;
  font-weight: 500;
  line-height: 32px;
  margin: 0 0 0 0;
  text-align: left;
  vertical-align: middle;
  display: inline-block;
  color: #303133;
}
// .el-button-group {
//   vertical-align: top;
// }

</style>
<style lang="scss" scoped>
@import 'fullcalendar.scss';

</style>

以上是主要页面的代码部分,其中样式在fullcalendar.scss这里,内容是:

.plan_management {
  .fc-col-header {
    height: 32px;
    line-height: 32px;
    background-color: #f5f7fa;
  }
  .fc-theme-standard .fc-scrollgrid {
    border: 0 !important;
  }
  .fc-daygrid-day-top {
    line-height: 18px;
    flex-direction: row !important;
  }
  .fc .fc-button-primary {
    background-color: $background-color;
    color: #606266;
    border-color: #DCDFE6;
  }
  .fc .fc-button-primary:not(:disabled).fc-button-active, .fc .fc-button-primary:not(:disabled):active {
    color: #fff;
    background-color: $tes-primary;
    border-color: $tes-primary;
  }
  .fc .fc-button-primary:not(:disabled).fc-button-active:focus, .fc .fc-button-primary:not(:disabled):active:focus, .fc .fc-button-primary:focus {
    box-shadow: none;
  }
  .fc-theme-standard td, .fc-theme-standard .fc-scrollgrid {
    border: 1px solid #ebeef5;
  }
  .fc-theme-standard td:first-child {
    border-left: 0;
    border-right: 0;
  }
  .fc-theme-standard th {
    border-bottom: 1px solid #ebeef5;
    border-right: 0;
    border-left: 0;
  }
  .fc .fc-button-primary:hover {
    color: $tes-primary;
    background-color: #fff;
    border-color: #DCDFE6;
  }
  .fc .fc-button-primary:disabled {
    color: #fff;
    background-color: $tes-primary;
    border-color: $tes-primary;
  }
  .fc-event-title {
    line-height: 16px;
  }
  .fc .fc-highlight {
    background: $tes-primary2;
  }
  // 周视图
  .fc .fc-timegrid-body {
    .fc-timegrid-slots {
      table tbody tr:nth-of-type(odd) td {
        border-bottom-color: transparent;
      }
    }
  }
  // 列视图
  .fc-theme-standard .fc-list-day-cushion {
    line-height: 20px;
    background-color: #f5f7fa;
  }
  .fc .fc-list-table td {
    line-height: 18px;
  }
  .fc-theme-standard .fc-list {
    border: 1px solid #ebeef5;
  }
  .fc .fc-daygrid-day-number {
    margin: 8px 0 0 8px;
    color: #303133;
    font-weight: 500;
  }
  .fc-scrollgrid-sync-inner {
    color: #303133;
  }
  .fc .fc-daygrid-day.fc-day-today {
    background-color: $tes-primary2;
    .fc-daygrid-day-number {
      background-color: $tes-primary;
      color: #fff;
      border-radius: 4px;
    }
  }
  .fc .fc-col-header-cell-cushion {
    padding: 0;
    user-select: none;
  }
  .fc-timegrid-slot-label-cushion {
    user-select: none;
  }
  .fc-event-title {
    line-height: 20px;
  }
  .fc .fc-daygrid-event {
    margin: 0 0 4px 0;
  }
  .fc-theme-standard .fc-popover-header {
    background-color: #fff;
  }
  .fc .fc-popover {
    z-index: 20;
  }
  .fc .fc-popover-header {
    padding: 20px 20px 14px 20px;
    border-radius: 10px 10px 0 0;
  }
  .fc .fc-popover-title {
    color: $tes-primary;
    font-size: 20px;
  }
  .fc .fc-more-popover .fc-popover-body {
    padding: 0 20px 16px 20px;
    border-radius: 0 0 10px 10px;
  }
  .fc-theme-standard th {
    font-weight: 400;
  }
  .fc-theme-standard .fc-popover {
    border-radius: 4px;
  }
  .fc-daygrid-day-bottom {
    color: $tes-primary;
  }
  .fc .fc-timegrid-col.fc-day-today {
    background-color: $tes-primary2;
  }
  .fc .fc-timegrid-slot {
    height: 48px;
  }
  .fc .fc-timegrid-divider {
    padding: 0;
  }
  .fc .fc-daygrid-body-natural .fc-daygrid-day-events {
    margin-bottom: 3px;
  }
  .fc-event {
    position: relative;
    line-height: 20px;
    padding: 0 0 0 8px;
    &:after {
      content: '';
      width: 4px;
      height: 100%;
      border-radius: 2px 0 0 2px;
      position: absolute;
      top: 0;
      left: 0;
    }
    .plan_title {
      color: #303133;
      max-width: 98%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    span {
      margin-right: 6px;
    }
  }
  
  .green.fc-event {
    &:after {
      background-color: #00B578;
    }
    span {
      color: #00B578;
    }
  }
  .red.fc-event {
    &:after {
      background-color: #FA5151;
    }
    span {
      color: #FA5151;
    }
  }
  .orange.fc-event {
    &:after {
      background-color: #FF8F1F;
    }
    span {
      color: #FF8F1F;
    }
  }
  .yellow.fc-event {
    &:after {
      background-color: #FFC300;
    }
    span {
      color: #FFC300;
    }
  }
  .cyan.fc-event {
    &:after {
      background-color: #07B9B9;
    }
    span {
      color: #07B9B9;
    }
  }
  .blue.fc-event {
    &:after {
      background-color: #3662EC;
    }
    span {
      color: #3662EC;
    }
  }
  .purple.fc-event {
    &:after {
      background-color: #8A38F5;
    }
    span {
      color: #8A38F5;
    }
  }
  .magenta.fc-event {
    &:after {
      background-color: #EB2F96;
    }
    span {
      color: #EB2F96;
    }
  }
  .fc-h-event {
    border-color: transparent;
  }
  .fc-direction-ltr .fc-daygrid-event.fc-event-end, .fc-direction-rtl .fc-daygrid-event.fc-event-start {
    margin-left: 4px;
    margin-right: 4px;
  }
  
  .fc-event.fc-event-draggable {
    overflow: hidden;
  }
  
  .fc-event.fc-daygrid-event {
    transition: all 0.1s;
  }
  
  .fc-event.fc-daygrid-event.green {
    background-color: rgba(0, 181, 120, 0.1);
    &:hover {
      background-color: rgba(0, 181, 120, 0.2);
    }
  }
  .fc-event.fc-daygrid-event.red {
    background-color: rgba(250, 81, 81, 0.1);
    &:hover {
      background-color: rgba(250, 81, 81, 0.2);
    }
  }
  .fc-event.fc-daygrid-event.orange {
    background-color: rgba(255, 143, 31, 0.1);
    &:hover {
      background-color: rgba(255, 143, 31, 0.2);
    }
  }
  .fc-event.fc-daygrid-event.yellow {
    background-color: rgba(255, 195, 0, 0.1);
    &:hover {
      background-color: rgba(255, 195, 0, 0.2);
    }
  }
  .fc-event.fc-daygrid-event.cyan {
    background-color: rgba(7, 185, 185, 0.1);
    &:hover {
      background-color: rgba(7, 185, 185, 0.2);
    }
  }
  .fc-event.fc-daygrid-event.blue {
    background-color: rgba(54, 98, 236, 0.1);
    &:hover {
      background-color: rgba(54, 98, 236, 0.2);
    }
  }
  .fc-event.fc-daygrid-event.purple {
    background-color: rgba(138, 56, 245, 0.1);
    &:hover {
      background-color: rgba(138, 56, 245, 0.2);
    }
  }
  .fc-event.fc-event-draggable.magenta {
    background-color: rgba(235, 47, 150, 0.1);
    &:hover {
      background-color: rgba(235, 47, 150, 0.2);
    }
  }
  .fc-timegrid-event {
    font-size: 14px;
  }
  .fc-event.fc-timegrid-event {
    background-color: #fff;
    border-radius: 0px 6px 6px 0px;
    box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2);
    padding: 7px 7px 7px 12px;
    height: 100%;
  }
  .fc-v-event {
    border: 0;
  }  
}

以上为这块儿的主要部分,其中新增,删除,编辑的组件不算复杂,都是系统里面普通的组件,没什么特别的地方!

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值