Browse Source

在线客服

zhengchengwu 4 years ago
parent
commit
9f7b880f14

+ 10 - 0
package-lock.json View File

@@ -12875,6 +12875,11 @@
12875 12875
       "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
12876 12876
       "dev": true
12877 12877
     },
12878
+    "spark-md5": {
12879
+      "version": "3.0.0",
12880
+      "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.0.tgz",
12881
+      "integrity": "sha1-NyIifFTi+vJLHcbZM8wUTm9xv+8="
12882
+    },
12878 12883
     "spdx-correct": {
12879 12884
       "version": "3.1.0",
12880 12885
       "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
@@ -14311,6 +14316,11 @@
14311 14316
         "minimalistic-assert": "^1.0.0"
14312 14317
       }
14313 14318
     },
14319
+    "webim-tencent": {
14320
+      "version": "1.0.2",
14321
+      "resolved": "https://registry.npmjs.org/webim-tencent/-/webim-tencent-1.0.2.tgz",
14322
+      "integrity": "sha512-sdSRjcTsb/4t9riUpEv3+01wNMxP8hbWOllPbmkqKJ2jhXy88w57K7Ae4BnaeFH55prdcpsKwBhsX7BiJYGv/w=="
14323
+    },
14314 14324
     "webpack": {
14315 14325
       "version": "3.10.0",
14316 14326
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz",

+ 2 - 0
package.json View File

@@ -61,6 +61,7 @@
61 61
     "showdown": "1.8.5",
62 62
     "simplemde": "1.11.2",
63 63
     "sortablejs": "1.7.0",
64
+    "spark-md5": "^3.0.0",
64 65
     "vue": "2.5.16",
65 66
     "vue-count-to": "1.0.13",
66 67
     "vue-i18n": "7.3.2",
@@ -69,6 +70,7 @@
69 70
     "vue-splitpane": "1.0.2",
70 71
     "vuedraggable": "^2.16.0",
71 72
     "vuex": "3.0.1",
73
+    "webim-tencent": "^1.0.2",
72 74
     "xlsx": "^0.11.16"
73 75
   },
