使用Fullcalendar管理日程事件(增刪改查拖放)

新版Fullcalendar(v4)擁有豐富的選項方法事件配置以及插件應用,對開發者很是友好,開發者能夠輕鬆的利用Fullcalendar定製一個完美的日程安排應用,本文將講解最實際的日程事件管理先後端交互實例,包括事件的增刪改查以及拖放應用的實現。javascript

【查看演示】php

準備

本實例將要實現的功能:打開日程安排月視圖,默認加載當前月視圖的全部事件;點擊視圖中的任意日期,會彈出新增事件表單,輸入事件相關信息後,保存便可;點擊視圖中的事件,會彈出修改事件表單,可對事件進行修改,也刪除事件;咱們也能夠對視圖中的事件進行拖放,拖放完畢也就改變了事件的時間。css

注意本文提到的「事件」是指Fullcalendar日程安排事件內容。html

本文涉及到的web技術有:前端

Vue + FullCalendar + Axios + Element-ui + PHP。vue

本文篇幅較長,建議最好邊閱讀邊實際操做。java

咱們使用Axios做爲Ajax請求模塊,具體使用教程能夠參考:《Vue項目中使用Axios封裝http請求》,咱們還用了Element-ui的Dialog、表單、日期時間拾取器等組件。ios

咱們在上一節文章《在Vue框架下使用Fullcalendar》的基礎上,新建Event.vue文件:git

<template>
    <FullCalendar defaultView="dayGridMonth" 
            locale="zh-cn" 
            timeZone="UTC" 
            firstDay="1" 
            weekNumberCalculation="ISO" 
            editable="true"
            droppable="true"
            displayEventEnd="true"
            :eventTimeFormat="evnetTime"
            :header="header"
            :plugins="calendarPlugins"
            :events="calendarEvents"
            @dateClick="handleDateClick" 
            @eventClick="handleEventClick"
            @eventDrop="calendarEventDrop"
            @datesRender="handleDatesRender"
             />
</template>

<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin, { Draggable } from '@fullcalendar/interaction';
import '@fullcalendar/core/main.css';
import '@fullcalendar/daygrid/main.css';
import '@fullcalendar/timegrid/main.css';

export default {
    components: {
        FullCalendar
    },
    data() {
        return {
            calendarPlugins: [ 
                dayGridPlugin,
                timeGridPlugin,
                interactionPlugin
            ],
            header: {
                left: 'prev,next today',
                center: 'title',
                right: 'dayGridMonth,timeGridWeek,timeGridDay'
            },
            evnetTime: {
                hour: 'numeric',
                minute: '2-digit',
                hour12: false
            },

            calendarEvents: [],
            calendarEventDrop: info => {
                this.dropEvent(info);
            },
            handleDatesRender: arg => {
                this.getEventsList(arg.view)
            },

            dialogFormVisible: false,
            form: {
                title: null,
                start: null,
                end: null
            },
            optTitle: '添加事件',
        }
    },
    created() {
        //
    },
    methods: {
        獲取事件列表
        getEventsList(info) {
            
        },
        handleDateClick(arg) {
            this.dialogFormVisible = true;
            this.optTitle = '新增事件';
            this.form.title = '',
            this.form.id = '',
            this.form.start = arg.date;
            this.form.end = arg.date;
        },
        handleEventClick(info) {
            info.el.style.borderColor = 'red';
            this.dialogFormVisible = true;
            this.optTitle = '修改事件';
            this.form = {
                id: info.event.id,
                title: info.event.title,
                start: info.event.start,
                end: info.event.end,
            };
        },
        //保存事件
        saveEvent() {
            
        },
        //刪除事件
        delEvent() {
            
        },
        //拖動事件
        dropEvent(info) {
            
        }
    }
}
</script>

讀取事件

咱們但願每次載入Fullcalendar,以及切換日期的時候,會讀取視圖中的日期範圍內的事件列表。Fullcalendar提供了事件源屬性events,支持json,數組,回調函數等方式獲取日程數據,可是若是要對數據進行修改會新增的時候處理起來比較麻煩了。而咱們採用Fullcalendar的另外一個方法函數datesRender,它的意思是當視圖中的日期渲染時,回調函數。web

咱們在data中,回調getEventsList()

handleDatesRender: arg => {
                this.getEventsList(arg.view)
            },

methods中的getEventsList()代碼以下:

getEventsList(info) {
            let params = {
                start: info.activeStart,
                end: info.activeEnd
            };
            this.$get('events.php', params)
            .then((res) => {
                this.calendarEvents = res;
            });
        },

