基于LayUI使用FullCalendar实现日程管理

引言

  最新工作中需要实现日程管理功能,由于技术选型(基于layui)限制,从网上对比查询最终选定使用FullCalendar插件来实现日程管理。
其中对比的日程还有XgCalendar、Google Calendar

实现效果
1、打开界面后,月视图
基于LayUI使用FullCalendar实现日程管理_第1张图片
2、切换到周视图
基于LayUI使用FullCalendar实现日程管理_第2张图片
3、切换到日视图
基于LayUI使用FullCalendar实现日程管理_第3张图片
4、在月视图,添加会议室预订
基于LayUI使用FullCalendar实现日程管理_第4张图片

5、在月视图,修改会议室预订
基于LayUI使用FullCalendar实现日程管理_第5张图片

6、在月视图,鼠标移到event,显示详情
基于LayUI使用FullCalendar实现日程管理_第6张图片
对应实现
1、依赖的js
下载路径:https://fullcalendar.io/docs/getting-started
基于LayUI使用FullCalendar实现日程管理_第7张图片
2、对应的index


<html lang='en'>
<head>
    <meta charset='utf-8' />
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">

    <link rel="stylesheet" href='/fullcalendar/core/main.css' rel='stylesheet' />
    <link rel="stylesheet" href='/fullcalendar/daygrid/main.css' rel='stylesheet' />
    <link rel="stylesheet" href='/fullcalendar/timegrid/main.css' rel='stylesheet' />
    <link rel="stylesheet" href="/assets/libs/layui/css/layui.css" media="all">
    <link rel="stylesheet" href="/assets/common.css" media="all">

    <style>
        #calendar {
            max-width: 1200px;
            margin: 0 auto;
        }

        #external-events {
            float: left;
            width: 150px;
            padding: 0 10px;
            border: 1px solid #ccc;
            background: #eee;
            text-align: left;
        }

        #external-events h4 span {
            font-size: 16px;
            margin-top: 0;
            padding-top: 1em;
        }

        .external-event { /* try to mimick the look of a real event */
            margin: 10px 0;
            padding: 2px 4px;
            background: #3366CC;
            color: #fff;
            font-size: .85em;
            cursor: pointer;
        }

        /*日期控件*/
        .layui-laydate-content>.layui-laydate-list {
            padding-bottom: 0px;
            overflow: hidden;
        }
        .layui-laydate-content>.layui-laydate-list>li{
            width:50%
        }

        /* pop */
        .popper,
        .tooltip {
            position: absolute;
            z-index: 9999;
            background: #FFC107;
            color: black;
            width: 150px;
            border-radius: 3px;
            box-shadow: 0 0 2px rgba(0,0,0,0.5);
            padding: 10px;
            text-align: center;
        }
        .style5 .tooltip {
            background: #1E252B;
            color: #FFFFFF;
            max-width: 200px;
            width: auto;
            font-size: .8rem;
            padding: .5em 1em;
        }
        .popper .popper__arrow,
        .tooltip .tooltip-arrow {
            width: 0;
            height: 0;
            border-style: solid;
            position: absolute;
            margin: 5px;
        }

        .tooltip .tooltip-arrow,
        .popper .popper__arrow {
            border-color: #FFC107;
        }
        .style5 .tooltip .tooltip-arrow {
            border-color: #1E252B;
        }
        .popper[x-placement^="top"],
        .tooltip[x-placement^="top"] {
            margin-bottom: 5px;
        }
        .popper[x-placement^="top"] .popper__arrow,
        .tooltip[x-placement^="top"] .tooltip-arrow {
            border-width: 5px 5px 0 5px;
            border-left-color: transparent;
            border-right-color: transparent;
            border-bottom-color: transparent;
            bottom: -5px;
            left: calc(50% - 5px);
            margin-top: 0;
            margin-bottom: 0;
        }
        .popper[x-placement^="bottom"],
        .tooltip[x-placement^="bottom"] {
            margin-top: 5px;
        }
        .tooltip[x-placement^="bottom"] .tooltip-arrow,
        .popper[x-placement^="bottom"] .popper__arrow {
            border-width: 0 5px 5px 5px;
            border-left-color: transparent;
            border-right-color: transparent;
            border-top-color: transparent;
            top: -5px;
            left: calc(50% - 5px);
            margin-top: 0;
            margin-bottom: 0;
        }
        .tooltip[x-placement^="right"],
        .popper[x-placement^="right"] {
            margin-left: 5px;
        }
        .popper[x-placement^="right"] .popper__arrow,
        .tooltip[x-placement^="right"] .tooltip-arrow {
            border-width: 5px 5px 5px 0;
            border-left-color: transparent;
            border-top-color: transparent;
            border-bottom-color: transparent;
            left: -5px;
            top: calc(50% - 5px);
            margin-left: 0;
            margin-right: 0;
        }
        .popper[x-placement^="left"],
        .tooltip[x-placement^="left"] {
            margin-right: 5px;
        }
        .popper[x-placement^="left"] .popper__arrow,
        .tooltip[x-placement^="left"] .tooltip-arrow {
            border-width: 5px 0 5px 5px;
            border-top-color: transparent;
            border-right-color: transparent;
            border-bottom-color: transparent;
            right: -5px;
            top: calc(50% - 5px);
            margin-left: 0;
            margin-right: 0;
        }
    style>
