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

Laravel 10中为嵌套数组实现分页功能

一对一聊天消息分组分页解决方案

针对你当前按日期分组消息后无法实现分页的问题,以下提供两种可行的实现方案,优先推荐游标分页(适配聊天场景下加载旧消息的需求):

方案一:游标分页(推荐)

通过传递最后加载的消息时间戳来获取更早的消息,避免页码分页因新消息插入导致的偏移问题。

修改后的代码

public function getMessages(Request $request)
{
    $validatedData = Validator::make($request->all(), [
        "receiver_id" => "required",
        "last_created_at" => "nullable|date_format:Y-m-d\TH:i:s.u\Z",
        "limit" => "nullable|integer|min:1|max:100",
    ]);

    if ($validatedData->fails()) {
        return $this->sendresponse('false', 'validation error', $validatedData->errors());
    }

    $user_id = Auth::user()->id;
    $receiver_id = $request->receiver_id;
    $limit = $request->limit ?? 20;

    // 构建消息查询条件
    $query = Message::where(function ($q) use ($user_id, $receiver_id) {
        $q->where('sender_id', $user_id)->where('receiver_id', $receiver_id);
    })->orWhere(function ($q) use ($user_id, $receiver_id) {
        $q->where('sender_id', $receiver_id)->where('receiver_id', $user_id);
    });

    // 若传递了last_created_at,获取该时间之前的消息
    if ($request->has('last_created_at')) {
        $query->where('created_at', '<', $request->last_created_at);
    }

    // 按时间倒序取指定条数,再反转回正序以匹配原分组逻辑
    $messages = $query->orderBy('created_at', 'desc')->take($limit)->get()->reverse();

    // 按日期分组并处理消息标记
    $groupedMessages = $messages->groupBy(function ($message) {
        return $message->created_at->format('l');
    })->map(function ($messagesByDay) use ($user_id) {
        return $messagesByDay->reverse()->values()->map(function ($message) use ($user_id) {
            $message->sent = $message->sender_id == $user_id ? 1 : 0;
            $message->received = $message->receiver_id == $user_id ? 1 : 0;
            $message->time = $message->created_at->format('h:i A');
            return $message;
        });
    });

    // 反转分组顺序,最新日期的消息组排在最前
    $groupedMessages = $groupedMessages->reverse();

    // 判断是否还有更多旧消息
    $hasMore = $messages->isNotEmpty() 
        ? $query->where('created_at', '<', $messages->last()->created_at)->exists() 
        : false;

    return $this->sendresponse('true', 'found', [
        'messages' => $groupedMessages,
        'receiver' => AppUser::where('id', $receiver_id)->selectbasic()->withCount('followers')->first(),
        'has_more' => $hasMore,
        'last_created_at' => $messages->isEmpty() ? null : $messages->last()->created_at->toIso8601String()
    ]);
}

前端调用逻辑

  1. 首次请求:无需传递last_created_at,获取最新的20条消息
  2. 加载更多:当用户滚动到消息顶部时,传递上一次返回的last_created_at,获取更早的消息
  3. 根据has_more判断是否还有更多数据,决定是否显示“加载更多”按钮

方案二:页码分页

适用于对分页逻辑要求简单的场景,但需注意新消息插入会导致页码偏移。

修改后的代码

public function getMessages(Request $request)
{
    $validatedData = Validator::make($request->all(), [
        "receiver_id" => "required",
        "page" => "nullable|integer|min:1",
        "per_page" => "nullable|integer|min:1|max:100",
    ]);

    if ($validatedData->fails()) {
        return $this->sendresponse('false', 'validation error', $validatedData->errors());
    }

    $user_id = Auth::user()->id;
    $receiver_id = $request->receiver_id;
    $perPage = $request->per_page ?? 20;

    // 构建消息查询条件并分页
    $messages = Message::where(function ($q) use ($user_id, $receiver_id) {
        $q->where('sender_id', $user_id)->where('receiver_id', $receiver_id);
    })->orWhere(function ($q) use ($user_id, $receiver_id) {
        $q->where('sender_id', $receiver_id)->where('receiver_id', $user_id);
    })->orderBy('created_at', 'asc')->paginate($perPage);

    // 按日期分组并处理消息标记
    $groupedMessages = $messages->getCollection()->groupBy(function ($message) {
        return $message->created_at->format('l');
    })->map(function ($messagesByDay) use ($user_id) {
        return $messagesByDay->reverse()->values()->map(function ($message) use ($user_id) {
            $message->sent = $message->sender_id == $user_id ? 1 : 0;
            $message->received = $message->receiver_id == $user_id ? 1 : 0;
            $message->time = $message->created_at->format('h:i A');
            return $message;
        });
    });

    // 反转分组顺序,最新日期的消息组排在最前
    $groupedMessages = $groupedMessages->reverse();

    return $this->sendresponse('true', 'found', [
        'messages' => $groupedMessages,
        'receiver' => AppUser::where('id', $receiver_id)->selectbasic()->withCount('followers')->first(),
        'pagination' => [
            'current_page' => $messages->currentPage(),
            'last_page' => $messages->lastPage(),
            'per_page' => $messages->perPage(),
            'total_messages' => $messages->total()
        ]
    ]);
}

关键说明

  • 两种方案均保留了原有的按日期分组、消息标记(sent/received)、分组顺序反转的逻辑
  • 游标分页通过last_created_at和has_more实现滚动加载,更符合聊天应用的用户体验
  • 页码分页返回标准的分页参数,适合需要跳转页码的场景

内容的提问来源于stack exchange,提问作者The Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 21:09:58