开源fullcalendar6.1.15得简单入门使用

996 阅读4分钟

1、实现简单维护日程事件,以及显示农历,显示节假日,一切简单实现功能,没有做的很完美。开发效果图如下: 1722492721970.png 1722492798831.png

2、Fullcalendar6.1.15得资料地址

  1. 查阅一些CSDN等资料,都是早期版本,一些API都已经不一样了,使用了最新6.1.15
  2. 官网地址Demos | FullCalendar
  3. GitHub - fullcalendar/fullcalendar: Full-sized drag & drop event calendar in JavaScript
  4. Vue3参考地址GitHub - fullcalendar/fullcalendar-vue: The official Vue 3 component for FullCalendar
  5. 建议看官网就可以,有问题直接debugger找Api

3、前端使用Vue3,Vben2.8,Antd3+,WindCss

  1. 引入: pnpm install @fullcalendar/vue3 @fullcalendar/core @fullcalendar/daygrid
  2. 引入农历,pnpm install js-calendar-converter; 资料地址js-calendar-converter - npm (npmjs.com)
  3. 长话短说,短话不说,直接看代码
<template>
  <div id="fullCalendar222">
    <div class="dotGroup">
      <span>
        <i class="dayDot"></i>
        值班
      </span>
      <span>
        <i class="shareDot"></i>
        休息
      </span>
    </div>
    <div class="btnAdd">
      <span>{{ oneDateDetail }}</span>
      <a-button
        type="primary"
        class="addSch"
        :disabled="addEventBtn"
        @click="openModal(true, { startDate: selectedStartDate, endDate: selectedEndDate })"
        >新建日程</a-button
      >
    </div>
    <FullCalendar ref="fullCalendarRef" :options="calendarOptions" class="demo-app-calendar" />
    <AddEventModal
      @register="registerModal"
      @success="handleAddSuccess"
      @updates="handlerUpdateSuccess"
      @deletes="handlerDeleteSuccess"
  /></div>
