赞
踩
composer require topthink/think-worker
在config/worker_server.php下面配置worker_class
worker文件源码在这里
<?php declare (strict_types = 1); namespace app\http; use think\facade\Db; use think\worker\Server; use Workerman\Lib\Timer; // define('HEARTBEAT_TIME', 30);// 心跳间隔 class Worker extends Server { protected $socket = 'websocket://0.0.0.0:2345'; protected static $heartbeat_time = 50; public function onWorkerStart($worker) { Timer::add(10, function()use($worker){ $time_now = time(); #这里统计下线人员的id $offline_user = []; foreach($worker->connections as $connection) { // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间 if (empty($connection->lastMessageTime)) { $connection->lastMessageTime = $time_now; continue; } // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接 // if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) { if ($time_now - $connection->lastMessageTime > self::$heartbeat_time) { #这里统计下线人员的id $offline_user[] = $connection->uid; #关闭连接 $connection->close(); } #这里是一个用户下线后通知其他用户 if (count($offline_user) > 0){ $msg = ['type'=>'message','uid'=>$connection->uid,"message"=>"用户【".implode(',',$offline_user)."】下线了"]; $connection->send(json_encode($msg)); } } }); } public function onMessage($connection,$data) { #最后接收消息时间 $connection->lastMessageTime = time(); $msg_data = json_decode($data,true); if (!$msg_data){ return; } #绑定用户ID if ($msg_data['type'] == 'bind' && !isset($connection->uid)){ $connection->uid = $msg_data['uid']; $this->worker->uidConnections[$connection->uid] = $connection; } // Db::name('online_customer_service')->insert(); #单人发消息 if ($msg_data['type'] == 'text' && $msg_data['mode'] == 'single'){ if (isset($this->worker->uidConnections[$msg_data['to_id']])){ $conn = $this->worker->uidConnections[$msg_data['to_id']]; $conn->send($data); } } #群聊 if ($msg_data['type'] == 'text' && $msg_data['mode'] == 'group'){ #实际项目通过群号查询群里有哪些用户 $group_user = [10009,10010,10011,10012,10013,10014,10015,10016,10017]; foreach ($group_user as $key => $val){ if (isset($this->worker->uidConnections[$val])){ $conn = $this->worker->uidConnections[$val]; $conn->send($data); } } } // #向所有用户发送消息 // foreach ($this->worker->connections as $key => $con){ // $con->send($data); // } // $connection->send(json_encode($data)); // $connection->send($data); } }
源码在这里
<?php /** * User BaiXiantao * Date 2022/7/4 * Time 10:34 */ namespace app\http\controller; use think\facade\View; class Chat { public function index() { #聊天首页 $from_id = input('from_id',10001); $to_id = 1; View::assign('from_id',$from_id); View::assign('to_id',$to_id); return View::fetch(); } }
源码在这里
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title></title> <link rel="stylesheet" type="text/css" href="/static/httpchat/font_Icon/iconfont.css"> <script src="/static/admin/jquery/jquery-3.6.0.min.js"></script> <style> .userlist li{ background: rgb(0 0 0 / 5%); text-align: left; padding: 5px; height: 49px; /*line-height: 30px;*/ font-size: 16px; border-bottom: 1px solid rgb(0 0 0 / 5%); } .userlist li img { width: 40px; height: 40px; padding-right: 5px; } .message-num{ right: 2px; } .ChatInfoName{ height: 50px; border-bottom: 1px solid #D9D9D9; line-height: 50px; font-size: 16px; padding: 0 10px; } .chatBox-content{ height: 498px !important; width: 100%; } .chatBox-content-demo{ width: 100%; height: 370px !important; overflow-y: scroll; } .div-textarea{ width: 490px !important; /*min-height: 20px;*/ height: 100px; _height: 120px; padding: 3px; outline: 0; background: #fff; font-size: 14px; line-height: 20px; word-wrap: break-word; overflow-x: hidden; overflow-y: auto; user-modify: read-write-plaintext-only; /*纯文本*/ -webkit-user-modify: read-write-plaintext-only; -moz-user-modify: read-write-plaintext-only; } .div-textarea:focus{ box-shadow: 0 0 15px rgba(82, 168, 236, 0.6); } .clearfloat:after{ display:block; clear:both; content:""; visibility:hidden; height:0 } .clearfloat{ zoom:1; margin: 10px 10px; } .clearfloat .right{ float: right; } .author-name{ text-align: center; margin: 15px 0 5px 0; color: #888; } .clearfloat .chat-message{ max-width: 252px; text-align: left; padding: 8px 12px; border-radius: 6px; word-wrap:break-word; display: inline-block; position: relative; } .clearfloat .left .chat-message{ background: #D9D9D9; min-height: 36px; } .clearfloat .left .chat-message:before{ position: absolute; content: ""; top: 8px; left: -6px; border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid #D9D9D9; } .clearfloat .right{ text-align: right; } .clearfloat .right .chat-message{ background: #8c85e6; color: #fff; text-align: left; min-height: 36px; } .clearfloat .right .chat-message:before{ position: absolute; content: ""; top: 8px; right: -6px; border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid #8c85e6; } .clearfloat .chat-avatars{ display: inline-block; width: 30px; height: 30px; border-radius: 50%; background: #eee; vertical-align: top; overflow: hidden; } .clearfloat .chat-avatars>img{ width: 30px; height: 30px; } .clearfloat .left .chat-avatars{ margin-right: 10px; } .clearfloat .right .chat-avatars{ margin-left: 10px; } .chatBox-send{ width: 100%; padding: 10px 5px; background: #eee; border-top: 1px #D0D0D0 solid; position: absolute; bottom: 0; left: 0; } .chatBox-send>div{ float: left; } .chatBox-send>div:nth-of-type(2){ font-size: 0; } .chatBox-send>div button{ padding: 1px 5px; margin-left: 3px; } .chatBox-send>div label{ padding: 1px 5px; margin-left: 3px; } #chat-biaoqing{ position: relative; } .hidden{ display: none; } .biaoqing-photo{ width: 200px; height: 160px; background: #ffffff; position: absolute; top: -160px; right: 40px; text-align: left; border-radius: 5px; border: solid 1px #c5c5c5; display: none; } .biaoqing-photo::before{ content: ''; position: absolute; border-top: solid 7px #c5c5c5; border-left: solid 9px transparent; border-right: solid 9px transparent; bottom: -7px; right: 36px; } .biaoqing-photo::after{ content: ''; position: absolute; border-top: solid 7px #fff; border-left: solid 10px transparent; border-right: solid 10px transparent; bottom: -5px; right: 35px; } .biaoqing-photo>ul{ margin: 0; width: 200px; height: 160px; padding: 3px 2px; list-style: none; } .biaoqing-photo>ul>li{ float: left; height: 30px; margin-left: 2px; } .emoji-picker-image{ display: inline-block; width: 30px; height: 30px; background: url(/static/httpchat/img/bqxtb01.png) no-repeat; background-size: 200px auto; cursor: pointer; } .biaoqing-photo>ul>li span.emoji-picker-image:hover{ border: solid 1px #f5f5f5; } .chat-message img{ width: 220px; height:auto; } .chat-name{ width: 230px; } /*按钮样式*/ .btn-default-styles { outline: none; resize: none; border: none; display: inline-block; padding: 5px 10px; margin-bottom: 0; font-size: 14px; font-weight: 400; line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; -ms-touch-action: manipulation; touch-action: manipulation; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-image: none; background: #bbb; color: #fff; border-radius: 4px; } .btn-default-styles:focus { outline: none; } .btn-default-styles:hover { background: #c5c5c5; animation: anniu 1s infinite; } .btn-default-styles:active { box-shadow: 0 2px 3px rgba(0, 0, 0, .2) inset; } /* 设置滚动条的样式 */ ::-webkit-scrollbar { width:5px; } /* 滚动槽 */ ::-webkit-scrollbar-track { border-radius:10px; } /* 滚动条滑块 */ ::-webkit-scrollbar-thumb { border-radius:10px; background:#8C85E6; -webkit-box-shadow:#8C85E6; } ::-webkit-scrollbar-thumb:window-inactive { background: rgba(175, 190, 255, 0.4); } @media all and (max-width: 768px) { .chatBox{ position: fixed; top: 0; left: 0; width: 100%; height: 100%; } } @media all and (max-width: 370px){ .chat-name{ width: 185px; } .chat-people>div:nth-of-type(2){ width: 120px; } .clearfloat .chat-message{ max-width: 240px; } } </style> </head> <body> <div class="layui-fluid" style="padding: 0"> <div class="layui-row" style="overflow: hidden;"> <div class="layui-col-md3 layui-col-lg3 layui-col-xs3 div-user" style="border-right: 1px solid #b4b2b2;height: 549px;overflow-y: scroll;"> <ul class="userlist" id="chatuser"> <li lay-id="1"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">管理员</span> <span class="message-num">20</span> </li> </ul> </div> <div class="layui-col-md9 layui-col-lg9 layui-col-xs9 "> <div id="chatcontent"> <div class="ChatInfoName">这里是用户昵称</div> <div> <div class="chatBox-content"> <div class="chatBox-content-demo" id="chatBox-content-demo"> </div> </div> <div class="chatBox-send"> <div class="div-textarea" contenteditable="true"></div> <div> <button id="chat-biaoqing" class="btn-default-styles"> <i class="iconfont icon-biaoqing"></i> </button> <label id="chat-tuxiang" title="发送图片" for="inputImage" class="btn-default-styles"> <input type="file" onchange="selectImg(this)" accept="image/jpg,image/jpeg,image/png" name="file" id="inputImage" class="hidden"> <i class="iconfont icon-tuxiang"></i> </label> <button id="chat-fasong" class="btn-default-styles"><i class="iconfont icon-fasong"></i> </button> </div> <div class="biaoqing-photo"> <ul> <li><span class="emoji-picker-image" style="background-position: -9px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -154px;"></span></li> </ul> </div> </div> </div> </div> </div> </div> </div> <!--<div class="layui-fluid">--> <!-- ……--> <!--</div>--> </body> </html> <script> var myavatars = ''; var myDate =new Date(); var year=myDate.getFullYear(); //获取当前年份 var mon=myDate.getMonth()+1; //获取当前月份 var da=myDate.getDate(); //获取当前日 var day=myDate.getDay(); //获取当前星期几 var h=myDate.getHours(); //获取小时 var m=myDate.getMinutes(); //获取分钟 var s=myDate.getSeconds(); //获取秒 var ms=myDate.getMilliseconds(); //获取当前毫秒数(0-999) var ld=myDate.toLocaleDateString(); //获取当前日期 var msgdate=year+'-'+mon+'-'+da+' '+h+':'+m+':'+s; var from_id = "{$from_id}"; var to_id = "{$to_id}"; //进聊天页面 $("#chatuser li").each(function () { $(this).click(function () { $("#chatuser li").css('background','rgb(0 0 0 / 5%)') $(this).css('background','#ffffff') var n = $(this).index(); to_id = $(this).attr('lay-id') // $(".chatBox-head-one").toggle(); // $(".chatBox-head-two").toggle(); // $(".chatBox-list").fadeToggle(); // $(".chatBox-kuang").fadeToggle(); //传名字 $(".ChatInfoName").text($(this).children(".chat-name").eq(0).html()); //赋值头像 myavatars = $(this).children('img').eq(0).attr("src"); // //传头像 //聊天框默认最底部 $(document).ready(function () { $("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight); }); // // 打开websocket // webSocket.onopen = function (event) { onOpen(); // }; }) }); // var userlist = [10009,10010,10011,10012,10013,10014,10015,10016,10017]; /** 0:未连接 1:连接成功,可通讯 2:正在关闭 3:连接已关闭或无法打开 */ //创建一个webSocket 实例 var webSocket = new WebSocket("ws://192.168.0.113:2345"); webSocket.onerror = function (event) { onError(event); }; // 打开websocket webSocket.onopen = function (event) { onOpen(event); }; //监听消息 webSocket.onmessage = function (event) { onMessage(event); }; webSocket.onclose = function (event) { onClose(event); } //关闭监听websocket function onError(event) { // document.getElementById("msg").innerHTML = "<p>关闭</p>"; console.log("错误: " + event.data); } function onOpen(event) { // console.log("打开: "+sockState()); var bild = '{"type":"bind","uid":"' + from_id + '"}'; webSocket.send(bild); setInterval(function () { webSocket.send('heartbeat'); //发送内容不限,只是为了证明客户端还没关闭还在线 }, 20000) //50秒发一次 } function onMessage(event) { // console.log(event.data) var massage = eval("(" + event.data + ")"); //这里表示一对一聊天 if (massage.type == 'text' && massage.mode == 'single') { //当前正在聊天的人 如果当前的发送对象id等于该消息来源的id,则为一个人 , if (this.to_id == massage.from_id) { // console.log("服务端消息:"+massage.content); // $("#chatBox-content-demo").append("<div>我是" + massage.from_id + ":" + massage.content + "</div>"); $("#chatBox-content-demo").append("<div class=\"clearfloat\">\n" + " <div class=\"author-name\">\n" + " <small class=\"chat-date\">"+ massage.datetime +"</small>\n" + " </div>\n" + " <div class=\"left\">\n" + " <div class=\"chat-avatars\"><img src=\"" + myavatars + "\" alt=\"头像\"/></div>\n" + " <div class=\"chat-message\">" + massage.content + "</div>\n" + " </div>\n" + " </div>"); return; } else { //不是当前聊天的人、将消息提醒发送到对应的列表,并将消息发送到对应页面 //在数据库请求该人的基本信息, } } //这里表示群聊 if (massage.type == 'text' && massage.mode == 'group') { console.log(massage); } } function onClose(event) { // document.getElementById("msg").innerHTML = "<p>他通讯已关闭</p>"; console.log("关闭: " + sockState()); webSocket.close(); } function sockState() { var status = ['未连接', '连接成功,可通讯', '正在关闭', '连接已关闭或无法打开']; return status[webSocket.readyState]; } function close(event) { webSocket.close(); } document.onkeydown = keyDownSearch; function keyDownSearch(e) { // 兼容FF和IE和Opera var theEvent = e || window.event; var code = theEvent.keyCode || theEvent.which || theEvent.charCode; if (code == 13) { //具体处理函数 chat_fasong() return false; } return true; } //未读信息数量为空时 var totalNum = $(".chat-message-num").html(); if (totalNum == "") { $(".chat-message-num").css("padding", 0); } $(".message-num").each(function () { var wdNum = $(this).html(); if (wdNum == "") { $(this).css("padding", 0); } }); // 发送信息 $("#chat-fasong").click(function () { chat_fasong() }); function chat_fasong() { var textContent = $(".div-textarea").html().replace(/[\n\r]/g, '<br>') if (textContent != "") { //发送到服务器 var msg1 = '{"type":"text","mode":"single","from_id":"' + from_id + '","to_id":"' + to_id + '","content":"' + textContent + '","datetime":"' + msgdate + '"}'; webSocket.send(msg1); $(".chatBox-content-demo").append("<div class=\"clearfloat\">" + "<div class=\"author-name\"><small class=\"chat-date\">" + msgdate + "</small> </div> " + "<div class=\"right\"> <div class=\"chat-message\"> " + textContent + " </div> " + "<div class=\"chat-avatars\"><img src=\"/static/httpchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>"); /*"/static/httpchat/img/icon01.png"*/ //发送后清空输入框 $(".div-textarea").html(""); //聊天框默认最底部 $(document).ready(function () { $("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight); }); } } // 发送表情 $("#chat-biaoqing").click(function () { $(".biaoqing-photo").toggle(); }); $(document).click(function () { $(".biaoqing-photo").css("display", "none"); }); $("#chat-biaoqing").click(function (event) { event.stopPropagation();//阻止事件 }); $(".emoji-picker-image").each(function () { $(this).click(function () { var bq = $(this).parent().html(); //发送到服务器 var msg2 = '{"type":"text","mode":"single","from_id":"' + from_id + '","to_id":"' + to_id + '","content":"' + bq + '","datetime":"' + msgdate + '"}'; webSocket.send(msg2); $(".chatBox-content-demo").append("<div class=\"clearfloat\">" + "<div class=\"author-name\"><small class=\"chat-date\">"+ msgdate +"</small> </div> " + "<div class=\"right\"> <div class=\"chat-message\"> " + bq + " </div> " + "<div class=\"chat-avatars\"><img src=\"/static/httpchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>"); //发送后关闭表情框 $(".biaoqing-photo").toggle(); //聊天框默认最底部 $(document).ready(function () { $("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight); }); }) }); // 发送图片 function selectImg(pic) { if (!pic.files || !pic.files[0]) { return; } var reader = new FileReader(); reader.onload = function (evt) { var images = evt.target.result; var to_img = "<img src=" + images + ">"; //发送到服务器 var msg3 = '{"type":"text","mode":"single","from_id":"' + from_id + '","to_id":"' + to_id + '","content":"' + to_img + '","datetime":"' + msgdate + '"}'; webSocket.send(msg3); $(".chatBox-content-demo").append("<div class=\"clearfloat\">" + "<div class=\"author-name\"><small class=\"chat-date\">"+ msgdate +"</small> </div> " + "<div class=\"right\"> <div class=\"chat-message\"><img src=" + images + "></div> " + "<div class=\"chat-avatars\"><img src=\"/static/httpchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>"); //聊天框默认最底部 $(document).ready(function () { $("#chatBox-content-demo").scrollTop($("#chatBox-content-demo")[0].scrollHeight); }); }; reader.readAsDataURL(pic.files[0]); } </script>
iconfont.css文件源码
@font-face {font-family: "iconfont"; src: url('iconfont.eot?t=1515469903495'); /* IE9*/ src: url('iconfont.eot?t=1515469903495#iefix') format('embedded-opentype'), /* IE6-IE8 */ url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'), url('iconfont.ttf?t=1515469903495') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ url('iconfont.svg?t=1515469903495#iconfont') format('svg'); /* iOS 4.1- */ } .iconfont { font-family:"iconfont" !important; font-size:16px; font-style:normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .icon-gouwuche2:before { content: "\e610"; } .icon-verylarger-view:before { content: "\e622"; } .icon-tehui:before { content: "\e60c"; } .icon-gengduo1:before { content: "\e606"; } .icon-xiaoxi:before { content: "\e609"; } .icon-houtui:before { content: "\e607"; } .icon-gouwuche:before { content: "\e60d"; } .icon-guojia:before { content: "\e6c0"; } .icon-xiaoxi1:before { content: "\e62d"; } .icon-shoucang:before { content: "\e60f"; } .icon-tuxiang:before { content: "\e645"; } .icon-yushou:before { content: "\e644"; } .icon-icon05:before { content: "\e630"; } .icon-jiadian:before { content: "\e670"; } .icon-shoucang1:before { content: "\e6a2"; } .icon-dingdan:before { content: "\e682"; } .icon-shuaxin:before { content: "\e6fc"; } .icon-kefu:before { content: "\e6df"; } .icon-shoucang2:before { content: "\e71a"; } .icon-wode2:before { content: "\e6f3"; } .icon-gengduo:before { content: "\e617"; } .icon-larger-view:before { content: "\e655"; } .icon-tuxiang1:before { content: "\e63d"; } .icon-geren2-copy:before { content: "\e657"; } .icon-jiushui:before { content: "\e61b"; } .icon-shuji:before { content: "\e61e"; } .icon-fasong:before { content: "\e625"; } .icon-xuanzhuan:before { content: "\e614"; } .icon-shouye:before { content: "\e60e"; } .icon-guanbi:before { content: "\e72c"; } .icon-wode:before { content: "\e61d"; } .icon-app:before { content: "\e62c"; } .icon-fanhui:before { content: "\e6d6"; } .icon-guanbi1:before { content: "\e705"; } .icon-yingyangbaojian:before { content: "\e639"; } .icon-fenlei:before { content: "\e60a"; } .icon-xiaoxi2:before { content: "\e69a"; } .icon-shanchu:before { content: "\e642"; } .icon-qian:before { content: "\e624"; } .icon-shoucangjia:before { content: "\e618"; } .icon-meishi:before { content: "\e7af"; } .icon-larger-view2:before { content: "\e627"; } .icon-dingbu:before { content: "\e67d"; } .icon-pingjia:before { content: "\e619"; } .icon-xiaoxi3:before { content: "\e61a"; } .icon-wode1:before { content: "\e621"; } .icon-wode4:before { content: "\e611"; } .icon-yingerfeng:before { content: "\e620"; } .icon-xiaoxi4:before { content: "\e623"; } .icon-xiaoxi5:before { content: "\e67e"; } .icon-ccgl-shouhuoguanli-3:before { content: "\e601"; } .icon-liwu_gift:before { content: "\e604"; } .icon-shoucang3:before { content: "\e613"; } .icon-jiaju:before { content: "\e65d"; } .icon-shoucang4:before { content: "\e602"; } .icon-sousuo2:before { content: "\e61c"; } .icon-biaoqing:before { content: "\e605"; } .icon-kouhong:before { content: "\e60b"; } .icon-gengduo2:before { content: "\e728"; } .icon-gift:before { content: "\e600"; } .icon-lingquan:before { content: "\e61f"; } .icon-jifen:before { content: "\e674"; } .icon-qianjin:before { content: "\e608"; } .icon-shoucang11:before { content: "\e603"; } .icon-shuaxin1:before { content: "\e626"; } .icon-zhongxin:before { content: "\e650"; } .icon-list-view:before { content: "\e628"; } .icon-fushi:before { content: "\e63c"; } .icon-saoyisao:before { content: "\e612"; } .icon-double-vertical:before { content: "\e615"; } .icon-up-down:before { content: "\e66f"; } .icon-sousuo1:before { content: "\e66e"; } .icon-double-cross:before { content: "\e616"; } .icon-left-right:before { content: "\e7b0"; }
控制器
<?php /** * User BaiXiantao * Date 2022/7/4 * Time 14:00 */ namespace app\admin\controller; use think\facade\View; class Chat extends Common { public function index() { $from_id = 1; //将这里的formid为1,表示管理员 $to_id = 1; View::assign('from_id',$from_id); View::assign('to_id',$to_id); return View::fetch(); } }
html文件
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title></title> <link rel="stylesheet" href="/static/admin/layui272/css/layui.css" media="all"> <!-- <link rel="stylesheet" type="text/css" href="/static/httpchat/css/chat.css">--> <link rel="stylesheet" type="text/css" href="/static/httpchat/font_Icon/iconfont.css"> <script src="/static/admin/jquery/jquery-3.6.0.min.js"></script> <style> .userlist li{ background: rgb(0 0 0 / 5%); text-align: left; padding: 5px; height: 49px; /*line-height: 30px;*/ font-size: 16px; border-bottom: 1px solid rgb(0 0 0 / 5%); } .userlist li img { width: 40px; height: 40px; padding-right: 5px; } .message-num{ /*right: 2px;*/ /*padding: 4px;*/ color: red; /*background: red;*/ /*position: relative;*/ /*margin-left: -20px;*/ /*top: -15px;*/ /*width: 5px;*/ /*height: 5px;*/ /*border-radius: 10px;*/ } .ChatInfoName{ height: 50px; border-bottom: 1px solid #D9D9D9; line-height: 50px; font-size: 16px; padding: 0 10px; } .chatBox-content{ height: 498px !important; width: 100%; } .chatBox-content-demo{ width: 100%; height: 370px !important; overflow-y: scroll; } .div-textarea{ width: 490px !important; /*min-height: 20px;*/ height: 100px; _height: 120px; padding: 3px; outline: 0; background: #fff; font-size: 14px; line-height: 20px; word-wrap: break-word; overflow-x: hidden; overflow-y: auto; user-modify: read-write-plaintext-only; /*纯文本*/ -webkit-user-modify: read-write-plaintext-only; -moz-user-modify: read-write-plaintext-only; } .div-textarea:focus{ box-shadow: 0 0 15px rgba(82, 168, 236, 0.6); } .clearfloat:after{ display:block; clear:both; content:""; visibility:hidden; height:0 } .clearfloat{ zoom:1; margin: 10px 10px; } .clearfloat .right{ float: right; } .author-name{ text-align: center; margin: 15px 0 5px 0; color: #888; } .clearfloat .chat-message{ max-width: 252px; text-align: left; padding: 8px 12px; border-radius: 6px; word-wrap:break-word; display: inline-block; position: relative; } .clearfloat .left .chat-message{ background: #D9D9D9; min-height: 36px; } .clearfloat .left .chat-message:before{ position: absolute; content: ""; top: 8px; left: -6px; border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-right: 10px solid #D9D9D9; } .clearfloat .right{ text-align: right; } .clearfloat .right .chat-message{ background: #8c85e6; color: #fff; text-align: left; min-height: 36px; } .clearfloat .right .chat-message:before{ position: absolute; content: ""; top: 8px; right: -6px; border-top: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid #8c85e6; } .clearfloat .chat-avatars{ display: inline-block; width: 30px; height: 30px; border-radius: 50%; background: #eee; vertical-align: top; overflow: hidden; } .clearfloat .chat-avatars>img{ width: 30px; height: 30px; } .clearfloat .left .chat-avatars{ margin-right: 10px; } .clearfloat .right .chat-avatars{ margin-left: 10px; } .chatBox-send{ width: 100%; padding: 10px 5px; background: #eee; border-top: 1px #D0D0D0 solid; position: absolute; bottom: 0; left: 0; } .chatBox-send>div{ float: left; } .chatBox-send>div:nth-of-type(2){ font-size: 0; } .chatBox-send>div button{ padding: 1px 5px; margin-left: 3px; } .chatBox-send>div label{ padding: 1px 5px; margin-left: 3px; } #chat-biaoqing{ position: relative; } .hidden{ display: none; } .biaoqing-photo{ width: 200px; height: 160px; background: #ffffff; position: absolute; top: -160px; right: 40px; text-align: left; border-radius: 5px; border: solid 1px #c5c5c5; display: none; } .biaoqing-photo::before{ content: ''; position: absolute; border-top: solid 7px #c5c5c5; border-left: solid 9px transparent; border-right: solid 9px transparent; bottom: -7px; right: 36px; } .biaoqing-photo::after{ content: ''; position: absolute; border-top: solid 7px #fff; border-left: solid 10px transparent; border-right: solid 10px transparent; bottom: -5px; right: 35px; } .biaoqing-photo>ul{ margin: 0; width: 200px; height: 160px; padding: 3px 2px; list-style: none; } .biaoqing-photo>ul>li{ float: left; height: 30px; margin-left: 2px; } .emoji-picker-image{ display: inline-block; width: 30px; height: 30px; background: url(/static/httpchat/img/bqxtb01.png) no-repeat; background-size: 200px auto; cursor: pointer; } .biaoqing-photo>ul>li span.emoji-picker-image:hover{ border: solid 1px #f5f5f5; } .chat-message img{ width: 220px; height:auto; } .chat-name{ width: 230px; } /*按钮样式*/ .btn-default-styles { outline: none; resize: none; border: none; display: inline-block; padding: 5px 10px; margin-bottom: 0; font-size: 14px; font-weight: 400; line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; -ms-touch-action: manipulation; touch-action: manipulation; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-image: none; background: #bbb; color: #fff; border-radius: 4px; } .btn-default-styles:focus { outline: none; } .btn-default-styles:hover { background: #c5c5c5; animation: anniu 1s infinite; } .btn-default-styles:active { box-shadow: 0 2px 3px rgba(0, 0, 0, .2) inset; } /* 设置滚动条的样式 */ ::-webkit-scrollbar { width:5px; } /* 滚动槽 */ ::-webkit-scrollbar-track { border-radius:10px; } /* 滚动条滑块 */ ::-webkit-scrollbar-thumb { border-radius:10px; background:#8C85E6; -webkit-box-shadow:#8C85E6; } ::-webkit-scrollbar-thumb:window-inactive { background: rgba(175, 190, 255, 0.4); } @media all and (max-width: 768px) { .chatBox{ position: fixed; top: 0; left: 0; width: 100%; height: 100%; } } @media all and (max-width: 370px){ .chat-name{ width: 185px; } .chat-people>div:nth-of-type(2){ width: 120px; } .clearfloat .chat-message{ max-width: 240px; } } </style> </head> <body> <div class="layui-fluid" style="padding: 0"> <div class="layui-row" style="overflow: hidden;"> <div class="layui-col-md3 layui-col-lg3 layui-col-xs3 div-user" style="border-right: 1px solid #b4b2b2;height: 549px;overflow-y: scroll;"> <ul class="userlist" id="chatuser"> <li id="10001"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10001</span> <span class="message-num"></span> </li> <li id="10002"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10002</span> <span class="message-num"></span> </li> <li id="10003"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10003</span> <span class="message-num"></span> </li> <li id="10004"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10004</span> <span class="message-num"></span> </li> <li id="10005"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10005</span> <span class="message-num"></span> </li> <li id="10006"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10006</span> <span class="message-num"></span> </li> <li id="10007"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10007</span> <span class="message-num"></span> </li> <li id="10008"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10008</span> <span class="message-num"></span> </li> <li id="10009"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10009</span> <span class="message-num"></span> </li> <li id="10010"> <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" alt=""> <span class="chat-name">用户10010</span> <span class="message-num"></span> </li> </ul> </div> <div class="layui-col-md9 layui-col-lg9 layui-col-xs9 "> <div id="chatcontent"> <div class="ChatInfoName">这里是用户昵称</div> <div> <div class="chatBox-content"> <div class="chatBox-content-demo chatBox-content-demo_1" id="chatBox-content-demo"> <!--这里是消息内容------没有更多消息--> </div> </div> <div class="chatBox-send"> <div class="div-textarea" contenteditable="true"></div> <div> <button id="chat-biaoqing" class="btn-default-styles"> <i class="iconfont icon-biaoqing"></i> </button> <label id="chat-tuxiang" title="发送图片" for="inputImage" class="btn-default-styles"> <input type="file" onchange="selectImg(this)" accept="image/jpg,image/jpeg,image/png" name="file" id="inputImage" class="hidden"> <i class="iconfont icon-tuxiang"></i> </label> <button id="chat-fasong" class="btn-default-styles"><i class="iconfont icon-fasong"></i> </button> </div> <div class="biaoqing-photo"> <ul> <li><span class="emoji-picker-image" style="background-position: -9px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -18px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -52px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -86px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -120px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -9px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -40px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -71px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -102px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -133px -154px;"></span></li> <li><span class="emoji-picker-image" style="background-position: -164px -154px;"></span></li> </ul> </div> </div> </div> </div> </div> </div> </div> </body> </html> <script> var myavatars = ''; var myDate =new Date(); var year=myDate.getFullYear(); //获取当前年份 var mon=myDate.getMonth()+1; //获取当前月份 var da=myDate.getDate(); //获取当前日 var day=myDate.getDay(); //获取当前星期几 var h=myDate.getHours(); //获取小时 var m=myDate.getMinutes(); //获取分钟 var s=myDate.getSeconds(); //获取秒 var ms=myDate.getMilliseconds(); //获取当前毫秒数(0-999) var ld=myDate.toLocaleDateString(); //获取当前日期 var msgdate=year+'-'+mon+'-'+da+' '+h+':'+m+':'+s; var from_id = "{$from_id}"; var to_id = "{$to_id}"; //进聊天页面 $("#chatuser li").each(function () { $(this).on('click',function () { $("#chatuser li").css('background','rgb(0 0 0 / 5%)') $(this).css('background','#ffffff') $(".chatBox-content-demo").css('display','none'); var n = $(this).index(); to_id = $(this).attr('id') //如果这个id不存在,就添加这个id if ($("#chatBox-content_"+to_id+"").length == 0){ console.log($("#chatBox-content_"+to_id+"").length) //插入新的div $(".chatBox-content").append("<div class='chatBox-content-demo' id='chatBox-content_"+to_id+"'></div>"); } $("#chatBox-content_"+to_id+"").css('display','block'); $("#"+to_id+" .message-num").text(''); // $(".chatBox-head-one").toggle(); // $(".chatBox-head-two").toggle(); // $(".chatBox-list").fadeToggle(); // $(".chatBox-kuang").fadeToggle(); //传名字 $(".ChatInfoName").text($(this).children(".chat-name").eq(0).html()); //赋值头像 myavatars = $(this).children('img').eq(0).attr("src"); //聊天框默认最底部 $(document).ready(function () { $(".chatBox-content-demo").scrollTop($(".chatBox-content-demo")[0].scrollHeight); }); // 打开websocket onOpen(); }) }); // var userlist = [10009,10010,10011,10012,10013,10014,10015,10016,10017]; /** 0:未连接 1:连接成功,可通讯 2:正在关闭 3:连接已关闭或无法打开 */ //创建一个webSocket 实例 var webSocket = new WebSocket("ws://192.168.0.113:2345"); webSocket.onerror = function (event) { onError(event); }; // 打开websocket webSocket.onopen = function (event) { onOpen(event); }; //监听消息 webSocket.onmessage = function (event) { onMessage(event); }; webSocket.onclose = function (event) { onClose(event); } //关闭监听websocket function onError(event) { console.log("错误: " + event.data); } function onOpen(event) { // console.log("打开: "+sockState()); var bild = '{"type":"bind","uid":"' + from_id + '"}'; webSocket.send(bild); // console.log("已发送绑定: "+bild); // webSocket.send(JSON.stringify(bild)); // document.getElementById("msg").innerHTML = "<p>连接到服务</p>"; setInterval(function () { webSocket.send('heartbeat'); //发送内容不限,只是为了证明客户端还没关闭还在线 }, 30000) //50秒发一次 } function onMessage(event) { // console.log(event.data) var massage = eval("(" + event.data + ")"); //这里表示一对一聊天 if (massage.type == 'text' && massage.mode == 'single') { //当前正在聊天的人 如果当前的发送对象id等于该消息来源的id,则为一个人 , if (this.to_id == massage.from_id) { console.log("服务端消息:"+massage.content); $("#chatBox-content_"+to_id+"").append("<div class=\"clearfloat\">\n" + " <div class=\"author-name\">\n" + " <small class=\"chat-date\">"+ massage.datetime +"</small>\n" + " </div>\n" + " <div class=\"left\">\n" + " <div class=\"chat-avatars\"><img src=\"" + myavatars + "\" alt=\"头像\"/></div>\n" + " <div class=\"chat-message\">" + massage.content + "</div>\n" + " </div>\n" + " </div>"); return; } else { //不是当前聊天的人、将消息提醒发送到对应的列表,并将消息发送到对应页面 //在数据库请求该人的基本信息, if ($("#chatBox-content_"+massage.from_id+"").length == 0){ console.log($("#chatBox-content_"+massage.from_id+"").length) //插入新的div $(".chatBox-content").append("<div class='chatBox-content-demo' id='chatBox-content_"+massage.from_id+"' style='display: none;'></div>"); } $("#chatBox-content_"+massage.from_id+"").append("<div class=\"clearfloat\">\n" + " <div class=\"author-name\">\n" + " <small class=\"chat-date\">"+ massage.datetime +"</small>\n" + " </div>\n" + " <div class=\"left\">\n" + " <div class=\"chat-avatars\"><img src=\"" + myavatars + "\" alt=\"头像\"/></div>\n" + " <div class=\"chat-message\">" + massage.content + "</div>\n" + " </div>\n" + " </div>"); // var this_message_num = parseInt($("#"+massage.from_id+" message-num").text()); var this_message_num = Number($("#"+massage.from_id+" .message-num").text()) + 1; console.log(this_message_num); $("#"+massage.from_id+" .message-num").text(this_message_num); return; } } //这里表示群聊 if (massage.type == 'text' && massage.mode == 'group') { console.log(massage); } //消息通知--用户下线消息通知等 if (massage.type == "message"){ console.log(massage.message); } } function onClose(event) { // document.getElementById("msg").innerHTML = "<p>他通讯已关闭</p>"; console.log("关闭: " + sockState()); webSocket.close(); } function sockState() { var status = ['未连接', '连接成功,可通讯', '正在关闭', '连接已关闭或无法打开']; return status[webSocket.readyState]; } function close(event) { webSocket.close(); } document.onkeydown = keyDownSearch; function keyDownSearch(e) { // 兼容FF和IE和Opera var theEvent = e || window.event; var code = theEvent.keyCode || theEvent.which || theEvent.charCode; if (code == 13) { //具体处理函数 chat_fasong() return false; } return true; } //未读信息数量为空时 var totalNum = $(".chat-message-num").html(); if (totalNum == "") { $(".chat-message-num").css("padding", 0); } $(".message-num").each(function () { var wdNum = $(this).html(); if (wdNum == "") { $(this).css("padding", 0); } }); // 发送信息 $("#chat-fasong").click(function () { chat_fasong() }); function chat_fasong() { var textContent = $(".div-textarea").html().replace(/[\n\r]/g, '<br>') if (textContent != "") { //发送到服务器 var msg1 = '{"type":"text","mode":"single","from_id":"' + from_id + '","to_id":"' + to_id + '","content":"' + textContent + '","datetime":"' + msgdate + '"}'; webSocket.send(msg1); $("#chatBox-content_"+to_id+"").append("<div class=\"clearfloat\">" + "<div class=\"author-name\"><small class=\"chat-date\">" + msgdate + "</small> </div> " + "<div class=\"right\"> <div class=\"chat-message\"> " + textContent + " </div> " + "<div class=\"chat-avatars\"><img src=\"/static/httpchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>"); /*"/static/httpchat/img/icon01.png"*/ //发送后清空输入框 $(".div-textarea").html(""); //聊天框默认最底部 $(document).ready(function () { $(".chatBox-content-demo").scrollTop($(".chatBox-content-demo")[0].scrollHeight); }); } } // 发送表情 $("#chat-biaoqing").click(function () { $(".biaoqing-photo").toggle(); }); $(document).click(function () { $(".biaoqing-photo").css("display", "none"); }); $("#chat-biaoqing").click(function (event) { event.stopPropagation();//阻止事件 }); $(".emoji-picker-image").each(function () { $(this).click(function () { var bq = $(this).parent().html(); //发送到服务器 var msg2 = '{"type":"text","mode":"single","from_id":"' + from_id + '","to_id":"' + to_id + '","content":"' + bq + '","datetime":"' + msgdate + '"}'; webSocket.send(msg2); $("#chatBox-content_"+to_id+"").append("<div class=\"clearfloat\">" + "<div class=\"author-name\"><small class=\"chat-date\">"+ msgdate +"</small> </div> " + "<div class=\"right\"> <div class=\"chat-message\"> " + bq + " </div> " + "<div class=\"chat-avatars\"><img src=\"/static/httpchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>"); //发送后关闭表情框 $(".biaoqing-photo").toggle(); //聊天框默认最底部 $(document).ready(function () { $(".chatBox-content-demo").scrollTop($(".chatBox-content-demo")[0].scrollHeight); }); }) }); // 发送图片 function selectImg(pic) { if (!pic.files || !pic.files[0]) { return; } var reader = new FileReader(); reader.onload = function (evt) { var images = evt.target.result; var to_img = "<img src=" + images + ">"; //发送到服务器 var msg3 = '{"type":"text","mode":"single","from_id":"' + from_id + '","to_id":"' + to_id + '","content":"' + to_img + '","datetime":"' + msgdate + '"}'; webSocket.send(msg3); $("#chatBox-content_"+to_id+"").append("<div class=\"clearfloat\">" + "<div class=\"author-name\"><small class=\"chat-date\">"+ msgdate +"</small> </div> " + "<div class=\"right\"> <div class=\"chat-message\"><img src=" + images + "></div> " + "<div class=\"chat-avatars\"><img src=\"/static/httpchat/img/icon01.png\" alt=\"头像\" /></div> </div> </div>"); //聊天框默认最底部 $(document).ready(function () { $(".chatBox-content-demo").scrollTop($(".chatBox-content-demo")[0].scrollHeight); }); }; reader.readAsDataURL(pic.files[0]); } </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。