基于 Laravel + Swoole + Vue 搭建实时在线聊天室(十):用户登录后获取未读消息数

接下来,我们正式开始开发聊天室聊天功能。

在用户每次登录后,需要将未读消息发送给客户端,以便提醒用户有多少条未读消息,今天我们就围绕这个功能来编写前后端代码。

前端入口页面逻辑

首先在前端打开 resources/js/pages/Load.vue,用户登录之后会跳转到该页面,这个 Vue 组件的 mounted 函数实现如下:

async mounted() {
    this.$store.commit("setTab", true);
    // 只全局监听一次
    if (!this.isLogin) {
        // 登录了,发送进入信息。
        if (this.userid) {
            // 处理未读消息
            socket.on("count", userCount => {
                this.$store.commit("setUnread", userCount);
                console.log(userCount);
            });
            this.$store.commit("setLoginState", true);
        }
    }
},

用户首次登录成功后,会监听 Websocket 服务端的 count 事件,并在回调函数中根据服务端返回数据初始化各个聊天室未读消息数。

前端代码比较简单,不用做任何调整,接下来我们到后端实现相应的获取未读消息数代码。

创建相关模型类和数据表

我们创建一个新的 counts 表来存放用户在每个聊天室中的未读消息数。

通过如下 Artisan 命令快速生成 Count 模型类及对应数据库迁移类:

php artisan make:model Count -m

然后修改模型类 app/Count.php 代码如下:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Count extends Model
{
    public static $ROOMLIST = [1, 2];
    public $timestamps = false;
}

注:这里为了简化逻辑,我们将聊天室房间数据写死。

database/migrations 目录下编辑刚刚生成的迁移类 CreateCountsTableup 方法如下:

class CreateCountsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('counts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('user_id');
            $table->smallInteger('room_id');
            $table->integer('count')->default(0);
        });
    }
    
    ...

我们在 counts 表中定义了四个字段,user_id 表示用户 ID,room_id 表示房间 ID,count 表示该用户在该房间中的未读消息数。

最后运行数据库迁移命令生成 counts 表:

php artisan migrate

编写 Websocket 路由实现代码

打开 Websocket 路由文件 routes/websocket.php,在 login 路由中编写获取未读消息代码如下:

WebsocketProxy::on('login', function (WebSocket $websocket, $data) {
    if (!empty($data['token']) && ($user = \App\User::where('api_token', $data['token'])->first())) {
        $websocket->loginUsing($user);
        // 获取未读消息
        $rooms = [];
        foreach (\App\Count::$ROOMLIST as $roomid) {
            // 循环所有房间
            $result = \App\Count::where('user_id', $user->id)->where('room_id', $roomid)->first();
            $roomid = 'room' . $roomid;
            if ($result) {
                $rooms[$roomid] = $result->count;
            } else {
                $rooms[$roomid] = 0;
            }
        }
        $websocket->toUser($user)->emit('count', $rooms);
    } else {
        $websocket->emit('login', '登录后才能进入聊天室');
    }
});

我们依次遍历所有房间下用户的未读消息,然后通过 count 管道将其发送给客户端,客户端如果在监听这个管道,就可以读取到这个消息数据并进行处理。

测试未读消息初始化

下面我们在浏览器重新登录用户,可以看到 Websocket 通信信息如下:

Websocket 通信消息

在 Vue->Vuex 中可以看到对应的未读消息数:

Vuex 中的未读消息数设置

此时数据表是空的,所以数据都是 0, 我们可以在 counts 表中插入一些测试数据:

插入测试数据到 counts 表

然后再次登录测试,就可以看到未读消息数了:

Websocket 通信消息

Vuex 中的未读消息数设置

上一篇: 基于 Laravel + Swoole + Vue 搭建实时在线聊天室(九):实现客服机器人聊天功能

下一篇: 基于 Laravel + Swoole + Vue 搭建实时在线聊天室(十一):进入聊天室后获取历史聊天记录