引言
最新工作中需要实现日程管理功能,由于技术选型(基于layui)限制,从网上对比查询最终选定使用FullCalendar插件来实现日程管理。
其中对比的日程还有XgCalendar、Google Calendar
实现效果
1、打开界面后,月视图
2、切换到周视图
3、切换到日视图
4、在月视图,添加会议室预订
6、在月视图,鼠标移到event,显示详情
对应实现
1、依赖的js
下载路径:https://fullcalendar.io/docs/getting-started
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