socket.io實現一對多的在線諮詢客服系統

目錄

 

前言

1.需求場景

2.頁面效果圖

3.線上地址

4.項目分析


前言

大三的時候寫過一個小demo,socket.io實現在線匿名聊天室

博客地址:https://blog.csdn.net/qq_30604453/article/details/64159036

demo地址:http://www.chunling.online:2800/(此處請不要計較樣式,畢竟只是造着玩的demo)

示例圖:

 

 

1.需求場景

閒來無事,改造一下這個demo,做一個一對多的在線諮詢客服的系統(不涉及數據庫操作)。

很多企業官網都會有在線諮詢客服的功能。【很想要找個樣例截圖一下,可是懶得找啊,看粗糙版的樣例吧 = =】

希望達到的效果:(1)每個用戶進入網站,立即生成一個匿名身份,可與客服進行在線交流。(2)單一客服,客服可以接收所有用戶的信息,並進行回覆交流。所以這是一個一對多的關係,多個用戶,一個客服。

 

2.頁面效果圖

用戶頁面:如上的gif圖。點擊右下角“在線諮詢”按鈕,彈出對話框,點擊“發送”按鈕或者“回車”可以發送消息給客服。點擊“關閉”按鈕關閉對話框

客服頁面:

左側面板顯示用戶列表,點擊可切換當前聊天對象,如有未讀消息顯示橙色背景,當前聊天對象顯示藍色背景。

中間面板則是聊天視窗。

右側面板記錄用戶進入網站,離開網站的時間。


用戶頁面(潦草地做一下移動端的適配)

    

 

3.線上地址

代碼地址:https://gitee.com/wuchunling/contact-online

demo地址:

客服頁面:http://www.chunling.online:2666/serve

用戶頁面:http://www.chunling.online:2666

 

4.項目分析

在線客服系統主要用socket.io。簡單回顧一下socketio的用法》》socket.io的基本用法

由於是基於之前的小demo改造的,此處就不用什麼高大上的框架。後端採用:express + socket.io;前端採用:jQuery + socket.io

 

4.1 用戶客戶端

(1)一對多的關鍵在於如何標識一個用戶?在這裏,我採用最簡單的方法,用時間戳來標識一個用戶。當用戶進入網站瀏覽時,生成一個時間戳,這個時間戳就標誌這個用戶。

$(document).ready(function () {
  if (!sessionStorage.username) {
    sessionStorage.username = new Date().getTime()
  }
  var username = sessionStorage.username;
})

(2)當用戶進入網站瀏覽,告知服務端“用戶進入網站”;當用戶離開網站,告知服務端“用戶離開了網站”

在這裏觸發兩個事件 loginIn和loginOut(或者說兩個消息),loginIn和loginOut需要服務端去監聽,服務端再將這兩個消息下發給客服端。

$(document).ready(function () {

  var iosocket = io.connect();

  if (!sessionStorage.username) {
    sessionStorage.username = new Date().getTime()
  }
  var username = sessionStorage.username;

  iosocket.emit('loginIn', username); // 進入頁面
  window.onunload = function () {  // 關閉頁面
    iosocket.emit('loginOut', username)
  }

})

(3)用戶發送消息,主要是觸發msgFromClient事件,將聊天信息和用戶標識發送給服務端,服務端監聽此事件,再將此消息轉發給客服。

  $(".btn-blue").click(function () {  // 點擊“發送”按鈕進行發送消息
    var text = $(".mesbox").val();
    if (text != "") {
      var data = {
        name: username,   // sessionStorage.username:標識用戶的時間戳
        content: text
      }
      iosocket.emit('msgFromClient', data);
      $('.mesbox').val('');
      sendHtml(username, text);   // dom操作,更新聊天窗的視圖
    }
  });

document.onkeydown = function (e) {
  var ev = document.all ? window.event : e;
  if (ev.keyCode == 13) {  // 回車發送消息
    $(".btn-blue").click();
    stopDefaultKey(e)
  }
}

(4)接收客服發送來的消息,主要是監聽發送給當前用戶的消息,此處用username接收,username即一開始進入頁面生成的時間戳。

  iosocket.on('connect', function () {
    iosocket.on(username, function (msg) { // 獲取客服消息
      reciveHtml('客服', msg.content);  // dom操作,更新聊天窗視圖
    });
  });

此時,用戶端的socket操作都已完成,剩下的都是dom操作,此處不贅述。

 

4.2 客服客戶端

(1)客服端有一個很重要的數據結構,需要存儲所有用戶的消息記錄。

var currentClient = { flag: -1, name: null } // 當前客戶
var clientList = {}  // 聊天記錄

