Fullcalendar+vue3 实现日程表

实现效果图

掘金文章链接 此处贴不上大的gif图片 跳转链接

框架:vue3+FullcalendaV6版本 官方地址

插件安装
    npm i @fullcalendar/core @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/list @fullcalendar/interaction
其他工具依赖 dayjs
    npm i dayjs
插件引入
  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 dayjs from 'dayjs';
完整代码(直接复制就能看到效果)
<template>
  <div class="container">
    <a-card class="general-card">
      <div class="top-button">
        <a-space>
          <a-typography-title :heading="6">
            {{ currentData }}
          </a-typography-title>
          <a-space>
            <a-button
              @click="
                Tcalendar.prev();
                dayTime();
              "
              ><icon-left
            /></a-button>
            <a-button
              @click="
                Tcalendar.next();
                dayTime();
              "
            >
              <icon-right
            /></a-button>
            <a-button
              type="primary"
              @click="
                Tcalendar.today();
                dayTime();
              "
              >今天</a-button
            >
          </a-space>
        </a-space>
        <a-radio-group v-model="type" type="button" @change="changeType">
          <a-radio value="dayGridMonth"></a-radio>
          <a-radio value="timeGridWeek"></a-radio>
          <a-radio value="timeGridDay"></a-radio>
          <a-radio value="listWeek"></a-radio>
        </a-radio-group>
      </div>
      <div ref="fullcalendar" class="card"> </div>
    </a-card>
    <!-- 详情抽屉 -->
    <a-drawer
      :width="480"
      :visible="visible"
      @ok="handleOk"
      @cancel="visible = false"
      title="面试详情"
    >
      <template #title> </template>
      <div
        >You can customize modal body text by the current situation. This modal
        will be closed immediately once you press the OK button.
      </div>
    </a-drawer>
  </div>
</template>

<script setup lang="ts">
  import { ref, nextTick, onMounted } from '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 dayjs from 'dayjs';

  const state = {
    infoList: [
      {
        id: '1',
        title: '第一个任务12312312312312312',
        name: '小李',
        start: '2024-04-01 13:00:00',
        end: '2024-04-01 13:30:00',
        class: 'tag_1',
        job: '产品经理',
        hr: '唐老鸭',
      },
      {
        id: '2',
        title: '第一个任务12312312312312312',
        name: '小李',
        start: '2024-04-01 13:30:00',
        end: '2024-04-01 14:00:00',
        class: 'tag_1',
        job: '产品经理',
        hr: '唐老鸭',
      },
    ],
    Tcalendar: ref(),
  };
  const fullcalendar = ref();
  const Tcalendar = ref();
  const type = ref('dayGridMonth');
  const currentData = ref();
  const visible = ref(false);

  const initCalendar = () => {
    Tcalendar.value = new Calendar(fullcalendar.value, {
      plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
      initialView: type.value,
      aspectRatio: 2.2,
      locale: 'zh-cn',
      handleWindowResize: true,
      //   loading: loading //控制表格加载
      editable: false, // 允许编辑表格
      droppable: false, //允许从外部拖拽进入日历
      eventDurationEditable: false, //控制时间段是否可以拖动
      eventResizableFromStart: false, //控制事件是否可以拖动
      selectable: false, // 允许用户通过单击和拖动来突出显示多个日期或时间段
      firstDay: 1, // 设置一周中显示的第一天是哪天,周日是0,周一是1,类推。
      unselectAuto: true, // 当点击页面日历以外的位置时,是否自动取消当前的选中状态
      dayMaxEvents: true, //在dayGrid视图中,给定日期内的最大事件数
      headerToolbar: false, // 关闭默认日历头部,采取自定义的方式切换日历视图
      allDaySlot: false,
      nowIndicator: true,
      eventMaxStack: 2,
      events: state.infoList, //主要数据
      slotMinTime: '09:00:00', //时间最大范围
      slotMaxTime: '21:00:00', //时间最小范围
      slotDuration: '00:15:00', //时间间段
      slotLabelFormat: {
        hour: '2-digit',
        minute: '2-digit',
        omitZeroMinute: false,
        meridiem: 'short',
      },
      eventClassNames: function (arg) {
        // 添加自定义class
        return [arg.event.extendedProps.class];
      },
      eventContent: function (arg) {
        // 日历上event显示的样式
        const italicEl = document.createElement('div');
        // 列表才显示
        if (type.value === 'listWeek') {
          // 标题
          const nameEl = document.createElement('h4');
          nameEl.setAttribute('class', `h4`);
          nameEl.innerHTML = arg.event.extendedProps.name;
          italicEl.append(nameEl);
          // 岗位
          const text1El = document.createElement('p');
          text1El.innerHTML = arg.event.extendedProps.job;
          italicEl.append(text1El);
          // 面试官
          const text2El = document.createElement('p');
          text2El.innerHTML = '面试官:' + arg.event.extendedProps.job;
          italicEl.append(text2El);
        } else {
          // 标题
          const titleEl = document.createElement('div');
          titleEl.setAttribute('class', `plan_title`);
          const nameEl = document.createElement('h5');
          nameEl.innerHTML = arg.event.extendedProps.name;
          titleEl.append(nameEl);
          // 时间
          const timeEl = document.createElement('span');
          timeEl.innerHTML =
            dayjs(arg.event.start).format('HH:mm') +
            '-' +
            dayjs(arg.event.end).format('HH:mm');
          titleEl.append(timeEl);
          italicEl.append(titleEl);
        }
        italicEl.setAttribute('class', `plan_card`);
        return { domNodes: [italicEl] };
      },
      noEventsContent: function () {
        const noEl = document.createElement('div');
        noEl.innerHTML = '暂无日程安排,请安排相关日程';
        return { domNodes: [noEl] };
      },
      // 点击查看时触发
      eventClick: function (info) {
        handleClick(info);
      },
      // 视图选择日期触发
      //   select: function (info) {
      //   handleSelectDate(info);
      //   },
      //   }
      // 拖拽event大小时触发
      //   eventResize: function (info) {
      //    handleEventResize(info);
      //   },
      // 拖拽停止时触发
      // eventDrop: function(info) {
      //   handleDrap(info)
      // },
    });
    Tcalendar.value.render();
  };

  //   切换类型
  const changeType = (type: any) => {
    Tcalendar.value.changeView(type);
    dayTime();
  };

  const dayTime = () => {
    if (type.value === 'dayGridMonth') {
      currentData.value = dayjs(Tcalendar.value.getDate()).format('YYYY年MM月');
    } else if (type.value === 'timeGridWeek' || type.value === 'listWeek') {
      currentData.value =
        dayjs(Tcalendar.value.getDate()).format('YYYY年MM月DD日') +
        ' - ' +
        dayjs(Tcalendar.value.getDate()).add(6, 'day').format('DD日');
    } else if (type.value === 'timeGridDay') {
      currentData.value = dayjs(Tcalendar.value.getDate()).format(
        'YYYY年MM月DD日'
      );
    }
  };

  const handleClick = (info) => {
    visible.value = true;
  };
  const handleOk = () => {};
  onMounted(() => {
    nextTick(() => {
      initCalendar();
      dayTime();
    });
  });
