FullCalendar中的重复事件
我正在使用jQuery FullCalendar作为我的网站中使用的日历可用性议程。
全日历中是否有任何function/方法/选项可以按天处理我的周期性事件? 例如,星期一只有上午7:00到上午9:00,星期二 – 下午4:00到9:00,这样的事情?
简单的重复事件
为了给这里列出的添加一个简单的select,Fullcalendar现在(有点)支持每周重复事件。 所以如果你只需要这样的东西: [Every Monday and Thursday from 10:00am to 02:00pm]
,你可以使用下面的内容:
events: [{ title:"My repeating event", start: '10:00', // a start time (10am in this example) end: '14:00', // an end time (2pm in this example) dow: [ 1, 4 ] // Repeat monday and thursday }],
的jsfiddle
这被logging在后台事件中,但是它也适用于常规事件。
保存到数据库不会很难。
添加一些限制
如果你不想让他们无限重复,你需要添加一些开始和结束date。
所以,在DB中:
- 让上面显示的事件代表父logging
- 有另一个表的开始/结束date。
- join表格示例:
eventId timeStart timeEnd dow dateStart dateEnd 1 10:00 12:00 [1,4] 2015/03/01 2015/04/01 // Month of March 1 10:00 12:00 [1,4] 2015/05/01 2015/06/01 // Month of May 1 10:00 12:00 [1,4] 2016/01/01 2017/01/01 // Year of 2017
以JSON的forms传递给客户端:
{ id:1, start:"10:00", end:"12:00", dow:[1,4], ranges[{start:"2015/03/01", end:"2015/04/01"}, {start:"2015/05/01", end:"2015/06/01"}, {start:"2016/01/01", end:"2017/01/01"},] }
而在客户端,使用fullcalendar的eventRender只在其中一个时间范围内呈现事件。 像这样的东西应该工作:
eventRender: function(event){ return (event.ranges.filter(function(range){ // test event against all the ranges return (event.start.isBefore(range.end) && event.end.isAfter(range.start)); }).length)>0; //if it isn't in one of the ranges, don't render it (by returning false) },
假设你的事件结构如下:
var repeatingEvents = [{ title:"My repeating event", id: 1, start: '10:00', end: '14:00', dow: [ 1, 4 ], ranges: [{ //repeating events are only displayed if they are within at least one of the following ranges. start: moment().startOf('week'), //next two weeks end: moment().endOf('week').add(7,'d'), },{ start: moment('2015-02-01','YYYY-MM-DD'), //all of february end: moment('2015-02-01','YYYY-MM-DD').endOf('month'), },/*...other ranges*/], },/*...other repeating events*/];
的jsfiddle
过夜
如果你想要一夜之间重复一些事件( 比如这里 ),只需在24:00
结束。 例如:
{ start: '10:00', //starts at 10 on monday end: '27:00', //24+3 is handled correctly. dow: [1] }
的jsfiddle
看看这个网站… http://fajitanachos.com/Fullcalendar-and-recurring-events/
它为经常性事件提供了很多好处。 FullCalendar确实支持关于id的重复事件。 您可以处理服务器端或客户端的事件,但首选项是服务器端。 我会给你一些想法,但不是全部包容。 正如我所了解的,经常性事件是一个难以维系的事情。
如果你想处理它们的客户端,你将不得不循环重复事件的频率和逻辑。 您可能需要使用eventRendercallback,然后使用选项callback来呈现每个循环的事件。 这个问题将是你仍然需要在数据库中保存频率选项和逻辑运算符。
(column1:frequency =(int)8,column2:type = enum(a'b'c),a = daily,b = weekly,c = monthly等)。
…然后,无论何时您编辑该事件,都将编辑所有事件。 如果您只需要删除一个事件,就会在逻辑中遇到一系列问题,并且很容易变成巨大的混乱。
第二个select是做所有这个服务器端。 创build两个表,其中一个包含父事件,第二个包含所有重复事件。 在父表中,您将存储一般信息,如独特的ID,颜色,背景颜色,标题,allDay,isRecurring,频率,types等。在子表中,您将使用父表中的唯一ID进行关联每一次重复(记住,如果你想删除/编辑个别事件的子表行,需要有自己的唯一ID以及一个标签列表所在的列)。 当你添加一个循环事件时,你需要添加一个枚举字段来标记它是否是一个循环事件或不是AKA …
柱:重复=枚举( '0', '1')—真/假
…然后你需要添加每个重复,到其具体的信息,如开始和结束等子表中。当你查询事件,你可以从父母查询,然后如果事件是重复获取这些事件关联第二个查询,或者您可以在一个查询中使用table1.id = table2.parentID上的INNER JOIN。
正如你所看到的,经常性事件可以非常快速地得到非常详细的信息,找出你需要什么逻辑,我希望这可以帮助你或者至less有人开始。 干杯。
在这里没有必要使父母和孩子的关系是提供简单的解决scheme,在jQuery中的循环事件的代码完整的日历使用下面的函数在你的PHP文件,你进一步调用所有的事件。
function render_fccalendar_events() { $_POST['start'] = strtotime('2013-05-01'); $_POST['end'] = strtotime('2013-05-31'); $start = date('Ym-d',$_POST['start']); $end = date('Ym-d', $_POST['end']); $readonly = (isset($_POST['readonly'])) ? true : false; $events = fcdb_query_events($start, $end); render_json(process_events($events, $start, $end, $readonly)); } function process_events($events, $start, $end, $readonly) { if ($events) { $output = array(); foreach ($events as $event) { $event->view_start = $start; $event->view_end = $end; $event = process_event($event, $readonly, true); if (is_array($event)) { foreach ($event as $repeat) { array_push($output, $repeat); } } else { array_push($output, $event); } } return $output; } } function process_event($input, $readonly = false, $queue = false) { $output = array(); if ($repeats = generate_repeating_event($input)) { foreach ($repeats as $repeat) { array_push($output, generate_event($repeat)); } } else { array_push($output, generate_event($input)); } if ($queue) { return $output; } render_json($output); } function generate_event($input) { $output = array( 'id' => $input->id, 'title' => $input->name, 'start' => $input->start_date, 'end' => $input->end_date, 'allDay' => ($input->allDay) ? true : false, //'className' => "cat{$repeats}", 'editable' => true, 'repeat_i' => $input->repeat_int, 'repeat_f' => $input->repeat_freq, 'repeat_e' => $input->repeat_end ); return $output; } function generate_repeating_event($event) { $repeat_desk = json_decode($event->repeat_desk); if ($event->repeat == "daily") { $event->repeat_int =0; $event->repeat_freq = $repeat_desk->every_day; } if ($event->repeat == "monthly") { $event->repeat_int =2; $event->repeat_freq = $repeat_desk->every_month; } if ($event->repeat == "weekly") { $event->repeat_int =1; $event->repeat_freq = $repeat_desk->every_weak; } if ($event->repeat == "year") { $event->repeat_int =3; $event->repeat_freq = $repeat_desk->every_year; } if ($event->occurrence == "after-no-of-occurrences") { if($event->repeat_int == 0){ $ext = "days"; } if($event->repeat_int == 1){ $ext = "weeks"; } if($event->repeat_int == 2){ $ext = "months"; } if($event->repeat_int == 3){ $ext = "years"; } $event->repeat_end = date('Ym-d',strtotime("+" . $event->repeat_int . " ".$ext)); } else if ($event->occurrence == "no-end-date") { $event->repeat_end = "2023-04-13"; } else if ($event->occurrence == "end-by-end-date") { $event->repeat_end = $event->end_date; } if ($event->repeat_freq) { $event_start = strtotime($event->start_date); $event_end = strtotime($event->end_date); $repeat_end = strtotime($event->repeat_end) + 86400; $view_start = strtotime($event->view_start); $view_end = strtotime($event->view_end); $repeats = array(); while ($event_start < $repeat_end) { if ($event_start >= $view_start && $event_start <= $view_end) { $event = clone $event; // clone event details and override dates $event->start_date = date(AEC_DB_DATETIME_FORMAT, $event_start); $event->end_date = date(AEC_DB_DATETIME_FORMAT, $event_end); array_push($repeats, $event); } $event_start = get_next_date($event_start, $event->repeat_freq, $event->repeat_int); $event_end = get_next_date($event_end, $event->repeat_freq, $event->repeat_int); } return $repeats; } return false; } function get_next_date($date, $freq, $int) { if ($int == 0) return strtotime("+" . $freq . " days", $date); if ($int == 1) return strtotime("+" . $freq . " weeks", $date); if ($int == 2) return get_next_month($date, $freq); if ($int == 3) return get_next_year($date, $freq); } function get_next_month($date, $n = 1) { $newDate = strtotime("+{$n} months", $date); // adjustment for events that repeat on the 29th, 30th and 31st of a month if (date('j', $date) !== (date('j', $newDate))) { $newDate = strtotime("+" . $n + 1 . " months", $date); } return $newDate; } function get_next_year($date, $n = 1) { $newDate = strtotime("+{$n} years", $date); // adjustment for events that repeat on february 29th if (date('j', $date) !== (date('j', $newDate))) { $newDate = strtotime("+" . $n + 3 . " years", $date); } return $newDate; } function render_json($output) { header("Content-Type: application/json"); echo json_encode(cleanse_output($output)); exit; } function cleanse_output($output) { if (is_array($output)) { array_walk_recursive($output, create_function('&$val', '$val = trim(stripslashes($val));')); } else { $output = stripslashes($output); } return $output; } function fcdb_query_events($start, $end) { global $wpdb; $limit = ($limit) ? " LIMIT {$limit}" : ""; $result = $wpdb->get_results("SELECT id, name,start_date,end_date,repeat_desk,`repeat`,occurrence,occurrence_desk FROM " . $wpdb->prefix . "lgc_events WHERE ( (start_date >= '{$start}' AND start_date < '{$end}') OR (end_date >= '{$start}' AND end_date < '{$end}') OR (start_date <= '{$start}' AND end_date >= '{$end}') OR (start_date < '{$end}' AND (`repeat`!= '')) ) ORDER BY start_date{$limit};"); return return_result($result); } function return_result($result) { if ($result === false) { global $wpdb; $this->log($wpdb->print_error()); return false; } return $result; }
在上面的代码中我使用了repeat_desk,其中我存储重复频率的json代码
和jquery调用你的文件
events: { url: '<?php echo $lgc_plugindir; ?>includes/imagerotator.php', data: { action: 'get_events' }, type: 'POST' }
我用这个WordPress的,你可以使用这个代码根据您的要求
目前我正在做项目,我有FullCalendar,我不得不做周期性事件。 所以这是我为什么可以做的。 希望这个代码有助于人:)
我有数据库中的下一个表:
CREATE TABLE IF NOT EXISTS `app_ext_calendar_events` ( `id` int(11) NOT NULL AUTO_INCREMENT, `users_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `description` text, `start_date` int(11) NOT NULL, `end_date` int(11) NOT NULL, `event_type` varchar(16) NOT NULL, `is_public` tinyint(1) DEFAULT NULL, `bg_color` varchar(16) DEFAULT NULL, `repeat_type` varchar(16) DEFAULT NULL, `repeat_interval` int(11) DEFAULT NULL, `repeat_days` varchar(16) DEFAULT NULL, `repeat_end` int(11) DEFAULT NULL, `repeat_limit` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_users_id` (`users_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=18 ;
我开发了下一个php类来获得重复事件的事件:
<?php class calendar { static public function get_events($date_from, $date_to,$calendar_type) { global $app_user; $list = array(); $events_query = db_query("select * from app_ext_calendar_events where FROM_UNIXTIME(start_date,'%Y-%m-%d')>='" . $date_from . "' and FROM_UNIXTIME(end_date,'%Y-%m-%d')<='" . $date_to . "' and event_type='" . $calendar_type . "' and users_id='" . db_input($app_user['id']) . "'"); while($events = db_fetch_array($events_query)) { $list[] = $events; } if(count($repeat_events_list = calendar::get_repeat_events($date_to,$calendar_type))) { $list = array_merge($list,$repeat_events_list); } return $list; } public static function weeks_dif($start, $end) { $year_start = date('Y',$start); $year_end = date('Y',$end); $week_start = date('W',$start); $week_end = date('W',$end); $dif_years = $year_end - $year_start; $dif_weeks = $week_end - $week_start; if($dif_years==0 and $dif_weeks==0) { return 0; } elseif($dif_years==0 and $dif_weeks>0) { return $dif_weeks; } elseif($dif_years==1) { return (42-$week_start)+$week_end; } elseif($dif_years>1) { return (42-$week_start)+$week_end+(($dif_years-2)*42); } } public static function months_dif($start, $end) { // Assume YYYY-mm-dd - as is common MYSQL format $splitStart = explode('-', date('Y-n',$start)); $splitEnd = explode('-', date('Y-n',$end)); if (is_array($splitStart) && is_array($splitEnd)) { $startYear = $splitStart[0]; $startMonth = $splitStart[1]; $endYear = $splitEnd[0]; $endMonth = $splitEnd[1]; $difYears = $endYear - $startYear; $difMonth = $endMonth - $startMonth; if (0 == $difYears && 0 == $difMonth) { // month and year are same return 0; } else if (0 == $difYears && $difMonth > 0) { // same year, dif months return $difMonth; } else if (1 == $difYears) { $startToEnd = 13 - $startMonth; // months remaining in start year(13 to include final month return ($startToEnd + $endMonth); // above + end month date } else if ($difYears > 1) { $startToEnd = 13 - $startMonth; // months remaining in start year $yearsRemaing = $difYears - 2; // minus the years of the start and the end year $remainingMonths = 12 * $yearsRemaing; // tally up remaining months $totalMonths = $startToEnd + $remainingMonths + $endMonth; // Monthsleft + full years in between + months of last year return $totalMonths; } } else { return false; } } public static function get_repeat_events($date_to,$calendar_type) { global $app_user; //convert date to timestamp $date_to_timestamp = get_date_timestamp($date_to); $list = array(); //get all events that already started (start_date<=date_to) $events_query = db_query("select * from app_ext_calendar_events where length(repeat_type)>0 and FROM_UNIXTIME(start_date,'%Y-%m-%d')<='" . $date_to . "' and event_type='" . $calendar_type . "' and users_id='" . db_input($app_user['id']) . "'"); while($events = db_fetch_array($events_query)) { $start_date = $events['start_date']; //set repeat end $repeat_end = false; if($events['repeat_end']>0) { $repeat_end = $events['repeat_end']; } //get repeat events by type switch($events['repeat_type']) { case 'daily': //check repeat events day bay day for($date = $start_date; $date<=$date_to_timestamp; $date+=86400) { if($date>$start_date) { $dif = round(abs($date-$start_date)/86400); if($dif>0) { $event_obj = $events; $event_obj['start_date'] = strtotime('+' . $dif . ' day',$event_obj['start_date']); $event_obj['end_date'] = strtotime('+' . $dif . ' day',$event_obj['end_date']); if(calendar::check_repeat_event_dif($dif,$event_obj,$repeat_end)) { $list[] = $event_obj; } } } } break; case 'weekly': //check repeat events day bay day for($date = $start_date; $date<=$date_to_timestamp; $date+=86400) { if($date>$start_date) { //find days dif $dif = round(abs($date-$start_date)/86400); //find week dif $week_dif = calendar::weeks_dif($start_date, $date); if($dif>0 and (in_array(date('N',$date),explode(',',$events['repeat_days'])))) { $event_obj = $events; $event_obj['start_date'] = strtotime('+' . $dif . ' day',$event_obj['start_date']); $event_obj['end_date'] = strtotime('+' . $dif . ' day',$event_obj['end_date']); if(calendar::check_repeat_event_dif($week_dif,$event_obj,$repeat_end)) { $list[] = $event_obj; } } } } break; case 'monthly': /** *in calendar we display 3 month in one view *so we have to check difference for each month */ //check 1 $date_to_timestamp2 = strtotime('-2 month',$date_to_timestamp); $dif = calendar::months_dif($start_date, $date_to_timestamp2); if($dif>0) { $event_obj = $events; $event_obj['start_date'] = strtotime('+' . $dif . ' month',$event_obj['start_date']); $event_obj['end_date'] = strtotime('+' . $dif . ' month',$event_obj['end_date']); if(calendar::check_repeat_event_dif($dif,$event_obj,$repeat_end)) { $list[] = $event_obj; } } //check 2 $date_to_timestamp1 = strtotime('-1 month',$date_to_timestamp); $dif = calendar::months_dif($start_date, $date_to_timestamp1); if($dif>0) { $event_obj = $events; $event_obj['start_date'] = strtotime('+' . $dif . ' month',$event_obj['start_date']); $event_obj['end_date'] = strtotime('+' . $dif . ' month',$event_obj['end_date']); if(calendar::check_repeat_event_dif($dif,$event_obj,$repeat_end)) { $list[] = $event_obj; } } //check 3 $dif = calendar::months_dif($start_date, $date_to_timestamp); if($dif>0) { $event_obj = $events; $event_obj['start_date'] = strtotime('+' . $dif . ' month',$event_obj['start_date']); $event_obj['end_date'] = strtotime('+' . $dif . ' month',$event_obj['end_date']); if(calendar::check_repeat_event_dif($dif,$event_obj,$repeat_end)) { $list[] = $event_obj; } } break; case 'yearly': $dif = date('Y',$date_to_timestamp)-date('Y',$start_date); if($dif>0) { $events['start_date'] = strtotime('+' . $dif . ' year',$events['start_date']); $events['end_date'] = strtotime('+' . $dif . ' year',$events['end_date']); if(calendar::check_repeat_event_dif($dif,$events,$repeat_end)) { $list[] = $events; } } break; } } return $list; } static public function check_repeat_event_dif($dif,$events,$repeat_end) { $check = true; if($dif>0) { //check interval if($dif/$events['repeat_interval']!=floor($dif/$events['repeat_interval'])) $check=false; //check repeat limit if($events['repeat_limit']>0) if(floor($dif/$events['repeat_interval'])>$events['repeat_limit']) $check=false; } else { $check=false; } //check repeat end date if($repeat_end>0) { if($repeat_end<$events['start_date']) { $check=false; } } return $check; } }
函数get_events以我的方式获取所有事件+重复事件有四种types的重复事件:每天,每周,每月,每年+有重复间隔,重复date结束和重复限制。
函数get_repeat_events计算每种types的事件的差异,如果存在则包括重复事件。
注意:函数db_query()可以replace为myslq_query或其他东西
准备事件到FullCalendar我正在使用下一个代码
$list = array(); foreach(calendar::get_events($_GET['start'],$_GET['end'],'personal') as $events) { $start = date('Ymd H:i',$events['start_date']); $end = date('Ymd H:i',$events['end_date']); $list[] = array('id' => $events['id'], 'title' => addslashes($events['name']), 'description' => str_replace(array("\n\r","\n","\r"),'<br>',$events['description']), 'start' => str_replace(' 00:00','',$start), 'end' => str_replace(' 00:00','',$end), 'color'=> $events['bg_color'], 'allDay'=>(strstr($start,'00:00') and strstr($end,'00:00')), 'url' => url_for('ext/calendar/personal_form','id=' . $events['id']) ); } echo json_encode($list);
这似乎在eventRender中很好地工作:function(event,element){}
EXAMPLE JSON: var json = [{title: "All Day Event", start: "2015-12-22T00:00", end: "2015-12-22T23:55", dow: [2,4], recurstart: moment("2015-12-22").startOf("week"), recurend: moment("2015-12-22").endOf("week").add(1,'w')},{ title: "Long Event", start: "2015-12-21T00:00", end: "2015-12-24T23:55", recurstart: moment("2015-12-21").startOf("month"), recurend: moment("2015-12-24").endOf("month"), }]; eventRender: function(event, element){ var theDate = moment(event.start).format("YYYY-MM-DD"); var startDate = event.recurstart; var endDate = event.recurend; if (startDate < theDate && theDate < endDate) { console.log(theDate); } else { return event.length>0; } }, /* End eventRender */
1)在JSON中设置一个开始/结束date和时间。
2)在JSON中创build两个自定义的重复开始和重复结束。
3)使用moment.js创build重复持续时间: http ://momentjs.com/docs/#/durations/。
4)重复开始使用(开始:)date查明星期的开始。
5)重复结束使用(结束:)date查明周末+增加1周。
6)增加1,2,3周可以创build循环限制。
7)添加名为(recurlimit:“”)的另一部分JSON可以pipe理循环限制。
8)在eventRender中使用variables – 设置我的例子使用的date(theDate)是时刻(event.start)。 这是正确的格式,这样的开始/结束/ recursart等所有匹配格式,即(YYYY-MM-DD) http://momentjs.com/docs/#/displaying/format/是很重要的; 。
9)自定义recurstartvariables
10)自定义recurend的variables
11)使用IF语句查看(theDate)在(recurstart)和(recurend)之间的天气 – logging结果
12)使用ELSE语句返回长度> 0,以隐藏不属于该参数的其他事件。
13)非经常性事件必须有一个时间(“匹配开始date”),startOf(“月”)和矩(“匹配开始date”),endOf(“月”),否则他们将不可见。
现在有一个插件,将做你想要的: http : //momentjs.com/docs/#/plugins/recur/