Detailed explanation of FullCalendar calendar plug-in schedule schedule schedule schedule nanny level (schedule schedule can be dragged)

(based on vue) to achieve the effect


foreword

I have nothing to do when I have nothing to do. I seem to have encountered this kind of demand before, but I didn’t do it. The main use is the FullCalendar plugin. Based on the vue framework writing method.

For basic functions, you can create a new schedule to see the style, and you can drag and drop the schedule into it.


提示:以下是本篇文章正文内容,下面案例可供参考

1. What is FullCalendar?

Fullcalendar is a very popular js component for calendar schedule processing. It has powerful functions, complete documentation, high customization, and can be seamlessly connected with your project.

Official website link: https://fullcalendar.io/demos

It is mainly for plug-ins written on the basis of jq. The official website documents are all in English, so it depends on the almighty Du Niang.

Here is a link to use Fullcalendar_Helloweba under the Vue framework

It explains in detail the usage of the plug-in written in vue, but I encountered many problems when copying it as it is, and I will summarize it later.

2. Use steps

1. Import library

The code is as follows (example):

npm install @fullcalendar/core

npm install @fullcalendar/vue

npm install @fullcalendar/daygrid

npm install @fullcalendar/interaction

npm install @fullcalendar/timegrid

npm install @fullcalendar/list

(This can also be npm install at one time. Since I had a problem with the one-time installation, I installed them one by one)

import '@fullcalendar/core'; // solves problem with Vite
import FullCalendar from '@fullcalendar/vue';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin,{ Draggable } from '@fullcalendar/interaction';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import moment from "moment";


2.html part of the code

There is nothing to say in this part. The page layout I made is purely static. If necessary, just copy and paste. I imported the css style with the scss file, and the code is placed below.

<template>
  <div class="calendar">
    <div class="calendar_header">
      <el-input v-model="searchVal" placeholder="请输入内容"></el-input>
      <el-button type="primary" @click="dialogAdd">+ 新建日程</el-button>
    </div>
    <div class="calendar_body">
      <div class="calendar_body_left">
        <div class="calendar_body_left_top">
          <div class="calendar_body_left_top_title">日程状态图例</div>
          <div>
            <el-button class="unstart_btn">未开始</el-button>
            <el-button class="doing_btn">进行中</el-button>
            <el-button class="success_btn">已完成</el-button>
            <el-button class="delay_btn">已延时</el-button>
          </div>
        </div>
        <div class="calendar_body_left_bottom">
            <div class="calendar_body_left_bottom_title">可拖动列表</div>
            <div class="date-box" id="list-group-item">
              <div class="flex-b box list-group-item" v-for="item in list" :key="item.name">
                  <div>{
   
   { item.name }}</div>
                  <div class="circle" :class="item.status">{
   
   { item.value }}</div>
              </div>
          </div>
        </div>
      </div>
      <div class="calendar_body_right">
        <template>
          <FullCalendar ref="fullCalendar" :options="calendarOptions" />
        </template>
      </div>
    </div>
    <!-- 新建日程弹窗 -->
    <el-dialog title="新建日程" :visible.sync="dialogFormVisible">
        <el-form :model="form" :rules="rules" ref="form">
          <el-form-item label="日程名称" :label-width="formLabelWidth"  prop="name">
            <el-input v-model="form.name" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="日程状态" :label-width="formLabelWidth" prop="status">
            <el-select v-model="form.status" placeholder="请选择日程状态">
              <el-option label="未开始" value="unstart"></el-option>
              <el-option label="进行中" value="doing"></el-option>
              <el-option label="已完成" value="success"></el-option>
              <el-option label="已延时" value="delay"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item label="日程时间" :label-width="formLabelWidth"  prop="date">
            <template>
              <el-date-picker
                v-model="form.date"
                type="datetimerange"
                value-format="yyyy-MM-dd HH:mm:ss"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期">
              </el-date-picker>
            </template>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button @click="dialogFormVisible = false">取 消</el-button>
          <el-button type="primary" @click="submitForm('form')">确 定</el-button>
        </div>
  </el-dialog>
  </div>