</script>

<style lang="less">
  .card {
    width: 100%;
    height: 600px;
    margin-top: 20px;
  }
  .top-button {
    display: flex;
    justify-content: space-between;
  }
  .fc-col-header-cell {
    height: 26px;
    line-height: 26px;
    background-color: var(--color-neutral-2);
  }
  .fc-v-event {
    border: none;
    box-shadow: 0 4px 10px rgb(var(--gray-2)) !important;
  }
  .fc-event {
    cursor: pointer;
  }
  .tag_1 {
    background-color: rgb(var(--danger-1));
    border-left: 3px solid rgb(var(--danger-6));
    padding-left: 4px;
    .fc-daygrid-event-dot {
      display: none;
    }
    .fc-event-time {
      color: rgb(var(--danger-6));
    }

    .fc-event-title {
      color: var(--color-text-1);
      font-weight: 400;
    }
  }
  .tag_2 {
    background-color: rgb(var(--success-1));
    border-left: 3px solid rgb(var(--success-6));
    padding-left: 4px;
    .fc-daygrid-event-dot {
      display: none;
    }
    .fc-event-time {
      color: rgb(var(--success-6));
    }
    .fc-event-title {
      color: var(--color-text-1);
      font-weight: 400;
    }
  }
  .tag_3 {
    background-color: rgb(var(--warning-1));
    border-left: 3px solid rgb(var(--warning-6));
    padding-left: 4px;
    .fc-daygrid-event-dot {
      display: none;
    }
    .fc-event-time {
      color: rgb(var(--warning-6));
    }
    .fc-event-title {
      color: var(--color-text-1);
      font-weight: 400;
    }
  }
  .tag_4 {
    background-color: rgb(var(--primary-1));
    border-left: 3px solid rgb(var(--primary-6));
    padding-left: 4px;
    .fc-daygrid-event-dot {
      display: none;
    }
    .fc-event-time {
      color: rgb(var(--primary-6));
    }
    .fc-event-title {
      color: var(--color-text-1);
      font-weight: 400;
    }
  }
  :root {
    --fc-border-color: rgb(229, 230, 235) !important;
    --fc-today-bg-color: rgb(232, 243, 255) !important;
    --fc-more-link-bg-color: rgb(232, 243, 255);
  }
  .fc .fc-daygrid-day-top {
    flex-direction: column;
  }
  .fc-list-event-dot {
    display: none !important;
  }
  .fc-timegrid-event-harness > .fc-timegrid-event {
    position: relative;
  }
  .plan_card {
    width: 100%;
    color: var(--color-text-2);
    .plan_title {
      display: flex;
      width: 100%;
      justify-content: space-between;
      color: var(--color-text-1);
      line-height: 22px;
      padding-right: 4px;
      span {
        color: var(--color-text-2);
      }
    }
    p {
      line-height: 22px;
      font-size: 12px;
    }
  }
  .h4 {
    color: var(--color-text-2);
    line-height: 24px;
  }
</style>

功能待完善 保留了拖拽事件触发 可以支持拖拽日期 拖拽添加日期事件

大家根据自身需求做出对应改动 👏欢迎各位同学自行讨论

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值