head>
<body>

<div class="layui-fluid">
    <div class="layui-card" style="padding-top: 5px; margin-bottom: 8px;">
        <div class="layui-row layui-col-space15">
            <div class="layui-col-xs12 layui-col-md2">
                <div id='external-events'>
                    <h4>会议室h4>
                    <#list roomList as room>
                        <div class="external-event" id="room${room.id}" roomId="${room.id}" onclick="changeRoom(this.id)">${room.name}div>
                    #list>
                    <#--<div id="1" roomId="1" onclick="changeRoom(this.id)">会议室1div>-->
                    <#--<div id="2" roomId="2" onclick="changeRoom(this.id)">会议室2div>-->
                    <#--<div id="3" roomId="3" onclick="changeRoom(this.id)">会议室3div>-->
                    <#--<div id="4" roomId="4" onclick="changeRoom(this.id)">会议室4div>-->
                div>
            div>
            <div class="layui-col-xs12 layui-col-md10">
                <div id='calendar'>div>
            div>
        div>
    div>
div>



<script  type="text/html" id="calendarForm">
    <form lay-filter="calendarForm" class="layui-form model-form">
        <input name="id" id="id" type="hidden"/>
        <div class="layui-form-item">
            <label class="layui-form-label">预约主题</label>
            <div class="layui-input-block">
                <input name="appointTheme" placeholder="请输入会议主题" type="text" class="layui-input" maxlength="50" lay-verify="required" required/>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">预约开始时间</label>
            <div class="layui-input-inline">
                <input type="text" class="layui-input" id="stime" name="stime" placeholder="HH:mm" lay-verify="required" required>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">预约结束时间</label>
            <div class="layui-input-inline">
                <input type="text" class="layui-input" id="etime" name="etime" placeholder="HH:mm" lay-verify="required" required>
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">预约人</label>
            <div class="layui-input-block">

                <input name="appointPerson" value="<#if currentUser.name!=''>${currentUser.name}<#else>${currentUser.loginName}" type="text" class="layui-input" maxlength="50" readonly />
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">联系方式</label>
            <div class="layui-input-block">
                <input name="tel" value="<#if currentUser.phone??>${currentUser.phone}" type="text" class="layui-input" maxlength="20" readonly />
            </div>
        </div>
        <div class="layui-form-item text-right">
            <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
            <button class="layui-btn" lay-filter="formSubmit" lay-submit>保存</button>
            <button class="layui-btn" type="button" id="delEdit" onclick="del()">删除</button>
        </div>
     </form>