</template>

3.css style code (the style is imported by writing a scss file separately)

.calendar{
    padding: 0 20px;
    .el-button{
        width: 100px;
    }
 .calendar_header{
    display: flex;
    margin: 30px 0;
    .el-input{
        width: 200px;
        margin-right: 16px;
    }
 }  
 .calendar_body{
    display: flex;
    .calendar_body_left{
        display: flex;
        flex-direction: column;
        width: 10%;
        .el-button{
            margin-left: 0 !important;
            color: #fff;
            margin-bottom: 4px;
        }
        .unstart_btn{
            background-color: #ffcc99;
        }
        .doing_btn{
            background-color: #5580ee;
        }
        .success_btn{
            background-color: #87d068;
        }
        .delay_btn{
            background-color: #FF0033;
        }
    }
    .calendar_body_right{
        width: 85%;
    }
 }
 .el-dialog{width: 30%;}
 .el-date-editor.el-range-editor.el-input__inner.el-date-editor--datetimerange{
    width: 100%;
 }
 .el-select{
    width: 100%;
 }
 .calendar_body_left_top{
    .calendar_body_left_top_title{
        margin-bottom: 15px;
        font-size: 18px;
        font-weight: bolder;
    }
 }
 .calendar_body_left_bottom{
    padding: 0 25px;
    margin-top: 20px;
    .calendar_body_left_bottom_title{
        font-size: 18px;
        font-weight: bolder;
    }
     .circle {
        background-color: #3788d8;
        border-radius: 10px;
        color: #fff;
        display: inline-block;
        font-size: 12px;
        height: 18px;
        line-height: 18px;
        padding: 0 6px;
        text-align: center;
        white-space: nowrap;
        border: 1px solid #fff;
      }
      .holiday {
        background-color: #FF6600;
      }
      .work{
        background-color: #66CCCC;
      }
      .date-box {
        //border: 1px solid #ccc;
        border-radius: 5px;
      }
      .box {
        margin-top:15px;
        border: 1px solid #FFFFCC;
        padding: 10px 20px;
        border-radius: 5px;
        display: flex;
        justify-content: space-between;
        cursor: pointer;
        background-color: #FFFFCC;
      }
 }
}

4. Logic code part 

code first

<script>
// @ is an alias to /src
import "@/assets/css/calendar.scss"

import '@fullcalendar/core'; // solves problem with Vite
import FullCalendar from '@fullcalendar/vue';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin,{ Draggable } from '@fullcalendar/interaction';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import moment from "moment";

