1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-08-01 16:38:02 +08:00

#75 增加chatbot socket.io server

This commit is contained in:
Hai Liang Wang 2018-09-11 20:25:27 +08:00
parent 45bf5d6333
commit 546b8e6ddc
8 changed files with 1234 additions and 32 deletions

View File

@ -705,7 +705,7 @@ public class UKDataContext {
IM("/im/user"),
AGENT("/im/agent"),
ENTIM("/im/ent"),
AIIM("/im/ai"),
CHATBOT("/im/chatbot"),
CALLCENTER("/callcenter/event"),
CALLOUT("/callout/event");

View File

@ -15,6 +15,8 @@ public abstract interface ChatbotRepository extends JpaRepository<Chatbot, Strin
public abstract boolean existsBySnsAccountIdentifierAndOrgi(String snsid, String orgi);
public abstract List<Chatbot> findByIdAndOrgi(String id, String orgi);
@Query(value = "select c from Chatbot c where " +
"(:myorgans is null or c.organ IN :myorgans)")
public Page<Chatbot> findByOrgans(@Param("myorgans") List<String> myorgans, Pageable pageRequest);

View File

@ -19,7 +19,7 @@ package com.chatopera.cc.webim.util.server;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import com.chatopera.cc.webim.util.server.handler.AiIMEventHandler;
import com.chatopera.cc.webim.util.server.handler.ChatbotEventHandler;
import com.chatopera.cc.webim.util.server.handler.EntIMEventHandler;
import com.chatopera.cc.webim.util.server.handler.IMEventHandler;
import org.springframework.beans.factory.annotation.Autowired;
@ -38,7 +38,7 @@ public class ServerRunner implements CommandLineRunner {
private final SocketIONamespace imSocketNameSpace ;
private final SocketIONamespace agentSocketIONameSpace ;
private final SocketIONamespace entIMSocketIONameSpace ;
private final SocketIONamespace aiIMSocketIONameSpace ;
private final SocketIONamespace chatbotSocketIONameSpace ;
private final SocketIONamespace callCenterSocketIONameSpace ;
private final SocketIONamespace calloutSocketIONameSpace ;
@ -48,7 +48,7 @@ public class ServerRunner implements CommandLineRunner {
imSocketNameSpace = server.addNamespace(UKDataContext.NameSpaceEnum.IM.getNamespace()) ;
agentSocketIONameSpace = server.addNamespace(UKDataContext.NameSpaceEnum.AGENT.getNamespace()) ;
entIMSocketIONameSpace = server.addNamespace(UKDataContext.NameSpaceEnum.ENTIM.getNamespace()) ;
aiIMSocketIONameSpace = server.addNamespace(UKDataContext.NameSpaceEnum.AIIM.getNamespace()) ;
chatbotSocketIONameSpace = server.addNamespace(UKDataContext.NameSpaceEnum.CHATBOT.getNamespace()) ;
if(UKDataContext.model.get("sales") != null && UKDataContext.model.get("sales") == true){
calloutSocketIONameSpace = server.addNamespace(UKDataContext.NameSpaceEnum.CALLOUT.getNamespace());
@ -81,10 +81,10 @@ public class ServerRunner implements CommandLineRunner {
return entIMSocketIONameSpace;
}
@Bean(name="aiimNamespace")
public SocketIONamespace getAiIMSocketIONameSpace(SocketIOServer server){
aiIMSocketIONameSpace.addListeners(new AiIMEventHandler(server));
return aiIMSocketIONameSpace;
@Bean(name="chatbotNamespace")
public SocketIONamespace getChatbotSocketIONameSpace(SocketIOServer server){
chatbotSocketIONameSpace.addListeners(new ChatbotEventHandler(server));
return chatbotSocketIONameSpace;
}
@Bean(name="callCenterNamespace")

View File

@ -0,0 +1,198 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.webim.util.server.handler;
import com.chatopera.cc.core.UKDataContext;
import com.chatopera.cc.util.IPTools;
import com.chatopera.cc.util.UKTools;
import com.chatopera.cc.util.client.NettyClients;
import com.chatopera.cc.webim.service.acd.ServiceQuene;
import com.chatopera.cc.webim.service.cache.CacheHelper;
import com.chatopera.cc.webim.service.repository.ConsultInviteRepository;
import com.chatopera.cc.webim.util.MessageUtils;
import com.chatopera.cc.webim.util.OnlineUserUtils;
import com.chatopera.cc.webim.util.router.OutMessageRouter;
import com.chatopera.cc.webim.util.server.message.AgentStatusMessage;
import com.chatopera.cc.webim.util.server.message.ChatMessage;
import com.chatopera.cc.webim.util.server.message.NewRequestMessage;
import com.chatopera.cc.webim.web.model.AgentService;
import com.chatopera.cc.webim.web.model.AiUser;
import com.chatopera.cc.webim.web.model.CousultInvite;
import com.chatopera.cc.webim.web.model.MessageOutContent;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.net.InetSocketAddress;
import java.util.Date;
public class ChatbotEventHandler
{
protected SocketIOServer server;
@Autowired
public ChatbotEventHandler(SocketIOServer server)
{
this.server = server ;
}
@OnConnect
public void onConnect(SocketIOClient client)
{
try {
String user = client.getHandshakeData().getSingleUrlParam("userid") ;
String orgi = client.getHandshakeData().getSingleUrlParam("orgi") ;
// String session = client.getHandshakeData().getSingleUrlParam("session") ;
String appid = client.getHandshakeData().getSingleUrlParam("appid") ;
String aiid = client.getHandshakeData().getSingleUrlParam("aiid") ;
// String agent = client.getHandshakeData().getSingleUrlParam("agent") ;
// String skill = client.getHandshakeData().getSingleUrlParam("skill") ;
if(!StringUtils.isBlank(user)){
// /**
// * 加入到 缓存列表
// */
NettyClients.getInstance().putIMEventClient(user, client);
MessageOutContent outMessage = new MessageOutContent() ;
CousultInvite invite = OnlineUserUtils.cousult(appid , orgi, UKDataContext.getContext().getBean(ConsultInviteRepository.class));
if(invite!=null && !StringUtils.isBlank(invite.getAisuccesstip())) {
outMessage.setMessage(invite.getAisuccesstip());
}else{
outMessage.setMessage("欢迎使用优客服小E我来帮您解答问题");
}
outMessage.setMessageType(UKDataContext.MessageTypeEnum.MESSAGE.toString());
outMessage.setCalltype(UKDataContext.CallTypeEnum.IN.toString());
outMessage.setNickName("AI");
outMessage.setCreatetime(UKTools.dateFormate.format(new Date()));
client.sendEvent(UKDataContext.MessageTypeEnum.STATUS.toString(), outMessage);
InetSocketAddress address = (InetSocketAddress) client.getRemoteAddress() ;
String ip = UKTools.getIpAddr(client.getHandshakeData().getHttpHeaders(), address.getHostString()) ;
AiUser aiUser = new AiUser(user, user, System.currentTimeMillis() , orgi,IPTools.getInstance().findGeography(ip)) ;
aiUser.setSessionid(UKTools.getContextID(client.getSessionId().toString()));
aiUser.setAppid(appid);
aiUser.setAiid(aiid);
aiUser.setUsername(UKDataContext.GUEST_USER+"_"+UKTools.genIDByKey(aiUser.getId()));
aiUser.setChannel(UKDataContext.ChannelTypeEnum.WEBIM.toString());
AgentService agentService = ServiceQuene.processAiService(aiUser, orgi) ;
aiUser.setAgentserviceid(agentService.getId());
CacheHelper.getOnlineUserCacheBean().put(user, aiUser, UKDataContext.SYSTEM_ORGI);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//添加@OnDisconnect事件客户端断开连接时调用刷新客户端信息
@OnDisconnect
public void onDisconnect(SocketIOClient client) throws Exception
{
String user = client.getHandshakeData().getSingleUrlParam("userid") ;
String orgi = client.getHandshakeData().getSingleUrlParam("orgi") ;
if(!StringUtils.isBlank(user)){
NettyClients.getInstance().removeIMEventClient(user , UKTools.getContextID(client.getSessionId().toString()));
AiUser aiUser = (AiUser) CacheHelper.getOnlineUserCacheBean().getCacheObject(user, orgi) ;
if(aiUser!=null) {
ServiceQuene.processAiService(aiUser, orgi) ;
CacheHelper.getOnlineUserCacheBean().delete(user,UKDataContext.SYSTEM_ORGI) ;
}
}
client.disconnect();
}
//消息接收入口网站有新用户接入对话
@OnEvent(value = "new")
public void onEvent(SocketIOClient client, AckRequest request, NewRequestMessage data)
{
}
//消息接收入口坐席状态更新
@OnEvent(value = "agentstatus")
public void onEvent(SocketIOClient client, AckRequest request, AgentStatusMessage data)
{
System.out.println(data.getMessage());
}
//消息接收入口收发消息用户向坐席发送消息和 坐席向用户发送消息
@OnEvent(value = "message")
public void onEvent(SocketIOClient client, AckRequest request, ChatMessage data)
{
String orgi = client.getHandshakeData().getSingleUrlParam("orgi") ;
String aiid = client.getHandshakeData().getSingleUrlParam("aiid") ;
String user = client.getHandshakeData().getSingleUrlParam("userid") ;
if(data.getType() == null){
data.setType("message");
}
/**
* 以下代码主要用于检查 访客端的字数限制
*/
CousultInvite invite = OnlineUserUtils.cousult(data.getAppid(),data.getOrgi(), UKDataContext.getContext().getBean(ConsultInviteRepository.class));
if(invite!=null && invite.getMaxwordsnum() > 0) {
if(!StringUtils.isBlank(data.getMessage()) && data.getMessage().length() > invite.getMaxwordsnum()){
data.setMessage(data.getMessage().substring(0 , invite.getMaxwordsnum()));
}
}else if(!StringUtils.isBlank(data.getMessage()) && data.getMessage().length() > 300){
data.setMessage(data.getMessage().substring(0 , 300));
}
data.setSessionid(UKTools.getContextID(client.getSessionId().toString()));
/**
* 处理表情
*/
data.setMessage(UKTools.processEmoti(data.getMessage()));
data.setTousername(UKDataContext.ChannelTypeEnum.AI.toString());
data.setAiid(aiid);
Object cacheData = (AiUser) CacheHelper.getOnlineUserCacheBean().getCacheObject(user,orgi) ;
if(cacheData!=null && cacheData instanceof AiUser){
AiUser aiUser = (AiUser)cacheData ;
data.setAgentserviceid(aiUser.getAgentserviceid());
data.setChannel(aiUser.getChannel());
/**
* 一定要设置 ContextID
*/
data.setContextid(aiUser.getAgentserviceid());
}
MessageOutContent outMessage = MessageUtils.createAiMessage(data , data.getAppid() , data.getChannel() , UKDataContext.CallTypeEnum.IN.toString() , UKDataContext.AiItemType.USERINPUT.toString() , UKDataContext.MediaTypeEnum.TEXT.toString(), data.getUserid()) ;
if(!StringUtils.isBlank(data.getUserid()) && UKDataContext.MessageTypeEnum.MESSAGE.toString().equals(data.getType())){
if(!StringUtils.isBlank(data.getTouser())){
OutMessageRouter router = null ;
router = (OutMessageRouter) UKDataContext.getContext().getBean(data.getChannel()) ;
if(router!=null){
router.handler(data.getTouser(), UKDataContext.MessageTypeEnum.MESSAGE.toString(), data.getAppid(), outMessage);
}
}
if(cacheData!=null && cacheData instanceof AiUser){
AiUser aiUser = (AiUser)cacheData ;
aiUser.setTime(System.currentTimeMillis());
CacheHelper.getOnlineUserCacheBean().put(user, aiUser, UKDataContext.SYSTEM_ORGI);
}
}
UKTools.ai(data);
}
}

View File

@ -56,6 +56,8 @@ import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@Controller
@ -474,32 +476,19 @@ public class IMController extends Handler {
if (UKDataContext.model.get("chatbot") != null &&
StringUtils.isNotBlank(invite.getAiid()) &&
invite.isAi() &&
(StringUtils.equals(ai, "true") || (invite.isAifirst() && ai == null))) { //启用 AI 并且 AI优先 接待
DataExchangeInterface dataInterface = (DataExchangeInterface) UKDataContext.getContext().getBean("aiconfig");
AiConfig aiConfig = (AiConfig) dataInterface.getDataByIdAndOrgi(aiid, invite.getOrgi());
if (aiConfig != null) {
map.addAttribute("aiConfig", aiConfig);
invite.isAifirst()) { //启用 AI 并且 AI优先 接待
HashMap<String, String> chatbotConfig = new HashMap<String, String>();
chatbotConfig.put("botname", invite.getAiname());
chatbotConfig.put("botid", invite.getAiid());
chatbotConfig.put("botwelcome", invite.getAimsg());
chatbotConfig.put("botfirst", Boolean.toString(invite.isAifirst()));
chatbotConfig.put("isai", Boolean.toString(invite.isAi()));
if (chatbotConfig != null) {
map.addAttribute("chatbotConfig", chatbotConfig);
}
view = request(super.createRequestPageTempletResponse("/apps/im/ai/index"));
view = request(super.createRequestPageTempletResponse("/apps/im/chatbot/index"));
if (CheckMobile.check(request.getHeader("User-Agent")) || !StringUtils.isBlank(mobile)) {
view = request(super.createRequestPageTempletResponse("/apps/im/ai/mobile")); //智能机器人 移动端
}
if (UKDataContext.model.get("xiaoe") != null) {
List<Topic> topicList = OnlineUserUtils.cacheHotTopic((DataExchangeInterface) UKDataContext.getContext().getBean("topic"), super.getUser(request), orgi, aiid);
/**
* 初步按照地区匹配分类筛选
*/
List<KnowledgeType> topicTypeList = OnlineUserUtils.topicType(orgi, ipdata, OnlineUserUtils.cacheHotTopicType((DataExchangeInterface) UKDataContext.getContext().getBean("topictype"), super.getUser(request), orgi, aiid));
/**
* 第二步按照 热点主题的 分类做筛选
*/
map.addAttribute("topicList", OnlineUserUtils.topic(orgi, topicTypeList, topicList));
/**
* 第三步筛选 分类如果无热点知识则不显示分类
*/
map.addAttribute("topicTypeList", OnlineUserUtils.filterTopicType(topicTypeList, topicList));
view = request(super.createRequestPageTempletResponse("/apps/im/chatbot/mobile")); //智能机器人 移动端
}
} else {
if (CheckMobile.check(request.getHeader("User-Agent")) || !StringUtils.isBlank(mobile)) {

View File

@ -20,6 +20,7 @@ import com.chatopera.chatbot.ChatbotAPIRuntimeException;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.Date;

View File

@ -0,0 +1,581 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<meta name="viewport"
content="width=device-width, maximum-scale=1.0, initial-scale=1.0,initial-scale=1.0,user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<title>在线咨询</title>
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico?t=1489039620156"/>
<link rel="stylesheet" type="text/css" href="/im/css/ukefu.css">
<link rel="stylesheet" id="skin" type="text/css" href="/im/css/default/ukefu.css">
<!-- kindeditor -->
<link rel="stylesheet" type="text/css" href="/im/js/kindeditor/themes/default/default.css">
<script src="/js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="/im/js/kindeditor/kindeditor.js"></script>
<script type="text/javascript" src="/im/js/kindeditor/lang/zh-CN.js"></script>
<script src="/im/js/socket.io.js"></script>
<script type="text/javascript">
var editor , words;
var newmessage = [] , ring = [];
newmessage['mp3'] = '/images/message.mp3';
ring['mp3'] = '/images/ring.mp3';
KindEditor.ready(function (K) {
editor = K.create('textarea[name="content"]', {
autoHeightMode: false,
width: "100%",
resizeType: 0,
themeType: 'simple',
fontsize: 16,
newlineTag : "br" ,
uploadJson : "/im/image/upload.html?userid=${userid!''}",
allowFileManager : false,
allowInsertUpload:false, //增加的参数,上传图片后是否插入到当前区域
allowImageRemote:false,
filterMode:true,
items: ['emoticons', 'cut' , 'image','insertfile'],
htmlTags: {img : ['src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'] , br:[]} ,
afterChange : function() {
var count = this.count() ;
var limitNum = <#if inviteData.maxwordsnum gt 0>${inviteData.maxwordsnum}<#else>300</#if>; //设定限制字数
var pattern = '还可以输入' + limitNum + '字';
var strValue = this.html();
if(count > limitNum) {
pattern = ('字数超过限制,请适当删除部分内容');
//超过字数限制自动截取
strValue = strValue.substring(0,limitNum);
editor.html(strValue);
} else {
//计算剩余字数
var result = limitNum - this.count();
pattern = '还可以输入' + result + '字';
if(result < 20){
document.getElementById('surplus').style.color = "red" ;
}else{
document.getElementById('surplus').style.color = "#000000" ;
}
}
if(this.count("text") == 0){
strValue= "" ;
}
if(words != this.count("text")){
socket.emit('message', {
appid : "${appid!''}",
userid:"${userid!''}",
type:"writing",
session:"${sessionid!''}",
orgi:"${orgi!''}",
message : strValue
});
}
words = this.count("text") ;
document.getElementById('surplus').innerHTML = count+"/"+limitNum+" , " + pattern; //输入显示
////////
},
afterCreate : function() { //设置编辑器创建后执行的回调函数
var self = this;
<#if inviteData?? && inviteData.ctrlenter?? && inviteData.ctrlenter == true>
//Ctrl+Enter提交表单
K.ctrl(document, 13, function() {
self.sync();
sendMessage();
});
K.ctrl(self.edit.doc, 13, function() {
self.sync();
sendMessage();
});
<#else>
var kindEditorIframe = $("iframe").contents().find("body");
kindEditorIframe.keydown(function (event) {
if(event.keyCode==13 && !event.ctrlKey){
self.sync();
sendMessage();
return false;
}else if(event.keyCode==13 && event.ctrlKey){
editor.insertHtml('<br/>');
}
});
//Ctrl+Enter提交表单
K.ctrl(document, 13, function() {
editor.insertHtml('<br/>');
});
K.ctrl(self.edit.doc, 13, function() {
editor.insertHtml('<br/>');
});
</#if>
}
});
});
KindEditor.options.cssData = "body { font-size: 15px; font-family:'Microsoft Yahei', 'Helvetica', 'Simsun', 'Arial';}";
var R3Ajax = {
ajax:function(opt){
var xhr = this.createXhrObject();
xhr.onreadystatechange = function(){
if(xhr.readyState!=4) return ;
(xhr.status===200 ?
opt.success(xhr.responseText,xhr.responseXML):
opt.error(xhr.responseText,xhr.status));
}
xhr.open(opt.type,opt.url,true);
if(opt.type!=='post')
opt.data=null;
else
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
opt.data = this.parseQuery(opt.data);
xhr.send(opt.data);
},
post:function(url,success,data){
var popt = {
url:url,
type:'post',
data:data,
success:success,
error:function(data){}
}
this.ajax(popt);
},
get:function(url,success){
var gopt = {
url:url,
type:'get',
success:success,
error:function(){}
}
this.ajax(gopt);
},
createXhrObject:function(){
var methods = [
function(){ return new XMLHttpRequest();},
function(){ return new ActiveXObject('Msxml2.XMLHTTP');},
function(){ return new ActiveXObject('Microsoft.XMLHTTP');}
];
for(var i=0;len=methods.length,i<len;i++){
try{
methods[i]();
}catch(e){
continue;
}
this.createXhrObject = methods[i];
return methods[i]();
}
throw new Error('Could not create an XHR object.');
},
parseQuery:function(json){
if(typeof json == 'object'){
var str = '';
for(var i in json){
str += "&"+i+"="+encodeURIComponent(json[i]);
}
return str.length==0 ? str : str.substring(1);
}else{
return json;
}
},
audioplayer:function(id, file, loop) {
var audioplayer = document.getElementById(id);
if (audioplayer != null) {
document.body.removeChild(audioplayer);
}
if (typeof(file) != 'undefined') {
if (navigator.userAgent.indexOf("MSIE") > 0) { // IE
var player = document.createElement('bgsound');
player.id = id;
player.src = file['mp3'];
player.setAttribute('autostart', 'true');
if (loop) {
player.setAttribute('loop', 'infinite');
}
document.body.appendChild(player);
} else { // Other FF Chome Safari Opera
var player = document.createElement('audio');
player.id = id;
player.setAttribute('autoplay', 'autoplay');
if (loop) {
player.setAttribute('loop', 'loop');
}
document.body.appendChild(player);
var mp3 = document.createElement('source');
mp3.src = file['mp3'];
mp3.type = 'audio/mpeg';
player.appendChild(mp3);
}
}
}
};
Date.prototype.format = function(fmt) {
var o = {
"M+" : this.getMonth()+1, //月份
"d+" : this.getDate(), //日
"h+" : this.getHours(), //小时
"m+" : this.getMinutes(), //分
"s+" : this.getSeconds(), //秒
"q+" : Math.floor((this.getMonth()+3)/3), //季度
"S" : this.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt)) {
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
}
for(var k in o) {
if(new RegExp("("+ k +")").test(fmt)){
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
}
}
return fmt;
}
var R3Helper = {
resize : function(){
var height = document.body.offsetHeight ;
document.getElementById('above').style.height = (height - 194 - 50)+"px" ;
}
}
function submitForm(form){
R3Ajax.post("/im/satis.html?orgi=${orgi!''}" , function(){
document.getElementById("diaShade").style.display = "none" ;
document.getElementById("dialogWrap").style.display = "none" ;
alert("服务评价已提及,请关闭浏览器!");
service_end = true;
} , "id="+form.id.value+"&satislevel="+document.getElementById("satislevel_input").value +"&satiscomment="+encodeURIComponent(document.getElementById("comment_input").value ));
return false ;
}
window.onbeforeunload = function(){
if(service_end == false){
<#if sessionConfig?? && sessionConfig.satisfaction?? && sessionConfig.satisfaction>
document.getElementById("diaShade").style.display = "block" ;
document.getElementById("dialogWrap").style.display = "block" ;
</#if>
return "您确定断开对话?" ;
}
}
</script>
<!-- kindeditor -->
</head>
<body style="overflow:hidden;" class="ukefu-point-text">
<div class="large ukefu-im-theme <#if type?? && type='text'>ukefu-theme-border-${inviteData.consult_dialog_color!''}</#if>">
<div id="containter" class="clearfix">
<div id="header" class="theme${inviteData.consult_dialog_color!''}">
<img src="<#if inviteData?? && inviteData.consult_dialog_logo??>/res/image.html?id=${inviteData.consult_dialog_logo?url}<#else>/images/logo.png</#if>" style="height:30px;padding:10px;">
<div class="ukefu-func-tab">
<ul>
<#if models?? && models["xiaoe"]?? && models["xiaoe"] == true && inviteData.ai && aiid??>
<#if !exchange?? || exchange == "true">
<li><a href="/im/index.html?appid=${appid!''}&orgi=${orgi!''}<#if aiid??>&aiid=${aiid}</#if>&ai=true<#if client??>&client=${client!''}</#if><#if type??>&type=text</#if><#if skill??>&skill=${skill!''}</#if><#if agent??>&agent=${agent!''}</#if><#if title??>&title=${title?url}</#if><#if url??>&url=${url?url}</#if><#if traceid??>&traceid=${traceid}</#if>&userid=${userid!''}&sessionid=${sessionid!''}&t=${.now?long}">智能客服</a></li>
</#if>
<li class="cur"><a href="javascript:void(0)">人工坐席</a></li>
<#else>
<li class="cur"><a href="javascript:void(0)">人工坐席</a></li>
</#if>
</ul>
</div>
</div>
<div class="content-left">
<div class="chat-above" id="above">
<#if welcomeAd>
<div class="clearfix message welcome">
<span id="welcome-message">
<#if welcomeAd.adtype =="image">
<a href='${welcomeAd.url!''}' title='${welcomeAd.tiptext!''}' target='_blank'><img src='${welcomeAd.imgurl!''}' style='max-width:420px;max-height:178px;margin:0px;vertical-align: middle;'/></a>
<#else>
<div style='padding:0px 5px 10px 5px;border-bottom:1px solid #dedede;'><a href='${welcomeAd.url!''}' title='${welcomeAd.tiptext!''}' target='_blank' id='point_ad_text'>${(welcomeAd.content!'')?no_esc}</a></div>
</#if>
</span>
</div>
</#if>
<div class="clearfix message welcome">
<span id="welcome-message">${(inviteData.dialog_message!'欢迎您来咨询!欢迎使用春松客服!如需帮助请联系 info@chatopera.com')?no_esc}</span></div>
<#if chatMessageList?? && chatMessageList.content??>
<#list chatMessageList.content?reverse as chatMessage>
<#if chatMessage.userid?? && userid?? && chatMessage.calltype?? && chatMessage.calltype = "呼入">
<div class="clearfix chat-block">
<div class="chat-right">
<img class="user-img" src="/im/img/user.png" alt="">
<div class="chat-message">
<label class="time">${chatMessage.createtime!''}</label>
<label class="user">${chatMessage.username!''}</label>
</div>
<div class="chatting-right">
<i class="arrow arrow${inviteData.consult_dialog_color!''}"></i>
<div class="chat-content theme${inviteData.consult_dialog_color!''}"><#include "/apps/im/media/message.html"></div>
</div>
</div>
</div>
<#else>
<div class="clearfix chat-block">
<div class="chat-left">
<img class="user-img" src="<#if inviteData?? && inviteData.consult_dialog_headimg??>/res/image.html?id=${inviteData.consult_dialog_headimg?url}<#else>/images/agent.png</#if>" alt="">
<div class="chat-message">
<label class="user"><#if chatMessage?? && chatMessage.chatype?? && chatMessage.chatype == 'aireply'>${inviteData.ainame!'小E'}<#else>${chatMessage.username!''}</#if></label>
<label class="time">${chatMessage.createtime!''}</label>
</div>
<div class="chatting-left">
<i class="arrow"></i>
<div class="chat-content"><#include "/apps/im/media/message.html"></div>
</div>
</div>
</div>
</#if>
</#list>
</#if>
</div>
<div class="chat-bottom" id="bottom">
<textarea id="message" name="content" style="visibility:hidden;"></textarea>
<div class="btn-push clearfix">
<div style="float:left;height:34px;line-height:34px;margin: 10px 20px 10px 5px;" id="surplus">0/200</div>
<button type="button" class="send-btn active special clearfix" id="sent" onclick="sendMessage()">
发送
</button>
</div>
</div>
</div>
<div class="content-rig">
<div class="content-list" style="padding-top:50px;">
<div class="content-head">
<p>信息提示</p>
</div>
<ul>
<#if inviteData.dialog_name?? && inviteData.dialog_name != "">
<li>
<p>名称:${inviteData.dialog_name!''}</p>
</li>
</#if>
<#if inviteData.dialog_address?? && inviteData.dialog_address != "">
<li>
<p>地址:${inviteData.dialog_address!''}</p>
</li>
</#if>
<#if inviteData.dialog_phone?? && inviteData.dialog_phone != "">
<li>
<p>电话:${inviteData.dialog_phone!''}</p>
</li>
</#if>
<#if inviteData.dialog_mail?? && inviteData.dialog_mail != "">
<li>
<p>邮件:${inviteData.dialog_mail!''}</p>
</li>
</#if>
<#if inviteData.dialog_mail?? && inviteData.dialog_introduction != "">
<li>
<p style="text-indent:25px;line-height:25px;">${(inviteData.dialog_introduction!'')?no_esc}</p>
</li>
</#if>
</ul>
</div>
<div class="content-pic" style="width:100%;height:192px;">
<#if imageAd>
<#if imageAd.adtype =="image">
<a href='${imageAd.url!''}' title='${imageAd.tiptext!''}' target='_blank'><img src='${imageAd.imgurl!''}' style='max-width:100%;max-height:190px;margin:0px;vertical-align: middle;'/></a>
<#else>
<div style='padding:0px 5px 10px 5px;border-bottom:1px solid #dedede;'><a href='${imageAd.url!''}' title='${imageAd.tiptext!''}' target='_blank' id='point_ad_text'>${(imageAd.content!'')?no_esc}</a></div>
</#if>
<#elseif inviteData.dialog_ad??>
<img src="/res/image.html?id=${inviteData.dialog_ad!''}" style="height:190px;width:100%;">
</#if>
</div>
</div>
</div>
<div id="footer"></div>
</div>
<#if sessionConfig?? && sessionConfig.satisfaction?? && sessionConfig.satisfaction>
<!--调查问卷弹框-->
<div class="diaShade" id="diaShade" style="display: none"></div>
<div class="dialogWrap" id="dialogWrap" style="display: none">
<div class="dialogCon">
<form id="commentContent" onSubmit="return submitForm(this)">
<input type="hidden" name="id" id="agentserviceid" name="agentserviceid">
<h2 class="diaHeader clearfix">
<span>评价</span>
<hr>
</h2>
<p class="title">您是否对此次服务满意?</p>
<!--评价-->
<p style="margin-top:20px;">
<span style="float:left;">评价:</span>
<span style="position: relative;top: 0px;left: 13px;">
<#assign defaultvalue = "">
<#if commentList??>
<#list commentList as comment>
<input type="radio" name="satislevel" value="${comment.code!''}" <#if comment_index == 0>checked="checked"</#if> id="dic_${comment.id!''}" onclick="document.getElementById('satislevel_input').value = this.value">
<label for="dic_${comment.id!''}" class="radio">${comment.name!''}</label>
<#if defaultvalue == "">
<#assign defaultvalue = comment.code>
</#if>
</#list>
</#if>
<input type="hidden" id="satislevel_input" name="t" value="${defaultvalue}">
</span>
</p>
<!--描述-->
<p style="margin-top:20px;">
<span style="float:left;">意见:</span>
<span style="position: relative;top: 0px;left: 10px;">
<input type="hidden" id="comment_input" name="t">
<#if commentItemList??>
<#list commentItemList as item>
<div style="margin-left:55px;margin-bottom:20px;">
<input type="radio" name="comment" id="item_${item.id!''}" value="${item.id!''}" onclick="document.getElementById('comment_input').value = this.value">
<label for="item_${item.id!''}" class="radio">
${item.name!''}
</label>
</div>
</#list>
</#if>
</span>
</p>
<!--按钮-->
<p class="submitBtnWrap">
<input type="submit" class="btn submitBtn" id="submitBtn" value="提 交">
</p>
</form>
</div>
</div>
</#if>
<script>
var service_end = false ;
R3Helper.resize();
// 调查问卷
var diaShade=document.getElementById('diaShade');
var dialogWrap=document.getElementById('dialogWrap');
function popup(para) {
diaShade.style.display=para;
dialogWrap.style.display=para;
}
<#if !welcomeAd>
document.getElementById('above').scrollTop = document.getElementById('above').scrollHeight ; //滚动到 对话内容的 底部
</#if>
// 参数连接
var hostname = location.hostname ;
var protocol = window.location.protocol.replace(/:/g,'');
var socket = io.connect(protocol + '://'+hostname+':${port}/im/chatbot?userid=${userid!''}&orgi=${orgi!''}&session=${sessionid!''}&appid=${appid!''}&osname=${(osname!'')?url}&browser=${(browser!'')?url}<#if skill??>&skill=${skill}</#if><#if username??>&nickname=${username}</#if><#if agent??>&agent=${agent}</#if><#if title??>&title=${title?url}</#if><#if traceid??>&url=${url?url}</#if><#if traceid??>&traceid=${traceid}</#if>');
socket.on('connect',function(){
<#if contacts?? && contacts.name??>
socket.emit('new', {
name : "${contacts.name!''}",
phone:"${contacts.phone!''}",
email:"${contacts.email}",
memo:"${contacts.memo!''}",
orgi:"${inviteData.orgi!''}",
appid : "${appid!''}"
});
</#if>
})
socket.on("agentstatus",function(data){
document.getElementById('connect-message').innerHTML=data.message;
})
socket.on("status",function(data){
<#if welcomeAd>
output('<span id="connect-message">'+data.message+'</span>' , 'message connect-message' , false);
<#else>
output('<span id="connect-message">'+data.message+'</span>' , 'message connect-message' , true);
</#if>
if(data.messageType == "end"){
service_end = true ;
editor.readonly();
<#if sessionConfig?? && sessionConfig.satisfaction?? && sessionConfig.satisfaction>
document.getElementById("diaShade").style.display = "block" ;
document.getElementById("dialogWrap").style.display = "block" ;
</#if>
}
if(document.getElementById("agentserviceid")){
document.getElementById("agentserviceid").value = data.agentserviceid ;
}
})
socket.on('message', function(data) {
var chat=document.getElementsByClassName('chatting-left').innerText;
chat = data.message;
if(data.messageType == "image"){
chat = "<a href='"+data.message+"_original' target='_blank'><img src='"+data.message+"' class='ukefu-media-image'/></a>" ;
}else if(data.messageType == "file"){
chat = "<div class='ukefu-message-file'><div class='ukefu-file-icon'><img src='/im/img/file.png'></div><div class='ukefu-file-desc'><a href='"+data.message+"' target='_blank'><div>"+data.filename+"</div><div>"+(data.filesize/1024).toFixed(3)+"Kb</div></a></div></div>" ;
}
if(data.calltype == "呼入"){
output('<div class="chat-right"> <img class="user-img" src="/im/img/user.png" alt=""><div class="chat-message"><label class="time">'+data.createtime+'</label><label class="user">'+data.nickName+'</label> </div><div class="chatting-right"><i class="arrow arrow${inviteData.consult_dialog_color!''}"></i><div class="chat-content theme${inviteData.consult_dialog_color!''}">'+chat+'</div></div>' , "chat-block");
}else if(data.calltype == "呼出"){
output('<div class="chat-left"> <img class="user-img" src="<#if inviteData?? && inviteData.consult_dialog_headimg??>/res/image.html?id=${inviteData.consult_dialog_headimg?url}<#else>/images/agent.png</#if>" alt=""><div class="chat-message"><label class="user">'+data.nickName+'</label><label class="time">'+data.createtime+'</label> </div><div class="chatting-left"><i class="arrow"></i><div class="chat-content">'+chat+'</div></div>' , "chat-block");
R3Ajax.audioplayer('audioplane', newmessage, false); // 播放
}
});
socket.on('disconnect',function() {
output('<span id="connect-message">连接坐席失败,在线咨询服务不可用</span>' , 'message connect-message');
});
function sendDisconnect(){
socket.disconnect();
}
function sendMessage() {
editor.sync();
var count = editor.count("text");
if(count>0 && service_end == false){
var message = document.getElementById('message').value;
if(message!= ""){
socket.emit('message', {
appid : "${appid!''}",
userid:"${userid!''}",
type:"message" ,
session:"${sessionid!''}",
orgi:"${orgi!''}",
message : message
});
}
}else if(service_end == true){
alert("坐席已断开和您的对话");
}
editor.html('');
}
function output(message , clazz , scroll) {
if(clazz == "message connect-message"){
var messages = document.getElementsByClassName("connect-message") ;
for(inx =0 ; inx < messages.length ; ){
document.getElementById('above').removeChild(messages[inx]) ;
inx++ ;
}
}
var element = ("<div class='clearfix "+clazz+"'>" +" " + message + "</div>");
document.getElementById('above').innerHTML= (document.getElementById('above').innerHTML + element);
if(scroll == null || scroll == true){
document.getElementById('above').scrollTop = document.getElementById('above').scrollHeight ;
}
}
function update(id , message) {
document.getElementById(id).innerHTML= message;
}
var message={
// text:data.message,
// picture:function(){
// }
// file:function(){
// }
// lang:function(){
// }
// goods:function(){
// }
// POI:function(){
// }
}
// 回车事件
document.onkeyup=function(e){
if(!e) e=window.event;
if((e.keyCode||e.which)==13){
document.getElementById('sent').click();
}
}
window.onresize = function(){
R3Helper.resize();
};
</script>
</body>
</html>

View File

@ -0,0 +1,431 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Cache-Control" content="no-siteapp" />
<meta name="viewport"
content="width=device-width, maximum-scale=1.0, initial-scale=1.0,initial-scale=1.0,user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<title>智能客服</title>
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico?t=1489039620156"/>
<link rel="stylesheet" type="text/css" href="/im/css/ukefu.css">
<link rel="stylesheet" id="skin" type="text/css" href="/im/css/default/ukefu.css">
<!-- kindeditor -->
<link rel="stylesheet" type="text/css" href="/im/js/kindeditor/themes/default/default.css">
<script type="text/javascript" src="/js/jquery-1.10.2.min.js"></script>
<script src="/js/jquery.form.js"></script>
<script type="text/javascript" src="/im/js/kindeditor/kindeditor.js"></script>
<script type="text/javascript" src="/im/js/kindeditor/lang/zh-CN.js"></script>
<style>
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
outline: none;
}
*:not(input,textarea) {
-webkit-touch-callout: none;
-webkit-user-select: none;
}
</style>
<script src="/im/js/socket.io.js"></script>
<script type="text/javascript">
var editor , words , textheight , wordinx = 0 ;
/**
* 文本框根据输入内容自适应高度
* @param {HTMLElement} 输入框元素
* @param {Number} 设置光标与输入框保持的距离(默认0)
* @param {Number} 设置最大高度(可选)
*/
var autoTextarea = function (elem, extra, maxHeight) {
extra = extra || 0;
var isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX' in window,
isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera'),
addEvent = function (type, callback) {
elem.addEventListener ?
elem.addEventListener(type, callback, false) :
elem.attachEvent('on' + type, callback);
},
getStyle = elem.currentStyle ? function (name) {
var val = elem.currentStyle[name];
if (name === 'height' && val.search(/px/i) !== 1) {
var rect = elem.getBoundingClientRect();
return rect.bottom - rect.top -
parseFloat(getStyle('paddingTop')) -
parseFloat(getStyle('paddingBottom')) + 'px';
};
return val;
} : function (name) {
return getComputedStyle(elem, null)[name];
},
minHeight = parseFloat(getStyle('height'));
elem.style.resize = 'none';
var textchange = function(){
changeTextArea(38);
}
var change = function () {
changeTextArea(0);
wordinx = getPositionForTextArea(document.getElementById('message'));
};
addEvent('propertychange', textchange);
addEvent('input', textchange);
addEvent('focus', changeTextArea);
change();
};
//多行文本框
function getPositionForTextArea(ctrl) {
var CaretPos = 0;
if (document.selection) { // IE Support
ctrl.focus();
var Sel = document.selection.createRange();
var Sel2 = Sel.duplicate();
Sel2.moveToElementText(ctrl);
var CaretPos = -1;
while (Sel2.inRange(Sel)) {
Sel2.moveStart('character');
CaretPos++;
}
} else if (ctrl.selectionStart || ctrl.selectionStart == '0') { // Firefox support
CaretPos = ctrl.selectionStart;
}
return (CaretPos);
}
function openFaceDialog(){
if(document.getElementById("faceindex").style.display == "none"){
document.getElementById("faceindex").style.display= "block";
document.getElementById("bottom").style.height = $('#message').height()+ 20 + document.getElementById("faceindex").offsetHeight + "px" ;
document.getElementById("above").style.height = "calc(100% - "+($('#bottom').height())+"px)"
}else{
closeFaceDialog(0);
}
return false ;
}
function closeFaceDialog(height){
document.getElementById("faceindex").style.display= "none";
document.getElementById("bottom").style.height = $('#message').height() + height + "px" ;
document.getElementById("above").style.height = "calc(100% - "+($('#message').height())+"px)" ;
}
function changeTextArea(height){
if(document.getElementById("faceindex").style.display == "none"){
$('#bottom').height($('#message').height() + height);
document.getElementById("above").style.height = "calc(100% - "+($('#message').height())+"px)"
}else{
$('#bottom').height($('#message').height() + $('#faceindex').height());
document.getElementById("above").style.height = "calc(100% - "+($('#message').height())+"px)"
}
}
function insertImg(obj){
if(wordinx >= 0){
var text = $('#message').val();
var value = text.substring(0 , wordinx) + "["+obj+"]" + text.substring(wordinx , text.length);
$('#message').val(value);
wordinx = wordinx + 2 + obj.length ;
}
}
$(document).ready(function(){
window.addEventListener('resize', function () {
if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') {
window.setTimeout(function () {
document.activeElement.scrollIntoViewIfNeeded()
}, 0)
}
});
// 在输入框获取焦点, 键盘弹起后, 真的是一行代码
$(document).on('submit.form.data-api','[data-toggle="ajax-form"]', function ( e ) {
var formValue = $(e.target) ;
$(this).ajaxSubmit({
url:formValue.attr("action"),
success: function(data){
},
error:function(xhr, type, s){
//notification("",false); //结束
}
});
return false;
});
});
</script>
<!-- kindeditor -->
</head>
<body class="ukefu-im-theme" style="overflow:hidden;height:calc(100%);overflow-y: atuo;/* 或者scroll */-webkit-overflow-scrolling: touch;/* 解决ios滑动不流畅问题 */" class="ukefu-point-text">
<div id="header" class="theme${inviteData.consult_dialog_color!''}">
<img
src="<#if inviteData?? && inviteData.consult_dialog_logo??>/res/image.html?id=${inviteData.consult_dialog_logo?url}<#else>/images/logo.png</#if>"
style="height:50px;padding:10px;">
<div class="ukefu-func-tab">
<ul>
<#if models?? && models["chatbot"]?? && models["chatbot"] == true && inviteData.ai?? && inviteData.ai == true && aiid??>
<li><a href="/im/index.html?appid=${appid!''}&orgi=${orgi!''}<#if aiid??>&aiid=${aiid}</#if>&ai=true<#if client??>&client=${client!''}</#if><#if type??>&type=text</#if><#if skill??>&skill=${skill!''}</#if><#if agent??>&agent=${agent!''}</#if>&userid=${userid!''}&sessionid=${sessionid!''}&t=${.now?long}">智能客服</a></li>
<li class="cur"><a href="javascript:void(0)">人工坐席</a></li>
<#else>
<li class="cur"><a href="javascript:void(0)">人工坐席</a></li>
</#if>
</ul>
</div>
</div>
<div id="cooperation" class="ukefu-cooperation" style="display:none;z-index: 100;background-color: #ffffff;position: fixed;left: 0px;width: 100%;top: 0px;top:0px;height: 100%;">
<div class='ukefu-image-canvas' id='ukefu-image-content' style="margin-top:2px;">
<img id="ukefu_img_ctx" style="max-width: 100%;max-height: 100%;">
</div>
<div class='drawBoard' style="position: absolute;left: 0;top: 0;margin-top:2px;z-index: 998;">
<canvas id="canvas-borad" class="brushBorad">你的浏览器不支持 canvas 绘图</canvas>
</div>
<div style="position: absolute;bottom: 10px;width: 100%;text-align: center;z-index:10000">
<button id="offcoop-btn" style="border-color:#009688 !important;color:#FFFFFF;display: inline-block;height: 38px;line-height: 38px;padding: 0 18px;background-color: #009688;color: #fff;white-space: nowrap;text-align: center;font-size: 14px;margin-right:10px;border: none;border-radius: 2px;cursor: pointer;opacity: .9;filter: alpha(opacity=90);background-color: #377FED !important;border:1px solid #FFFFFF;" onclick="offCoop();">退出协作</button>
</div>
</div>
<div class="chat-above" id="above" style="height:calc(100% - 60px);padding-bottom:100px;">
<div class="clearfix message welcome">
<span id="welcome-message">${(inviteData.dialog_message!'欢迎您来咨询!欢迎使用春松客服!如需帮助请联系 info@chatopera.com')?no_esc}</span>
</div>
<#if chatMessageList?? && chatMessageList.content??>
<#list chatMessageList.content?reverse as chatMessage>
<#if chatMessage.userid?? && userid?? && chatMessage.calltype?? && chatMessage.calltype = "呼入">
<div class="clearfix chat-block">
<div class="chat-right">
<img class="user-img" src="/im/img/user.png" alt="">
<div class="chat-message">
<label class="time">${chatMessage.createtime!''}</label> <label
class="user">${chatMessage.username!''}</label>
</div>
<div class="chatting-right">
<i class="arrow arrow${inviteData.consult_dialog_color!''}"></i>
<div
class="chat-content theme${inviteData.consult_dialog_color!''}"><#include
"/apps/im/media/message.html"></div>
</div>
</div>
</div>
<#else>
<div class="clearfix chat-block">
<div class="chat-left">
<img class="user-img"
src="<#if inviteData?? && inviteData.consult_dialog_headimg??>/res/image.html?id=${inviteData.consult_dialog_headimg?url}<#else>/images/agent.png</#if>"
alt="">
<div class="chat-message">
<label class="user">${chatMessage.username!''}</label> <label
class="time">${chatMessage.createtime!''}</label>
</div>
<div class="chatting-left">
<i class="arrow"></i>
<div class="chat-content"><#include "/apps/im/media/message.html"></div>
</div>
</div>
</div>
</#if> </#list> </#if>
</div>
<div class="mobile-chat-bottom" id="bottom">
<form id="imgForm" action="/im/image/upload.html?userid=${userid!''}&appid=${appid!''}&username=${username!''}&orgi=${orgi!''}" data-toggle="ajax-form"" enctype="multipart/form-data">
<a href="javascript:;" class="imgFile" onclick="closeFaceDialog(0)">
<img src="/im/img/img.png" class="chat-type" style="width:32px;height:32px;">
<input type="file" name="imgFile" id="imgFile" accept="image/*" onChange="$('#imgForm').submit();$(this).val('');">
</a>
</form>
<textarea id="message" name="content" maxlength="<#if inviteData.maxwordsnum gt 0>${inviteData.maxwordsnum}<#else>300</#if>"></textarea>
<div class="btn-push clearfix" class="tools">
<img id="facedialog" onclick="return openFaceDialog()" src="/im/img/face.png" style="width:32px;height:32px;"></a>
<a href="javascript:void(0)" onClick="sendMessage();return false;"><img src="/im/img/send.png" style="width:32px;height:32px;"></a>
</div>
<div id="faceindex" style="display:none;height:200px;position: absolute;bottom: 0px;width:100%;overflow-x:auto;">
<table class="ke-table" cellpadding="0" cellspacing="0" border="0" style="min-width:100%;">
<tbody>
<#list 0..4 as row>
<tr>
<#list 0..20 as col>
<td class="ke-cell"><span class="ke-img"><img
src="/im/js/kindeditor/plugins/emoticons/images/${row*20 + col}.png"
border="0" alt="" onClick="insertImg('${row*20 + col}')"></span></td>
</#list>
</tr>
</#list>
</tbody>
</table>
</div>
</div>
</div>
<script>
var service_end = false;
// 调查问卷
var diaShade = document.getElementById('diaShade');
var dialogWrap = document.getElementById('dialogWrap');
function popup(para) {
diaShade.style.display = para;
dialogWrap.style.display = para;
}
document.getElementById('above').scrollTop = document
.getElementById('above').scrollHeight; //滚动到 对话内容的 底部
// 参数连接
// 参数连接
var hostname = location.hostname ;
var protocol = window.location.protocol.replace(/:/g,'');
var socket = io.connect(protocol + '://'+hostname+':${port}/im/chatbot?userid=${userid!''}<#if aiid??>&aiid=${aiid}</#if>&orgi=${orgi!''}&session=${sessionid!''}&appid=${appid!''}&osname=${(osname!'')?url}&browser=${(browser!'')?url}<#if skill??>&skill=${skill}</#if><#if agent??>&agent=${agent}</#if>');
socket.on('connect',function(){
//service.sendRequestMessage();
//output('<span id="callOutConnect-message">'+ new Date().format("yyyy-MM-dd hh:mm:ss") + ' 开始沟通' +'</span>' , 'message callOutConnect-message');
})
socket.on("agentstatus",function(data){
document.getElementById('connect-message').innerHTML=data.message;
})
socket.on("status",function(data){
output('<span id="connect-message">'+data.message+'</span>' , 'message connect-message');
if(data.messageType == "end"){
service_end = true ;
//editor.readonly();
}
})
socket.on('message', function(data) {
var chat=document.getElementsByClassName('chatting-left').innerText;
chat = data.message;
if(data.messageType == "image"){
chat = "<a href='"+data.message+"_original' target='_blank'><img src='"+data.message+"' class='ukefu-media-image'/></a>" ;
}else if(data.messageType == "cooperation"){
chat = "<a href='javascript:void(0)' onclick='acceptInvite(\""+data.message+"\", \""+data.attachmentid+"\")'>您收到一个协作邀请,点击进入协作</a>" ;
}else if(data.messageType == "action"){
//检查访客是否在协作页面上,如果在协作页面上,就开始执行重绘,否则不做处理
drawCanvasImage(data.attachmentid) ;
}
if(data.calltype == "呼入"){
output('<div class="chat-right"> <img class="user-img" src="/im/img/user.png" alt=""><div class="chat-message"><label class="time">'+data.createtime+'</label><label class="user">'+data.nickName+'</label> </div><div class="chatting-right"><i class="arrow arrow${inviteData.consult_dialog_color!''}"></i><div class="chat-content theme${inviteData.consult_dialog_color!''}">'+chat+'</div></div>' , "chat-block");
}else if(data.calltype == "呼出"){
output('<div class="chat-left"> <img class="user-img" src="<#if inviteData?? && inviteData.consult_dialog_headimg??>/res/image.html?id=${inviteData.consult_dialog_headimg?url}<#else>/images/agent.png</#if>" alt=""><div class="chat-message"><label class="user">'+data.nickName+'</label><label class="time">'+data.createtime+'</label> </div><div class="chatting-left"><i class="arrow"></i><div class="chat-content">'+chat+'</div></div>' , "chat-block");
}
});
socket.on('disconnect',function() {
output('<span id="connect-message">连接坐席失败,在线咨询服务不可用</span>' , 'message connect-message');
});
function sendDisconnect(){
socket.disconnect();
}
function acceptInvite(msgid,fileid){
document.getElementById("cooperation").style.display = "block" ;
document.getElementById("ukefu_img_ctx").src = "/res/image.html?id=upload/"+fileid ;
$("#ukefu_img_ctx").load(function() {
var height = document.getElementById("ukefu-image-content").offsetHeight;
var width = document.getElementById("ukefu-image-content").offsetWidth;
var canvas = document.getElementById("canvas-borad") ;
if(canvas.getContext){
canvas.width = width;
canvas.height = height;
drawCanvasImage(fileid) ;
}
});
}
function drawCanvasImage(fileid){
var canvas = document.getElementById("canvas-borad") ;
if (canvas.getContext && document.getElementById("cooperation").style.display == "block") {
var ctx = canvas.getContext("2d");
//创建新的图片对象
var img = new Image();
//指定图片的URL
img.src = "/res/image.html?id=upload/" + fileid + "_cooperation";
//浏览器加载图片完毕后再绘制图片
img.onload = function() {
ctx.clearRect(0,0,canvas.width,canvas.height);
//以Canvas画布上的坐标(10,10)为起始点,绘制图像
ctx.drawImage(img, 0, 0 , canvas.width,canvas.height);
};
}
}
function offCoop(){
document.getElementById("cooperation").style.display = "none" ;
}
function sendMessage() {
var count = document.getElementById('message').value.length;
if (count > 0 && service_end == false) {
var message = $("#message").val();
sendMessageText(message);
$("#message").val("");
wordinx = 0;
} else if (service_end == true) {
alert("服务器已断开和您的对话");
}
closeFaceDialog(0);
}
function sendMessageText(message) {
if (message != "") {
socket.emit('message', {
appid : "${appid!''}",
userid : "${userid!''}",
username : "${username!''}",
channel : "webim",
type : "message",
contextid : "${sessionid!''}",
orgi : "${orgi!''}",
message : message
});
}
}
function output(message, clazz) {
if (clazz == "message connect-message") {
var messages = document.getElementsByClassName("connect-message");
for (inx = 0; inx < messages.length;) {
document.getElementById('above').removeChild(messages[inx]);
inx++;
}
}
var element = ("<div class='clearfix "+clazz+"'>" + " " + message + "</div>");
document.getElementById('above').innerHTML = (document
.getElementById('above').innerHTML + element);
document.getElementById('above').scrollTop = document.getElementById('above').scrollHeight ;
//$("#welcome-message").html(document.getElementById('above').scrollHeight);
}
function update(id, message) {
document.getElementById(id).innerHTML = message;
}
autoTextarea(document.getElementById("message"));// 调用
$('#message').click(function() {
wordinx = getPositionForTextArea(document.getElementById('message'));
closeFaceDialog(44);
});
var message = {
// text:data.message,
// picture:function(){
// }
// file:function(){
// }
// lang:function(){
// }
// goods:function(){
// }
// POI:function(){
// }
}
</script>
</body>
</html>