</template>
<script lang="ts" setup>
  import { ref, onMounted } from 'vue';
  import FullCalendar from '@fullcalendar/vue3';
  import dayGridPlugin from '@fullcalendar/daygrid';
  import timeGridPlugin from '@fullcalendar/timegrid';
  import interactionPlugin from '@fullcalendar/interaction';
  import zhCnLocale from '@fullcalendar/core/locales/zh-cn';
  import { getBaseWorkDutyListApi, getBaseWorkDutyOneApi } from '/@/api/workDuty';
  import dayjs from 'dayjs';
  import { useModal } from '/@/components/Modal';
  import AddEventModal from './components/addEventModal.vue';
  import calendar from 'js-calendar-converter';

  const [registerModal, { openModal }] = useModal();
  const selectedStartDate = ref('');
  const selectedEndDate = ref('');
  const addEventBtn = ref(true);
  let fullCalendarRef = ref<any>({});
  let calendarEvents = <any>[];
  const oneDateDetail = ref('');

  //下个月,上个月渲染
  async function getCalendarEvents(info, successCallback, failureCallback) {
    const { data } = await getBaseWorkDutyListApi({
      startDateFrom: dayjs(info.start).format('YYYY-MM-DD'),
      startDateTo: dayjs(info.end).format('YYYY-MM-DD'),
    });
    calendarEvents = [];
    data.forEach((item) => {
      calendarEvents.push(packageEventinfo(item));
    });
    successCallback(calendarEvents);
  }
  async function handleEventClick(info) {
    //日程点击事件
    const { data } = await getBaseWorkDutyOneApi({ id: info.event.id });
    data.endDate =  dayjs(data.endDate).subtract(1).format('YYYY-MM-DD');
    openModal(true, data);
  }
  function handleDateClick(info) {
    //日期方格点击事件
    // console.log(arg);
  }
  function handleDateSelect(startDate, endDate, allDay, jsEvent, view) {
    //选中日期事件
    // console.log(startDate.startStr);
    selectedStartDate.value = startDate.startStr;
    selectedEndDate.value = dayjs(startDate.end).subtract(1).format('YYYY-MM-DD');
    addEventBtn.value = false;
    if (selectedStartDate.value === selectedEndDate.value) {
      const nowDate = dayjs(selectedStartDate.value);
      debugger
      let _dateF = calendar.solar2lunar(nowDate.year(), nowDate.month()+1, nowDate.date());
      oneDateDetail.value =
        _dateF.cYear +
        '-' +
        _dateF.cMonth +
        '-' +
        _dateF.cDay +
        '  ' +
        _dateF.IMonthCn +
        '-' +
        _dateF.IDayCn;
    }else{
       oneDateDetail.value ='';
    }
  }
  function handleDateUnSelect(view, jsEvent) {
    //取消选中日程事件
    selectedStartDate.value = '';
    selectedEndDate.value = '';
    addEventBtn.value = true;
  }
  /**日程创建成功回调 */
  function handleAddSuccess(item) {
    // console.log(addInfo);
    let calendarApi = fullCalendarRef.value.getApi();
    calendarApi.addEvent(packageEventinfo(item));
  }
  function handlerUpdateSuccess(item) {
    let calendarApi = fullCalendarRef.value.getApi();
    const now = calendarApi.getEventById(item.id);
    now.remove();
    calendarApi.addEvent(packageEventinfo(item));
    // calendarApi.refetchEvents();
  }
  function handlerDeleteSuccess(item) {
    let calendarApi = fullCalendarRef.value.getApi();
    const now = calendarApi.getEventById(item.id);
    now.remove();
    // calendarApi.refetchEvents();
  }

  function packageEventinfo(item) {
    let obj = {
      soureData: item,
      id: item.id,
      title: item.remark,
      start: item.startDate,
      end: item.endDate,
      allDay: true,
      // display: 'background',
      textColor: 'black',
      backgroundColor: item.hasHoliday ? '#FF0000' : '#00CD00',
    };
    return obj;
  }
  const calendarOptions = {
    plugins: [
      // 加载插件,V5采用插件模块方式加入
      dayGridPlugin,
      timeGridPlugin,
      interactionPlugin, // needed for dateClick
    ],
    themeSystem: 'Cerulean',
    height: 'auto', //日历高度 auto自适应 parent父级别容器 数值表示固定
    aspectRatio: 1.6, // 日历格的宽高比
    width: 600,
    fixedWeekCount: false, //true显示1个月6周,false按照当前月周显示
    headerToolbar: {
      // 头部toolba
      left: 'dayGridMonth,today,prev,next',
      center: 'title',
      right: '',
    },
    buttonText: {
      today: '今天',
      month: '月',
      week: '周',
      day: '天',
      list: '列表',
    },
    handleWindowResize: true, //随浏览器窗口变化
    initialView: 'dayGridMonth', // 初始化插件显示
    unselectAuto: false,
    selectable: true,
    views: {
      dayGridMonth: {
        //转农历
        dayCellContent(item) {
          let mark = sessionStorage.getItem('joinholiday');
          let _date = new Date(item.date).toLocaleDateString().split('/');
          let _dateF = calendar.solar2lunar(_date[0], _date[1], _date[2]);
          if (item.dayNumberText == mark + '日') {
            return {
              html: `<h3 id='selectedHolidy'><label>${_dateF.cDay}</label></h3><h3><span>${
                _dateF.IDayCn === '初一' ? _dateF.IMonthCn : _dateF.IDayCn
              }</span></h3>`,
            };
          } else
            return {
              html: `<h3><label>${_dateF.cDay}</label></h3><h3><span>${
                _dateF.IDayCn === '初一' ? _dateF.IMonthCn : _dateF.IDayCn
              }</span></h3>`,
            };
        },
      },
    },
    select: handleDateSelect,
    unselect: handleDateUnSelect,
    dateClick: handleDateClick, //日期方格点击事件
    eventClick: handleEventClick, //日程点击事件
    locale: zhCnLocale,
    weekMode: 'fixed',
    weekNumbers: false,
    nextDayThreshold: '01:00:00',
    events: getCalendarEvents,
  };
  onMounted(async () => {
    //  getFcList();
  });
