使用環信WebIm實現一個客服功能


介紹環信

環信 Web IM SDK 為PC/移動 Web 應用,提供完善的即時通信功能開發能力,屏蔽其內部復雜細節,對外提供較為簡潔的 API 接口,方便第三方應用快速集成即時通信功能。

 

完成功能

環信的SDK集成和配置基本按照官網給的文檔就可以實現。本文僅完成了根據用戶名互相發收文字信息的功能,更多功能可在此基礎上參考官方文檔、API。

 

web IM的SDK集成和配置

首先需要購買環信服務,申請appkey,使用賬號和密碼申請環信賬號。

// 以下部分是在前端部分的集成和配置

step1:在官網下載WEIM SDK+體驗demo(下載自己所需要的版本即可)

step2:創建自己的項目,將下載的文件解壓,並將sdk目錄下的三個文件復制到自己的項目中:

step3:創建html文件,用於展示聊天界面,在該html中使用使用引入外部js文件的方式,將step2中的三個文件引入進來。

step4:創建webIMConfig.js文件,用於對webim的配置:

// 配置
WebIM.config = {
    xmppURL: 'http://im-api-v2.easemob.com/ws', // xmpp Server地址
    apiURL: 'http://a1.easemob.com', // rest Server地址
    appkey: '', // App key

    https: false, // 是否使用https

    isHttpDNS: true, // 3.0 SDK支持,防止DNS劫持從服務端獲取XMPPUrl、restUrl 

    isMultiLoginSessions: false, // 是否開啟多頁面同步收消息,注意,需要先聯系商務開通此功能

    isAutoLogin: true, // 自動出席,(如設置為false,則表示離線,無法收消息,需要在登錄成功后手動調用conn.setPresence()才可以收消息)

    isDebug: false, // 打開調試,會自動打印log,在控制台的console中查看log

    autoReconnectNumMax: 2, // 斷線重連最大次數

    autoReconnectInterval: 2, // 斷線重連時間間隔

    heartBeatWait: 4500, // 使用webrtc(視頻聊天)時發送心跳包的時間間隔,單位ms

    delivery: true, // 是否發送已讀回執

    Host: "",
}

// 創建連接
var conn = {};
conn = WebIM.conn = new WebIM.default.connection({
    appKey: WebIM.config.appkey,
    isHttpDNS: WebIM.config.isHttpDNS,
    isMultiLoginSessions: WebIM.config.isMultiLoginSessions,
    host: WebIM.config.Host,
    https: WebIM.config.https,
    url: WebIM.config.xmppURL,
    apiUrl: WebIM.config.apiURL,
    isAutoLogin: WebIM.config.isAutoLogin,
    heartBeatWait: WebIM.config.heartBeatWait,
    autoReconnectNumMax: WebIM.config.autoReconnectNumMax,
    autoReconnectInterval: WebIM.config.autoReconnectInterval,
    isStropheLog: WebIM.config.isStropheLog,
    delivery: WebIM.config.delivery
})

以上內容都是直接從官網文檔復制的,注意修改的地方有三個(代碼中用紅色標出的部分):

1.appkey:要替換成自己申請的appkey;

2.Host:配置成自己的服務器的主機號+端口號;

3.new webIM.default.connection,官網文檔中給出的是new webIM.connection,但是報connection未定義的錯誤,我將webIM打印出來發現這個connection在default下邊,所以改成了這樣。直接復制代碼的話可能會有這類似的問題,可以注意一下。

同樣在step2中引入的webIMSDK3.0.6.js也有同樣的錯誤,我也在webIM后邊加上了.default。

step5:添加回調監聽,官網文檔里復制的:

conn.listen({
    onOpened: function(message) { //連接成功回調
        // 如果isAutoLogin設置為false,那么必須手動設置上線,否則無法收消息
        // 手動上線指的是調用conn.setPresence(); 如果conn初始化時已將isAutoLogin設置為true
        // 則無需調用conn.setPresence(); 
        console.log("連接成功")
    },
    onClosed: function(message) {}, //連接關閉回調
    onTextMessage: function(message) {
        console.log(message);
        receiverMessage(message)
    }, //收到文本消息
    onEmojiMessage: function(message) {}, //收到表情消息
    onPictureMessage: function(message) {}, //收到圖片消息
    onCmdMessage: function(message) {}, //收到命令消息
    onAudioMessage: function(message) {}, //收到音頻消息
    onLocationMessage: function(message) {}, //收到位置消息
    onFileMessage: function(message) {}, //收到文件消息
    onVideoMessage: function(message) {
        var node = document.getElementById('privateVideo');
        var option = {
            url: message.url,
            headers: {
                'Accept': 'audio/mp4'
            },
            onFileDownloadComplete: function(response) {
                var objectURL = WebIM.utils.parseDownloadResponse.call(conn, response);
                node.src = objectURL;
            },
            onFileDownloadError: function() {
                console.log('File down load error.')
            }
        };
        WebIM.utils.download.call(conn, option);
    }, //收到視頻消息
    onPresence: function(message) {
        handlePresence(message);
    }, //處理“廣播”或“發布-訂閱”消息,如聯系人訂閱請求、處理群組、聊天室被踢解散等消息
    onRoster: function(message) {}, //處理好友申請
    onInviteMessage: function(message) {}, //處理群組邀請
    onOnline: function() {}, //本機網絡連接成功
    onOffline: function() {
        console.log("offline")
    }, //本機網絡掉線
    onError: function(message) {
        console.log('onError: ', message);
    }, //失敗回調
    onBlacklistUpdate: function(list) { //黑名單變動
        // 查詢黑名單,將好友拉黑,將好友從黑名單移除都會回調這個函數,list則是黑名單現有的所有好友信息
        console.log(list);
    },
    onRecallMessage: function(message) {}, //收到撤回消息回調
    onReceivedMessage: function(message) {}, //收到消息送達服務器回執
    onDeliveredMessage: function(message) {}, //收到消息送達客戶端回執
    onReadMessage: function(message) {}, //收到消息已讀回執
    onCreateGroup: function(message) {}, //創建群組成功回執(需調用createGroupNew)
    onMutedMessage: function(message) {} //如果用戶在A群組被禁言,在A群發消息會走這個回調並且消息不會傳遞給群其它成員
});

 

實現客服功能

以上已經將環信配置完畢了,接下來使用環信的API制作客服功能。

這里我們申請了兩個環信賬號,一個作為客服,一個作為客戶。

先來看一下效果:

客服端:

 

客戶端:

 

前端樣式非常簡單,我直接將代碼放在后邊。注意在進行對話之前要先登錄。由於這個項目會接入到商城中,因此不用顯式登陸,會寫一個接口傳入用戶名和密碼,並自動完成登陸功能。

以下講述幾個制作中的難點:

難點1:接收和發送的信息展示在頁面里。

為了讓消息交替錯落的展示,每一條消息都是一個<div>塊級元素,這樣就能自動完成換行。當接收或者發送消息的時候,在頁面中插入一個相應的<div>。

 

難點2:當消息過多的時候,能夠自動向上滾動,以顯示最新消息。

使用的scrollTop動畫來完成。給scrollTop設置一個很大的值,這樣頁面就能總是能滑動顯示出最新的消息。

 

難點3:客服端的側邊顯示來自不同用戶的消息,並且顯示消息未讀小紅點。

當收到信息時,我們收到的消息中包含一個from字段,表示消息來自哪個用戶,根據這個字段將消息插入到對應的對話界面中。當當前顯示的對話界面不是該用戶時,就要出現小紅點提示有未讀信息。

添加一個全局變量talkTo,其中保存當前對話方的用戶名,表示當前在與誰對話。通過點擊消息列表中的用戶來改變這個變量的值。我們用這個值來完成消息的發送等功能。同時也可以用這個值來判斷出當前展示的對話界面,從而判斷是否顯示消息未讀的小紅點。

 

難點4:顯示與不同用戶的交流界面

使用<div>包裹用戶名+用戶對話界面,並給這個div添加帶有用戶信息的獨特id。默認這個<div>是display:none。當通過側邊列表項選擇對話方時,將對應的<div>設置為display:block

 

在官方文檔中提供了消息的發送和接收的示例函數,可以直接復制過來再稍加改動,添加一點顯示方面的代碼就可以了。

 

代碼

客戶端和客服端代碼基本一致,只是客戶端沒有旁邊的列表,也不用顯示不同的對話界面,所以html和css上稍有差異,js中對消息的處理和顯示也稍簡單一點。