① currentClient表示當前聊天對象,name爲用戶標識(時間戳),flag爲服務端傳過來的客戶計數(表示第幾個用戶),例如:

{
  "name": "1573104726051",
  "flag": "11"
}

② clientList存儲所有用戶的所有聊天記錄,例如:

{
  "1573104726051": {
    "list": [
      {
        "from": "client",
        "content": "helo world"
      },
      {
        "from": "client",
        "content": "this is Peter!"
      },
      {
        "from": "client",
        "content": "在嗎?"
      },
      {
        "from": "serve",
        "content": "(*´▽`)ノノ"
      }
    ],
    "flag": 11,
    "noread": false
  },
  "1573105081440": {
    "list": [
      {
        "from": "client",
        "content": "this is Jessica!"
      },
      {
        "from": "client",
        "content": "Hello!"
      }
    ],
    "flag": 12,
    "noread": true
  },
  "1573105218701": {
    "list": [],
    "flag": 13,
    "noread": false
  },
  "1573105224254": {
    "list": [],
    "flag": 14,
    "noread": false
  },
  "1573109712098": {
    "list": [
      {
        "from": "client",
        "content": "你好呀"
      },
      {
        "from": "client",
        "content": "諮詢一下"
      }
    ],
    "flag": 15,
    "noread": true
  }
}

(2)客服發送消息給用戶

  $('.btn-blue').click(function () { // 點擊發送按鈕
    if (currentClient) {
      var text = $(".mesbox").val();
      if (text != "") {
        var data = {
          from: 'serve',
          to: currentClient,
          content: text
        }
        iosocketServe.emit('msgFromServe', data); // data發送給服務端
        $('.mesbox').val(''); // 清空輸入框
        updateRoomView(0, data, currentClient.name); // dom操作
      }
    }
  })
document.onkeydown = function (e) { // 回車發送
  var ev = document.all ? window.event : e;
  if (ev.keyCode == 13) {
    $(".btn-blue").click();
  }
}

(3)用戶進入網站,通知客服端

$(document).ready(function () {
  const iosocketServe = io.connect();
  iosocketServe.on('connect', function () {
    iosocketServe.on('clientInto', function (client) { // 用戶進入網站
      clientIn(client)
    })
    iosocketServe.on('clientLeave', function (client) { // 用戶離開網站
      clientOut(client)
    })
    iosocketServe.on('reciveClientMsg', function (msg) { // 接收用戶消息
      updateRoomView(1, msg, msg.name)
    })
  })
})

自此,客服端的socket操作已經完成,剩下的是dom操作,此處不贅述。

 

4.3 服務端

服務端主要起到橋樑的作用,連接用戶與客服,將用戶發送的消息轉發給客服,將客服的消息轉發給用戶。

const path = require('path');
const express = require('express');
const socketio = require("socket.io");
const app = new express();
const port = 2666;
app.use(express.static('public'));

app.get('/*', (req, res) => {
  const pathname = req.params['0'];
  if (!pathname) {
    res.sendFile(path.join(__dirname, 'views', 'index.html'));
    return;
  }
  res.sendFile(path.join(__dirname, 'views', pathname + '.html'))
});
var server = app.listen(port, (error) => {
  if (error) {
    console.error(error);
  } else {
    console.info('==> Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port);
  }
});
const clientList = []
let onlinePeople = 0
socketio.listen(server).on('connection', function (socket) {
  socket.on('msgFromClient', function (msg) { // 接收客戶端發送的消息
    socket.broadcast.emit('reciveClientMsg', {
      from: 'client',
      content: msg.content,
      name: msg.name
    })  // 發送給客服:客戶發送消息
  });
  socket.on('loginIn', function (msg) { // 客戶進入頁面
    onlinePeople++
    let obj = {
      name: msg,  // 用時間戳來標識用戶
      flag: onlinePeople // 第幾個
    }
    clientList.push(obj)
    console.log( obj.name + '進入頁面' )
    socket.broadcast.emit('clientInto', obj) // 發送給客服:有新客戶進入頁面
  });
  socket.on('loginOut', function (msg) { // 客戶退出頁面
    let obj = null
    for(let i=0;i<clientList.length;i++) {
      if(clientList[i].name == msg) {
        obj = clientList[i]
        clientList.splice(i, 1)
        break
      }
    }
    console.log(obj.name + '退出頁面')
    socket.broadcast.emit('clientLeave', obj); // 發送給客服:用戶退出頁面
  });
  socket.on('msgFromServe', function (msg) { 
    socket.broadcast.emit(msg.to.name, msg)
  })
});

完整代碼戳:》》https://gitee.com/wuchunling/contact-online

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章