工作中因为需要课表方面的显示,所以为了方便就用到了一个开源的日历插件,中遇到了一些问题;因此做一个小小的汇总,希望能对大家有一些帮助!
首先 发一下文档的地址:https://fullcalendar.io/
1.如何通过ajax展示数据。
为了方便展示数据最好把数据库的字段对应上,这样的话数据库中的数据直接映射进Model的话就可以直接把Model转成json串而不用根据fullcalendar所需要的json串的模式进行更改,数据库设计如下:
layui.use('form', function(){
var form = layui.form;
var calendar = $('#calendar');
form.on("submit(query)", function(data){
calendar.fullCalendar('refetchEvents');//重新渲染事件,这里就相当与重新执行events,这里的主要场景就是上面有一个搜索框,通过点击搜索,重新执行events中的ajax
return false;
});
var myfn = {
initCalendar : function () {
var me = this;
calendar.fullCalendar({
weekNumbers:true,
firstDay: 1,
defaultView: 'agendaDay',
allDaySlot: false,
allDayDefault: false,
minTime: "9:00",
header: {
left: 'prev,next today',
center: 'title',
right: 'agendaWeek,agendaDay'
},
editable: false,//不允许拖拽调整
navLinks: true, // 显示导航栏
eventLimit: true, // 事件太多时, 折叠展示
events: function(start, end, timezone, callback) {
$.ajax({
url: '/schedule/todayCalendar/todayCalendarJson',
dataType: 'json',
type : 'post',
data: {
start: start.unix(),
end: end.unix(),
'_query.w_lk.s.studentName' : $("#studentName").val(),
'_query.w_lk.s.teacherName' : $("#teacherName").val(),
'_query.w_lk.s.roomName' : $("#roomName").val(),
'_query.w_eq.p.courseId' : $("#courseName").val()
},
success: function(doc) {
callback(doc); //回调 doc中就是一个个上面所说数据库的model的json串
}
});
},
timeFormat: 'H(:mm)',
eventMouseover: function( event, jsEvent, view ) { //鼠标划过的事件
layer.tips(event.remarks, this, {tips : 1});
},
eventMouseout:function( event, jsEvent, view ) { //鼠标离开的事件
var index = layer.tips();
layer.close(index);
},
eventClick: function(eventObj) {//这里是事件的点击事件
layer.open({
type: 2,
title: '课表操作',
shadeClose: true,
shade: false,
maxmin: true, //开启最大化最小化按钮
area: ['893px', '600px'],
content: '/schedule/todayCalendar/todayCalendarOperator/' + eventObj.id
});
},
});
}
}
myfn.initCalendar(); //初始化fullcalendar,也就是绘制日历
});
这就是一个基础的日历的展示的功能,因为前端框架用的layui所以其中出现了layui字段;这都可以忽略!
上面的js要注意的地方主要是重新渲染日历中的事件要用到$("#生成日历的div的Id").fullCalendar('refetchEvents');
还有就是events中的callback() ,其中要传一个以日历需要数据的json串,如果以之前所说的数据库表数据生成的json串就没问题,要不然就自己给一个json串 类似{start:'2018-01-12 20:36:11', end :'2018-01-12 20:56:11' , title: 'test'} 也是没问题的;
eventMouseover和eventMouseout主要是为了展示课程的细节
2.如何让用户禁止点击某个时间段
业务背景:其中有一个需求要通过点击课表进行排课,然后为了防止排课的时间段发生重叠,还有防止老师,教室发生冲突,需要在日历中以灰块标志出来!
layui.use('form', function(){
var form = layui.form;
//回显之前有的课程 以及老师的上课事件教室占用的事件
$.post("/schedule/calendar/showClass", data.field,
function(msg){
//进行禁止点击 的 设置
myfn.businessTimes = [];
$.post("/schedule/calendar/getTeacherAndRoomBussiness", data.field, function(info){
myfn.pushBusinessTimes(msg);
var info2 = new Array();
$.extend(true, info2, info);//这里遇到一个大坑,因为一直以为info和info2为不同的对象改变info时info2不会受影响,所以之前两行代码是用var info2 = info.concat();但一直都是info变的话info2也会变;后来就觉得info和info2虽然是不同的对象,但他们引用的字符串是一样的;所以会变
msg = msg.concat(info2);
for(var i in info) {
info[i].start = info[i].dateStr + " " + info[i].start;
info[i].end = info[i].dateStr + " " + info[i].end;
}
myfn.pushBusinessTimes(info);
$("#calendar").fullCalendar('removeEvents');//移除日历中原有的事件
$("#calendar").fullCalendar('renderEvents', msg, true);//添加事件
});
});
form.on('select(change)', function(data){
myfn.saveData();
$("#calendar").fullCalendar('destroy');//摧毁日历,一般是想对日历中的参数修改的情况用到这个(像修改businessHours),然后再重新‘画’一个日历
});
var myfn={
formData : null,
//获取日期格式化后的
businessTimes : [
],//这个主要是记录不能点击的区域时间
removeBusinessTimes : function(id){//移除日历中时间时候,移除BusinessTimes
var business = myfn.businessTimes;
for(var i in business) {
if(business[i].id == id) {
business.splice(i, 1);
}
}
},
pushBusinessTimes : function(msg) {//添加BusinessTimes的方法
for(var i in msg) {
var temp = {id : msg[i].id, start : Number(new Date(msg[i].start)) / 1000, end : Number(new Date(msg[i].end)) / 1000};
myfn.businessTimes.push(temp);
}
},
compireTime : function(start, end) {//比较BusinessTimes和点击区域的时间
var busyTime = myfn.businessTimes;
var clickTime = {start : start, end : end};
for(var i in busyTime) {
if(!myfn.checkTime(clickTime, busyTime[i])) {
return false;
}
}
return true;
},
checkTime : function(timeScope1, timeScope2) {
if(timeScope1.start >= timeScope2.end) {
return true;
}
if(timeScope1.start < timeScope2.start) {
if(timeScope1.end <= timeScope2.start) {
return true;
}
}
return false;
},
createCalendarConfig : {
weekNumbers:true,
selectable: true,
firstDay: 1,
timezone: 'local',
defaultView: 'agendaWeek',
allDaySlot: false,
allDayDefault: false,
minTime: "9:00",
maxTime: "22:00",
header: false,
editable: false,//不允许拖拽调整
navLinks: true, // 显示导航栏
businessHours : false,
eventLimit: true, // 事件太多时, 折叠展示
timeFormat: 'HH:mm',
select:function(start, end, jsEvent) { //点击日历上的某个时间触发的函数
//添加 记录
},
selectAllow : function(clickInfo) {//可不可以点击主要是通过这个方法来限定,返回false就不能点击
var start = clickInfo.start.unix();
var end = start + 60 * myfn.formData.para_classTime;
if(myfn.compireTime(start, end)) {
return true;
}
return false;
},
eventClick: function(eventObj) {
}
},
createCalendar: function() {
$("#calendar").fullCalendar(myfn.createCalendarConfig);
}
});
这里的主要判断思想就是把不能点击的时间放在一个字符串中,然后每次点击通过selectAllow方法去判断点击要不要触发事件!
但是类似那种有教室被占用的情况,也就是不能有select事件的区域是一个一个事件的时候,可以通过events返回特定的数据结构来禁止点击事件;
events中的json串可以返回这样的结构
[
{
id: 'available_hours',
start: '2015-1-13T8:00:00',
end: '2015-1-13T19:00:00',
rendering: 'background'
color:'gray'
},
{
id: 'work',
start: '2015-1-13T10:00:00',
end: '2015-1-13T16:00:00',
rendering: 'background'
color:'gray'
}
]
这样就不需要用businessHours了,因为businessHours json串中定义的是可以使用的时间,也就是不要阴影的时间,而且对与阴影部分插件也没有加什么限制,只不过是把样式改了一下,感觉比较坑!