export default {
  name: 'Home',
  components: {
  FullCalendar
  },
  data() {
  return {
    n:4,
    searchVal:'',
    dialogFormVisible:false,
    formLabelWidth: '120px',
      form:{
        name: '',
        date: '',
        status:'',
      },
      rules: {
          name: [
            { required: true, message: '请输入日程名称', trigger: 'blur' },
            // { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
          ],
          date: [
            { required: true, message: '请选择日期', trigger: 'change' }
          ],
          status: [
            { required: true, message: '请选择日程状态', trigger: 'change' }
          ]
    },
    testData:[{
            id: 1,
            title: '任务1未开始',
            start: '2023-04-06 10:30:00',
            end: '2023-04-07 10:30:00',
            // color: '#ffcc99',
            status:'unstart',
            editable: true, //允许拖动缩放,不写默认就是false
            overlap: true, //允许时间重叠,即可以与其他事件并存,不写默认就是false
        },{
            id: 2,
            title: '任务2进行中',
            start: '2023-04-06 10:30:00',
            end: '2023-04-08 10:30:00',
            // color: '#5580ee',
            status:'doing',
            editable: true, //允许拖动缩放
            overlap: true, //允许时间重叠,即可以与其他事件并存,不写默认就是false
        },{
            id: 3,
            title: '任务3已完成',
            start: '2023-04-09 10:30:00',
            end: '2023-04-09 18:30:00',
            // color: '#87d068',
            status:'success',
            editable: true, //允许拖动缩放
            overlap: true, //允许时间重叠,即可以与其他事件并存,不写默认就是false
        },{
            id: 4,
            title: '任务4已延时',
            start: '2023-04-18 10:30:00',
            end: '2023-04-18 10:30:00',
            // color: '#ff99b3',
            status:'delay',
            editable: true, //允许拖动缩放
            overlap: true, //允许时间重叠,即可以与其他事件并存,不写默认就是false
        }],
      // 可拖动列表数据
      list: [
        // { name: '删除假日', value: '0', color: 'blue'  }
        { name: '工作日1', value: '1', status: 'work' },
        { name: '工作日2', value: '5', status: 'work' },
        { name: '春节放假', value: '7', status: 'holiday' },
        { name: '中秋节放假', value: '3', status: 'holiday'  },
        { name: '国庆节放假', value: '7', status: 'holiday'  },
      ],
    calendarOptions: {
      plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin, listPlugin],
      initialView: 'dayGridMonth',
      locale: 'zh-cn', //? 配置中文
      firstDay: 1,// 把每周设置为从周一开始
      initialDate: moment().format("YYYY-MM-DD HH:mm:ss"), // 自定义设置背景颜色时一定要初始化日期时间
      aspectRatio: 2.6, // 设置日历单元格宽度与高度的比例。
      buttonText: {/* 设置按钮文字 */
        today: '今天',
        month: '月',
        week: '周',
        day: '日',
        list: '周列表',
      },
      headerToolbar: {//日历头部
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay listWeek',
      },
      selectable: true,//可编辑
      // dayMaxEvents: true,
      // slotMinutes: 15,
      editable: false, // 日历上是否可拖拽
      droppable: true,
      dropAccept: '.list-group-item',
      drop: this.drop,
      height: 650,
      validRange: this.validRange,  //设置可显示的总日期范围
      events: [], //背景色 (添加相同时间的背景色时颜色会重叠)
      datesSet: this.datesSet, //日期渲染;修改日期范围后触发
      eventClick: this.handleEventClick, //点击日程触发
      dateClick: this.handleDateClick, //点击日期触发
      eventDrop: this.calendarEventDropOrResize, //拖动事件触发
      eventResize: this.calendarEventDropOrResize, //缩放事件触发
      displayEventTime: false, //不显示具体时间
    },
    validRange: {
      start: '2023-01-01 ',
      end: moment().add(6, 'months').format('YYYY-MM-DD HH:mm:ss'),
    },
    new_startDate:'',
    new_endDate:'',
  }
},
mounted() {
  // 初始化日历 调用获取视图活动数据方法
  this.datesSet();

  // 拖拽
  var containerEl = document.getElementById('list-group-item');
    // 初始化外部事件
    new Draggable(containerEl, {
        itemSelector: '.list-group-item',
      }
    )
},
methods: {
  datesSet(info) {   //注意:该方法在页面初始化时就会触发一次
      // console.log(info)
      // this.search()  //请求本页数据
      //虚拟数据
      this.testData.forEach((item,index) => {
        // console.log('item',item)
          if(item.status == 'unstart'){
            this.$set(item,"color", "#ffcc99")
        }else if(item.status == 'doing'){
          this.$set(item,"color", "#5580ee")
        }else if(item.status == 'success'){
          this.$set(item,"color", "#87d068")
        }else if(item.status == 'delay'){
          this.$set(item,"color", "#FF0033")
        }else if(item.status == 'work'){
          this.$set(item,"color", "#66CCCC")
        }else{
          this.$set(item,"color", "#FF6600")
        }
      });
      this.calendarOptions.events = this.testData
      this.list.forEach((item,index) => {
        if(item.status == 'work'){
          this.$set(item,"color","#66CCCC")
        }else{
          this.$set(item,"color","#FF6600")
        }
      })
    },
  dialogAdd(){
    this.dialogFormVisible = true
  },
  submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {
            this.dialogFormVisible = false;
            this.n ++
            // console.log('date',this.form.date)
            let obj = {
              id: Number(this.n),
              title: String(this.form.name),
              start: String(this.form.date[0]),
              end: String(this.form.date[1]),
              // color: '#ff99b3',
              status:String(this.form.status),
              editable: true, //允许拖动缩放
              overlap: true, //允许时间重叠,即可以与其他事件并存,不写默认就是false
          }
            this.testData.push(obj)
            this.datesSet();
            // console.log('this.calendarOptions.events',this.calendarOptions.events)
          } else {
            console.log('error submit!!');
            return false;
          }
        });
  },
  // 转换时间格式
  parseTime(date) {
    const yy = date.getFullYear()
				const MM = (date.getMonth() + 1) < 10 ? '0' + (
                    date.getMonth() + 1) : (date.getMonth() + 1)
				const dd = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
				const HH = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
				const mm = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
				const ss = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
			const	newDate = yy + '-' + MM + '-' + dd + ' ' + HH + ':' + mm + ':' + ss;
    return newDate;
  },
  handleEventClick(info) {},
  handleDateClick(info){},
  // 拖拽事件
  calendarEventDropOrResize(info){
    // console.log(info) //获取拖拽目标信息
    // 获取拖拽后的时间
    this.new_startDate = this.parseTime(info.event._instance.range.start)
    this.new_endDate = this.parseTime(info.event._instance.range.end)
  },
  drop(date, allDay) {
      // let typeNumber = null
      // const firstChildName = null
      const isWork = date.draggedEl.lastChild.className.indexOf('work') > 0
      console.log('date',date)
      date.draggedEl.remove()
      this.n ++
      const obj = {
        // dayNum: date.draggedEl.lastChild.innerHTML,
          id: Number(this.n),
          title: String(date.draggedEl.firstChild.innerHTML),
          start: Date.parse(moment(date.dateStr).format()), // 开始时间
          end: Date.parse(moment(date.dateStr).add(date.draggedEl.lastChild.innerHTML, 'days').format()), // 结束时间
          // color: '#ff99b3',
          status:isWork ? 'work' : 'holiday',
          editable: true, //允许拖动缩放
          overlap: true, //允许时间重叠,即可以与其他事件并存,不写默认就是false
      }
      this.testData.push(obj)
      this.datesSet();
      // console.log(this.calendarOptions.events)
      // console.log('date.draggedEl.lastChild.innerHTML',date.draggedEl.lastChild.className.indexOf('holiday'))
    }
}

};
</script>

 5. Stepping on the pit part