你們一看就明白,咱們使用了Axios發送get請求,參數就是當前視圖中的開始事件和結束時間,獲取events.php返回的數據,並將數據賦給events

新增事件

當咱們單擊視圖中的某一天時,觸發日期點擊事件:@dateClick="handleDateClick",咱們在handleDateClick()中,彈出表單框,定義表單元素默認值。注意參數arg是一個內置對象,能夠獲取當前點擊的日期等數據。

handleDateClick(arg) {
            this.dialogFormVisible = true;
            this.optTitle = '新增事件';
            this.form.title = '',
            this.form.id = '',
            this.form.start = arg.date;
            this.form.end = arg.date;
        },

在彈出的dialog表單中,有日程事件的名稱,起始和結束時間。當新增和編輯的時候咱們共用這一個表單,在編輯表單時會顯示刪除按鈕。

<el-dialog :title="optTitle" :visible.sync="dialogFormVisible">
  <el-form :model="form">
    <el-form-item label="事件名稱" label-width="80px">
      <el-input v-model="form.title" auto-complete="off" placeholder="請輸入事件名稱"></el-input>
    </el-form-item>
    <el-form-item label="開始時間" label-width="80px">
        <el-date-picker
          v-model="form.start"
          type="datetime"
          placeholder="選擇日期時間">
        </el-date-picker>
    </el-form-item>
    <el-form-item label="結束時間" label-width="80px">
        <el-date-picker
          v-model="form.end"
          type="datetime"
          placeholder="選擇日期時間">
        </el-date-picker>
    </el-form-item>
  </el-form>
  <div slot="footer" class="dialog-footer">
    <el-button type="warning" @click="delEvent" v-if="form.id" style="float: left;">刪 除</el-button>
    <el-button @click="dialogFormVisible = false">取 消</el-button>
    <el-button type="primary" @click="saveEvent">確 定</el-button>
  </div>
</el-dialog>

當點擊表單中的「肯定」按鈕時,調用saveEvent

saveEvent() {
            this.$post('events.php?action=save', this.form)
            .then((res) => {
                if (res.code === 0) {
                    if (this.form.id === undefined || this.form.id == '') { //新增
                        this.form.id = res.id;
                        this.calendarEvents.push(this.form);
                        this.$message({
                            message: '新增成功!',
                            type: 'success'
                        });
                    } else { //修改
                        this.calendarEvents.forEach((item, index, arr) => {
                            if (item.id == this.form.id) {
                                arr[index].title = this.form.title
                                arr[index].start = this.form.start
                                arr[index].end = this.form.end
                            }
                        });
                        this.$message({
                            message: '修改爲功!',
                            type: 'success'
                        });
                    }
                    
                    this.dialogFormVisible = false;
                } else {
                    this.$message({
                        message: res.message,
                        type: 'error'
                    });
                }
            });
        },

使用Axios發送了一個post請求,根據返回數據和本地form對象中是否有id參數,若是沒有則是新增事件,直接this.calendarEvents.push(this.form);,就是往事件數組追加當前表單的數據,而後關閉Dialog,這時對應的日期內就會顯示剛剛添加的事件。

修改事件

當點擊視圖中的某一個日程事件,會彈出Dialog,這時會觸發@eventClick="handleEventClick"

handleEventClick(info) {
            info.el.style.borderColor = 'red';
            this.dialogFormVisible = true;
            this.optTitle = '修改事件';
            this.form = {
                id: info.event.id,
                title: info.event.title,
                start: info.event.start,
                end: info.event.end,
            };
        },

handleEventClick自帶info參數,能夠根據該參數獲取當前要修改事件的標題名稱、起始和結束日期等數據。將這些數據賦值給form,並彈出Dialog。和新增事件同樣,保存表單的時候也執行了saveEvent。由於修改事件時已知了事件的id,這個時候修改好的事件怎麼替換原有的事件呢?咱們使用forEach方法遍歷事件數組,比對若是事件id與當前表單id至關時則修改事件名稱和日期時間等,詳情請看上面修改事件部分。

刪除事件

點擊修改事件彈出框Dialog時,左下角會出現「刪除」按鈕,點擊該按鈕,調用delEvent()

delEvent() {
            this.$post('events.php?action=del', {id: this.form.id})
            .then((res) => {
                if (res.code === 0) {
                    this.calendarEvents.forEach((item, index, arr) => {
                        if(item.id == this.form.id) {
                            arr.splice(index, 1);
                        }
                    });
                    this.dialogFormVisible = false;
                    this.$message({
                        message: '刪除成功!',
                        type: 'success'
                    });
                } else {
                    this.$message({
                        message: res.message,
                        type: 'error'
                    });
                }
            });
        },