script>


<script src='/fullcalendar/core/main.js'>script>
<script src='/fullcalendar/core/locales-all.js'>script>
<script src='/fullcalendar/daygrid/main.js'>script>
<script src='/fullcalendar/interaction/main.js'>script>
<script src='/fullcalendar/timegrid/main.js'>script>
<script src='/fullcalendar/core/locales/zh-cn.js'>script>
<script src="/assets/libs/jquery/jquery-3.2.1.min.js">script>
<script src='/fullcalendar/popper.min.js'>script>
<script src='/fullcalendar/tooltip.min.js'>script>
<script type="text/javascript" src="/assets/libs/layui/layui.all.js">script>
<script type="text/javascript" src="/assets/js/calendar/index.js">script>
body>
html>

3、对应的js

var addIndex;
var roomId;
var calendar;
var $ = layui.jquery;
var layer = layui.layer;
var form = layui.form;
var laydate = layui.laydate;

roomId = $("#room1").attr("roomId");
$("#room1").css("backgroundColor", "#003399");

document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');

    calendar = new FullCalendar.Calendar(calendarEl, {
        plugins: [ 'interaction', 'dayGrid', 'timeGrid' ],
        defaultView: 'dayGridMonth',
        // defaultDate: '2019-05-07',
        selectable: true, // dataClick生效
        locale: 'zh-cn', // 设置中文
        eventLimit: 4, // 显示更多
        displayEventEnd: true, // 显示结束时间
        header: {
            left: 'prev,next today',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,timeGridDay'
        },
        events: function(info, successCallback, failureCallback) {

            $.get("/erpcalendartask/getByParams", {roomId: roomId, sTime: info.start.valueOf(), eTime: info.end.valueOf()}, function (res) {
                if(res.code == 200) {
                    successCallback(res.data);
                }else {
                    failureCallback(res.errStr);
                }
            });
        }
        ,eventClick: function(info) {
            console.log('eventClick ' + info);
            openEditLayer(info);
        }
        ,dateClick: function(info) {
            console.log('dateClick ' + info.dateStr);
            openLayer(info);
        }
        ,eventRender: function(info) {
            var tooltip = new Tooltip(info.el, {
                title: popContent(info.event.title, info.event.extendedProps.appointPerson, info.event.start, info.event.end, info.event.extendedProps.tel),
                placement: 'top',
                trigger: 'hover',
                container: 'body',
                html: true
            });
        }
    });

    calendar.render();
});

