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

Laravel Yajra Datatables服务端分页异常:点击第二页后无法进入第三页

问题分析与解决方案

问题根源

  1. 手动分页导致Datatables无法获取总记录数:你在查询中手动使用skip()和take()截取当前页数据,传给Datatables时它只能拿到当前页的2条数据,无法计算出总共有8条记录,因此分页按钮生成逻辑错误,第三页及以后的按钮消失。
  2. 条件判断错误:if (!empty($req['start']))会在start=0(第一页)时返回false,导致第一页能拿到全部数据、分页显示正常;但第二页start=2时会执行手动分页,Datatables拿到部分数据后分页逻辑混乱。
  3. 日期过滤条件笔误:!empty($req['date_to']) && !empty($req['date_to'])重复判断了date_to,应该同时校验date_from和date_to。
  4. SQL注入风险:直接拼接日期参数到whereRaw中存在注入风险,需改用参数绑定。

修复方案

  • 移除手动的skip()和take()逻辑,让Laravel Datatables自动处理分页参数
  • 将未执行get()的查询构建器直接传给Datatables::of(),这样Datatables能获取总记录数和过滤后的记录数,正确生成分页按钮
  • 修正日期过滤的条件判断
  • 替换SQL拼接为参数绑定,避免注入风险

修正后的代码

public function reservationListing(Request $request)
{
    $req = $request->all();

    $query = EventReservation::selectRaw("
        reservation_date,
        event_reservations.outlet_id,
        event_reservations.event_id,
        SUM(event_reservations.total_adults) as ttl_adult,
        SUM(event_reservations.total_kids) as ttl_kid,
        SUM(event_reservations.total_adults + event_reservations.total_kids) as ttl_pax,
        SUM(CASE WHEN event_reservations.total_attendees is NULL then 0 Else event_reservations.total_attendees End) as ttl_attended,
        SUM(CASE WHEN payment_status = 'pending' THEN 1 ELSE 0 END) as ttl_pending,
        SUM(CASE WHEN payment_status = 'paid' THEN 1 ELSE 0 END) as ttl_paid,
        events.name as event_name,
        outlets.name as outlet_name
    ")
    ->leftjoin("events", "events.id", "=", "event_reservations.event_id")
    ->leftjoin("outlets", "outlets.id", "=", "event_reservations.outlet_id")
    ->groupby('reservation_date', 'outlet_id', 'event_id');

    // 修正日期过滤条件,使用参数绑定避免SQL注入
    if (!empty($req['date_from']) && !empty($req['date_to'])) {
        $query->whereRaw("DATE(reservation_date) BETWEEN ? AND ?", [$req['date_from'], $req['date_to']]);
    }

    if (!empty($req['outlet_id'])) {
        $query->where("event_reservations.outlet_id", $req['outlet_id']);
    }

    if (!empty($req['event_id'])) {
        $query->where("event_reservations.event_id", $req['event_id']);
    }

    $query->orderBy("reservation_date");

    // 直接传入查询构建器,而非分页后的集合
    return Datatables::of($query)
        ->addIndexColumn()
        ->make(true);
}

补充说明

Laravel Datatables包会自动识别请求中的start、length、search等参数,自动完成分页、排序、过滤操作,不需要手动处理skip()、take()或setOffset()。只要传入完整的查询构建器,它会负责计算总记录数、过滤后记录数,并生成正确的分页数据。

内容的提问来源于stack exchange,提问作者Najwa Tech

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 11:53:17