他們都公用環信的配置、初始化和監聽函數,盡量減少兩者在監聽中的差異,不同之處在各自的js中處理。

項目代碼如下:

客服端:

HTML

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html>
<!--<![endif]-->

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="index.css">
</head>

<body>
    <!-- 消息列表 -->
    <ul class="sidebar" id="roster" onclick="showDialogist()">
        <div>消息列表</div>
    </ul>
    <div class="message">
        <!-- 信息顯示 -->
        <div class="display" id="display">
            <!-- 默認對話界面 -->
            <div>
                <div class="dialogist">歡迎來到客戶服務平台</div>
                <div class="content">
                </div>
            </div>
        </div>
        <!-- 信息編輯 -->
        <div class="edit">
            <textarea id="sendContent"></textarea>
            <button onclick="sendMessage()">發送信息</button>
        </div>
    </div>

    <script type='text/javascript' src='lib/jquery-3.2.1.js'></script>
    <script type='text/javascript' src='lib/webimSDK3.0.6.js'></script>
    <script type='text/javascript' src='lib/EMedia_x1v1.js'></script>
    <!-- <script type='text/javascript' src='lib/EMedia_sdk-dev.js'></script> -->
    <script type='text/javascript' src='WebIMConfig.js'></script>
    <script type='text/javascript' src='index.js'></script>
</body>

</html>    

CSS

body {
    margin: 0;
}


/* 側邊欄 */

.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: 250px;
    height: 100%;
    background: #444;
    margin: 0;
    padding: 0;
}

.sidebar div {
    width: 100%;
    text-align: center;
    color: #FFF;
    font-size: 18px;
    font-weight: bold;
    margin-top: 16px;
    margin-bottom: 19px;
}

.sidebar li {
    padding: 18px;
    display: flex;
    align-items: center;
    position: relative;
    cursor: pointer;
}

.sidebar img {
    width: 45px;
    height: 45px;
    margin-right: 16px;
}