刪除當前事件後,一樣的咱們用forEach遍歷事件數組,使用splice將當前刪除的事件從事件數組中剔除。

拖放事件

當按住視圖中的某一個日程事件,拖動至另外一個日期中,觸發@eventDrop="calendarEventDrop"

calendarEventDrop: info => {
                this.dropEvent(info);
            },

eventDrop傳遞info參數給this.dropEvent(info)

dropEvent(info) {
            this.form = {
                id: info.event.id,
                title: info.event.title,
                start: info.event.start,
                end: info.event.end
            };
            this.saveEvent();
        }

在拖動後,咱們將data中的form對象的值改變,並調用saveEvent()保存拖動後的數據。

後端PHP

後端提供了與前端交互的API接口,PHP接收請求,並做出響應,Mysql提供數據存儲查詢功能。首先建立數據表:

CREATE TABLE `fullcalendar` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(128) NOT NULL,
  `start_time` int(10) NOT NULL DEFAULT '0',
  `end_time` int(10) NOT NULL DEFAULT '0',
  `created_at` datetime NOT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

events.php接收穫取事件列表、新增、修改、刪除事件的接口,具體代碼以下:

require_once('conn.php');

$action = isset($_GET['action']) ? $_GET['action'] : '';

if ($action == 'save') { //添加|修改
    $res['code'] = -1;
    $data = file_get_contents('php://input');
    $post = json_decode($data, true);
    $title = htmlentities($post['title']);
    $start = htmlentities($post['start']);
    $end = htmlentities($post['end']);
    if (empty($end)) {
        $end = $start;
    }
    if (empty($title)) {
        $res['message'] = '名稱不能爲空!';
        echo json_encode($res);
        exit;
    }
    $id = isset($post['id']) ? (int)$post['id'] : '0';
    if ($id == 0) { //添加
        $sql = "INSERT INTO `fullcalendar` (title,start_time,end_time,created_at) VALUES (:title,:start_time,:end_time,:created_at)";
        $stmt = $db->prepare($sql);
        $stmt->execute([
            ':title' => $title,
            ':start_time' => strtotime($start),
            ':end_time' => strtotime($end),
            ':created_at' => date('Y-m-d H:i:s')
        ]);
        $lastid = $db->lastInsertId();
        if ($lastid > 0) {
            $res['id'] = $lastid;
            $res['code'] = 0;
        } 
    } else { //修改
        $sql = "UPDATE `fullcalendar` SET title=:title,start_time=:start_time,end_time=:end_time,updated_at=:updated_at WHERE id=:id";
        $stmt = $db->prepare($sql);
        $stmt->execute([
            ':title' => $title,
            ':start_time' => strtotime($start),
            ':end_time' => strtotime($end),
            ':updated_at' => date('Y-m-d H:i:s'),
            ':id' => $id
        ]);
        $res['code'] = 0;
    }
    
    echo json_encode($res);

} elseif ($action == 'del') { //刪除
    $res['code'] = -1;
    $data = file_get_contents('php://input');
    $post = json_decode($data, true);
    $id = isset($post['id']) ? (int)$post['id'] : '0';
    if ($id == 0) {
        $res['message'] = '非法參數';
        echo json_encode($res);
        exit;
    }

    $sql = "DELETE FROM `fullcalendar` WHERE id=:id";
    $stmt = $db->prepare($sql);
    $rs = $stmt->execute([
        ':id' => $id
    ]);
    if ($rs) {
        $res['code'] = 0;
    } else {
        $res['message'] = '刪除失敗';
    }
    echo json_encode($res);

} else {
    $start = isset($_GET['start']) ? (int)$_GET['start']/1000 : 0;
    $end = isset($_GET['end']) ? (int)$_GET['end']/1000 : 0;

    $start = isset($_GET['start']) ? strtotime($_GET['start']) : 0;
    $end = isset($_GET['end']) ? strtotime($_GET['end']) : 0;

    $sql = "SELECT id,title,start_time,end_time FROM `fullcalendar` WHERE start_time>=:startTime AND end_time<:endTime ORDER BY id desc";
    $stmt = $db->prepare($sql);
    $stmt->execute([
        ':startTime' => $start,
        ':endTime' => $end
    ]);
    $list = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach ($list as $key => &$val) {
        $val['start'] = date('Y-m-d H:i:s', $val['start_time']);
        $val['end'] = date('Y-m-d H:i:s', $val['end_time']);
        $val['description'] = 'aaa';
    }
    echo json_encode($list);
}

完整的實例代碼請到Helloweba官網下載源碼查看。

提高閱讀:使用Fullcalendar管理時間計劃調度安排

相關文章
相關標籤/搜索