</script>
<style lang="less" scoped>
  #fullCalendar222 {
    position: relative;
    padding: 10px;
    // height: 100%;
    .btnAdd {
      position: absolute;
      right: 20px;
      top: 20px;
      .addSch {
        height: 28px;
        line-height: 28px;
        padding: 0 10px;
      }
    }
    .dotGroup {
      position: absolute;
      left: 250px;
      top: 23px;
      display: flex;
      align-items: center;
      span {
        margin-right: 20px;
        display: flex;
        align-items: center;
        i {
          display: inline-block;
          width: 6px;
          height: 6px;
          border-radius: 50%;
          margin-right: 8px;
        }
        .dayDot {
          background: #00cd00;
        }
        .shareDot {
          background: #ff0000;
        }
      }
    }
    .fc .fc-toolbar.fc-header-toolbar .fc-center > div {
      display: flex;
      align-items: center;
    }
  }
</style>
  1. 细节说明
    1. fullCalenDar得选中日期区间,结尾日期endDate是多一天得,比如7月25-到8月1号,endDate值:08-02。使用过程需要注意;
    2. 假期来源于后端数据提供
  2. 每年得节假日如何获取 参考这边博客,感谢大大。调用免费API查询全年工作日、周末、法定节假日、节假日调休补班数据 - huanzi-qch - 博客园 (cnblogs.com)
    1. 废话不说,直接上代码,照抄。
@Slf4j
@Component
@AllArgsConstructor
public class HolidayTimer {
    private BaseWorkDutyService workDutyService;

    /**
     * 发送get请求
     */
    private String get(String url) {
        StringBuilder inputLine = new StringBuilder();
        String read;
        try {
            HttpURLConnection urlConnection = (HttpURLConnection)new URL(url).openConnection();
            urlConnection.setReadTimeout(50 * 1000);
            urlConnection.setConnectTimeout(50 * 1000);
            urlConnection.setRequestProperty("Charset", "UTF-8");
            urlConnection.setRequestProperty("User-Agent",
                "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36)");
            BufferedReader in =
                new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8));
            while ((read = in.readLine()) != null) {
                inputLine.append(read);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return inputLine.toString();
    }

    @Scheduled(cron = "0 0 20 12 12 ?")
    public void handlerHoliday() throws JsonProcessingException {
        LocalDate localDate = LocalDate.now();
        LocalDate nextYear = localDate.plusYears(1);
        String response = get("https://timor.tech/api/holiday/year/" + nextYear.getYear() + "/");
        Map holidayMap = ObjectMapperUtil.instanceDefault().readValue(response, Map.class);
        Integer code = (Integer)holidayMap.get("code");
        if (code != null && !code.equals(0)) {
            log.error("查询下一年度的假期错误,接口返回失败");
            return;
        }
        LinkedHashMap holidayList = (LinkedHashMap)holidayMap.get("holiday");
        List<BaseWorkDutyModel> saveModels = new ArrayList<>();
        holidayList.forEach((key, value) -> {
            BaseWorkDutyModel holidayVo = new BaseWorkDutyModel();
            Map value1 = (Map)value;
            holidayVo.setYear(nextYear.getYear());
            String dateTime = value1.get("date").toString();
            holidayVo.setStartDate(LocalDate.parse(dateTime));
            holidayVo.setEndDate(LocalDate.parse(dateTime));
            String name = value1.get("name").toString();
            boolean holiday = Boolean.valueOf(value1.get("holiday").toString());
            if (holiday) {
                holidayVo.setHasHoliday(true);
                holidayVo.setRemark(name);
            } else {
                holidayVo.setHasHoliday(false);
                holidayVo.setRemark(name);
            }
            saveModels.add(holidayVo);
        });
        // saveModels按照selectDate升序排序
        List<BaseWorkDutyModel> sortModels = saveModels.stream()
            .sorted(Comparator.comparing(BaseWorkDutyModel::getStartDate)).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(sortModels)) {
            log.info("已经保存{}年共{}条假期数据数据", nextYear.getYear(), sortModels.size());
            workDutyService.saveAndRedis(nextYear.getYear(), sortModels);
        }
    }
}
  1. 其他得业务各位朋友自行补充,暂时先做到这够用了。