The above code directly cv should be able to implement a static calendar schedule. Let me talk about the problems I encountered during the implementation process:

(1) In this piece, what others write is import '@fullcalendar/core/vdom' // solves problem with Vite

But what we wrote in vue2 is not applicable. But if there is a core file in the nodemodules package, I will remove it

(2) The following error will always appear during installation

viewType "" is not available. Please make sure you've loaded all neccessary plugins

Do not specify the installation version and install it directly. If the error report fails, uninstall all and download again. The uninstallation is complete only when the package.json file is gone. The problem I encountered was that an error was reported after a one-time download. I didn’t uninstall it. It was okay to look at other people’s versions. I think there should be no error when installing the code above, provided that your node version is similar to mine haha

(3) The Info of the event of these Fullcalendar calendar plug-ins can print out the current drag information, such as the time before and after dragging, and the style can be modified here. Print it out and attach it below. event is the information after dragging, and oldevent is the information before dragging. I mainly take time, so the screenshot is below.

 

(4) The drag of drop is mainly to drag and drop the schedule in the draggable list on the left to the Fullcalendar calendar. You can also get a lot of useful information by printing the date after dragging the schedule block on the left

 


Summarize


The above is the rudiment of implementing simple schedule scheduling. Complex functions still need to be based on data. Static is just a rough look. Let me talk so much first, I will write later if there are pitfalls; and see if I can add some fun functions later.

Guess you like

Origin blog.csdn.net/m0_49017085/article/details/130006849