74 76
   "devDependencies": {

+ 8 - 0
src/api/kefu/tencentim.js View File

@@ -0,0 +1,8 @@
1
+import request from '@/utils/request'
2
+
3
+export function getusersig() {
4
+  return request({
5
+    url: '/api/tencent/usersig', 
6
+    method: 'get',
7
+  })
8
+}

+ 2 - 0
src/router/index.js View File

@@ -13,6 +13,7 @@ import org from './modules/org'
13 13
 import marketing_tool from './modules/marketing_tool'
14 14
 import system from './modules/system'
15 15
 import site from './modules/site'
16
+import kefu from './modules/kefu'
16 17
 
17 18
 /** note: submenu only apppear when children.length>=1
18 19
  *   detail see  https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
@@ -79,6 +80,7 @@ var _constant_router_map = [{
79 80
 
80 81
 var _asy_router_map = [
81 82
   member,
83
+  kefu,
82 84
   article,
83 85
   marketing_tool,
84 86
   org,

+ 23 - 0
src/router/modules/kefu.js View File

@@ -0,0 +1,23 @@
1
+import Layout from '@/views/layout/Layout'
2
+//客服管理模块
3
+
4
+
5
+export default {
6
+    alwaysShow: true,
7
+    path: '/kefu',
8
+    component: Layout,
9
+    redirect: 'noredirect',
10
+    name: 'kefu',
11
+    meta: {
12
+      title: '客服管理',
13
+      icon: 'message'
14
+    },
15
+    children: [
16
+      {
17
+        path: '/kefu',
18
+        component: () => import('@/scrm_pages/kefu'),
19
+        name: 'kefuBox',
20
+        meta: { title: '咨询管理', noCache: true }
21
+      },
22
+    ]
23
+  }

+ 762 - 49
src/scrm_pages/contactBox/index.vue View File

@@ -1,13 +1,10 @@
1 1
 <template>
2 2
     <div class="contact-box" id="contact-box">
3 3
         <div class="contact-box-item msg-box" >
4
-            <div class="box-btn " @click="showMsgBox=true">
4
+            <div class="box-btn " @click="toggleMsgBox">
5 5
                 <i class="el-icon-service"></i>
6 6
                 <span>在线客服</span>
7 7
             </div>
8
-            <div class="contact-info-box" v-show="!showMsgBox">
9
-                点击打开在线客服
10
-            </div>
11 8
             <div class="contact-msg-box" v-show="showMsgBox">
12 9
                 <div class="msg-box-panel">
13 10
                     <div class="panel-header">
@@ -17,57 +14,669 @@
17 14
                     </div>
18 15
                     <div class="panel-body">
19 16
                         <ul class="msg-inner scroll-y">
20
-                            <li>1</li>
21
-                            <li>1</li>
22
-                            <li>1</li>
23
-                            <li>1</li>
24
-                            <li>1</li>
25
-                            <li>1</li>
26
-                            <li>1</li>
27
-                            <li>1</li>
28
-                            <li>1</li>
29
-                            <li>1</li>
30
-                            <li>1</li>
31
-                            <li>1</li>
32
-                            <li>1</li>
33
-                            <li>1</li>
34
-                            <li>1</li>
35
-                            <li>1</li>
36
-                            <li>1</li>
37
-                            <li>1</li>
38
-                            <li>1</li>
39
-                            <li>1</li>
40
-                            <li>1</li>
41
-                            <li>1</li>
42
-                            <li>1</li>
43
-                            <li>1</li>
44
-                            <li>1</li>
45
-                            <li>1</li>
17
+                            <li v-for="(messageitem, key) in messageBox" :key="key" :id="'id_'+messageitem.id" class="cell clearfix" :class="messageitem.float=='right'?'cell_right':''">
18
+                                <template v-if="messageitem.float=='right'">
19
+                                    <div class="msg_body fl">
20
+                                        <div class="inner" v-html="messageitem.message"></div>
21
+                                    </div>
22
+                                    <div class="cell_pic fl">
23
+                                        <div class="pic">
24
+                                            <img :src="messageitem.avatar" alt="">
25
+                                        </div>
26
+                                    </div>
27
+                                </template>
28
+                                <template v-else>
29
+                                    <div class="cell_pic fl">
30
+                                        <div class="pic">
31
+                                            <img :src="messageitem.avatar" alt="">
32
+                                        </div>
33
+                                    </div>
34
+                                    <div class="msg_body fl">
35
+                                        <div class="inner" v-html="messageitem.message"></div>
36
+                                    </div>
37
+                                </template>
38
+                            </li>
46 39
                         </ul>
47 40
                     </div>
41
+                    <div class="panel-tool">
42
+                        <i class="icon-face" title="表情" @click="showEmotion"></i>
43
+                        <el-upload
44
+                        class="avatar-uploader"
45
+                        action="https://jsonplaceholder.typicode.com/posts/"
46
+                        :show-file-list="false"
47
+                        :http-request='handleIMPicUload'
48
+                        :on-success="handleIMPicSuccess"
49
+                        :before-upload="beforeIMPicUpload">
50
+                        <i class="el-icon-picture" title="图片"></i>
51
+                        </el-upload>
52
+                        <div class="face-box" v-show="showFace">
53
+                            <div class="face-box-title">
54
+                                <span>表情</span>
55
+                                <i class="el-icon-close " @click="showFace=false" style="float:right" ></i>
56
+                            </div>
57
+                            <ul class="face-box-list clearfix">
58
+                                <li v-for="(faceitem, index) in facelist" :key="index" @click="selectEmotion(faceitem)" >
59
+                                    <img :src="faceitem[1]" :id="faceitem[0]"  alt="">
60
+                                </li>
61
+                            </ul>
62
+                        </div>
63
+
64
+                    </div>
65
+                    <div class="panel-booter">
66
+                        <div class="msg-input-box">
67
+                            <textarea class="textarea scroll-y message-textarea"  v-model="message" placeholder="请输入"></textarea>
68
+                        </div>
69
+                        <div class="msg-send-btn-box">
70
+                            <span class="time fl">服务时间:工作时间:9:00-22:00 节假日:9:00-18:00</span>
71
+                            <el-button type="primary" icon="el-icon-edit" class="fr" size="mini" @click="sendMessage">发送</el-button>
72
+                            <!-- <button type="submit" id="sendadminkfmsg" class="send_btn fr">发送</button> -->
73
+                        </div>
74
+                    </div>
48 75
                 </div>
49 76
             </div>
50 77
         </div>
51 78
         <div class="contact-box-item phone-box">
52
-            <div class="box-btn">
79
+            <div class="box-btn" @click="togglePhoneBox">
53 80
                 <i class="el-icon-phone-outline"></i>
54 81
                 <span>客服电话</span>
55 82
             </div>
56
-            <div class="contact-phone-box">
57
-                <i class="el-icon-phone-outline"></i>
83
+            <div class="contact-phone-box" v-show="showPhoneBox">
84
+                <i class="el-icon-phone-outline" ></i>
58 85
                 <span>0755-86526342</span>
59 86
             </div>
60 87
         </div>
61 88
     </div>
62 89
 </template>
63 90
 <script>
91
+import {getusersig} from "@/api/kefu/tencentim";
92
+import webim from 'webim-tencent';
93
+let selType =  webim.SESSION_TYPE.C2C;
94
+let reqMsgCount = 15; //每次请求的历史消息(c2c获取群)条数
95
+var msgList = [];
96
+var getPrePageC2CHistroyMsgInfoMap = {};
64 97
 export default {
65 98
     name:'contactBox',
66 99
     data(){
67 100
         return{
68 101
             showMsgBox:false,
102
+            showPhoneBox:false,
103
+            selToID:'',
104
+            loginInfo: {
105
+                sdkAppID: '', //用户所属应用id,必填
106
+                appIDAt3rd: '',
107
+                identifier: '', //当前用户ID,必须是否字符串类型,必填
108
+                accountType: '', //用户所属应用帐号类型,必填
109
+                userSig: '', //当前用户身份凭证,必须是字符串类型,必填
110
+                identifierNick: '', //当前用户昵称,不用填写,登录接口会返回用户的昵称,如果没有设置,则返回用户的id
111
+                headurl: '', //当前用户默认头像,选填,如果设置过头像,则可以通过拉取个人资料接口来得到头像信息
112
+            },
113
+            useradmin:{
114
+                usersig: '',
115
+                Indentifier: '',
116
+                appIDAt3rd:'',
117
+                IdentifierNick:'',
118
+                HeadURL:'',
119
+            },
120
+            kefuUrl:'https://images.shengws.com/ico_gjh.png',
121
+            userSigFlag:false,
122
+            imloginFlag:false,
123
+            message:'',
124
+            messageBox:[],
125
+            facelist:[],
126
+            showFace:false,
69 127
         }
70
-    }
128
+    },
129
+    created(){
130
+        
131
+        this.getusersig();
132
+    },
133
+    methods:{
134
+        getusersig() {
135
+            getusersig().then(response => {
136
+                if (response.data.state == 0) {
137
+                    this.$message.error(response.data.msg);
138
+                    return false;
139
+                } else {
140
+                    this.useradmin = {
141
+                        usersig: response.data.data.sig,
142
+                        Indentifier: response.data.data.Indentifier,
143
+                        appIDAt3rd:response.data.data.appIDAt3rd,
144
+                        IdentifierNick:response.data.data.IdentifierNick,
145
+                        HeadURL:response.data.data.HeadURL,
146
+                    } 
147
+                    
148
+                    this.loginInfo.appIDAt3rd = this.useradmin.appIDAt3rd
149
+                    this.loginInfo.identifier = this.useradmin.Indentifier
150
+                    this.loginInfo.userSig = this.useradmin.usersig
151
+                    this.loginInfo.identifierNick = this.useradmin.IdentifierNick
152
+                    this.loginInfo.headurl = this.useradmin.HeadURL
153
+                    this.loginInfo.sdkAppID = response.data.data.sdkAppID
154
+                    this.loginInfo.accountType = response.data.data.accountType
155
+                    this.selToID = response.data.data.selToAdmin;
156
+                    this.userSigFlag = true;
157
+                }
158
+            });
159
+        },
160
+        showEmotion:function(){
161
+            this.facelist = [];
162
+            for (const index in webim.Emotions) {
163
+                this.facelist.push(webim.Emotions[index]);
164
+            }
165
+            this.showFace = true;
166
+        },
167
+        selectEmotion:function(face){
168
+            this.message += face[0];
169
+            this.showFace = false;
170
+        },
171
+        sendMessage:function(){
172
+            var message = this.message.trim();
173
+            var msgLen = webim.Tool.getStrBytes(message);
174
+            if(message == '') {
175
+                this.$message.error('不能发送空消息');
176
+                return false;
177
+            }
178
+            var maxLen, errInfo;
179
+            if (selType == webim.SESSION_TYPE.C2C) {
180
+                maxLen = webim.MSG_MAX_LENGTH.C2C;
181
+                errInfo = "消息长度超出限制(最多" + Math.round(maxLen / 3) + "汉字)";
182
+            } else {
183
+                maxLen = webim.MSG_MAX_LENGTH.GROUP;
184
+                errInfo = "消息长度超出限制(最多" + Math.round(maxLen / 3) + "汉字)";
185
+            }
186
+            if (msgLen > maxLen) {
187
+                this.$message.error(errInfo);
188
+                return false;
189
+            }
190
+            this.handleMsgSend(message);
191
+        },
192
+        handleMsgSend(msgContent) {
193
+            var selSess = new webim.Session(selType, this.selToID, this.selToID, this.kefuUrl, Math.round(new Date().getTime() / 1000));
194
+            var isSend = true; //是否为自己发送
195
+            var seq = -1; //消息序列,-1表示sdk自动生成,用于去重
196
+            var random = Math.round(Math.random() * 4294967296); //消息随机数,用于去重
197
+            var msgTime = Math.round(new Date().getTime() / 1000); //消息时间戳
198
+            var subType; //消息子类型
199
+            if (selType == webim.SESSION_TYPE.C2C) {
200
+                subType = webim.C2C_MSG_SUB_TYPE.COMMON;
201
+            } else {
202
+                subType = webim.GROUP_MSG_SUB_TYPE.COMMON;
203
+            }
204
+            var msg = new webim.Msg(selSess, isSend, seq, random, msgTime, this.loginInfo.identifier, subType, this.loginInfo.identifierNick);
205
+
206
+            var text_obj, face_obj, tmsg, emotionIndex, emotion, restMsgIndex;
207
+            //解析文本和表情
208
+            var expr = /\[[^[\]]{1,3}\]/mg;
209
+            var emotions = msgContent.match(expr);
210
+            if (!emotions || emotions.length < 1) {
211
+                text_obj = new webim.Msg.Elem.Text(msgContent);
212
+                msg.addText(text_obj);
213
+            } else {
214
+                for (var i = 0; i < emotions.length; i++) {
215
+                    tmsg = msgContent.substring(0, msgContent.indexOf(emotions[i]));
216
+                    if (tmsg) {
217
+                        text_obj = new webim.Msg.Elem.Text(tmsg);
218
+                        msg.addText(text_obj);
219
+                    }
220
+                    emotionIndex = webim.EmotionDataIndexs[emotions[i]];
221
+                    emotion = webim.Emotions[emotionIndex];
222
+
223
+                    if (emotion) {
224
+                        face_obj = new webim.Msg.Elem.Face(emotionIndex, emotions[i]);
225
+                        msg.addFace(face_obj);
226
+                    } else {
227
+                        text_obj = new webim.Msg.Elem.Text(emotions[i]);
228
+                        msg.addText(text_obj);
229
+                    }
230
+                    restMsgIndex = msgContent.indexOf(emotions[i]) + emotions[i].length;
231
+                    msgContent = msgContent.substring(restMsgIndex);
232
+                }
233
+                if (msgContent) {
234
+                    text_obj = new webim.Msg.Elem.Text(msgContent);
235
+                    msg.addText(text_obj);
236
+                }
237
+            }
238
+
239
+            msg.PushInfo = {
240
+                "PushFlag": 0,
241
+                "Desc": '测试离线推送内容', //离线推送内容
242
+                "Ext": '测试离线推送透传内容', //离线推送透传内容
243
+                "AndroidInfo": {
244
+                    "Sound": "android.mp3" //离线推送声音文件路径。
245
+                },
246
+                "ApnsInfo": {
247
+                    "Sound": "apns.mp3", //离线推送声音文件路径。
248
+                    "BadgeMode": 1
249
+                }
250
+            };
251
+
252
+            msg.PushInfoBoolean = true; //是否开启离线推送push同步
253
+            msg.sending = 1;
254
+            msg.originContent = msgContent;
255
+            // turnoffFaces_box();
256
+            var _this = this;
257
+
258
+            webim.sendMsg(msg, function (resp) {
259
+                _this.addMsg(msg);
260
+                _this.message = '';
261
+            }, function (err) {
262
+                console.log(err)
263
+            });
264
+        },
265
+        addMsg(msg, prepage) {
266
+            var messageitem = {
267
+                id:'',
268
+                message:'',
269
+                avatar:'',
270
+                time:'',
271
+                float:''
272
+            };
273
+            var isSelfSend, fromAccount, fromAccountNick, fromAccountImage, sessType, subType;
274
+
275
+            //webim.SESSION_TYPE.GROUP-群聊,
276
+            //webim.SESSION_TYPE.C2C-私聊,
277
+            sessType = msg.getSession().type();
278
+            isSelfSend = msg.getIsSend();//消息是否为自己发的
279
+            fromAccount = msg.getFromAccount();
280
+            if (!fromAccount) {
281
+                return;
282
+            }
283
+            if (isSelfSend) {//如果是自己发的消息
284
+                messageitem.avatar = this.loginInfo.headurl;
285
+                messageitem.float = "right";
286
+            } else {
287
+                messageitem.avatar = this.kefuUrl;
288
+                messageitem.float = "left";
289
+            }
290
+            messageitem.id = msg.random;
291
+            messageitem.time = webim.Tool.formatText2Html(webim.Tool.formatTimeStamp(msg.getTime()));
292
+            messageitem.message = this.convertMsgtoHtml(msg)
293
+            this.messageBox.push(messageitem);
294
+
295
+            var msgflow = document.getElementsByClassName("msg-inner")[0];
296
+            if (prepage) {
297
+                //300ms后,等待图片加载完,滚动条自动滚动到底部
298
+                if (msgflow.scrollTop == 0) {
299
+                    setTimeout(function () {
300
+                        msgflow.scrollTop = 0;
301
+                    }, 300);
302
+                }
303
+            } else {
304
+                //300ms后,等待图片加载完,滚动条自动滚动到底部
305
+                setTimeout(function () {
306
+                    msgflow.scrollTop = msgflow.scrollHeight;
307
+                }, 300);
308
+            }
309
+        },
310
+        sendPic(images, imgName) {
311
+            var _this = this;
312
+            if (!this.selToID) {
313
+                alert("请先选择对话用户");
314
+                return;
315
+            }
316
+
317
+            if (!this.selSess) {
318
+                this.selSess = new webim.Session(selType, this.selToID, this.selToID, this.kefuUrl, Math.round(new Date().getTime() / 1000));
319
+            }
320
+            var msg = new webim.Msg(this.selSess, true, -1, -1, -1, this.loginInfo.identifier, 0, this.loginInfo.identifierNick);
321
+            var images_obj = new webim.Msg.Elem.Images(images.File_UUID);
322
+            for (var i in images.URL_INFO) {
323
+                var img = images.URL_INFO[i];
324
+                var newImg;
325
+                var type;
326
+                switch (img.PIC_TYPE) {
327
+                    case 1://原图
328
+                        type = 1;//原图
329
+                        break;
330
+                    case 2://小图(缩略图)
331
+                        type = 3;//小图
332
+                        break;
333
+                    case 4://大图
334
+                        type = 2;//大图
335
+                        break;
336
+                }
337
+                newImg = new webim.Msg.Elem.Images.Image(type, img.PIC_Size, img.PIC_Width, img.PIC_Height, img.DownUrl);
338
+                images_obj.addImage(newImg);
339
+            }
340
+            msg.addImage(images_obj);
341
+            //if(imgName){
342
+            //    var data=imgName;//通过自定义消息中的data字段保存图片名称
343
+            //    var custom_obj = new webim.Msg.Elem.Custom(data, '', '');
344
+            //    msg.addCustom(custom_obj);
345
+            //}
346
+            //调用发送图片消息接口
347
+            webim.sendMsg(msg, function (resp) {
348
+                if (selType == webim.SESSION_TYPE.C2C) {//私聊时,在聊天窗口手动添加一条发的消息,群聊时,长轮询接口会返回自己发的消息
349
+                    _this.addMsg(msg);
350
+                }
351
+            }, function (err) {
352
+                alert(err.ErrorInfo);
353
+            });
354
+        },
355
+        bindScrollHistoryEvent(axtion){
356
+            var msgflow = document.getElementsByClassName("msg-inner")[0];
357
+            var _this = this;
358
+            if (axtion=='init') {
359
+                msgflow.onscroll = function () {
360
+                    if (msgflow.scrollTop == 0) {
361
+                        msgflow.scrollTop = 10;
362
+                        if (selType == webim.SESSION_TYPE.C2C) {
363
+                            _this.getPrePageC2CHistoryMsgs();
364
+                        } 
365
+                    }
366
+                }
367
+            }else {
368
+                msgflow.onscroll = null;
369
+            }
370
+        },
371
+        getPrePageC2CHistoryMsgs  (cbOk, cbError) {
372
+            var _this = this;
373
+            if (selType == webim.SESSION_TYPE.GROUP) {
374
+                _this.$message.error("当前的聊天类型为群聊天,不能进行拉取好友历史消息操作");
375
+                return;
376
+            }
377
+            var tempInfo = getPrePageC2CHistroyMsgInfoMap[_this.selToID];//获取下一次拉取的c2c消息时间和消息Key
378
+            var lastMsgTime;
379
+            var msgKey;
380
+            if (tempInfo) {
381
+                lastMsgTime = tempInfo.LastMsgTime;
382
+                msgKey = tempInfo.MsgKey;
383
+            } else {
384
+                _this.$message.error("获取下一次拉取的c2c消息时间和消息Key为空");
385
+                return;
386
+            }
387
+            var options = {
388
+                'Peer_Account': _this.selToID, //好友帐号
389
+                'MaxCnt': reqMsgCount, //拉取消息条数
390
+                'LastMsgTime': lastMsgTime, //最近的消息时间,即从这个时间点向前拉取历史消息
391
+                'MsgKey': msgKey
392
+            };
393
+            webim.getC2CHistoryMsgs(
394
+                options,
395
+                function (resp) {
396
+                    var complete = resp.Complete;//是否还有历史消息可以拉取,1-表示没有,0-表示有
397
+                    if (resp.MsgList.length == 0) {
398
+                        webim.Log.warn("没有历史消息了:data=" + JSON.stringify(options));
399
+                        return;
400
+                    }
401
+                    getPrePageC2CHistroyMsgInfoMap[_this.selToID] = {//保留服务器返回的最近消息时间和消息Key,用于下次向前拉取历史消息
402
+                        'LastMsgTime': resp.LastMsgTime,
403
+                        'MsgKey': resp.MsgKey
404
+                    };
405
+                    if (cbOk) {
406
+                        cbOk(resp.MsgList);
407
+                    } else {
408
+                        _this.getHistoryMsgCallback(resp.MsgList, true);
409
+                    }
410
+                },
411
+                cbError
412
+            );
413
+        },
414
+        getLastC2CHistoryMsgs (cbOk, cbError) {
415
+            var _this = this;
416
+            var lastMsgTime = 0;//第一次拉取好友历史消息时,必须传0
417
+            var msgKey = '';
418
+            var options = {
419
+                'Peer_Account': this.selToID, //好友帐号
420
+                'MaxCnt': reqMsgCount, //拉取消息条数
421
+                'LastMsgTime': lastMsgTime, //最近的消息时间,即从这个时间点向前拉取历史消息
422
+                'MsgKey': msgKey
423
+            };
424
+            this.selSess = null;
425
+            webim.MsgStore.delSessByTypeId(selType, this.selToID);
426
+
427
+            webim.getC2CHistoryMsgs(
428
+                options,
429
+                function (resp) {
430
+                    var complete = resp.Complete;//是否还有历史消息可以拉取,1-表示没有,0-表示有
431
+
432
+                    if (resp.MsgList.length == 0) {
433
+                        webim.Log.warn("没有历史消息了:data=" + JSON.stringify(options));
434
+                        return;
435
+                    }
436
+                    getPrePageC2CHistroyMsgInfoMap[_this.selToID] = {//保留服务器返回的最近消息时间和消息Key,用于下次向前拉取历史消息
437
+                        'LastMsgTime': resp.LastMsgTime,
438
+                        'MsgKey': resp.MsgKey
439
+                    };
440
+                    
441
+                    if (cbOk)
442
+                        cbOk(resp.MsgList);
443
+                },
444
+                cbError
445
+            );
446
+        },
447
+        getHistoryMsgCallback(msgList, prepage) {
448
+            var msg;
449
+            var prepage = prepage || false;
450
+
451
+            //如果是加载前几页的消息,消息体需要prepend,所以先倒排一下
452
+            if (prepage) {
453
+                msgList.reverse();
454
+            }
455
+
456
+            for (var j in msgList) {//遍历新消息
457
+                msg = msgList[j];
458
+                if (msg.getSession().id() == this.selToID) {//为当前聊天对象的消息
459
+                    this.selSess = msg.getSession();
460
+                    //在聊天窗体中新增一条消息
461
+                    this.addMsg(msg, prepage);
462
+                }
463
+            }
464
+            //消息已读上报,并将当前会话的消息设置成自动已读
465
+            webim.setAutoRead(this.selSess, true, true);
466
+        },
467
+        convertMsgtoHtml(msg) {
468
+            var html = "",
469
+                elems, elem, type, content;
470
+            elems = msg.getElems(); //获取消息包含的元素数组
471
+            var count = elems.length;
472
+            for (var i = 0; i < count; i++) {
473
+                elem = elems[i];
474
+                type = elem.getType();//获取元素类型
475
+                content = elem.getContent();//获取元素对象
476
+                switch (type) {
477
+                    case webim.MSG_ELEMENT_TYPE.TEXT:
478
+                        var eleHtml = this.convertTextMsgToHtml(content);
479
+                        //转义,防XSS
480
+                        html += webim.Tool.formatText2Html(eleHtml);
481
+                        break;
482
+                    case webim.MSG_ELEMENT_TYPE.FACE:
483
+                        html += this.convertFaceMsgToHtml(content);
484
+                        break;
485
+                    case webim.MSG_ELEMENT_TYPE.IMAGE:
486
+                        if (i <= count - 2) {
487
+                            var customMsgElem = elems[i + 1];//获取保存图片名称的自定义消息elem
488
+                            var imgName = customMsgElem.getContent().getData();//业务可以自定义保存字段,demo中采用data字段保存图片文件名
489
+                            html += this.convertImageMsgToHtml(content, imgName);
490
+                            i++;//下标向后移一位
491
+                        } else {
492
+                            html += this.convertImageMsgToHtml(content);
493
+                        }
494
+                        break;
495
+                    case webim.MSG_ELEMENT_TYPE.SOUND:
496
+                        html += this.convertSoundMsgToHtml(content);
497
+                        break;
498
+                    case webim.MSG_ELEMENT_TYPE.FILE:
499
+                        html += this.convertFileMsgToHtml(content);
500
+                        break;
501
+                    case webim.MSG_ELEMENT_TYPE.LOCATION:
502
+                        html += this.convertLocationMsgToHtml(content);
503
+                        break;
504
+                    case webim.MSG_ELEMENT_TYPE.CUSTOM:
505
+                        var eleHtml = this.convertCustomMsgToHtml(content);
506
+                        //转义,防XSS
507
+                        html += webim.Tool.formatText2Html(eleHtml);
508
+                        break;
509
+                    case webim.MSG_ELEMENT_TYPE.GROUP_TIP:
510
+                        var eleHtml = this.convertGroupTipMsgToHtml(content);
511
+                        //转义,防XSS
512
+                        html += webim.Tool.formatText2Html(eleHtml);
513
+                        break;
514
+                    default:
515
+                        webim.Log.error('未知消息元素类型: elemType=' + type);
516
+                        break;
517
+                }
518
+            }
519
+            return html;
520
+        },
521
+        convertTextMsgToHtml(content) {
522
+            return content.getText();
523
+        },
524
+        //解析表情消息元素
525
+        convertFaceMsgToHtml(content) {
526
+            var faceUrl = null;
527
+            var data = content.getData();
528
+            var index = webim.EmotionDataIndexs[data];
529
+
530
+            var emotion = webim.Emotions[index];
531
+            if (emotion && emotion[1]) {
532
+                faceUrl = emotion[1];
533
+            }
534
+            if (faceUrl) {
535
+                return "<img src='" + faceUrl + "'/>";
536
+            } else {
537
+                return data;
538
+            }
539
+        },
540
+        //解析图片消息元素
541
+        convertImageMsgToHtml(content, imageName) {
542
+            var smallImage = content.getImage(webim.IMAGE_TYPE.SMALL);//小图
543
+            var bigImage = content.getImage(webim.IMAGE_TYPE.LARGE);//大图
544
+            var oriImage = content.getImage(webim.IMAGE_TYPE.ORIGIN);//原图
545
+            if (!bigImage) {
546
+                bigImage = smallImage;
547
+            }
548
+            if (!oriImage) {
549
+                oriImage = smallImage;
550
+            }
551
+            return "<img name='" + imageName + "' src='" + smallImage.getUrl() + "#" + bigImage.getUrl() + "#" + oriImage.getUrl() + "' style='CURSOR: hand' id='" + content.getImageId() + "' bigImgUrl='" + bigImage.getUrl() + "'/>";
552
+        }, 
553
+        handleIMPicUload:function(fileobj){
554
+            var file = fileobj.file
555
+            console.log("file", file);
556
+            var _this = this;
557
+            var businessType;//业务类型,1-发群图片,2-向好友发图片
558
+            if (selType != webim.SESSION_TYPE.C2C) {//向好友发图片
559
+                this.$message.error('不支持群聊');
560
+                return; 
561
+            } 
562
+            businessType = webim.UPLOAD_PIC_BUSSINESS_TYPE.C2C_MSG;
563
+            //封装上传图片请求
564
+            var opt = {
565
+                'file': file, //图片对象
566
+                'onProgressCallBack': this.onProgressCallBack, //上传图片进度条回调函数
567
+                //'abortButton': document.getElementById('upd_abort'), //停止上传图片按钮
568
+                'To_Account': this.selToID, //接收者
569
+                'businessType': businessType//业务类型
570
+            };
571
+            //上传图片
572
+            webim.uploadPic(opt,
573
+                function (resp) {
574
+                    //上传成功发送图片
575
+                    _this.sendPic(resp, file.name);
576
+                    
577
+                },
578
+                function (err) {
579
+                    alert(err.ErrorInfo);
580
+                }
581
+            );
582
+        },
583
+        handleIMPicSuccess:function(){},
584
+        beforeIMPicUpload:function(file){
585
+            var fileType = file.type;
586
+            const isJPG = fileType.indexOf("image") > -1;
587
+            if (!isJPG) {
588
+                this.$message.error('只能上传图片');
589
+            }
590
+            return isJPG;
591
+        },
592
+        togglePhoneBox:function(){
593
+            if (this.showPhoneBox) {
594
+                this.showPhoneBox = false;
595
+            }else {
596
+                this.showPhoneBox = true;
597
+            }
598
+            this.showMsgBox = false;
599
+        },
600
+        toggleMsgBox:function(){
601
+            if (this.showMsgBox) {
602
+                this.showMsgBox = false;
603
+            }else {
604
+                this.showMsgBox = true;
605
+            }
606
+            this.showPhoneBox = false;
607
+        },
608
+        webimlogin(){
609
+            let _this = this;
610
+            let listeners = {
611
+                "onConnNotify": this.onConnNotify //监听连接状态回调变化事件,必填
612
+                , "jsonpCallback": this.jsonpCallback //IE9(含)以下浏览器用到的jsonp回调函数,
613
+                , "onMsgNotify": this.onMsgNotify //监听新消息(私聊,普通群(非直播聊天室)消息,全员推送消息)事件,必填
614
+                , "onProfileSystemNotifys": this.onProfileSystemNotifys //监听资料系统(自己或好友)通知事件,选填
615
+                , "onKickedEventCall": this.onKickedEventCall //被其他登录实例踢下线
616
+                , "onC2cEventNotifys": this.onC2cEventNotifys //监听C2C系统消息通道
617
+            };
618
+            webim.login(this.loginInfo, listeners, this.loginOptions, 
619
+                function(resp){
620
+                    _this.$message.success('webim登录成功');
621
+                    _this.imloginFlag = true;
622
+                },
623
+                function(err) {
624
+                    _this.$message.error('webim登录错误');
625
+                }
626
+            );
627
+        },
628
+        onConnNotify(){},
629
+        jsonpCallback(){},
630
+        onMsgNotify(newMsgList){
631
+            //监听新消息事件
632
+            var msgList = [];
633
+            var dateStart = null;
634
+            var dateEnd = null;
635
+
636
+            //console.warn(newMsgList);
637
+            var sess, newMsg, formId;
638
+            //获取所有聊天会话
639
+            var sessMap = webim.MsgStore.sessMap();
640
+
641
+            for (var j in newMsgList) {//遍历新消息
642
+
643
+                newMsg = newMsgList[j];
644
+                formId = newMsg.getSession().id();
645
+                if (formId.indexOf("AdminKeFu")<0) {
646
+                    continue;
647
+                }else {
648
+                    if (newMsg.getSession().id() == this.selToID) {//为当前聊天对象的消息
649
+                        this.addMsg(newMsg);
650
+                    }
651
+                    msgList.push(newMsg.elems[0].content.text);
652
+                }
653
+                
654
+            }
655
+        },
656
+        onProfileSystemNotifys(){},
657
+        onKickedEventCall(){},
658
+        onC2cEventNotifys(){},
659
+    },
660
+    watch:{
661
+        'userSigFlag':function(value){
662
+            if(this.userSigFlag) {
663
+                this.webimlogin();
664
+            }
665
+        },
666
+        'imloginFlag':function(value) {
667
+            var _this = this;
668
+            if (this.imloginFlag) {
669
+                this.bindScrollHistoryEvent('reset');
670
+                this.getLastC2CHistoryMsgs(function (msgList) {
671
+                    _this.getHistoryMsgCallback(msgList);
672
+                    _this.bindScrollHistoryEvent('init');
673
+                    //绑定滚动操作
674
+                }, function (err) {
675
+                    alert(err.ErrorInfo);
676
+                });
677
+            }
678
+        }
679
+    },
71 680
 
72 681
 }
73 682
 </script>
@@ -78,7 +687,7 @@ export default {
78 687
     right: 12px;
79 688
     bottom: 10%;
80 689
     margin-top: -100px;
81
-    z-index: 99999;
690
+    z-index: 9999;
82 691
 }
83 692
     
84 693
 .contact-box .contact-box-item{
@@ -102,18 +711,17 @@ export default {
102 711
     color: #59a3ec;
103 712
     display: inline-block;
104 713
 }
105
-.contact-box .contact-box-item .box-btn:hover {
106
-    background: #5aa6f1;
107
-}
714
+/* .contact-box .contact-box-item .box-btn:hover {
715
+} */
108 716
 .contact-box .box-btn span{
109 717
     display: none;
110
-}
111
-
112
-.contact-box .box-btn:hover span{
113
-    display: block;
114 718
     color:#fff;
115 719
     padding: 8px;
116 720
     font-size: 14px;
721
+    background: #5aa6f1;
722
+}
723
+.contact-box .box-btn:hover span{
724
+    display: block;
117 725
 }
118 726
 .contact-box .box-btn:hover i{
119 727
     display: none;
@@ -124,10 +732,9 @@ export default {
124 732
     bottom: 0px;
125 733
     right: 56px;
126 734
     height: 48px;
127
-    /* display: block; */
735
+    display:flex;
128 736
     background: #fff;
129 737
     width: 230px;
130
-    display:none;
131 738
     align-items: center;
132 739
 }
133 740
 .contact-box .contact-phone-box i {
@@ -135,10 +742,6 @@ export default {
135 742
     font-size:30px; 
136 743
     margin: 9px;
137 744
 }
138
-.contact-box .phone-box:hover .contact-phone-box{
139
-    display:flex;
140
-}
141
-
142 745
 .contact-box .contact-phone-box span {
143 746
     font-size:20px; 
144 747
     margin-left: 15px;
@@ -153,7 +756,7 @@ export default {
153 756
     display: none;
154 757
     background: #fff;
155 758
     width: 175px;
156
-    z-index: 1000000;
759
+    z-index: 10000;
157 760
 }
158 761
 .contact-box .msg-box:hover .contact-info-box{
159 762
     display:block;
@@ -216,4 +819,114 @@ export default {
216 819
 .contact-box .scroll-y::-webkit-scrollbar-track {
217 820
     border-radius: 2px;
218 821
 }
822
+.contact-box .msg-inner .cell {
823
+    margin-bottom: 15px;
824
+}
825
+.contact-box .cell_right {
826
+    float: right;
827
+}
828
+
829
+.contact-box .clearfix {
830
+    clear: both;
831
+}
832
+.contact-box .msg-inner .msg_body {
833
+    border: 1px #e5e5e5 solid;
834
+    line-height: 22px;
835
+    display: inline-block;
836
+    padding: 6px;
837
+    max-width: 292px;
838
+}
839
+.contact-box .fl {
840
+    float: left;
841
+}
842
+.contact-box .msg-inner .msg_body .inner {
843
+    color: #465b6e;
844
+}
845
+.contact-box .msg-inner .cell_pic {
846
+    width: 40px;
847
+    height: 40px;
848
+    display: inline-block;
849
+    margin: 0 20px;
850
+}
851
+.contact-box .msg-inner .cell_pic .pic {
852
+    width: 40px;
853
+    height: 40px;
854
+    display: flex;
855
+}
856
+.contact-box .msg-inner .cell_pic .pic img {
857
+    width: 40px;
858
+    height: 40px;
859
+    border-radius: 50%;
860
+    object-fit: cover;
861
+    object-position: center;
862
+}
863
+
864
+.contact-box .msg-box-panel .panel-booter .textarea {
865
+    border: 1px #fff solid;
866
+    padding: 10px 20px;
867
+    color: #465b6e;
868
+    height: 100px;
869
+    resize: none;
870
+    width: 100%;
871
+}
872
+.contact-box .msg-box-panel .panel-booter .msg-send-btn-box {
873
+    padding: 0 20px 10px 20px;
874
+    float: left;
875
+    background: #fff;
876
+    width: 408px;
877
+}
878
+.contact-box .msg-box-panel .panel-booter .time {
879
+    font-size: 12px;
880
+    color: #bebebe;
881
+    height: 26px;
882
+    line-height: 26px;
883
+}
884
+.contact-box .msg-box-panel .panel-booter .msg-send-btn-box .send_btn {
885
+    color: #fff;
886
+    padding: 6px 20px;
887
+    border-radius: 4px;
888
+    font-size: 12px;
889
+    background: #58a1ed;
890
+    border: none;
891
+}
892
+
893
+.contact-box  .panel-tool {
894
+    color: #465b6e;
895
+    height: 30px;
896
+    border-bottom: 1px #e5e5e5 solid;
897
+    display:flex;
898
+    align-items: center;
899
+}
900
+
901
+.contact-box  .panel-tool i {
902
+    font-size: 20px;
903
+    padding: 0 5px;
904
+    margin: 0 5px;
905
+    cursor: pointer;
906
+}
907
+
908
+.contact-box  .panel-tool .icon-face::before {
909
+    content: '\1F642';
910
+    font-size: 15px;
911
+}
912
+.contact-box .face-box {
913
+    width: 304px;
914
+    z-index: 10001;
915
+    background: #fff;
916
+    position: relative;
917
+    bottom: 70px;
918
+    left: -100px;
919
+    border: 2px #e5e5e5 solid;
920
+}
921
+.contact-box .face-box-list li {
922
+    display: inline-block;
923
+    
924
+    border-right: 1px #CCC solid;
925
+    border-bottom: 1px #CCC solid;
926
+    cursor: pointer;
927
+}
928
+.contact-box .face-box-title {
929
+    border-bottom: 1px #e5e5e5 solid;
930
+    margin: 2px 0;
931
+}
219 932
 </style>

+ 965 - 0
src/scrm_pages/kefu/index.vue View File

@@ -0,0 +1,965 @@
1
+<template>
2
+  <div class="main-contain">
3
+    <div class="position">
4
+      <bread-crumb :crumbs='crumbs'></bread-crumb>
5
+    </div>
6
+    <div class="app-container">
7
+        <div class="customer_plate white-bg">
8
+            <div class="aside">
9
+                <div class="customer_search clearfix">
10
+                <div class="super_searchbox">
11
+                    <span class="search_icon"></span>
12
+                    <input type="text" class="cus_search_input" v-model="searchname" placeholder="请输入客户名称">
13
+                </div>
14
+                </div>
15
+                <div class="client_list_box">
16
+                <div class="client_list">
17
+                    <ul class="users-list">
18
+                    <li v-for="(patient, key) in patientsMap" v-show="searchname == '' || (patient.name.indexOf(searchname)>=0)" :class="thisPatient && patient.user_id==thisPatient.user_id?'Active':''" :key="key" :id="'sessDiv_User_'+patient.user_id" class="item" :data-username="patient.name" @click="chooseThisUser(patient)">
19
+                        <span :id="'badgeDiv_User_'+patient.user_id" class="circle-count" style="" v-show="patient.unread_msg_count"><i class="count">{{patient.unread_msg_count}}</i></span>
20
+                        <figure :id="'faceImg_User_'+patient.user_id" class="session-pic"><img :src="patient.avatar"></figure>
21
+                        <h3 :id="'nameDiv_User_'+patient.user_id" class="nick">{{patient.name}}</h3>
22
+                        <!-- <span class="square-close" title="退出接待" :data-toid="'User_'+patient.user_id">×</span> -->
23
+                    </li>
24
+                    </ul>
25
+                </div>
26
+                </div>
27
+            </div>
28
+
29
+            <div class="left_content">
30
+                <div class="conversation-admin">
31
+                <span class="nickname">
32
+                    <span></span>
33
+                </span>
34
+                </div>
35
+                <div class="message-list-wrap">
36
+                <div class="message-list-item">
37
+                    <ul class="message-list">
38
+                    
39
+                    <li v-for="(messageitem, key) in messageBox" :key="key" :id="'id_'+messageitem.id" class="message-item clearfix">
40
+                        <div class="time"><span v-html="messageitem.time"></span></div>
41
+                        <div class="user " :class="messageitem.float">
42
+                            <figure class="bg-pic circle-bg-pic">
43
+                            <div class="bg-pic-content">
44
+                                <img :src="messageitem.avatar">
45
+                            </div>
46
+                            </figure>
47
+                        </div>
48
+                        <div class="message-body " :class="messageitem.float"><div class="inner" v-html="messageitem.message"></div></div>
49
+                    </li>
50
+
51
+                    </ul>
52
+                </div>
53
+                <div class="no_session">
54
+                    <span class="no_session_pic"></span>
55
+                    <p class="no_session_txt">没有选中会话哦!</p>
56
+                </div>
57
+                </div>
58
+                <div class="send_box" v-loading="loadingbox" :element-loading-text="loadingboxtext">
59
+                <div class="inputer_actions">
60
+                    <!-- <div class="face">
61
+                    <span class="face_icon" @click="showEmotionDialog"></span>
62
+                    </div> -->
63
+                    <div class="picture">
64
+                    <span class="picture_icon" @click="selectPicClick"></span>
65
+                    </div>
66
+                </div>
67
+                <div id="wl_faces_box" class="wl_faces_box" v-bind:style="{left:'0px', display:facesBoxDisplay}">
68
+                    <div class="wl_faces_content">
69
+                    <div class="title">
70
+                        <ul>
71
+                        <li class="title_name">常用表情</li>
72
+                        <li class="wl_faces_close">
73
+                            <span @click="facesBoxDisplay='none'">&nbsp;</span>
74
+                        </li>
75
+                        </ul>
76
+                    </div>
77
+                    <div id="wl_faces_main" class="wl_faces_main">
78
+                        <ul id="emotionUL">
79
+                        <li v-for="(emotion, key) in emotionList" :key="key" @click="chooseThisFace(emotion)">
80
+                            <img :src="emotion.src" :id="emotion.id" alt="" style="cursor:pointer;">
81
+                        </li>
82
+                        </ul>
83
+                    </div>
84
+                    </div>
85
+                    <div class="wlf_icon"></div>
86
+                </div>
87
+                <div class="inputer-area">
88
+                    <textarea
89
+                    maxlength="500" v-model="message"
90
+                    class="message-textarea transparent-txta"
91
+                    placeholder
92
+                    id="message"
93
+                    ></textarea>
94
+                </div>
95
+                <div class="send_box_btn">
96
+                    <button class="send_btn" id="sendMessaeg" @click="sendMessage">发送</button>
97
+                </div>
98
+                </div>
99
+            </div>
100
+        </div>
101
+    </div>
102
+  </div>
103
+</template>
104
+
105
+<script>
106
+  import BreadCrumb from '../components/bread-crumb'
107
+  export default {
108
+    name: 'commentList',
109
+    components:{
110
+      BreadCrumb,
111
+    },
112
+    data(){
113
+      return{
114
+        crumbs: [
115
+          { path: false, name: '客服管理' },
116
+          { path: false, name: '咨询管理' }
117
+        ],
118
+        searchname:'',
119
+        patientsMap:{},
120
+        thisPatient:null,
121
+        messageBox:[],
122
+      }
123
+    },
124
+    methods:{},
125
+    created(){
126
+    }
127
+  }
128
+</script>
129
+
130
+<style scoped>
131
+  /*.app-container .cell.clearfix .time ul li {*/
132
+    /*float: left;*/
133
+    /*list-style: none;*/
134
+    /*cursor: pointer;*/
135
+    /*padding: 6px 20px;*/
136
+    /*color: #606266;*/
137
+    /*border-radius: 4px;*/
138
+    /*margin: 0 8px 0 0;*/
139
+    /*font-size: 14px;*/
140
+    /*text-align: center;*/
141
+  /*}*/
142
+
143
+  
144
+.app-container{
145
+  height: 750px;  
146
+}
147
+.customer_plate {
148
+  width: 100%;
149
+  display: -webkit-box;
150
+  display: -webkit-flex;
151
+  display: -moz-box;
152
+  display: -ms-flexbox;
153
+  display: flex;
154
+  -webkit-box-flex: 1;
155
+  -webkit-flex: 1;
156
+  -moz-box-flex: 1;
157
+  -ms-flex: 1;
158
+  flex: 1;
159
+  height:100%;
160
+}
161
+.customer_plate .aside {
162
+  width: 282px;
163
+  -webkit-flex-shrink: 0;
164
+  -ms-flex-negative: 0;
165
+  flex-shrink: 0;
166
+  position: relative;
167
+  border-right: 1px solid #e5e8ea;
168
+}
169
+.customer_plate .aside .client_list_box {
170
+  position: absolute;
171
+  width: 100%;
172
+  top: 50px;
173
+  left: 0;
174
+  bottom: 0;
175
+  overflow-x: visible;
176
+  overflow-y: auto;
177
+}
178
+.channelswitch-wrap {
179
+  position: absolute;
180
+  top: 0;
181
+  left: 0;
182
+  right: 0;
183
+  bottom: 0;
184
+}
185
+.customer_plate .aside .client_list_box .client_list {
186
+  height: 100%;
187
+  overflow: hidden;
188
+  overflow-y: auto;
189
+}
190
+.customer_plate .aside .customer_search {
191
+  margin: 0 10px;
192
+  height: 34px;
193
+}
194
+.customer_plate .aside .super_searchbox {
195
+  padding: 0 8px;
196
+  background-color: #f4f7fa;
197
+  border-radius: 30px;
198
+  margin-top: 15px;
199
+  font-size: 12px;
200
+}
201
+.customer_plate .aside .super_searchbox .cus_search_input {
202
+  border: none;
203
+  background: none;
204
+  width: 224px;
205
+  height: 22px;
206
+  line-height: 22px;
207
+}
208
+.customer_plate .aside .super_searchbox .search_icon {
209
+  display: inline-block;
210
+  width: 12px;
211
+  height: 12px;
212
+  background: url(http://jk.kuyicloud.com/static/images/ico.png) no-repeat;
213
+  float: left;
214
+  background-position: -460px -314px;
215
+  margin: 4px 5px 0 0;
216
+}
217
+.left_content {
218
+  -webkit-box-flex: 1;
219
+  -webkit-flex: 1;
220
+  -moz-box-flex: 1;
221
+  -ms-flex: 1;
222
+  flex: 1;
223
+  display: -webkit-box;
224
+  display: -webkit-flex;
225
+  display: -moz-box;
226
+  display: -ms-flexbox;
227
+  display: flex;
228
+  position: relative;
229
+  width: 100%;
230
+  justify-content: flex-start;
231
+  flex-direction: column;
232
+}
233
+.left_content .message-list-wrap {
234
+  position: absolute;
235
+  top: 50px;
236
+  overflow: hidden;
237
+  left: 0;
238
+  right: 0;
239
+  border-bottom: 1px #e5e8ea solid;
240
+  bottom: 210px;
241
+}
242
+.left_content .message-list-wrap .message-list-item {
243
+  height: 100%;
244
+  overflow-x: hidden;
245
+  overflow-y: auto;
246
+}
247
+.left_content .message-list-wrap .message-list {
248
+  padding: 0 12px 20px;
249
+}
250
+.left_content .conversation-admin {
251
+  height: 48px;
252
+  line-height: 48px;
253
+  border-bottom: 1px #e5e8ea solid;
254
+  margin-left: 2px;
255
+  width: 100%;
256
+}
257
+.left_content .conversation-admin .nickname {
258
+  padding-left: 22px;
259
+}
260
+.client_list ul {
261
+  list-style: none;
262
+}
263
+.client_list ul .item {
264
+  padding: 17px 12px 17px 62px;
265
+  min-height: 36px;
266
+  cursor: pointer;
267
+  font-size: 12px;
268
+  transition: background-color 0.2s linear;
269
+  -webkit-transition: background-color 0.2s linear;
270
+  -moz-transition: background-color 0.2s linear;
271
+  position: relative;
272
+}
273
+.client_list ul .Active {
274
+  background: #f4f7fa;
275
+}
276
+.client_list ul .item .nick {
277
+  font-size: 14px;
278
+  color: #485b6d;
279
+  margin-bottom: 7px;
280
+}
281
+.client_list ul .item:hover {
282
+  background: #dfedfb;
283
+}
284
+.client_list ul .item .time {
285
+  position: absolute;
286
+  top: 14px;
287
+  right: 12px;
288
+  color: #a8b3ba;
289
+}
290
+.client_list ul .item .circle-count {
291
+  padding: 2px;
292
+  background-color: #ff7979;
293
+  text-align: center;
294
+  left: 8px;
295
+  z-index: 2;
296
+  min-width: 17px;
297
+  min-height: 15px;
298
+  line-height: 12px;
299
+  border-radius: 10px;
300
+  position: absolute;
301
+  top: 12px;
302
+  display: inline-block;
303
+}
304
+.client_list ul .item .circle-count .count {
305
+  color: #fff;
306
+  display: inline-block;
307
+  -webkit-transform: scale(0.83);
308
+  -moz-transform: scale(0.83);
309
+  -ms-transform: scale(0.83);
310
+  transform: scale(0.83);
311
+}
312
+.client_list ul .item .session-pic {
313
+  position: absolute;
314
+  top: 17px;
315
+  left: 13px;
316
+  width: 40px;
317
+  height: 40px;
318
+  border-radius: 50%;
319
+  overflow: hidden;
320
+  display: inline-block;
321
+}
322
+.client_list ul .item .session-pic img {
323
+  width: 40px;
324
+  height: 40px;
325
+}
326
+.client_list ul .item .square-close {
327
+  color: #fff;
328
+  background-color: #d2d2d5;
329
+  display: none;
330
+  width: 14px;
331
+  height: 14px;
332
+  line-height: 12px;
333
+  text-align: center;
334
+  position: absolute;
335
+  top: 0;
336
+  right: 0;
337
+}
338
+.client_list ul .item:hover .square-close {
339
+  display: block;
340
+}
341
+.client_list ul .item .desc {
342
+  color: #a8b3ba;
343
+  text-overflow: ellipsis;
344
+  white-space: nowrap;
345
+  overflow: hidden;
346
+  width: 150px;
347
+}
348
+.service_fixed {
349
+  position: fixed;
350
+}
351
+.message-list-wrap ul li {
352
+  padding: 12px;
353
+}
354
+.message-list-wrap .message-item .time {
355
+  text-align: center;
356
+  margin: 20px 0 6px 0;
357
+}
358
+.message-list-wrap .message-item .time span {
359
+  font-size: 12px;
360
+  color: #a8b3ba;
361
+}
362
+.message-list .message-item .user .bg-pic {
363
+  display: inline-block;
364
+  margin-right: 20px;
365
+}
366
+.message-list .message-item .message-body {
367
+  background: #e5e8ea;
368
+  padding: 16px 12px 12px 12px;
369
+  border-radius: 4px;
370
+  color: #485b6d;
371
+  max-width: 520px;
372
+}
373
+.message-list .message-item .user .bg-pic .bg-pic-content {
374
+  border-radius: 50%;
375
+  display: inline-block;
376
+  width: 40px;
377
+  height: 40px;
378
+}
379
+.message-list .message-item .user .bg-pic img {
380
+  width: 40px;
381
+  height: 40px;
382
+  border-radius: 50%;
383
+  display: inline-block;
384
+}
385
+.no_session {
386
+  text-align: center;
387
+}
388
+.send_box {
389
+  position: absolute;
390
+  font-size: 13px;
391
+  bottom: 0;
392
+  height: 210px;
393
+  left: 0;
394
+  right: 0;
395
+  display: -webkit-box;
396
+  display: -webkit-flex;
397
+  display: -moz-box;
398
+  display: -ms-flexbox;
399
+  display: flex;
400
+  -webkit-box-orient: vertical;
401
+  -webkit-box-direction: normal;
402
+  -webkit-flex-direction: column;
403
+  -moz-box-orient: vertical;
404
+  -moz-box-direction: normal;
405
+  -ms-flex-direction: column;
406
+  flex-direction: column;
407
+}
408
+.send_box .inputer_actions {
409
+  padding: 10px;
410
+  background: #f5f5f5;
411
+}
412
+
413
+.send_box .inputer_actions .face {
414
+  float: left;
415
+  margin: 0;
416
+  height: auto;
417
+}
418
+.send_box .inputer_actions .face_icon {
419
+  width: 24px;
420
+  height: 22px;
421
+  background: url(http://jk.kuyicloud.com/static/images/ico.png) no-repeat -478px -314px;
422
+  display: inline-block;
423
+  margin-right: 22px;
424
+  cursor: pointer;
425
+}
426
+.send_box .inputer_actions .picture_icon {
427
+  width: 28px;
428
+  height: 24px;
429
+  background: url(http://jk.kuyicloud.com/static/images/ico.png) no-repeat -508px -314px;
430
+  display: inline-block;
431
+  margin-right: 22px;
432
+  cursor: pointer;
433
+}
434
+.inputer-area {
435
+  -webkit-box-flex: 1;
436
+  -webkit-flex: 1;
437
+  -moz-box-flex: 1;
438
+  -moz-flex: 1;
439
+  -ms-flex: 1;
440
+  flex: 1;
441
+  margin: 2px;
442
+  overflow: hidden;
443
+  display: -webkit-box;
444
+  display: -webkit-flex;
445
+  display: -moz-flex;
446
+  display: -ms-flexbox;
447
+  display: -moz-box;
448
+  display: flex;
449
+  -webkit-box-direction: normal;
450
+  -webkit-box-orient: vertical;
451
+  -webkit-flex-direction: column;
452
+  -moz-flex-direction: column;
453
+  -ms-flex-direction: column;
454
+  flex-direction: column;
455
+}
456
+.inputer-area .message-textarea {
457
+  display: -webkit-box;
458
+  display: -webkit-flex;
459
+  display: -moz-flex;
460
+  display: -ms-flexbox;
461
+  display: -moz-box;
462
+  display: flex;
463
+  -webkit-box-flex: 1;
464
+  -webkit-flex: 1;
465
+  -moz-box-flex: 1;
466
+  -moz-flex: 1;
467
+  -ms-flex: 1;
468
+  flex: 1;
469
+  width: auto;
470
+  height: 100%;
471
+  resize: none;
472
+  margin: 0;
473
+  padding: 9px 4px;
474
+  font-size: 14px;
475
+  line-height: 1.5em;
476
+  border: none;
477
+  overflow-x: hidden;
478
+  overflow-y: auto;
479
+  border-radius: 0;
480
+  -webkit-box-shadow: none;
481
+  box-shadow: none;
482
+  padding: 0 9px 4px;
483
+}
484
+.send_box .send_box_btn {
485
+  position: absolute;
486
+  bottom: 26px;
487
+  right: 40px;
488
+}
489
+.send_box .send_box_btn .send_btn {
490
+  background: #58a2ec;
491
+  color: #fff;
492
+  padding: 12px 55px;
493
+  border-radius: 4px;
494
+  border: none;
495
+  font-size: 14px;
496
+}
497
+/*
498
+To change this license header, choose License Headers in Project Properties.
499
+To change this template file, choose Tools | Templates
500
+and open the template in the editor.
501
+*/
502
+/*
503
+    Created on : 2015-7-6, 15:55:30
504
+    Author     : peakerdong
505
+*/
506
+
507
+#login {
508
+    display: block;
509
+    margin: 150px auto;
510
+    text-align: center;
511
+}
512
+
513
+.aio {
514
+    display: none;
515
+    width: 734px;
516
+    border: 1px black solid;
517
+    padding: 0px;
518
+    background: white;
519
+    margin: 20px auto;
520
+    font: 10px/1.5 "微软雅黑";
521
+}
522
+
523
+.titlebar {
524
+    height: 82px;
525
+    background: #5c95b3;
526
+}
527
+
528
+.titlebar #p_my_face {
529
+    position: relative;
530
+    width: 60px;
531
+    height: 60px;
532
+    border: 1px white solid;
533
+    margin: 10px;
534
+    float: left;
535
+}
536
+
537
+.titlebar #t_my_name {
538
+    position: relative;
539
+    top: 10px;
540
+    left: 10px;
541
+    float: left;
542
+    font-size: 20px;
543
+    color: white;
544
+}
545
+
546
+.titlebar #t_my_menu {
547
+    width: 150px;
548
+    position: relative;
549
+    top: 5px;
550
+    right: 5px;
551
+    float: right;
552
+
553
+}
554
+
555
+.sesspart {
556
+    clear: both;
557
+    float: left;
558
+    width: 208px;
559
+    height: 535px;
560
+    background: #d7eaf3;
561
+}
562
+
563
+.accordion {
564
+    margin-bottom: 18px;
565
+}
566
+
567
+.accordion-group {
568
+    margin-bottom: 2px;
569
+    border: 1px solid #e5e5e5;
570
+    -webkit-border-radius: 4px;
571
+    -moz-border-radius: 4px;
572
+    border-radius: 4px;
573
+}
574
+
575
+.accordion-heading {
576
+    border-bottom: 0;
577
+    background-color: bisque;
578
+}
579
+
580
+.accordion-heading .accordion-toggle {
581
+    display: block;
582
+    padding: 8px 15px;
583
+    font-size: medium;
584
+}
585
+
586
+.accordion-inner {
587
+    padding: 9px 15px;
588
+    border-top: 1px solid #e5e5e5;
589
+}
590
+.sesslist-recent {
591
+    height: 450px;
592
+    background: #f5f5f5;
593
+    border-width: 0px 1px 0px 0px;
594
+    border-color: #d5d6d7;
595
+    border-style: solid;
596
+}
597
+
598
+
599
+.sesslist {
600
+    /* height: 400px; */
601
+    height: 450px;
602
+    background: #f5f5f5;
603
+    border-width: 0px 1px 0px 0px;
604
+    border-color: #d5d6d7;
605
+    border-style: solid;
606
+    overflow: auto;
607
+}
608
+
609
+.sesslist-group {
610
+    /* height: 400px; */
611
+    height: 450px;
612
+    background: #f5f5f5;
613
+    border-width: 0px 1px 0px 0px;
614
+    border-color: #d5d6d7;
615
+    border-style: solid;
616
+    overflow: auto;
617
+}
618
+
619
+.sessinfo {
620
+    clear: both;
621
+    height: 50px;
622
+    border-width: 0px 0px 1px 0px;
623
+    border-color: #d5d6d7;
624
+    border-style: solid;
625
+}
626
+
627
+.sessinfo-sel {
628
+    clear: both;
629
+    height: 50px;
630
+    border-width: 0px 0px 1px 0px;
631
+    border-color: #d5d6d7;
632
+    border-style: solid;
633
+    background: #d7eaf3;
634
+}
635
+
636
+.face {
637
+    float: left;
638
+    width: 40px;
639
+    height: 40px;
640
+    margin: 5px 5px 5px 10px;
641
+}
642
+
643
+.name {
644
+    float: left;
645
+    height: 20px;
646
+    text-indent: 2px;
647
+    font-size: 12px;
648
+    color: #1f1f1f;
649
+    margin: 15px 0 0 0;
650
+}
651
+
652
+.badge {
653
+    display: none;
654
+    float: right;
655
+    margin: 18px 0 0 0;
656
+    width: 32px;
657
+    height: 20px;
658
+    background: #f00000;
659
+    color: white;
660
+    text-align: center;
661
+    -webkit-border-radius: 10px;
662
+    -moz-border-radius: 10px;
663
+    border-radius: 10px;
664
+}
665
+
666
+.badge span {
667
+    position: relative;
668
+    top: 1px;
669
+    font-size: 10px;
670
+}
671
+
672
+.chatpart {
673
+    float: right;
674
+    width: 526px;
675
+    border: 0px red solid;
676
+    background: #d7eaf3;
677
+    margin-top: -535px;
678
+}
679
+
680
+.msgflow {
681
+    width: 525px;
682
+    height: 380px;
683
+    border: 1px rgb(181, 178, 178) solid;
684
+    padding: 20px 6px 0 6px;
685
+    background: #f5f5f5;
686
+    overflow: auto;
687
+}
688
+.msgflow .onemsg{position:relative;}
689
+.msgflow .onemsg .msghead {
690
+    color: green;
691
+    line-height: 12px;
692
+    font-size: 12px;
693
+}
694
+
695
+.msgflow .onemsg .msgbody {
696
+    margin: 0 0 0 18px;
697
+    line-height: 13px;
698
+    font-size: 14px;
699
+}
700
+
701
+.msgflow .msgbody img {
702
+    max-width: 500px;
703
+}
704
+
705
+.editbar {
706
+    width: 526px;
707
+    height: 25px;
708
+}
709
+
710
+.chat02_title_btn {
711
+    background: url('http://jk.kuyicloud.com/static/plugins/tencentim/IMSDK_V1.7/img/icon.png') no-repeat 0 0;
712
+    cursor: pointer;
713
+    float: left;
714
+    display: block;
715
+    width: 15px;
716
+    height: 15px;
717
+    margin: 5px 6px;
718
+}
719
+
720
+.ctb01 {
721
+    background-position: 0 -90px;
722
+    margin-left: 18px;
723
+    _margin-left: 8px;
724
+}
725
+
726
+.ctb03 {
727
+    background-position: 0 -152px;
728
+}
729
+
730
+.ctb02 {
731
+    background-position: 0 -457px;
732
+}
733
+
734
+.ctb05 {
735
+    background-position: 0 -217px;
736
+}
737
+
738
+.ctb04 {
739
+    background-position: 0 -543px;
740
+}
741
+
742
+.wl_faces_box {
743
+    background: url('http://jk.kuyicloud.com/static/plugins/tencentim/IMSDK_V1.7/img/wlf_bg.png') repeat 0 0;
744
+    position: relative;
745
+    /*position: absolute;*/
746
+    width: 428px;
747
+    height: 225px;
748
+    bottom: 290px;
749
+    left: -42px;
750
+    display: none;
751
+}
752
+
753
+.wl_faces_content {
754
+    background: #fff;
755
+    border: 1px #ccc solid;
756
+    width: 417px;
757
+    height: 216px;
758
+    margin: 3px 4px;
759
+}
760
+
761
+.wl_faces_content .title {
762
+    background: url('http://jk.kuyicloud.com/static/plugins/tencentim/IMSDK_V1.7/img/wlf_title_bg.jpg') repeat-x 0 0;
763
+    height: 40px;
764
+    position: relative;
765
+}
766
+
767
+.wl_faces_content .title ul {
768
+
769
+}
770
+
771
+.wl_faces_content .title ul li {
772
+    position: absolute;
773
+    display: block;
774
+}
775
+
776
+.wl_faces_content .title ul li.title_name {
777
+    background: url('http://jk.kuyicloud.com/static/plugins/tencentim/IMSDK_V1.7/img/wlf_title_btn.jpg') no-repeat 0 0;
778
+    width: 82px;
779
+    height: 30px;
780
+    bottom: 0;
781
+    _bottom: -2px;
782
+    left: 15px;
783
+    text-align: center;
784
+    line-height: 32px;
785
+    font-weight: bold;
786
+    color: #333;
787
+}
788
+
789
+.wl_faces_content .title ul li.wl_faces_close {
790
+    right: 8px;
791
+    top: 15px;
792
+}
793
+
794
+.wl_faces_content .title ul li.wl_faces_close span {
795
+    background: url('http://jk.kuyicloud.com/static/plugins/tencentim/IMSDK_V1.7/img/icon.png') repeat-x 0 0;
796
+    cursor: pointer;
797
+    display: block;
798
+    width: 15px;
799
+    height: 15px;
800
+}
801
+
802
+.wl_faces_main {
803
+
804
+}
805
+
806
+.wl_faces_main ul {
807
+    margin: 12px 12px;
808
+    padding: 0px;
809
+    overflow: hidden;
810
+    border-top: 1px #CCC solid;
811
+    border-left: 1px #CCC solid;
812
+    list-style: none;
813
+    width: 393px;
814
+}
815
+
816
+.wl_faces_main ul li {
817
+    float: left;
818
+    border-right: 1px #CCC solid;
819
+    border-bottom: 1px #CCC solid;
820
+    height: 28px;
821
+    width: 28px;
822
+    margin: 0px 0px 0px 0px;
823
+    padding: 4px 2px;
824
+    text-align: center;
825
+}
826
+
827
+.wl_faces_main ul li img {
828
+    width: 24px;
829
+    height: 24px;
830
+}
831
+
832
+.wlf_icon {
833
+    background: url('http://jk.kuyicloud.com/static/plugins/tencentim/IMSDK_V1.7/img/layer_arrow.png') no-repeat 0 0;
834
+    position: absolute;
835
+    width: 22px;
836
+    height: 9px;
837
+    bottom: -4px;
838
+    _bottom: -11px;
839
+    left: 61px;
840
+}
841
+
842
+.msgedit {
843
+    width: 525px;
844
+    height: 100px;
845
+    border: 1px rgb(181, 178, 178) solid;
846
+    background: #f5f5f5;
847
+    padding: 6px 6px;
848
+    line-height: 1.5;
849
+}
850
+
851
+.sendbar {
852
+    width: 526px;
853
+    height: 30px;
854
+}
855
+
856
+.sendbtn {
857
+    float: right;
858
+    width: 80px;
859
+    margin-right: 10px;
860
+    font: 10px/1.5 "微软雅黑";
861
+}
862
+
863
+.closebtn {
864
+    float: right;
865
+    width: 80px;
866
+    margin-right: 10px;
867
+    font: 10px/1.5 "微软雅黑";
868
+}
869
+
870
+.bottom {
871
+    clear: both;
872
+    height: 3px;
873
+    background: #d7eaf3;
874
+}
875
+
876
+#demo_type_desc {
877
+    color: red;
878
+}
879
+
880
+#myself_type_desc {
881
+    display: none;
882
+    color: red;
883
+}
884
+
885
+#qcloudLink {
886
+    color: blue;
887
+}
888
+
889
+#sdkAppIdDiv {
890
+    display: none;
891
+}
892
+
893
+#accountTypeDiv {
894
+    display: none;
895
+}
896
+
897
+.pic_thumb {
898
+    width: 200px;
899
+    height: 200px;
900
+}
901
+
902
+
903
+
904
+.spinner {
905
+    width: 60px;
906
+    text-align: center;
907
+    position: absolute;
908
+    right: 10px;
909
+    top: 32px;
910
+    text-align: right;
911
+}
912
+
913
+.spinner > div {
914
+  width: 6px;
915
+  height: 6px;
916
+  background-color: #333;
917
+
918
+  border-radius: 100%;
919
+  display: inline-block;
920
+  -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
921
+  animation: sk-bouncedelay 1.4s infinite ease-in-out both;
922
+}
923
+
924
+.spinner .bounce1 {
925
+  -webkit-animation-delay: -0.32s;
926
+  animation-delay: -0.32s;
927
+}
928
+
929
+.spinner .bounce2 {
930
+  -webkit-animation-delay: -0.16s;
931
+  animation-delay: -0.16s;
932
+}
933
+
934
+@-webkit-keyframes sk-bouncedelay {
935
+  0%, 80%, 100% { -webkit-transform: scale(0) }
936
+  40% { -webkit-transform: scale(1.0) }
937
+}
938
+
939
+@keyframes sk-bouncedelay {
940
+  0%, 80%, 100% {
941
+    -webkit-transform: scale(0);
942
+    transform: scale(0);
943
+  } 40% {
944
+    -webkit-transform: scale(1.0);
945
+    transform: scale(1.0);
946
+  }
947
+}
948
+
949
+.headurlClass{
950
+    height: 30px;
951
+    width: 30px;
952
+    border-radius: 50%;
953
+}
954
+
955
+.delChat{
956
+    color: red;
957
+    width: 50px;
958
+    padding: 16px 0;
959
+    float: right;
960
+    margin-right: 5px;
961
+}
962
+figure {
963
+  margin: 0;
964
+}
965
+</style>

File diff suppressed because it is too large
+ 8282 - 0
static/webim.js