.sidebar .name {
    margin-right: 5px;
    color: #c8c9cc;
    font-size: 18px;
    width: 130px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar .redIcon {
    width: 12px;
    height: 12px;
    background-color: red;
    border-radius: 50%;
    position: absolute;
    top: 3px;
    left: 56px;
}


/* 側邊欄標簽鼠標移入樣式 */

.sidebar li:hover {
    background-color: #666;
    color: #FFF;
}


/* 側邊欄標簽選中樣式 */

.sidebar-selected,
.sidebar .sidebar-selected:hover {
    background: #FFF;
}

.sidebar-selected .name {
    color: #333;
}


/* 信息部分 */

.message {
    margin-left: 250px;
    width: calc(100% - 250px);
}


/* 信息顯示部分 */

.message .display {
    width: 100%;
}

.message .display .dialogist {
    border-bottom: 1px solid #333;
    padding: 16px;
    font-size: 20px;
}

.message .display .content {
    width: 100%;
    height: 385px;
    padding-bottom: 16px;
    overflow-y: scroll;
}

.message .display .head {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    margin: 5px 16px;
}

.message .display .time {
    color: #bbb;
    font-size: 12px;
    margin: 5px 8px;
    display: inline-block;
}

.message .display .textBox {
    max-width: 250px;
    min-height: 20px;
    border-radius: 5px;
    padding: 8px 16px;
    box-shadow: 0 0 2px 1px #ddd;
    word-break: break-all;
}

.message .display .left {
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    padding-left: 10px;
    margin-top: 16px;
}

.message .display .right {
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    padding-right: 10px;
    margin-top: 16px;
}

.message .display .left .time {
    text-align: left;
}

.message .display .right .time {
    text-align: right;
}

.message .display .left .textBox {
    background-color: yellowgreen;
}

.message .display .right .textBox {
    background-color: #fff;
}


/* 信息編輯部分 */

.message .edit {
    border-top: 1px solid #333;
    height: 230px;
    width: 100%;
}

.message .edit textarea {
    width: calc(100% - 20px);
    height: calc(100% - 70px);
    resize: none;
    padding: 10px;
    font-size: 16px;
    border: 0;
    outline: none;
}

.message .edit button {
    float: right;
    background-color: #333;
    border: 0;
    color: #fff;
    padding: 8px 16px;
    cursor: pointer;
    margin-right: 30px;
}

.message .edit button:hover {
    background-color: #666;
}

JS

var username = "";//客服賬號
var password = "";//客服密碼
var talkTo = "";//當前對話方
var curTalkList = new Set();//當前對話用戶列表

window.onload = function() {
    this.login();
}

// 登陸
function login() {
    //登陸API
    var options = {
        apiUrl: WebIM.config.apiURL,
        user: username,
        pwd: password,
        appKey: WebIM.config.appkey
    };
    conn.open(options);
}

//   退出
function logOut() {
    conn.close();
}

// 單聊發送文本信息
//官方文檔示例函數,稍加修改,與發送消息顯示函數連接到一起
function sendPrivateText(myTime, content) {
    var id = conn.getUniqueId(); // 生成本地消息id
    var msg = new WebIM.default.message('txt', id); // 創建文本消息

    msg.set({
        msg: content, // 消息內容
        to: talkTo, // 接收消息對象(用戶id)
        roomType: false,
        ext: {
            "time": myTime
        }, //擴展消息
        success: function(id, serverMsgId) {
            console.log('send private text Success');
        }, // 對成功的相關定義,sdk會將消息id登記到日志進行備份處理
        fail: function(e) {
                console.log("Send private text error");
            } // 對失敗的相關定義,sdk會將消息id登記到日志進行備份處理
    });
    msg.body.chatType = 'singleChat';
    conn.send(msg.body);
};

// 顯示已發送信息
function sendMessage() {
    var myTime = new Date().toLocaleString();
    var content = document.getElementById("sendContent").value;
    document.getElementById("sendContent").value = "";
    $("#" + talkTo + "_i").children(".content").append('<div class="right">' +
        '<div class="time">' + myTime + '</div>' +
        '<div class="textBox">' + content + '</div>' +
        '<img class="head" src="./img/logo.png"></div>')
    $("#" + talkTo + "_i").children(".content").animate({ scrollTop: 9999 }, 200)
    sendPrivateText(myTime, content);
}

// 顯示接收到的信息
// 客服端:在列表中顯示消息
function receiverMessage(message) {
    var name = message.from,
        time = message.ext.time,
        content = message.data;

    if (curTalkList.has(name)) {
        $("#" + name + "_i").children(".content").append('<div class="left">' +
            '<img class="head" src="./img/logo.png">' +
            '<div class="textBox">' + content + '</div>' +
            '<div class="time">' + time + '</div></div>')

        if (talkTo == name) {
            $("#" + name).children(".redIcon").attr("style", "display:block;");
        }
    } else {
        // 添加消息列表中的信息
        curTalkList.add(name);
        $("#roster").append('<li id="' + name + '"><div class="redIcon"></div><img src="./img/logo.png"><div class="name">' + name + '</div></li>');

        // 添加消息顯示框中的信息
        $("#display").append('<div style="display:none;" id="' + name + '_i"><div class="dialogist">' + name + '</div>' +
            '<div class="content">' +
            '<div class="left">' +
            '<img class="head" src="./img/logo.png">' +
            '<div class="textBox">' + content + '</div>' +
            '<div class="time">' + time + '</div></div>' +
            '</div></div>')
    }

    $("#" + name + "_i").children(".content").animate({ scrollTop: 9999 }, 200)
}

// 點擊列表中的用戶,顯示對應的對話界面
function showDialogist() {
    $("#roster").children("li").attr("class", "");
    $("#display").children("div").attr("style", "display:none;");

    var cur = event.target.closest("li").id;
    talkTo = cur;
    $("#" + cur).attr("class", "sidebar-selected");
    $("#" + cur).children(".redIcon").attr("style", "display:none;");
    $("#" + cur + "_i").attr("style", "display:block;");
}

 

客戶端:

HTML

<!DOCTYPE html>
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!-->
<html>
<!--<![endif]-->

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title></title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="client.css">
</head>

<body>
    <div class="message">
        <!-- 信息顯示 -->
        <div class="display">
            <div class="dialogist">商城-客服</div>
            <div class="content" id="display">
            </div>
        </div>
        <!-- 信息編輯 -->
        <div class="edit">
            <textarea id="sendContent"></textarea>
            <button onclick="sendMessage()">發送信息</button>
        </div>
    </div>

    <script type='text/javascript' src='lib/jquery-3.2.1.js'></script>
    <script type='text/javascript' src='lib/webimSDK3.0.6.js'></script>
    <script type='text/javascript' src='lib/EMedia_x1v1.js'></script>
    <!-- <script type='text/javascript' src='lib/EMedia_sdk-dev.js'></script> -->
    <script type='text/javascript' src='WebIMConfig.js'></script>
    <script type='text/javascript' src='client.js'></script>
</body>

</html>

CSS

body {
    margin: 0;
}


/* 信息部分 */

.message {
    width: 100%;
}


/* 信息顯示部分 */

.message .display {
    width: 100%;
}

.message .display .dialogist {
    height: 27px;
    border-bottom: 1px solid #333;
    padding: 16px;
    font-size: 20px;
}

.message .display .content {
    width: 100%;
    height: 385px;
    padding-bottom: 16px;
    overflow-y: scroll;
}

.message .display .head {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    margin: 5px 16px;
}

.message .display .time {
    color: #bbb;
    font-size: 12px;
    margin: 5px 8px;
    display: inline-block;
}

.message .display .textBox {
    max-width: 250px;
    min-height: 20px;
    border-radius: 5px;
    padding: 8px 16px;
    box-shadow: 0 0 2px 1px #ddd;
    word-break: break-all;
}

.message .display .left {
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    padding-left: 10px;
    margin-top: 16px;
}

.message .display .right {
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    padding-right: 10px;
    margin-top: 16px;
}

.message .display .left .time {
    text-align: left;
}

.message .display .right .time {
    text-align: right;
}

.message .display .left .textBox {
    background-color: yellowgreen;
}

.message .display .right .textBox {
    background-color: #fff;
}


/* 信息編輯部分 */

.message .edit {
    border-top: 1px solid #333;
    height: 205px;
    width: 100%;
}

.message .edit textarea {
    width: calc(100% - 20px);
    height: calc(100% - 70px);
    resize: none;
    padding: 10px;
    font-size: 16px;
    border: 0;
    outline: none;
}

.message .edit button {
    float: right;
    background-color: #333;
    border: 0;
    color: #fff;
    padding: 8px 16px;
    cursor: pointer;
    margin-right: 30px;
}

.message .edit button:hover {
    background-color: #666;
}

JS

// 登陸
var username = "";//客戶用戶名
var password = "";//客戶密碼
var talkTo = "";//客服用戶名
window.onload = function() {
    this.login();
}

function login() {
    var options = {
        apiUrl: WebIM.config.apiURL,
        user: username,
        pwd: password,
        appKey: WebIM.config.appkey
    };
    conn.open(options);
}

//   退出
function logOut() {
    conn.close();
}

// 單聊發送文本信息
function sendPrivateText(myTime, content) {
    var id = conn.getUniqueId(); // 生成本地消息id
    var msg = new WebIM.default.message('txt', id); // 創建文本消息

    msg.set({
        msg: content, // 消息內容
        to: talkTo, // 接收消息對象(用戶id)
        roomType: false,
        ext: {
            "time": myTime
        }, //擴展消息
        success: function(id, serverMsgId) {
            console.log('send private text Success');
        }, // 對成功的相關定義,sdk會將消息id登記到日志進行備份處理
        fail: function(e) {
                console.log("Send private text error");
            } // 對失敗的相關定義,sdk會將消息id登記到日志進行備份處理
    });
    msg.body.chatType = 'singleChat';
    conn.send(msg.body);
};

// 顯示已發送信息
function sendMessage() {
    var myTime = new Date().toLocaleString();
    var content = document.getElementById("sendContent").value;
    document.getElementById("sendContent").value = "";
    $("#display").append('<div class="right">' +
        '<div class="time">' + myTime + '</div>' +
        '<div class="textBox">' + content + '</div>' +
        '<img class="head" src="./img/logo.png"></div>')
    $("#display").animate({ scrollTop: 9999 }, 200)
    sendPrivateText(myTime, content);
}

// 顯示接收到的信息
function receiverMessage(message) {
    var time = message.ext.time,
        content = message.data;
    $("#display").append('<div class="left">' +
        '<img class="head" src="./img/logo.png">' +
        '<div class="textBox">' + content + '</div>' +
        '<div class="time">' + time + '</div></div>')
    $("#display").animate({ scrollTop: 9999 }, 200)
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM