Javascript 完整日历、营业时间和日期范围

Javascript 完整日历、营业时间和日期范围,javascript,fullcalendar,Javascript,Fullcalendar,在我的项目中,用户可以预订房间。我的房间有争议时间,如08:00-17:00。我尽量利用营业时间,但争议在夏季和冬季会发生变化 我还尝试使用日期范围为的反向背景事件,如,但如果使用selectConstraint,则不考虑该范围 最好是将日期范围添加到营业时间,但它似乎尚未实现 有人能解决我的需要吗 谢谢 编辑:这是我的完整日历选项 function FCInit(){ var formatColumn, formatColumnWeek; // Entete

在我的项目中,用户可以预订房间。我的房间有争议时间,如08:00-17:00。我尽量利用营业时间,但争议在夏季和冬季会发生变化

我还尝试使用日期范围为的反向背景事件,如,但如果使用selectConstraint,则不考虑该范围

最好是将日期范围添加到营业时间,但它似乎尚未实现

有人能解决我的需要吗

谢谢

编辑:这是我的完整日历选项

function FCInit(){
        var formatColumn, formatColumnWeek;

        // Entete des colonnes
        if ($(window).width() < 600) {
            formatColumn = 'ddd';
            formatColumnWeek = 'ddd\nDD/MM';
        }
        else {
            formatColumn = 'dddd';
            formatColumnWeek = 'dddd\nDD/MM';
        }

        var fcOpts = {

            header: {                               
                left: 'today,datePickerButton',
                center: 'prev,title,next',
                right: 'month,agendaWeek,agendaDay'
            },

            contentHeight: 'auto',                  
            eventLimit: false,                      
            allDaySlot: true,                       
            slotEventOverlap: false,                    
            nowIndicator: true,                     
            timeFormat: 'H:mm',                     
            columnFormat: formatColumn,             // Format des jours dans l'entete     ddd: Mon  /  ddd M/D : Mon 09/07  /  dddd : MOnday /
            navLinks: true,                         

            eventOverlap: false,                        
            selectable: true,
            selectHelper: true,
            selectOverlap: true,
            selectConstraint:999,
            unselectCancel: '#reservation',
            views: {                                
                week: {
                    columnFormat: formatColumnWeek
                }
            },

            events:[{
                     id:3,
                     title:"R\u00e9serv\u00e9",
                     start:"2017-11-02 08:00",
                     end:"2017-11-02 10:00",
                     overlap:false,
                     color:"#C41305"
            },{
                     id:999,
                     className:"fc-nonbusiness",
                     title:"",
                     start:"08:00",
                     end:"17:00",
                     dow:[4],
                     ranges:[
                        {
                          start:"2017-11-01",
                          end:"2017-11-30"
                        }
                     ],
                     rendering:"inverse-background",
            }],

            /* Ajout de datepicker (nécessite Jquery UI css et js) */
            customButtons: {
                datePickerButton: {
                    text: '',
                    click: function () {

                        var $btnCustom = $('.fc-datePickerButton-button'); // name of custom  button in the generated code
                        $btnCustom.after('<input type="hidden" id="hiddenDate" class="datepicker"/>');

                        $("#hiddenDate").datepicker({
                            flat: true,
                            showOn: "button",
                            dateFormat: "yy-mm-dd",
                            onSelect: function (dateText, inst) {
                                $('#full-calendar').fullCalendar('changeView', 'agendaDay', dateText);
                            }
                        });

                        var $btnDatepicker = $(".ui-datepicker-trigger"); // name of the generated datepicker UI
                        //Below are required for manipulating dynamically created datepicker on custom button click
                        $("#hiddenDate").show().focus().hide();
                        $btnDatepicker.trigger("click"); //dynamically generated button for datepicker when clicked on input textbox
                        $btnDatepicker.hide();
                        $btnDatepicker.remove();
                        $("input.datepicker").not(":first").remove();//dynamically appended every time on custom button click

                    }
                }
            },
            dayRender: function(date, cell){
                if(date.isBefore(new Date())){
                    cell.css('cursor','no-allowed');
                }
            },

            eventRender: function (event, element) {

                if(event.ranges) {
                    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(event.rendering === "background"){
                    // Just add some text or html to the event element.
                    element.append("<div class='fc-title'>"+event.title+"</div>");
                }

            },
            dayClick: function(date, jsEvent, view){
                if(date.isSameOrAfter(new Date()) && view.name === 'month'){
                    $('#full-calendar').fullCalendar('changeView', 'agendaWeek', date);
                }
            },
            select: function(start, end, jsEvent, view){
                if(start.isSameOrAfter(new Date()) && view.name !== 'month'){
                    $('#reservation_dateFrom').val(start.format('DD/MM/YYYY HH:mm'));
                    $('#reservation_dateTo').val(end.format('DD/MM/YYYY HH:mm'));
                    $('#reservation').modal('show');
                }else if(start.isBefore(new Date())){
                    alert('Il n\'est pas possible de réserver dans le passé');
                    $('#full-calendar').fullCalendar('unselect');
                }

            }

        };
        $('#full-calendar').fullCalendar(fcOpts);

    };

多亏了@ADyson,我或多或少做了我想做的事。这是我的解决办法

function isAllowed(start, end) {

        var events = $('#full-calendar').fullCalendar('clientEvents', function (event) {
            return event.rendering === 'inverse-background' && event.start && event.end;
        });

        var allow = events.filter(function (event) {
            return (start.isBetween(moment(new Date(event.ranges[0].start)), moment(new Date(event.ranges[0].end)))
                && end.isBetween(moment(new Date(event.ranges[0].start)), moment(new Date(event.ranges[0].end)))
                && start.format("HH:mm") >= event.start.format("HH:mm") && end.format("HH:mm") <= event.end.format("HH:mm")
                && event.dow.indexOf(start.day()) > -1
                && event.dow.indexOf(end.day()) > -1)
        });

        events = $('#full-calendar').fullCalendar('clientEvents', function (event) {
            return event.rendering !== 'inverse-background' && event.start && event.end;
        });


        var overlap = events.filter(function (event) {
            return event.start.isBefore(end) && event.end.isAfter(start);
        });

        if (allow.length && overlap.length == 0) {
            return true;
        }
        return false;
    }

    function FCInit() {
        var formatColumn, formatColumnWeek;

        if ($(window).width() < 600) {
            formatColumn = 'ddd';
            formatColumnWeek = 'ddd\nDD/MM';
        }
        else {
            formatColumn = 'dddd';
            formatColumnWeek = 'dddd\nDD/MM';
        }

        var fcOpts = {
            header: {                               // Ordre des boutons de l'entete
                left: 'today,datePickerButton',
                center: 'prev,title,next',
                right: 'month,agendaWeek,agendaDay'
            },

            contentHeight: 'auto',                  
            eventLimit: false,                      
            allDaySlot: true,                   
            slotEventOverlap: false,            
            nowIndicator: true,                                     
            timeFormat: 'H:mm',                     
            columnFormat: formatColumn,             
            navLinks: true,                                             
            eventOverlap: false,
            selectable: true,
            selectHelper: true,
            {% if businessHours is defined and businessHours is not empty %}
            selectAllow: function (eventInfo) {
                return isAllowed(eventInfo.start, eventInfo.end);
            },
            {% else %}
            selectOverlap: false,
            {% endif %}
            unselectCancel: '#reservation',
            views: {                                
                week: {
                    columnFormat: formatColumnWeek
                }
            },

            events: [{
                 id:3,
                 title:"R\u00e9serv\u00e9",
                 start:"2017-11-02 08:00",
                 end:"2017-11-02 10:00",
                 overlap:false,
                 color:"#C41305"
        },{
                 id:999,
                 className:"fc-nonbusiness",
                 title:"",
                 start:"08:00",
                 end:"17:00",
                 dow:[4],
                 ranges:[
                    {
                      start:"2017-11-01",
                      end:"2017-11-30"
                    }
                 ],
                 rendering:"inverse-background",
                 }],

            /* Ajout de datepicker (nécessite Jquery UI css et js) */
            customButtons: {
                datePickerButton: {
                    text: '',
                    click: function () {

                        var $btnCustom = $('.fc-datePickerButton-button'); // name of custom  button in the generated code
                        $btnCustom.after('<input type="hidden" id="hiddenDate" class="datepicker"/>');

                        $("#hiddenDate").datepicker({
                            flat: true,
                            showOn: "button",
                            dateFormat: "yy-mm-dd",
                            onSelect: function (dateText, inst) {
                                $('#full-calendar').fullCalendar('changeView', 'agendaDay', dateText);
                            }
                        });

                        var $btnDatepicker = $(".ui-datepicker-trigger"); // name of the generated datepicker UI
                        //Below are required for manipulating dynamically created datepicker on custom button click
                        $("#hiddenDate").show().focus().hide();
                        $btnDatepicker.trigger("click"); //dynamically generated button for datepicker when clicked on input textbox
                        $btnDatepicker.hide();
                        $btnDatepicker.remove();
                        $("input.datepicker").not(":first").remove();//dynamically appended every time on custom button click

                    }
                }
            },
            dayRender: function (date, cell) {
                if (date.isBefore(new Date())) {
                    cell.css('cursor', 'no-allowed');
                }
            },

            eventRender: function (event, element, view) {

                if (event.rendering === 'inverse-background' && event.ranges) {
                    return (event.ranges.filter(function (range) { // test event against all the ranges

                        var start = moment(new Date(range.start));
                        var end = moment(new Date(range.end));
                        return (view.start.isSameOrBefore(end) &&
                            view.end.isSameOrAfter(start)) &&
                            view.start.day(event.dow[0]).isBetween(start, end);

                    }).length > 0);
                }

                if (event.rendering === "background") {
                    // Just add some text or html to the event element.
                    $(element).data("title",event.title);
                }

            },
            dayClick: function (date, jsEvent, view) {
                if (date.isSameOrAfter(new Date()) && view.name === 'month') {
                    $('#full-calendar').fullCalendar('changeView', 'agendaWeek', date);
                }
            },
            select: function (start, end, jsEvent, view) {
                if (start.isSameOrAfter(new Date()) && view.name !== 'month') {
                    $('#reservation_dateFrom').val(start.format('DD/MM/YYYY HH:mm'));
                    $('#reservation_dateTo').val(end.format('DD/MM/YYYY HH:mm'));
                    $('#reservation').modal('show');
                } else if (start.isBefore(new Date())) {
                    alert('Il n\'est pas possible de réserver dans le passé');
                    $('#full-calendar').fullCalendar('unselect');
                }

            }

        };
        $('#full-calendar').fullCalendar(fcOpts);

工作示例fullcalendar动态道琼斯指数范围

假设您需要在以下日期范围之间设置事件

start: "2018-06-01",

end: "2018-08-01"

你做了什么请分享你的代码最好的事情是让你的代码检查它运行的日期,并相应地设置工作时间。在服务器上,您可以将一年中不同时间的小时数存储在数据库中。如果用户更改fullCalendar中查看的日期,请处理该更改事件,重新检查显示的日期,并根据需要更改“工作时间”选项。我敢肯定那会有用的。或者,您可以使用具有自定义重叠规则的背景事件来停止超出特定范围的事件。刚刚看到您的编辑。您可以将selectOverlap:true替换为一个自定义函数,该函数检查重叠的事件是否为反向背景事件,并使用该函数确定是否允许重叠。请参阅@ADyson。问题是selectOverlap没有在事件的相反部分调用,因此检查不会在事件之外进行。有趣的是,我不知道这一点。如何使用一些自定义代码来引用您的日期和时间范围。将来,请在您的帖子中包含所有相关代码,而不仅仅是包含代码托管站点的链接。你的帖子应该独立于任何其他资源;考虑一下如果这个网站将来会发生什么情况!
start: "2018-06-01",

end: "2018-08-01"