首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Laravel-Websockets向特定用户发送消息(一对一聊天)

使用Laravel-Websockets向特定用户发送消息(一对一聊天)
EN

Stack Overflow用户
提问于 2019-07-10 14:18:20
回答 1查看 1.5K关注 0票数 2

我在我的应用程序中有一个websocket群聊,它将用户的消息广播给所有其他用户。我想做一个一对一的聊天,这将广播消息只有双方。如何告诉websocket将消息广播给特定用户?

我的控制器:

代码语言:javascript
复制
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Message;

use App\Events\MessageSent;

use Auth;

class ChatsController extends Controller
{

    public function index()
    {
        if (Auth::check() === false) {

            return view('login');

        }
        else
        {

            return view('chats');

        }
    }

    public function fetchMessages()
    {
        return Message::with('user')->get();
    }

    public function sendMessage(Request $request)
    {
        $message = auth()->user()->messages()->create([
            'message' => $request->message
        ]);
        broadcast(new MessageSent($message->load('user')))->toOthers();
        return ['status' => 'success'];
    }
}

我的Vue文件:

代码语言:javascript
复制
<template>
   <div class="row">

       <div class="col-8">
           <div class="card card-default">
               <div class="card-header">Messages</div>
               <div class="card-body p-0">
                   <ul class="list-unstyled" style="height:300px; overflow-y:scroll" v-chat-scroll>
                       <li class="p-2" v-for="(message, index) in messages" :key="index" >

                          <div style="background: #009afb; padding: 8px; color: white; border-radius: 15px;">

                             <img v-if="message.user.image == 'img'" src="https://www.stickpng.com/assets/images/585e4bf3cb11b227491c339a.png" style="width: 35px; height: 35px;">
                            <img v-else v-bind:src="'../images/' + message.user.image" 
                             style="width: 35px; height: 35px;border-radius: 50%;">

                             <strong>{{ message.user.name }} {{ message.user.surname }} :</strong>

                             {{ message.message }}

                              <p style="color:lightgray;">
                                {{ message.created_at }}
                              </p>

                          </div>

                       </li>
                   </ul>
               </div>

               <input
                    @keydown="sendTypingEvent"
                    @keyup.enter="sendMessage"
                    v-model="newMessage"
                    type="text"
                    name="message"
                    placeholder="Enter your message..."
                    class="form-control">
           </div>
            <span class="text-muted" v-if="activeUser" >{{ activeUser.name }} is typing...</span>
       </div>

        <div class="col-4">
            <div class="card card-default">
                <div class="card-header">Active Users</div>
                <div class="card-body">
                    <ul>
                        <li class="py-2" v-for="(user, index) in users" :key="index">
                            {{ user.name }}
                        </li>
                    </ul>
                </div>
            </div>
        </div>

   </div>
</template>
<script>
    export default {
        props:['user'],
        data() {
            return {
                messages: [],
                newMessage: '',
                users:[],
                activeUser: false,
                typingTimer: false,
            }
        },
        created() {
            this.fetchMessages();
            Echo.join('chat')
                .here(user => {
                    this.users = user;
                })
                .joining(user => {
                    this.users.push(user);
                })
                .leaving(user => {
                    this.users = this.users.filter(u => u.id != user.id);
                })
                .listen('MessageSent',(event) => {
                    this.messages.push(event.message);
                })
                .listenForWhisper('typing', user => {
                   this.activeUser = user;
                    if(this.typingTimer) {
                        clearTimeout(this.typingTimer);
                    }
                   this.typingTimer = setTimeout(() => {
                       this.activeUser = false;
                   }, 3000);
                })
        },
        methods: {
            fetchMessages() {
                axios.get('messages').then(response => {
                    this.messages = response.data;
                })
            },
            sendMessage() {
                this.messages.push({
                    user: this.user,
                    message: this.newMessage
                });
                axios.post('messages', {message: this.newMessage});
                this.newMessage = '';
            },
            sendTypingEvent() {
                Echo.join('chat')
                    .whisper('typing', this.user);
            }
        }
    }
</script>

我的表有id、user_id和message字段。

EN

回答 1

Stack Overflow用户

发布于 2021-07-09 22:07:58

您好,我有同样的问题,并像这样解决它,但请注意,我有额外的逻辑

1- in channels.php

代码语言:javascript
复制
Broadcast::channel('chat.{ticketId}', function ($user, $ticketId) {
    $ticket = \App\Models\Ticket::find($ticketId);
    return $user->id == $ticket->asked_user_id || $user->id == $ticket->responded_user_id;
});

2-我只允许用户彼此聊天,他们中的一个被要求提供支持票证或回复用户的管理员

在我的事件中,我有这样的代码

代码语言:javascript
复制
class MessageSentEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;


    public $message;
    public $ticket;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct(TicketMEssage $message, Ticket $ticket)
    {
        $this->message = $message;
        $this->ticket = $ticket;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PresenceChannel('chat.' . $this->ticket->id);
    }

    public function toBroadcast()
    {
        return new MessageSentEvent($this->message);
    }

}

3-我收到这样的消息和罚单

代码语言:javascript
复制
$ticket = Ticket::find($id);
    $messages = $ticket->messages;
    $messages->load('user');

    return response()->json([
        'messages' => $messages,
        'ticket' => $ticket,
        'user' => auth()->user()
    ]);

4-我像下面这样存储和广播消息

代码语言:javascript
复制
$ticket = Ticket::find($request->ticket_id);
    $message = $ticket->messages()->create([
        'message' => $request->message,
        'for' => auth()->id() == $ticket->asked_user_id ? TicketMessage::FOR_USER['asked'] : TicketMessage::FOR_USER['responded'],
        'user_id' => auth()->id(),
    ]);

    $message->load('user');
    broadcast(new MessageSentEvent($message, $ticket));
    return ['status' => 'success', 'message' => $message];

5-以及js文件中的重要部分(React或Vue或...)

代码语言:javascript
复制
 window.Echo.join(`chat.${props.ticketId}`)
        .listen('MessageSentEvent', (message) => {
        setMessages((prevState) => [...prevState, message.message]);
    });

我只监听带有我从props获得的票证id的频道(你应该以任何方式传递它)

关键部分是1、4和5

希望这对你有帮助:)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56964429

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档