You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效获取摩托车分类下全量预订的连续日期范围以适配FullCalendar背景事件

如何高效获取摩托车分类下全量预订的连续日期范围以适配FullCalendar背景事件

我正在使用FullCalendar.js库来可视化租赁公司的预订信息。我把摩托车按引擎排量分类存储为数组,每个分类下的children数组包含该类别的所有具体车辆,示例如下:

// The resources array contains information about the motorbikes in a rental store.
// The parent array contains the information about the motorbike engine, 
// while the children array contains the information about the unique motorbikes belonging to each engine category.
resources = [{
    id: "scooter50",
    title: "Scooter 50",
    children: [{
            id: "aa123ab",
            title: "AA 123 AB"
        },
        {
            id: "aa456cd",
            title: "AA 456 CD"
        },
        {
            id: "aa789ef",
            title: "AA 789 EF"
        },
        {
            id: "aa101gh",
            title: "AA 101 GH"
        }
    ]
},
{
    id: "scooter125",
    title: "Scooter 125",
    children: [{
            id: "bb123ab",
            title: "BB 123 AB"
        },
        {
            id: "bb456cd",
            title: "BB 456 CD"
        },
        {
            id: "bb789ef",
            title: "BB 789 EF"
        },
        {
            id: "bb101gh",
            title: "BB 101 GH"
        }
    ]
},
{
    id: "scooter250",
    title: "Scooter 250",
    children: [{
            id: "cc123ab",
            title: "CC 123 AB"
        },
        {
            id: "cc456cd",
            title: "CC 456 CD"
        },
        {
            id: "cc789ef",
            title: "CC 789 EF"
        },
        {
            id: "cc101gh",
            title: "CC 101 GH"
        }
    ]
}
];

另外,我有一些关联到具体车辆的预订事件:

// The events array contains information about the motorbikes that are rented, including the start and end date of the rental.
events = [{
    start: new Date(2025, 0, 6, 0, 0),
    end: new Date(2025, 0, 9, 23, 59, 59),
    resourceId: "bb101gh",
    title: "Event 0"
},
{
    start: new Date(2025, 0, 11, 0, 0),
    end: new Date(2025, 0, 14, 23, 59, 59),
    resourceId: "bb101gh",
    title: "Event 1"
},
{
    start: new Date(2025, 0, 7, 0, 0),
    end: new Date(2025, 0, 11, 23, 59, 59),
    resourceId: "bb123ab",
    title: "Event 2"
},
{
    start: new Date(2025, 0, 9, 0, 0),
    end: new Date(2025, 0, 14, 23, 59, 59),
    resourceId: "bb456cd",
    title: "Event 3"
},
{
    start: new Date(2025, 0, 7, 0, 0),
    end: new Date(2025, 0, 10, 23, 59, 59),
    resourceId: "bb789ef",
    title: "Event 4"
},
{
    start: new Date(2025, 0, 11, 0, 0),
    end: new Date(2025, 0, 15, 23, 59, 59),
    resourceId: "bb789ef",
    title: "Event 5"
},
{
    start: new Date(2025, 0, 6, 0, 0),
    end: new Date(2025, 0, 15, 23, 59, 59),
    resourceId: "cc101gh",
    title: "Event 6"
},
{
    start: new Date(2025, 0, 8, 0, 0),
    end: new Date(2025, 0, 11, 23, 59, 59),
    resourceId: "cc123ab",
    title: "Event 7"
}
]

这些事件可以在FullCalendar时间线图表的截图中查看(截图)。

我想要实现的效果是:当某一分类下的所有摩托车在某个时间段内都被完全预订时,在该分类的资源行上显示红色背景(示例参考这里)。这可以通过FullCalendar的背景事件(官方文档:背景事件)轻松实现,但问题在于我还没找到一种可靠且高效的方法,来计算出某个分类下所有车辆都被预订的连续日期范围。

目前我已经实现了一个半可行的方案:先获取所有事件的最早和最晚日期,然后以30分钟为间隔遍历这些时间点,当某一分类下的所有车辆在该时间点都被占用时,就为该分类添加一个30分钟的背景事件。代码如下:

// Get the minimum and maximum date in the events array
minDate = events.map(event => event.start).reduce((a, b) => a < b ? a : b);
maxDate = events.map(event => event.end).reduce((a, b) => a > b ? a : b);

// Iterate between the dates using 30 minutes intervals.
unavailableDateRanges = [];
for (let i = minDate; i <= maxDate; i.setMinutes(i.getMinutes() + 30)) {
    // Filter the events that are happening at this time and get the resources that are being used.
    let usedResources = events.filter(event => event.start <= i && event.end >= i).map(event => event.resourceId);

    // If all resources from a certain category are used, store a 30 minutes unavailable range for that category.
    let unavailableCategories = resources.filter(resource => resource.children.every(child => usedResources.includes(child.id))).map(resource => resource.id);
    for (category of unavailableCategories) {
        let start = new Date(i);
        let end = new Date(i);
        end.setMinutes(end.getMinutes() + 30);
        unavailableDateRanges.push({
            start: start,
            end: end,
            resourceId: category,
            title: "Unavailable",
            display: "background"
        });
    }
}

但这个方案并不够可靠,因为它只检查30分钟的时间间隔,如果有预订在比如9:45开始,那么9:45到10:00这段时间就不会被标记为不可用。而这个红色背景需要在不同的时间粒度下都准确显示,所以这会成为问题。

由于日期是连续的时间变量(UNIX时间戳),我觉得应该可以按分类筛选事件,然后找出该分类下有n个(n等于该分类的车辆总数)预订重叠的连续时间段——前提是同一辆车的预订不会重叠(这点我已经确保了)。我尝试编写这个逻辑但没有成功。

我知道有一些处理日期范围的库,比如date-fns,但看起来它也无法直接解决这个问题。

有没有有经验的开发者能帮我解决这个问题?


备注:内容来源于stack exchange,提问作者Matteo Berra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 03:23:06