Fullcalendar V5踩坑 (周视图篇)


<template>
  <div class="M_container">
    <div class="top-title">
      <i class="el-icon-arrow-left" @click="getPrev"></i>
      第{{week}}周({{title}})
      <i class="el-icon-arrow-right" @click="getNext"></i>
    </div>
    <FullCalendar
      ref="fullCalendar"
      class="fullcalendar week"
      :options="calendarOptions"
      id="calendar1"
    >
    <!-- <template v-slot:dayHeaderContent='arg'>
      <div class="top"  @click="changeToDay(arg.date)">
        {{arg|formateHeaderContent}}
        <span v-if="weekEventNumObj[arg.dow]>1" class="moreTips">更多日程</span>
       </div>
    </template> -->
    </FullCalendar>
  </div>
</template>
 
<script>
import { GetWeekList } from "@/api/schedule/index";
import FullCalendar from "@fullcalendar/vue";
import dayGridPlugin from "@fullcalendar/daygrid";
import timeGridPlugin from "@fullcalendar/timegrid";
import interactionPlugin from "@fullcalendar/interaction";
import { getWeek, y2k } from "@/utils/schedule/formate";
import {slotLabelContent,eventContetFun,changeStartEnd,eventMouseEnter} from "@/utils/schedule/fullcalendarHandler" ;
import elementResizeDetectorMaker from "element-resize-detector";
export default {
  name: "byWeek",
  components: {
    FullCalendar,
  },
  filters: {
    formateHeaderContent: (arg) => {
      let weekDay = arg.dow;
      let weekObj = {0: "星期天",1: "星期一",2: "星期二",3: "星期三",4: "星期四", 5: "星期五", 6: "星期六",};
      let weekName = weekObj[weekDay];
      weekName += "( " + arg.text.replace("/", "-") + " )";
      return weekName;
    },
  },
  props: ["type"],
  data() {
    return {
      title: "",
      startDate: "",
      endDate: "",
      week: "",
      weekEventNumObj: { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 },
      calendarOptions: {
        // 引入的插件,比如fullcalendar/daygrid,fullcalendar/timegrid引入后才可显示月,周,日
        plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
        initialView: "timeGridWeek", // 默认为那个视图(月:dayGridMonth,周:timeGridWeek,日:timeGridDay)
        events: [],
        /* eventOrder:'duration,start,allDay,title', */
        firstDay: 1, // 设置一周中显示的第一天是哪天,周日是0,周一是1,类推
        locale: "zh-cn",
        eventColor: "#fff",
        themeSystem: "bootstrap", // 主题色(本地测试未能生效)
        expandRows: true,
        contentHeight: 910,
        timeGridEventMinHeight: " 30", // 设置事件的最小高度
        /*  weekNumbers:true,
        weekText: "周", */
        // displayEventTime: false, // 是否显示时间
        eventLimit: true, // 设置月日程,与all-day slot的最大显示数量,超过的通过弹窗显示
        allDaySlot: true,
        allDayText: "全天",
        scrollTimeReset: true,
        scrollTime: "12:00:00",
        slotMinTime: "07:00:00",
        slotMaxTime: "20:00:00",
        slotDuration: "01:00",
        slotLabelInterval:"01:00",
        showNonCurrentDates: false,
        /* slotEventOverlap: false, */
        eventMouseEnter:eventMouseEnter,
        dayHeaderContent:this.dayHeaderContent,
        slotLabelContent:slotLabelContent,
        eventContent:eventContetFun,
        moreLinkDidMount:this.moreLinkDidMount,
        moreLinkWillUnmount:this.moreLinkWillUnmount,
        allowContextMenu: false,
        views: {
          timeGridWeek: {
            eventMaxStack: 4,
            eventLimit: 5,
            dayMaxEventRows: 4,
            moreLinkContent: "更多",
            moreLinkClick: "popover",
            dayHeaderFormat: {
              month: "2-digit",
              day: "2-digit",
              omitCommas: true,
            },
            titleFormat: { year: "numeric", month: "2-digit", day: "2-digit" },
          },
        },
        headerToolbar: false,
        slotLabelFormat: {
          hour: "2-digit",
          minute: "2-digit",
          meridiem: false,
          hour12: false, // 设置时间为24小时
        },
        eventLimitNum: {
          // 事件显示数量限制(本地测试未能生效)
          dayGrid: {
            eventLimit: 3,
          },
          timeGrid: {
            eventLimit: 2, // adjust to 6 only for timeGridWeek/timeGridDay
          },
        },
        eventClick: this.handleEventClick,
        /*  dayClick: function(event, jsEvent, view) {
          console.log("222222");
        }, */
      },
    };
  },
  mounted() {
    if (!this.type || this.type == "init") {
      this.getDateFun();
    }
    this.resizeCalendarBox();
  },
  methods: {
    resizeCalendarBox(){
       const _this=this;
      const erd=elementResizeDetectorMaker();
      erd.listenTo(document.getElementById("calendar1"),(element)=>{
           _this.$nextTick(()=>{
           let calendarApi = this.$refs.fullCalendar.getApi(); 
          calendarApi.gotoDate(_this.startDate )
          })
         
      })
    },
    changeToDay(date) {
      this.$emit("turnToDaySchedule", date);
    },
    //获取当前日期范围
    getDateFun() {
      let calendarApi = this.$refs.fullCalendar.getApi();
      let title = calendarApi.view.title;
      let dateArr = title.split("–");
      let start = this.$refs.fullCalendar.getApi().view.activeStart;
      let now = new Date(start);
      this.week = getWeek(y2k(now.getYear()), now.getMonth(), now.getDate());
      if (dateArr.length > 0) {
        this.startDate = dateArr[0].replace(/\//g, "-").replace(/\s*/g, "");
        this.endDate = dateArr[1].replace(/\//g, "-").replace(/\s*/g, "");
        this.title = title;
        this.$nextTick(() => {
          this.$emit("changeWeekDate", title);
        });
        this.getWeekData();
      }
    },
    //日视图数据请求
    getWeekData() {
      const _this = this;
      GetWeekList({
        startDate: this.startDate,
        endDate: this.endDate,
      }).then((res) => {
        let resData = res.data,
          result = resData.flat(Infinity);
        const handleData = result.map((item) => {
          let start = item.startTime ? item.startTime : item.allDayStartTime;
          let day = start.split(" ")[0];
          let timeObj = changeStartEnd(day, item);
          return {
            start: timeObj.itemStart,
            end: timeObj.itemEnd,
            startTimes: new Date(item.startTime ? item.startTime : item.allDayStartTime),
            endTimes: new Date(item.endTime ? item.endTime : item.allDayEndTime),
            title: item.sysScheduleContent,
            classNames: item.actualCompleteTime ? "blue" : "orange",
            sysScheduleArrangeAllRecordId: item.sysScheduleArrangeAllRecordId,
            sysScheduleArrangeId: item.sysScheduleArrangeId,
            status: item.status,
            actualCompleteTime: item.actualCompleteTime,
            important: item.important,
          };
        });
       
        _this.calendarOptions.events = handleData;
      });
    },
    //根据日期更新视图
    gotoDate(arg) {
      let calendarApi = this.$refs.fullCalendar.getApi();
      calendarApi.gotoDate(new Date(arg[0]));
      this.getDateFun();
    },
    getPrev() {
      let calendarApi = this.$refs.fullCalendar.getApi();
      calendarApi.prev();
      this.getDateFun();
    },
    getNext() {
      let calendarApi = this.$refs.fullCalendar.getApi();
      calendarApi.next();
      this.getDateFun();
    },
    dayHeaderContent(arg) {
      const _this=this;
      let weekDay = arg.dow;
      let weekObj={0:'星期天',1:'星期一',2:'星期二',3:'星期三',4:'星期四',5:'星期五',6:'星期六'}
      let weekName=weekObj[weekDay];
      weekName+= "( "+arg.text.replace('/', '-')+" )"
      let italicEle= document.createElement('div');
      italicEle.className="top";     
      italicEle.addEventListener('click',function(){
        _this.$emit("turnToDaySchedule", arg.date);
      });
      if(this.weekEventNumObj[arg.dow]>0){
        italicEle.innerHTML=weekName+"<span  class='moreTips'>更多日程</span>"
      }else{
        italicEle.innerHTML=weekName;
      }
      return {domNodes:[italicEle]}
    },
    moreLinkWillUnmount(){
      this.weekEventNumObj={ 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0 }
    },
    moreLinkDidMount(arg){
      let date= arg.el.closest('.fc-day').dataset.date;
      let weekday=new Date(date).getDay();  
      let weekEventNumObj = this.weekEventNumObj;
      if(weekEventNumObj[weekday]<arg.num){
        weekEventNumObj[weekday]=arg.num;
        this.weekEventNumObj = weekEventNumObj;
        let calendarApi = this.$refs.fullCalendar.getApi();
        calendarApi.gotoDate(new Date(date));
      }
     },
    /**
     * 点击日历日程事件
     *
     * info: 事件信息
     * event是日程(事件)对象
     * jsEvent是个javascript事件
     * view是当前视图对象。
     */
    handleEventClick(info) {
      if(info.el.closest('.fc-more-popover')){
        let removeObj=info.el.closest('.fc-more-popover');
        removeObj.parentNode.removeChild(removeObj)
      } 
      const data = info.event._def.extendedProps;
      const scheduleID = {
        sysScheduleArrangeAllRecordId: data.sysScheduleArrangeAllRecordId,
        sysScheduleArrangeId: data.sysScheduleArrangeId,
        status: data.status,
      };
      this.$emit("getScheduleID", scheduleID);
    },
  },
};
</script>
 
<style lang="scss" scoped>
.top-title {
  height: 70px;
  line-height: 70px;
  font-size: 18px;
  color: #1890ff;
  text-align: right;
  margin-top: -70px;
  i {
    cursor: pointer;
  }
}

::v-deep {
  /* .fc-timegrid-slot {
    height: 3em; // 1.5em by default
  } */
  .fc-scrollgrid-sync-inner {
    position: relative;
  }
  .moreTips {
    font-size: 12px;
    color: #1890ff;
    width: 30px;
    display: inline-block;
    white-space: break-spaces;
    line-height: 1.2em;
    padding-top: 5px;
    position: absolute;
    z-index: 99;
    right: 8px;
    top: 6px;
  }
  .time {
    white-space: nowrap;
  }
  .tit {
    font-size: 14px;
    position: relative;
    font-weight: 700;
    width: 100%;
    overflow: hidden;
    height: 1.2em;
    line-height: 1.2em;
    margin-top: 5px;
    .red {
      color: #ff2323;
    }
  }

  .finish {
    color: #1890ff;
    position: absolute;
    top: 0px;
    z-index: 1009;
    background: #e8f4ff;
  }
  .unfinish {
    color: #ff7c3d;
    position: absolute;
    background: #e8f4ff;
    top: 0px;
    z-index: 1009;
  }
  .fc-direction-ltr .fc-timegrid-more-link {
    display: none;
  }
  .fc .fc-timegrid-col.fc-day-today {
    background: none;
  }
  .fc-v-event .fc-event-main {
    color: #333333ff;
    overflow: hidden;
  }

  .fc-direction-ltr .fc-daygrid-event {
    background: #e8f4ffff;
    border: none;
    border-left: 5px solid #63b4ffff;
    margin-left: 0;
    display: block;
    margin-top: 0;
    /*  border-bottom: 1px solid #fff; */
    margin-bottom: 1px;
    padding-left: 3px;
    height: 42px;
    overflow: hidden;
  }
  .fc-timegrid-event{
    margin-bottom: 0;
  }
  .fc-timegrid-event-harness-inset .fc-timegrid-event.orange,
  .orange.fc-daygrid-event.fc-event-end {
    border-left: 5px solid #ffb18dff !important;
    background: rgba(255, 224, 209, 0.9) !important;
  }
  .fc-timegrid-event-harness-inset .fc-timegrid-event.blue,
  .blue.fc-daygrid-event.fc-event-end {
    border-left: 5px solid #63b4ffff !important;
    background: rgba(232, 244, 255, 0.9) !important;
  }
  .fc-timegrid-event-harness-inset .fc-timegrid-event.red,
  .red.fc-daygrid-event.fc-event-end {
    border-left: 5px solid #ff2323 !important;
  }
  .fc-daygrid-event.fc-event-end {
    margin-right: 0;
  }
  .fc-direction-ltr .fc-daygrid-event.fc-event-start {
    margin-left: 0;
  }
  .fc-direction-ltr .fc-timegrid-col-events {
    margin: 0;
  }
  .fc-theme-standard th {
    height: 50px;
    line-height: 50px;
    background: #ececec;
    font-size: 18px;
    color: #333;
    font-weight: 400;
  }
  .week.fc .fc-toolbar-title {
    display: inline-block;
    font-weight: 400;
    font-size: 18px;
    color: #1890ff;
  }
  .week.fc .fc-button-primary {
    background: #fff;
    border: none;
    color: #1890ff;
    display: inline-block;
  }
  .week.fc .fc-toolbar.fc-header-toolbar {
    margin-bottom: 1.5em;
    position: absolute;
    z-index: 1000;
    top: 110px;
    right: 30px;
  }
  .fc-h-event .fc-event-main {
    color: #333;
  }
  .fc .fc-daygrid-body-natural .fc-daygrid-day-events {
    margin-bottom: 0;
  }
  .fc .fc-timegrid-divider {
    padding: 0;
    display: none;
  }
  .fc .fc-timegrid-slot-minor {
    display: none;
  }
  .fc .fc-daygrid-day.fc-day-today {
    background: none;
  }
  .fc .fc-daygrid-day-bottom {
    position: absolute;
    z-index: 99;
    bottom: 3px;
    right: 0;
    font-size: 14px;
  }
  .fc .fc-daygrid-day-frame .fc-daygrid-day-events{
    max-height: 173px;
    overflow: hidden;
  }
  .fc .fc-daygrid-event-harness-abs{
    position:relative !important;
    visibility: visible !important;
    
  }
  .text {
    width: calc(100% - 10px);
    overflow: hidden;
    text-overflow: ellipsis;
    height: 1em;
    line-height: 1em;
    display: inline-block;
    white-space: nowrap;
  }
  .slim {
    font-size: 12px;
    padding-top: 0px;
    height: 1.1em;
    line-height: 1.1em;
    /* font-weight: 400; */
    margin-top: 0;
  }
}
</style>

功能点 :

1.点击相应日期调跳转到日视图界面,周头部格式改成星期几格式

 dayHeaderContent(arg) {
      const _this=this;
      let weekDay = arg.dow;
      let weekObj={0:'星期天',1:'星期一',2:'星期二',3:'星期三',4:'星期四',5:'星期五',6:'星期六'}
      let weekName=weekObj[weekDay];
      weekName+= "( "+arg.text.replace('/', '-')+" )"
      let italicEle= document.createElement('div');
      italicEle.className="top";     
      italicEle.addEventListener('click',function(){
        _this.$emit("turnToDaySchedule", arg.date);
      });
      if(this.weekEventNumObj[arg.dow]>0){
        italicEle.innerHTML=weekName+"<span  class='moreTips'>更多日程</span>"
      }else{
        italicEle.innerHTML=weekName;
      }
      return {domNodes:[italicEle]}
    },

2.修复页面伸缩出现空白问题

 mounted() {
    this.resizeCalendarBox();
  },
resizeCalendarBox(){
       const _this=this;
      const erd=elementResizeDetectorMaker();
      erd.listenTo(document.getElementById("calendar1"),(element)=>{
           _this.$nextTick(()=>{
           let calendarApi = this.$refs.fullCalendar.getApi(); 
          calendarApi.gotoDate(_this.startDate )
          })
         
      })
    },

3.鼠标悬停文字显示

export function eventMouseEnter(info){
  let startTime = info.event._def.extendedProps.startTimes;
  let endTime = info.event._def.extendedProps.endTimes;
  const showTimeStart = (startTime.getHours() < 10 ? "0" + startTime.getHours() : startTime.getHours()) + ":" + (startTime.getMinutes() < 10 ? "0" + startTime.getMinutes() : startTime.getMinutes());
  const showTimeEnd = (endTime.getHours() < 10 ? "0" + endTime.getHours() : endTime.getHours()) + ":" + (endTime.getMinutes() < 10 ? "0" + endTime.getMinutes() : endTime.getMinutes());
  let Time=showTimeStart+"-"+showTimeEnd;
  const title=info.event.title;
  let allDay = info.event.allDay;
  if(allDay){
    Time="全天"
  }
  tippy(info.el, {
     content:title+"<div>"+"("+Time+")"+"</div>",
     arrow:false,
     placement: "top-start",
     allowHTML:true,
   });
}

4.左侧 时间轴 

export function slotLabelContent(arg){
  if (Number(arg.time.milliseconds) < 28800000) {
    return "08:00前";
  }
  if (
    Number(arg.time.milliseconds) >= 28800000 &&
    Number(arg.time.milliseconds) <= 64800000
  ) {
    return arg.text;
  }
  if (Number(arg.time.milliseconds) > 64800000) {
    return "19:00后";
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值