学习总结
1.在workerman框架中判断某个连接是否掉线,需要添加onclose()方法。
2.在服务端如果客户登录,则新建一个消息列表给该客户,存放此客户和客服的聊天记录,并且模拟点击一下。
1.workerman框架中的websocket文件ws_test.php
<?php
use Workerman\Worker;
require_once __DIR__ . '/../Workerman/Autoloader.php';
/// 注意:这里与上个例子不同,使用的是websocket协议
$ws_worker = new Worker("websocket://0.0.0.0:2001");
// 启动4个进程对外提供服务
$ws_worker->count = 4;
//连接信息定义为全局变量
$m_list = []; //客户连接信息
$a_list = [];//客服人员连接信息
// 当收到客户端发来的数据后返回hello $data给客户端
$ws_worker->onMessage = function($connection, $data)
{
global $m_list;
global $a_list;
$data = json_decode($data,true);
print_r($data);
// echo $connection->getRemoteIp(); 获取当前连接的ip
//登录
if($data['type']==='login'){
//无论是客户还是客服人员在登录的时候,都需要把连接注册在大数组中
$connection->from_id = $connection->id;
//如果是客户登录,则把连接数据放在$m_list数组中
if($data['group']==='member'){
$m_list[$connection->id] = $connection;
$data['from_id'] = $connection->from_id;
if($a_list):
$index = array_rand($a_list);
$a_list[$index]->to_id = $m_list[$connection->id]->from_id;
$m_list[$connection->id]->to_id = $a_list[$index]->from_id;
$res['code'] = 0;
$res['msg'] = '连接成功';
$res['type'] = 'login';
$res['id'] = $m_list[$connection->id]->from_id;
$a_list[$index]->send(json_encode($res));
$res['id'] = $a_list[$index]->from_id;
$m_list[$connection->id]->send(json_encode($res));
else:
$connection->send(json_encode(['code'=>1,'msg'=>'没有客服在线,请稍候']));
endif;
}
//如果是客服登录,就把客服登录链接放在$a_list数组中
if($data['group']==='admin'){
$a_list[$connection->id] = $connection;
}
}
//发送信息
if($data['type']==='msg')
{
$res =['code'=>0,'msg'=>$data['msg'],'type'=>'msg','id'=>$connection->id];
if($data['group']==='member'){
$a_list[$data['to_id']]->send(json_encode($res));
}
if($data['group']==='admin'){
$m_list[$data['to_id']]->send(json_encode($res));
}
}
//$connection->send(json_encode($data));
};
$ws_worker->onClose = function($connection)
{
global $m_list;
global $a_list;
$index = $connection->id;
//客户掉线
if(array_key_exists($index,$m_list)){
// echo '客户'.$index.'掉线了!';
if(isset($m_list[$index]->to_id))
{
$to_id = $m_list[$index]->to_id; //to_id是在和哪个客服通信
$res = [];
$res['code'] = 0;
$res['msg'] = '客户掉线';
$res['type'] = 'logout';
$res['id'] = $index;
$a_list[$to_id]->send(json_encode($res));//通知客服人员该客户掉线了
}
unset($m_list[$index]);//从客户大数组中删除该客户
$m_list = array_filter($m_list);//清除大数组中的空值
// print_r($m_list);
}
//客服掉线
if(array_key_exists($index,$a_list)){//判断数组中是否存在$index这个key
echo '客服'.$index.'掉线了!';
unset($a_list[$index]);//删除键名为$index这个key的键和值,位置保存
$a_list = array_filter($a_list); //把数组值为空的去掉
print_r($a_list);
}
};
// 运行worker
Worker::runAll();
?>
2.服务端index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
<script src="/static/plugins/layui/layui.js"></script>
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>客户服务</title>
<style>
.main{
width: 600px;
height: 450px;
margin: 20px;
box-sizing: border-box;
border: 1px solid #c2c2c2;
display: flex;
flex-flow: row nowrap;
}
.main>.member{
width: 30%;
padding: 10px 10px;
border-right: 1px solid #c2c2c2;
}
/* 客户列表 */
.main>.member>.m_item{
height: 20px;
padding: 5px 5px;
margin-bottom: 5px;
background-color: #f1f1f1;
border-radius: 5px;
border: 1px solid #cdcdcd;
text-align: center;
}
/* 客户列表被点击 */
.main>.member>.m_item.active{
background-color: #3FADFF;
color: white;
}
.main>.member>div:hover{
background-color: #3FADFF;
cursor: pointer;
}
.main>.admin{
width: 70%;
display: flex;
flex-flow: column nowrap;
}
/* 客服消息列表 */
.main>.admin>.msg_list{
padding: 10px 10px;
height: 65%;
border-bottom: 1px solid #c2c2c2;
}
/* 客户发来的消息 */
.main>.admin>.msg_list .msg_item{
text-align: left;
background-color: #f1f1f1;
border-radius: 5px;
height: 25px;
margin: 5px 5px;
padding: 5px 5px;
}
/* 客服自己的消息 */
.main>.admin>.msg_list .msg_item.me{
text-align: right;
background-color: lightgreen;
}
/* 客服消息输入框 */
.main>.admin>.msg_input{
padding: 10px 10px;
height: 35%;
overflow: auto;
}
/* 客服消息发送按钮 */
.main>.admin>.btn_send>button{
margin-left: 84%;
margin-bottom: 5px;
}
</style>
</head>
<body>
<div class="main">
<div class="member">
{{-- 客户列表 --}}
{{-- <div class="m_item active" m_id="2" onclick="back(2)">客户2</div>
<div class="m_item" m_id="3" onclick="back(3)">客户3</div> --}}
</div>
<div class="admin">
<div class="msg_list">
{{-- 消息列表 --}}
{{-- <div msg_list_id='2'>
<div class="msg_item me">我说:您好</div>
<div class="msg_item">客户2说:华为手机多少钱?</div>
<div class="msg_item me">我说:您好</div>
<div class="msg_item">客户2说:华为手机多少钱?</div>
</div>
<div msg_list_id='3'>
<div class="msg_item me">我说:您好</div>
<div class="msg_item">客户3说:华为手机多少钱?</div>
<div class="msg_item me">我说:您好</div>
<div class="msg_item">客户3说:华为手机多少钱?</div>
</div> --}}
</div>
<div class="msg_input" contenteditable="true">
{{-- 消息输入框 --}}
</div>
<div class="btn_send">
<button class="layui-btn layui-btn-normal" type="button" onclick="send()">发送</button>
</div>
</div>
</div>
</body>
</html>
<script>
layui.use(['layer'],function(){
layer = layui.layer;
$ = layui.jquery;
// 假设服务端ip为127.0.0.1
ws = new WebSocket("ws://127.0.0.1:2001");
data = {};
data.type = 'login';//当前是登录操作
data.group='admin';//角色是客服
ws.onopen = function() {
ws.send(JSON.stringify(data));
};
ws.onmessage = function(e) {
res = JSON.parse(e.data);
console.log(res);
if(res.code>0)
{
alert(res.msg);
}
else
{
to_id = res.id;
switch (res.type)
{
case 'login':
//在客户列表中添加对应的客户
html = '<div class="m_item" m_id='+res.id+' onclick="back('+res.id+')">客户'+res.id+'</div>';
$('.member').append(html);
//客户登录时添加这个客户的消息列表div
$('.msg_list').append('<div msg_list_id="'+res.id+'"></div>');
//点击事件
back(res.id);
break;
//客户发来消息
case 'msg':
html = '<div class="msg_item">'+res.msg+'</div>';
//哪个客户发来的的消息,添加到对应的消息列表div中
$('div[msg_list_id="'+res.id+'"]').append(html);
break;
case 'logout':
//在客户列表中删除对应的客户
$('.m_item[m_id="'+res.id+'"]').remove();
break;
default:
alert(res.msg);
}
}
};
});
function back(id)
{
to_id = id;
//给当前点击的客户添加active样式,其它的客户取消active样式
$('.m_item[m_id="'+id+'"]').addClass('active').siblings().removeClass('active');
//点击哪个客户,显示和哪个客户的聊天信息
$('div[msg_list_id="'+id+'"]').show().siblings().hide();//显示点击客户的聊天记录
}
// //客服向客户发送消息
function send()
{
data['type'] = 'msg';
data['group'] = 'admin';
data['msg'] =$('.msg_input').text();
data['to_id'] =to_id;
ws.send(JSON.stringify(data));
html = '<div class="msg_item me">'+$('.msg_input').text()+'</div>';
//是发给哪个客户的消息,添加到对应的消息列表div中
$('div[msg_list_id="'+to_id+'"]').append(html);
$('.msg_input').text('');
}
</script>
3.客户端index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/plugins/layui/css/layui.css">
<script src="/static/plugins/layui/layui.js"></script>
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>百度商桥IM通讯</title>
<style>
.msg{
margin:10px 10px;
height: 95vh;
}
.msg>.list{
padding: 10px;
border: 1px solid #c2c2c2;
border-radius: 5px;
height: 70%;
margin-bottom: 10px;
}
/* 客服发来的消息 */
.msg>.list>.item{
text-align: left;
background-color: #f1f1f1;
border-radius: 5px;
height: 25px;
margin: 5px 5px;
padding: 5px 5px;
}
/* 客户自己发送的消息 */
.msg>.list>.item.me{
text-align: right;
background-color: lightgreen;
}
/* 消息输入框 */
.msg>.msg_input>{
height: 30%;
}
</style>
</head>
<body>
<div class="msg">
<div class="list">
{{-- <div class="item me">您好,华为手机多少钱?</div>
<div class="item">1988元</div> --}}
</div>
<div class="msg_input">
<textarea class="layui-textarea" name="msg"></textarea>
</div>
</div>
</body>
</html>
<script>
layui.use(['layer'],function(){
layer = layui.layer;
$ = layui.jquery;
// 假设服务端ip为127.0.0.1
ws = new WebSocket("ws://127.0.0.1:2001");
data = {};
data.type = 'login';//当前是登录操作
data.group='member';//角色是客户
ws.onopen = function() {
ws.send(JSON.stringify(data));
};
ws.onmessage = function(e) {
res = JSON.parse(e.data);
console.log(res);
if(res.code>0)
{
alert(res.msg);
}
else
{
switch (res.type)
{
case 'login':
html = '<div class="item">您好,客服'+res.id+'为您服务...</div>';
break;
case 'msg':
html = '<div class="item">客服'+res.id+': '+res.msg+'</div>';
break;
default:
}
to_id = res.id;//记录是哪个客服为我服务
$('.list').append(html);
}
};
});
// //客户向服务器的客服人员发送消息
function send()
{
data['type'] = 'msg';
data['group'] = 'member';
data['msg'] =$('textarea[name="msg"]').val();
data['to_id'] =to_id;
ws.send(JSON.stringify(data));
html = '<div class="item me">'+$('textarea[name="msg"]').val()+'</div>';
$('.list').append(html);
$('textarea[name="msg"]').val('');
}
</script>