function popContent(title, appointPerson, stime, etime, tel) {
    var sDate =new Date(stime);
    var s = sDate.getHours() + '点' + sDate.getMinutes() + '分';
    var eDate =new Date(etime);
    var e = eDate.getHours() + '点' + eDate.getMinutes() + '分';
    var str = '
' + title + '
'
; str += '
'
str += '
预订人:' + appointPerson + '
'
; str += '
预订时间:' + s + ' - ' + e + '
'
; str += '
预订电话:' + tel + '
'
return str; } $(document).ready(function () { }); function initDateCtrl() { //日期时间选择器 laydate.render({ elem: '#stime' //指定元素 ,type: 'time' ,format: 'HH:mm' ,done: function(value, date){ var etime = $("#etime").val(); var ehour = parseInt(etime.split(":")[0]); var eminute = parseInt(etime.split(":")[1]); var hour = date.hours; var minute = date.minutes; if(ehour < hour) { $("#finishtime").val(value); } else { if(eminute < minute) { $("#etime").val(value); } } } }); //日期时间选择器 laydate.render({ elem: '#etime' //指定元素 ,type: 'time' ,format: 'HH:mm' ,done: function(value, date){ var stime = $("#stime").val(); var shour = parseInt(stime.split(":")[0]); var sminute = parseInt(stime.split(":")[1]); var hour = date.hours; var minute = date.minutes; if(shour > hour) { $("#stime").val(value); } else { if(sminute > minute) { $("#stime").val(value); } } } }); } function openEditLayer(info){ addIndex=layer.open({ title : ' 编辑日程', type : 1, fix : false, skin : 'layui-layer-rim', // 加上边框 area : [ '470px', '450px' ], // 宽高 content : $('#calendarForm').html(), success: function (layero, index) { initDateCtrl(); $("#delEdit").show(); var data = {}; data.id = info.event.id; var sDate =new Date(info.event.start); data.stime = sDate.getHours() + ':' + sDate.getMinutes() ; var eDate =new Date(info.event.end); data.etime = eDate.getHours() + ':' + eDate.getMinutes() ; data.appointTheme = info.event.title; data.appointPerson = info.event.extendedProps.appointPerson; data.tel = info.event.extendedProps.tel; form.val('calendarForm', data); // 表单提交事件 form.on('submit(formSubmit)', function (d) { var dataStr = sDate.getFullYear() + '-' + (sDate.getMonth() + 1) + '-' + sDate.getDate(); d.field.roomId = roomId; d.field.stime = dataStr + " " + d.field.stime + ":00"; d.field.etime = dataStr + " " + d.field.etime + ":00"; $.ajax({ type: 'POST', url: '/erpcalendartask/update',//发送请求 contentType: "application/json; charset=utf-8", async: true, data: JSON.stringify(d.field), dataType: "json", success: function (res) { layer.closeAll("loading"); if(res.code == 200){ // layer.msg("添加成功!", {icon: 1}); calendar.refetchEvents(); layer.closeAll('page'); }else{ layer.msg(res.msg, {icon: 2}); } } }); return false; }); } }); } function openLayer(info){ addIndex=layer.open({ title : ' 新增日程', type : 1, fix : false, skin : 'layui-layer-rim', // 加上边框 area : [ '470px', '450px' ], // 宽高 content : $('#calendarForm').html(), success: function (layero, index) { initDateCtrl(); $("#delEdit").hide(); // 表单提交事件 form.on('submit(formSubmit)', function (d) { d.field.roomId = roomId; d.field.stime = info.dateStr + " " + d.field.stime + ":00"; d.field.etime = info.dateStr + " " + d.field.etime + ":00"; $.ajax({ type: 'POST', url: '/erpcalendartask/create',//发送请求 contentType: "application/json; charset=utf-8", async: true, data: JSON.stringify(d.field), dataType: "json", success: function (res) { layer.closeAll("loading"); if(res.code == 200){ // layer.msg("添加成功!", {icon: 1}); calendar.refetchEvents(); layer.closeAll('page'); }else{ layer.msg(res.msg, {icon: 2}); } } }); return false; }); } }); } function changeRoom(id){ $(".external-event").each(function(i){ if(this.id==id){ $(this).css("backgroundColor", "#003399"); roomId = $(this).attr("roomId"); }else{ $(this).css("backgroundColor", "#3366CC"); } }); calendar.refetchEvents(); } function del(){ var id=$("#id").val(); layer.confirm('确定要删除吗?', { offset: '65px', title: '提示' }, function (i) { layer.close(i); layer.load(2); $.post("/erpcalendartask/deleteByID", {id: id}, function (res){ layer.closeAll('loading'); if(res.code == 200){ // layer.msg("删除成功"); calendar.refetchEvents(); layer.closeAll('page'); }else{ layer.msg(res.message); } }); }); } // 所有ew-event $('body').on('click', '*[ew-event]', function () { var event = $(this).attr('ew-event'); if (event == 'closeDialog') { var id = $(this).parents('.layui-layer').attr('id').substring(11); layer.close(id); } });

考虑到Java服务端只是CRUD,避免文字的篇幅太长,所以大家如需继续研究,可以在git上下载:
https://github.com/chyanwu/erp-framework

更多精彩,更多技术请关注:码蚁在线(coding_online)
基于LayUI使用FullCalendar实现日程管理_第8张图片

你可能感兴趣的:(工作随笔)