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

Fix AgentServiceRepository related class

This commit is contained in:
dengchao@xgtl 2020-04-17 15:03:47 +08:00
parent 6064584884
commit e463139cc2
6 changed files with 461 additions and 492 deletions

View File

@ -20,39 +20,39 @@ import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.model.AgentService; import com.chatopera.cc.model.AgentService;
import com.chatopera.cc.model.AgentUser; import com.chatopera.cc.model.AgentUser;
import com.chatopera.cc.persistence.repository.AgentServiceRepository; import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.springframework.lang.NonNull;
import org.slf4j.LoggerFactory; import org.springframework.lang.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Date; import java.util.Date;
@Slf4j
@Component @Component
@RequiredArgsConstructor
public class ACDChatbotService { public class ACDChatbotService {
private final static Logger logger = LoggerFactory.getLogger(ACDChatbotService.class);
@Autowired @NonNull
private AgentServiceRepository agentServiceRes; private final AgentServiceRepository agentServiceRes;
/** /**
* 为访客分配机器人客服 ACD策略此处 AgentStatus 是建议 坐席 如果启用了 历史服务坐席 优先策略 则会默认检查历史坐席是否空闲如果空闲则分配如果不空闲 分配当前建议的坐席 * 为访客分配机器人客服 ACD策略此处 AgentStatus 是建议 坐席 如果启用了 历史服务坐席 优先策略 则会默认检查历史坐席是否空闲如果空闲则分配如果不空闲 分配当前建议的坐席
*
* @param agentUser
* @param orgi
* @return
* @throws Exception
*/ */
@Nullable
public AgentService processChatbotService(final String botName, final AgentUser agentUser, final String orgi) { public AgentService processChatbotService(final String botName, final AgentUser agentUser, final String orgi) {
AgentService agentService = new AgentService(); //放入缓存的对象 AgentService agentService = new AgentService(); //放入缓存的对象
Date now = new Date(); Date now = new Date();
if (StringUtils.isNotBlank(agentUser.getAgentserviceid())) { if (StringUtils.isNotBlank(agentUser.getAgentserviceid())) {
agentService = agentServiceRes.findByIdAndOrgi(agentUser.getAgentserviceid(), orgi); agentService = agentServiceRes.findByIdAndOrgi(agentUser.getAgentserviceid(), orgi);
agentService.setEndtime(now); if (agentService != null) {
if (agentService.getServicetime() != null) { agentService.setEndtime(now);
agentService.setSessiontimes(System.currentTimeMillis() - agentService.getServicetime().getTime()); if (agentService.getServicetime() != null) {
agentService.setSessiontimes(System.currentTimeMillis() - agentService.getServicetime().getTime());
}
agentService.setStatus(MainContext.AgentUserStatusEnum.END.toString());
} }
agentService.setStatus(MainContext.AgentUserStatusEnum.END.toString());
} else { } else {
agentService.setServicetime(now); agentService.setServicetime(now);
agentService.setLogindate(now); agentService.setLogindate(now);
@ -81,7 +81,9 @@ public class ACDChatbotService {
agentService.setLeavemsg(false); agentService.setLeavemsg(false);
} }
agentServiceRes.save(agentService); if (agentService != null) {
agentServiceRes.save(agentService);
}
return agentService; return agentService;
} }

View File

@ -23,22 +23,19 @@ import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import com.chatopera.cc.util.Menu; import com.chatopera.cc.util.Menu;
import com.chatopera.cc.util.RestResult; import com.chatopera.cc.util.RestResult;
import com.chatopera.cc.util.RestResultType; import com.chatopera.cc.util.RestResultType;
import org.springframework.beans.factory.annotation.Autowired; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -47,33 +44,26 @@ import java.util.List;
*/ */
@RestController @RestController
@RequestMapping("/api/leavemsg") @RequestMapping("/api/leavemsg")
@RequiredArgsConstructor
public class ApiLeavemsgController extends Handler { public class ApiLeavemsgController extends Handler {
@Autowired @NonNull
private AgentServiceRepository agentServiceRepository; private final AgentServiceRepository agentServiceRepository;
/** /**
* 获取留言列表 * 获取留言列表
*
* @param request
* @param username 搜索用户名精确搜索
* @return
*/ */
@RequestMapping("/list") @RequestMapping("/list")
@Menu(type = "apps", subtype = "app", access = true) @Menu(type = "apps", subtype = "app", access = true)
public ResponseEntity<RestResult> list(HttpServletRequest request, @RequestBody RequestValues<AgentService> values) { public ResponseEntity<RestResult> list(@RequestBody RequestValues<AgentService> values) {
Page<AgentService> page = agentServiceRepository.findAll(new Specification<AgentService>() { Page<AgentService> page = agentServiceRepository.findAll((Specification<AgentService>) (root, query, cb) -> {
@Override List<Predicate> list = new ArrayList<>();
public Predicate toPredicate(Root<AgentService> root, CriteriaQuery<?> query, list.add(cb.equal(root.get("leavemsg").as(Boolean.class), true));
CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
list.add(cb.equal(root.get("leavemsg").as(Boolean.class), true));
list.add(cb.equal(root.get("leavemsgstatus").as(String.class), MainContext.LeaveMsgStatus.NOTPROCESS.toString())); list.add(cb.equal(root.get("leavemsgstatus").as(String.class), MainContext.LeaveMsgStatus.NOTPROCESS.toString()));
Predicate[] p = new Predicate[list.size()]; Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p)); return cb.and(list.toArray(p));
}
}, PageRequest.of(super.getP(values.getQuery()), super.getPs(values.getQuery()), Sort.Direction.DESC, "createtime")); }, PageRequest.of(super.getP(values.getQuery()), super.getPs(values.getQuery()), Sort.Direction.DESC, "createtime"));
return new ResponseEntity<>(new RestResult(RestResultType.OK, page), HttpStatus.OK); return new ResponseEntity<>(new RestResult(RestResultType.OK, page), HttpStatus.OK);
} }

View File

@ -23,23 +23,20 @@ import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import com.chatopera.cc.util.Menu; import com.chatopera.cc.util.Menu;
import com.chatopera.cc.util.RestResult; import com.chatopera.cc.util.RestResult;
import com.chatopera.cc.util.RestResultType; import com.chatopera.cc.util.RestResultType;
import org.springframework.beans.factory.annotation.Autowired; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -49,31 +46,24 @@ import java.util.List;
*/ */
@RestController @RestController
@RequestMapping("/api/quality") @RequestMapping("/api/quality")
@RequiredArgsConstructor
public class ApiQualityController extends Handler { public class ApiQualityController extends Handler {
@Autowired @NonNull
private AgentServiceRepository agentServiceRepository; private final AgentServiceRepository agentServiceRepository;
/** /**
* 获取质检列表 * 获取质检列表
*
* @param request
* @param username 搜索用户名精确搜索
* @return
*/ */
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
@Menu(type = "apps", subtype = "app", access = true) @Menu(type = "apps", subtype = "app", access = true)
public ResponseEntity<RestResult> list(HttpServletRequest request, @Valid AgentService agentService, @Valid String begin, @Valid String end) { public ResponseEntity<RestResult> list(HttpServletRequest request) {
Page<AgentService> page = agentServiceRepository.findAll(new Specification<AgentService>() { Page<AgentService> page = agentServiceRepository.findAll((Specification<AgentService>) (root, query, cb) -> {
@Override List<Predicate> list = new ArrayList<>();
public Predicate toPredicate(Root<AgentService> root, CriteriaQuery<?> query, list.add((cb.equal(root.get("qualitystatus").as(String.class), MainContext.QualityStatusEnum.NODIS.toString())));
CriteriaBuilder cb) {
List<Predicate> list = new ArrayList<Predicate>();
list.add((cb.equal(root.get("qualitystatus").as(String.class), MainContext.QualityStatusEnum.NODIS.toString())));
Predicate[] p = new Predicate[list.size()]; Predicate[] p = new Predicate[list.size()];
return cb.and(list.toArray(p)); return cb.and(list.toArray(p));
}
}, PageRequest.of(super.getP(request), super.getPs(request), Sort.Direction.DESC, "createtime")); }, PageRequest.of(super.getP(request), super.getPs(request), Sort.Direction.DESC, "createtime"));
return new ResponseEntity<>(new RestResult(RestResultType.OK, page), HttpStatus.OK); return new ResponseEntity<>(new RestResult(RestResultType.OK, page), HttpStatus.OK);
} }

View File

@ -20,27 +20,27 @@ import com.chatopera.cc.controller.Handler;
import com.chatopera.cc.model.AgentService; import com.chatopera.cc.model.AgentService;
import com.chatopera.cc.persistence.repository.AgentServiceRepository; import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import com.chatopera.cc.util.Menu; import com.chatopera.cc.util.Menu;
import org.springframework.beans.factory.annotation.Autowired; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
@Controller @Controller
@RequestMapping("/service") @RequestMapping("/service")
public class CommentController extends Handler{ @RequiredArgsConstructor
@Autowired public class CommentController extends Handler {
private AgentServiceRepository agentServiceRes ; @NonNull
private final AgentServiceRepository agentServiceRes;
@RequestMapping("/comment/index") @RequestMapping("/comment/index")
@Menu(type = "service" , subtype = "comment" , admin= true) @Menu(type = "service", subtype = "comment", admin = true)
public ModelAndView index(ModelMap map , HttpServletRequest request , String userid , String agentservice , @Valid String channel) { public ModelAndView index(ModelMap map, HttpServletRequest request) {
Page<AgentService> agentServiceList = agentServiceRes.findByOrgiAndSatisfaction(super.getOrgi(request), true, PageRequest.of(super.getP(request), super.getPs(request))); Page<AgentService> agentServiceList = agentServiceRes.findByOrgiAndSatisfaction(super.getOrgi(request), true, PageRequest.of(super.getP(request), super.getPs(request)));
map.addAttribute("serviceList", agentServiceList); map.addAttribute("serviceList", agentServiceList);
return request(super.createAppsTempletResponse("/apps/service/comment/index")); return request(super.createAppsTempletResponse("/apps/service/comment/index"));

View File

@ -1,273 +1,263 @@
/* /*
* Copyright (C) 2017 优客服-多渠道客服系统 * Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2019 Chatopera Inc, <https://www.chatopera.com> * Modifications copyright (C) 2018-2019 Chatopera Inc, <https://www.chatopera.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.chatopera.cc.socketio.handler; package com.chatopera.cc.socketio.handler;
import com.chatopera.cc.acd.ACDServiceRouter; import com.chatopera.cc.acd.ACDServiceRouter;
import com.chatopera.cc.acd.ACDVisitorDispatcher; import com.chatopera.cc.acd.ACDVisitorDispatcher;
import com.chatopera.cc.acd.basic.ACDComposeContext; import com.chatopera.cc.acd.basic.ACDComposeContext;
import com.chatopera.cc.acd.basic.ACDMessageHelper; import com.chatopera.cc.acd.basic.ACDMessageHelper;
import com.chatopera.cc.basic.MainContext; import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainContext.CallType; import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.basic.MainContext.ChannelType; import com.chatopera.cc.model.Contacts;
import com.chatopera.cc.basic.MainContext.MessageType; import com.chatopera.cc.model.CousultInvite;
import com.chatopera.cc.basic.MainContext.ReceiverType; import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import com.chatopera.cc.basic.MainUtils; import com.chatopera.cc.proxy.AgentUserProxy;
import com.chatopera.cc.model.Contacts; import com.chatopera.cc.proxy.OnlineUserProxy;
import com.chatopera.cc.model.CousultInvite; import com.chatopera.cc.socketio.client.NettyClients;
import com.chatopera.cc.persistence.repository.AgentServiceRepository; import com.chatopera.cc.socketio.message.AgentStatusMessage;
import com.chatopera.cc.proxy.AgentUserProxy; import com.chatopera.cc.socketio.message.ChatMessage;
import com.chatopera.cc.proxy.OnlineUserProxy; import com.chatopera.cc.socketio.util.HumanUtils;
import com.chatopera.cc.socketio.client.NettyClients; import com.chatopera.cc.socketio.util.IMServiceUtils;
import com.chatopera.cc.socketio.message.AgentStatusMessage; import com.chatopera.cc.util.IP;
import com.chatopera.cc.socketio.message.ChatMessage; import com.chatopera.cc.util.IPTools;
import com.chatopera.cc.socketio.message.Message; import com.corundumstudio.socketio.AckRequest;
import com.chatopera.cc.socketio.util.HumanUtils; import com.corundumstudio.socketio.SocketIOClient;
import com.chatopera.cc.socketio.util.IMServiceUtils; import com.corundumstudio.socketio.SocketIOServer;
import com.chatopera.cc.util.IP; import com.corundumstudio.socketio.annotation.OnConnect;
import com.chatopera.cc.util.IPTools; import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.AckRequest; import com.corundumstudio.socketio.annotation.OnEvent;
import com.corundumstudio.socketio.SocketIOClient; import org.apache.commons.lang.StringUtils;
import com.corundumstudio.socketio.SocketIOServer; import org.slf4j.Logger;
import com.corundumstudio.socketio.annotation.OnConnect; import org.slf4j.LoggerFactory;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent; import java.net.InetSocketAddress;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; @SuppressWarnings("unused")
import org.slf4j.LoggerFactory; public class IMEventHandler {
private static final Logger logger = LoggerFactory.getLogger(IMEventHandler.class);
import java.net.InetSocketAddress; private static AgentUserProxy agentUserProxy;
import java.util.Date; private static AgentServiceRepository agentServiceRepository;
private static ACDVisitorDispatcher acdVisitorDispatcher;
public class IMEventHandler { protected SocketIOServer server;
private final static Logger logger = LoggerFactory.getLogger(IMEventHandler.class);
protected SocketIOServer server; public IMEventHandler(SocketIOServer server) {
this.server = server;
public IMEventHandler(SocketIOServer server) { }
this.server = server;
} private static AgentUserProxy getAgentUserProxy() {
if (agentUserProxy == null) {
static private AgentUserProxy agentUserProxy; agentUserProxy = MainContext.getContext().getBean(AgentUserProxy.class);
static private AgentServiceRepository agentServiceRepository; }
static private ACDVisitorDispatcher acdVisitorDispatcher; return agentUserProxy;
}
/**
* 接入访客并未访客寻找坐席服务人员 private static AgentServiceRepository getAgentServiceRepository() {
* if (agentServiceRepository == null) {
* @param client agentServiceRepository = MainContext.getContext().getBean(AgentServiceRepository.class);
*/ }
@OnConnect return agentServiceRepository;
public void onConnect(SocketIOClient client) { }
try {
final String user = client.getHandshakeData().getSingleUrlParam("userid"); private static ACDVisitorDispatcher getAcdVisitorDispatcher() {
final String orgi = client.getHandshakeData().getSingleUrlParam("orgi"); if (acdVisitorDispatcher == null) {
final String session = MainUtils.getContextID(client.getHandshakeData().getSingleUrlParam("session")); acdVisitorDispatcher = MainContext.getContext().getBean(ACDVisitorDispatcher.class);
// 渠道标识 }
final String appid = client.getHandshakeData().getSingleUrlParam("appid"); return acdVisitorDispatcher;
// 要求目标坐席服务 }
final String agent = client.getHandshakeData().getSingleUrlParam("agent");
// 要求目标技能组服务 /**
final String skill = client.getHandshakeData().getSingleUrlParam("skill"); * 接入访客并未访客寻找坐席服务人员
// 是否是邀请后加入会话 */
final boolean isInvite = StringUtils.equalsIgnoreCase( @OnConnect
client.getHandshakeData().getSingleUrlParam("isInvite"), "true"); public void onConnect(SocketIOClient client) {
try {
final String title = client.getHandshakeData().getSingleUrlParam("title"); final String user = client.getHandshakeData().getSingleUrlParam("userid");
final String url = client.getHandshakeData().getSingleUrlParam("url"); final String orgi = client.getHandshakeData().getSingleUrlParam("orgi");
final String traceid = client.getHandshakeData().getSingleUrlParam("traceid"); final String session = MainUtils.getContextID(client.getHandshakeData().getSingleUrlParam("session"));
// 渠道标识
String nickname = client.getHandshakeData().getSingleUrlParam("nickname"); final String appid = client.getHandshakeData().getSingleUrlParam("appid");
// 要求目标坐席服务
final String osname = client.getHandshakeData().getSingleUrlParam("osname"); final String agent = client.getHandshakeData().getSingleUrlParam("agent");
final String browser = client.getHandshakeData().getSingleUrlParam("browser"); // 要求目标技能组服务
final String skill = client.getHandshakeData().getSingleUrlParam("skill");
logger.info( // 是否是邀请后加入会话
"[onConnect] user {}, orgi {}, session {}, appid {}, agent {}, skill {}, title {}, url {}, traceid {}, nickname {}, isInvite {}", final boolean isInvite = StringUtils.equalsIgnoreCase(
user, orgi, session, appid, agent, skill, title, url, traceid, nickname, isInvite); client.getHandshakeData().getSingleUrlParam("isInvite"), "true");
// save connection info final String title = client.getHandshakeData().getSingleUrlParam("title");
client.set("session", session); final String url = client.getHandshakeData().getSingleUrlParam("url");
client.set("userid", user); final String traceid = client.getHandshakeData().getSingleUrlParam("traceid");
client.set("appid", appid);
client.set("isInvite", isInvite); String nickname = client.getHandshakeData().getSingleUrlParam("nickname");
// 保证传入的Nickname不是null final String osname = client.getHandshakeData().getSingleUrlParam("osname");
if (StringUtils.isBlank(nickname)) { final String browser = client.getHandshakeData().getSingleUrlParam("browser");
logger.info("[onConnect] reset nickname as it does not present.");
nickname = "Guest_" + user; logger.info(
} "[onConnect] user {}, orgi {}, session {}, appid {}, agent {}, skill {}, title {}, url {}, traceid {}, nickname {}, isInvite {}",
user, orgi, session, appid, agent, skill, title, url, traceid, nickname, isInvite);
if (StringUtils.isNotBlank(user)) {
InetSocketAddress address = (InetSocketAddress) client.getRemoteAddress(); // save connection info
String ip = MainUtils.getIpAddr(client.getHandshakeData().getHttpHeaders(), address.getHostString()); client.set("session", session);
client.set("userid", user);
/** client.set("appid", appid);
* 加入到 缓存列表 client.set("isInvite", isInvite);
*/
NettyClients.getInstance().putIMEventClient(user, client); // 保证传入的Nickname不是null
if (StringUtils.isBlank(nickname)) {
/** logger.info("[onConnect] reset nickname as it does not present.");
* 更新坐席服务类型 nickname = "Guest_" + user;
*/ }
IMServiceUtils.shiftOpsType(user, orgi, MainContext.OptType.HUMAN);
if (StringUtils.isNotBlank(user)) {
IP ipdata = null; InetSocketAddress address = (InetSocketAddress) client.getRemoteAddress();
if ((StringUtils.isNotBlank(ip))) { String ip = MainUtils.getIpAddr(client.getHandshakeData().getHttpHeaders(), address.getHostString());
ipdata = IPTools.getInstance().findGeography(ip);
} /*
* 加入到 缓存列表
/** */
* 用户进入到对话连接 排队用户请求 , 如果返回失败 NettyClients.getInstance().putIMEventClient(user, client);
* 表示当前坐席全忙用户进入排队状态当前提示信息 显示 当前排队的队列位置
* 不可进行对话用户发送的消息作为留言处理 /*
*/ * 更新坐席服务类型
final ACDComposeContext ctx = ACDMessageHelper.getWebIMComposeContext( */
user, IMServiceUtils.shiftOpsType(user, orgi, MainContext.OptType.HUMAN);
nickname,
orgi, IP ipdata = null;
session, if ((StringUtils.isNotBlank(ip))) {
appid, ipdata = IPTools.getInstance().findGeography(ip);
ip, }
osname,
browser, /*
"", * 用户进入到对话连接 排队用户请求 , 如果返回失败
ipdata, * 表示当前坐席全忙用户进入排队状态当前提示信息 显示 当前排队的队列位置
MainContext.ChannelType.WEBIM.toString(), * 不可进行对话用户发送的消息作为留言处理
skill, */
agent, final ACDComposeContext ctx = ACDMessageHelper.getWebIMComposeContext(
title, user,
url, nickname,
traceid, orgi,
user, session,
isInvite, appid,
MainContext.ChatInitiatorType.USER.toString()); ip,
getAcdVisitorDispatcher().enqueue(ctx); osname,
ACDServiceRouter.getAcdAgentService().notifyAgentUserProcessResult(ctx); browser,
} else { "",
logger.warn("[onConnect] invalid connection, no user present."); ipdata,
//非法链接 MainContext.ChannelType.WEBIM.toString(),
client.disconnect(); skill,
} agent,
} catch (Exception e) { title,
logger.error("[onConnect] error", e); url,
client.disconnect(); traceid,
} user,
} isInvite,
MainContext.ChatInitiatorType.USER.toString());
//添加@OnDisconnect事件客户端断开连接时调用刷新客户端信息 getAcdVisitorDispatcher().enqueue(ctx);
@OnDisconnect ACDServiceRouter.getAcdAgentService().notifyAgentUserProcessResult(ctx);
public void onDisconnect(SocketIOClient client) { } else {
final String user = client.getHandshakeData().getSingleUrlParam("userid"); logger.warn("[onConnect] invalid connection, no user present.");
final String orgi = client.getHandshakeData().getSingleUrlParam("orgi"); //非法链接
logger.info("[onDisconnect] user {}, orgi {}", user, orgi); client.disconnect();
if (user != null) { }
try { } catch (Exception e) {
/** logger.error("[onConnect] error", e);
* 用户主动断开服务 client.disconnect();
*/ }
MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi).ifPresent(p -> { }
ACDServiceRouter.getAcdAgentService().finishAgentService(p
, orgi); //添加@OnDisconnect事件客户端断开连接时调用刷新客户端信息
}); @OnDisconnect
} catch (Exception e) { public void onDisconnect(SocketIOClient client) {
logger.warn("[onDisconnect] error", e); final String user = client.getHandshakeData().getSingleUrlParam("userid");
} final String orgi = client.getHandshakeData().getSingleUrlParam("orgi");
NettyClients.getInstance().removeIMEventClient( logger.info("[onDisconnect] user {}, orgi {}", user, orgi);
user, MainUtils.getContextID(client.getSessionId().toString())); if (user != null) {
} try {
} /*
* 用户主动断开服务
// 消息接收入口用于接受网站资源用户传入的 个人信息 */
@OnEvent(value = "new") MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi)
public void onNewEvent(SocketIOClient client, AckRequest request, Contacts contacts) { .ifPresent(p -> ACDServiceRouter.getAcdAgentService().finishAgentService(p, orgi));
String user = client.getHandshakeData().getSingleUrlParam("userid"); } catch (Exception e) {
String orgi = client.getHandshakeData().getSingleUrlParam("orgi"); logger.warn("[onDisconnect] error", e);
}
MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi).ifPresent(p -> { NettyClients.getInstance().removeIMEventClient(
p.setName(contacts.getName()); user, MainUtils.getContextID(client.getSessionId().toString()));
p.setPhone(contacts.getPhone()); }
p.setEmail(contacts.getEmail()); }
p.setResion(contacts.getMemo());
p.setChatbotops(false); // 非机器人客服 // 消息接收入口用于接受网站资源用户传入的 个人信息
p.setOpttype(MainContext.OptType.HUMAN.toString()); @OnEvent(value = "new")
getAgentUserProxy().save(p); public void onNewEvent(SocketIOClient client, AckRequest request, Contacts contacts) {
}); String user = client.getHandshakeData().getSingleUrlParam("userid");
String orgi = client.getHandshakeData().getSingleUrlParam("orgi");
getAgentServiceRepository().findOneByUseridAndOrgiOrderByLogindateDesc(
user, orgi).ifPresent(p -> { MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi).ifPresent(p -> {
p.setName(contacts.getName()); p.setName(contacts.getName());
p.setPhone(contacts.getPhone()); p.setPhone(contacts.getPhone());
p.setEmail(contacts.getEmail()); p.setEmail(contacts.getEmail());
p.setResion(contacts.getMemo()); p.setResion(contacts.getMemo());
agentServiceRepository.save(p); p.setChatbotops(false); // 非机器人客服
}); p.setOpttype(MainContext.OptType.HUMAN.toString());
} getAgentUserProxy().save(p);
});
// 消息接收入口坐席状态更新
@OnEvent(value = "agentstatus") getAgentServiceRepository().findOneByUseridAndOrgiOrderByLogindateDesc(
public void onAgentStatusEvent(SocketIOClient client, AckRequest request, AgentStatusMessage data) { user, orgi).ifPresent(p -> {
logger.info("[onEvent] {}", data.getMessage()); p.setName(contacts.getName());
} p.setPhone(contacts.getPhone());
p.setEmail(contacts.getEmail());
// 消息接收入口收发消息用户向 坐席发送消息 向用户发送消息 p.setResion(contacts.getMemo());
@OnEvent(value = "message") agentServiceRepository.save(p);
public void onMessageEvent(SocketIOClient client, AckRequest request, ChatMessage data) { });
if (data.getType() == null) { }
data.setType("message");
} // 消息接收入口坐席状态更新
/** @OnEvent(value = "agentstatus")
* 以下代码主要用于检查 访客端的字数限制 public void onAgentStatusEvent(SocketIOClient client, AckRequest request, AgentStatusMessage data) {
*/ logger.info("[onEvent] {}", data.getMessage());
CousultInvite invite = OnlineUserProxy.consult(data.getAppid(), data.getOrgi()); }
int dataLength = data.getMessage().length(); // 消息接收入口收发消息用户向 坐席发送消息 向用户发送消息
if (invite != null && invite.getMaxwordsnum() > 0) { @OnEvent(value = "message")
if (StringUtils.isNotBlank(data.getMessage()) && dataLength > invite.getMaxwordsnum()) { public void onMessageEvent(SocketIOClient client, AckRequest request, ChatMessage data) {
data.setMessage(data.getMessage().substring(0, invite.getMaxwordsnum())); if (data.getType() == null) {
} data.setType("message");
} }
// else if (StringUtils.isNotBlank(data.getMessage()) && dataLength > 600) { /*
// data.setMessage(data.getMessage().substring(0, 600)); * 以下代码主要用于检查 访客端的字数限制
// } */
/** CousultInvite invite = OnlineUserProxy.consult(data.getAppid(), data.getOrgi());
* 处理表情
*/ int dataLength = data.getMessage().length();
data.setMessage(MainUtils.processEmoti(data.getMessage())); if (invite != null && invite.getMaxwordsnum() > 0) {
HumanUtils.processMessage(data, data.getUserid()); if (StringUtils.isNotBlank(data.getMessage()) && dataLength > invite.getMaxwordsnum()) {
} data.setMessage(data.getMessage().substring(0, invite.getMaxwordsnum()));
}
private static AgentUserProxy getAgentUserProxy() { }
if (agentUserProxy == null) { // else if (StringUtils.isNotBlank(data.getMessage()) && dataLength > 600) {
agentUserProxy = MainContext.getContext().getBean(AgentUserProxy.class); // data.setMessage(data.getMessage().substring(0, 600));
} // }
return agentUserProxy; /*
} * 处理表情
*/
private static AgentServiceRepository getAgentServiceRepository() { data.setMessage(MainUtils.processEmoti(data.getMessage()));
if (agentServiceRepository == null) { HumanUtils.processMessage(data, data.getUserid());
agentServiceRepository = MainContext.getContext().getBean(AgentServiceRepository.class); }
}
return agentServiceRepository; }
}
private static ACDVisitorDispatcher getAcdVisitorDispatcher() {
if (acdVisitorDispatcher == null) {
acdVisitorDispatcher = MainContext.getContext().getBean(ACDVisitorDispatcher.class);
}
return acdVisitorDispatcher;
}
}

View File

@ -1,152 +1,149 @@
/* /*
* Copyright (C) 2017 优客服-多渠道客服系统 * Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2019 Chatopera Inc, <https://www.chatopera.com> * Modifications copyright (C) 2018-2019 Chatopera Inc, <https://www.chatopera.com>
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.chatopera.cc.socketio.util; package com.chatopera.cc.socketio.util;
import com.chatopera.cc.basic.Constants; import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.MainContext; import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainContext.ChannelType; import com.chatopera.cc.basic.MainContext.ChannelType;
import com.chatopera.cc.basic.MainContext.MessageType; import com.chatopera.cc.basic.MainContext.MessageType;
import com.chatopera.cc.basic.MainContext.ReceiverType; import com.chatopera.cc.basic.MainContext.ReceiverType;
import com.chatopera.cc.model.AgentService; import com.chatopera.cc.model.AgentService;
import com.chatopera.cc.model.AgentUser; import com.chatopera.cc.model.AgentUser;
import com.chatopera.cc.persistence.repository.AgentServiceRepository; import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import com.chatopera.cc.socketio.message.ChatMessage; import com.chatopera.cc.socketio.message.ChatMessage;
import com.chatopera.cc.socketio.message.Message; import com.chatopera.cc.socketio.message.Message;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class HumanUtils { import java.util.Optional;
private final static Logger logger = LoggerFactory.getLogger(HumanUtils.class);
private static AgentServiceRepository agentServiceRes; public class HumanUtils {
private final static Logger logger = LoggerFactory.getLogger(HumanUtils.class);
private static AgentServiceRepository agentServiceRes;
/**
* 发送文本消息
* /**
* @param data * 发送文本消息
* @param userid */
*/ public static void processMessage(ChatMessage data, String userid) {
public static void processMessage(ChatMessage data, String userid) { processMessage(data, MainContext.MediaType.TEXT.toString(), userid);
processMessage(data, MainContext.MediaType.TEXT.toString(), userid); }
}
/**
/** * 发送各种消息的底层方法
* 发送各种消息的底层方法 */
* protected static void processMessage(final ChatMessage chatMessage, final String msgtype, final String userid) {
* @param chatMessage logger.info("[processMessage] userid {}, msgtype {}", userid, msgtype);
* @param msgtype AgentUser agentUser = MainContext.getCache().findOneAgentUserByUserIdAndOrgi(
* @param userid userid, MainContext.SYSTEM_ORGI).orElse(null);
*/
protected static void processMessage(final ChatMessage chatMessage, final String msgtype, final String userid) { Message outMessage = new Message();
logger.info("[processMessage] userid {}, msgtype {}", userid, msgtype);
AgentUser agentUser = MainContext.getCache().findOneAgentUserByUserIdAndOrgi( /*
userid, MainContext.SYSTEM_ORGI).orElse(null); * 访客的昵称
*/
Message outMessage = new Message(); // TODO 确定该值代表访客昵称
String userNickName = (agentUser != null) && StringUtils.isNotBlank(
/** agentUser.getNickname()) ? agentUser.getNickname() : "";
* 访客的昵称
*/ if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentserviceid())) {
// TODO 确定该值代表访客昵称 Optional<AgentService> optional = getAgentServiceRes().findById(agentUser.getAgentserviceid());
String userNickName = (agentUser != null) && StringUtils.isNotBlank( if (optional.isPresent()) {
agentUser.getNickname()) ? agentUser.getNickname() : ""; AgentService agentService = optional.get();
if (StringUtils.isNotBlank(agentService.getUsername())) {
if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentserviceid())) { userNickName = agentService.getUsername();
AgentService agentService = getAgentServiceRes().findOne( }
agentUser.getAgentserviceid()); }
if (StringUtils.isNotBlank(agentService.getUsername())) { }
userNickName = agentService.getUsername();
} // 将访客名称修改为关联联系人的名称
} chatMessage.setUsername(userNickName);
// 将访客名称修改为关联联系人的名称 outMessage.setMessage(chatMessage.getMessage());
chatMessage.setUsername(userNickName); outMessage.setFilename(chatMessage.getFilename());
outMessage.setFilesize(chatMessage.getFilesize());
outMessage.setMessage(chatMessage.getMessage());
outMessage.setFilename(chatMessage.getFilename()); outMessage.setMessageType(msgtype);
outMessage.setFilesize(chatMessage.getFilesize()); outMessage.setCalltype(MainContext.CallType.IN.toString());
outMessage.setAgentUser(agentUser);
outMessage.setMessageType(msgtype); outMessage.setSnsAccount(null);
outMessage.setCalltype(MainContext.CallType.IN.toString());
outMessage.setAgentUser(agentUser); Message statusMessage = null;
outMessage.setSnsAccount(null); if (agentUser == null) {
statusMessage = new Message();
Message statusMessage = null; statusMessage.setMessage(chatMessage.getMessage());
if (agentUser == null) { statusMessage.setMessageType(MainContext.MessageType.STATUS.toString());
statusMessage = new Message(); statusMessage.setCalltype(MainContext.CallType.OUT.toString());
statusMessage.setMessage(chatMessage.getMessage()); statusMessage.setMessage("当前坐席全忙,请稍候");
statusMessage.setMessageType(MainContext.MessageType.STATUS.toString()); } else {
statusMessage.setCalltype(MainContext.CallType.OUT.toString()); chatMessage.setUserid(agentUser.getUserid());
statusMessage.setMessage("当前坐席全忙,请稍候"); chatMessage.setTouser(agentUser.getAgentno());
} else { chatMessage.setAgentuser(agentUser.getId());
chatMessage.setUserid(agentUser.getUserid()); chatMessage.setAgentserviceid(agentUser.getAgentserviceid());
chatMessage.setTouser(agentUser.getAgentno()); chatMessage.setAppid(agentUser.getAppid());
chatMessage.setAgentuser(agentUser.getId()); chatMessage.setOrgi(agentUser.getOrgi());
chatMessage.setAgentserviceid(agentUser.getAgentserviceid()); chatMessage.setMsgtype(msgtype);
chatMessage.setAppid(agentUser.getAppid()); // agentUser作为 session id
chatMessage.setOrgi(agentUser.getOrgi()); chatMessage.setUsession(agentUser.getUserid());
chatMessage.setMsgtype(msgtype); chatMessage.setContextid(agentUser.getContextid());
// agentUser作为 session id chatMessage.setCalltype(MainContext.CallType.IN.toString());
chatMessage.setUsession(agentUser.getUserid()); if (StringUtils.isNotBlank(agentUser.getAgentno())) {
chatMessage.setContextid(agentUser.getContextid()); chatMessage.setTouser(agentUser.getAgentno());
chatMessage.setCalltype(MainContext.CallType.IN.toString()); }
if (StringUtils.isNotBlank(agentUser.getAgentno())) { chatMessage.setChannel(agentUser.getChannel());
chatMessage.setTouser(agentUser.getAgentno()); outMessage.setContextid(agentUser.getContextid());
} outMessage.setChannel(agentUser.getChannel());
chatMessage.setChannel(agentUser.getChannel()); outMessage.setAgentUser(agentUser);
outMessage.setContextid(agentUser.getContextid()); outMessage.setCreatetime(Constants.DISPLAY_DATE_FORMATTER.format(chatMessage.getCreatetime()));
outMessage.setChannel(agentUser.getChannel()); }
outMessage.setAgentUser(agentUser);
outMessage.setCreatetime(Constants.DISPLAY_DATE_FORMATTER.format(chatMessage.getCreatetime())); outMessage.setChannelMessage(chatMessage);
}
// 将消息返送给 访客
outMessage.setChannelMessage(chatMessage); if (StringUtils.isNotBlank(chatMessage.getUserid()) && MainContext.MessageType.MESSAGE.toString().equals(
chatMessage.getType())) {
// 将消息返送给 访客 MainContext.getPeerSyncIM().send(ReceiverType.VISITOR, ChannelType.toValue(outMessage.getChannel()),
if (StringUtils.isNotBlank(chatMessage.getUserid()) && MainContext.MessageType.MESSAGE.toString().equals( outMessage.getAppid(), MessageType.MESSAGE, chatMessage.getUserid(),
chatMessage.getType())) { outMessage, true);
MainContext.getPeerSyncIM().send(ReceiverType.VISITOR, ChannelType.toValue(outMessage.getChannel()), if (statusMessage != null) {
outMessage.getAppid(), MessageType.MESSAGE, chatMessage.getUserid(), MainContext.getPeerSyncIM().send(ReceiverType.VISITOR, ChannelType.toValue(outMessage.getChannel()),
outMessage, true); outMessage.getAppid(), MessageType.STATUS, chatMessage.getUserid(),
if (statusMessage != null) { statusMessage, true);
MainContext.getPeerSyncIM().send(ReceiverType.VISITOR, ChannelType.toValue(outMessage.getChannel()), }
outMessage.getAppid(), MessageType.STATUS, chatMessage.getUserid(), }
statusMessage, true);
} // 将消息发送给 坐席
} if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentno())) {
MainContext.getPeerSyncIM().send(ReceiverType.AGENT,
// 将消息发送给 坐席 ChannelType.WEBIM,
if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentno())) { agentUser.getAppid(),
MainContext.getPeerSyncIM().send(ReceiverType.AGENT, MessageType.MESSAGE,
ChannelType.WEBIM, agentUser.getAgentno(),
agentUser.getAppid(), outMessage, true);
MessageType.MESSAGE, }
agentUser.getAgentno(), }
outMessage, true);
} private static AgentServiceRepository getAgentServiceRes() {
} if (agentServiceRes == null) {
agentServiceRes = MainContext.getContext().getBean(AgentServiceRepository.class);
private static AgentServiceRepository getAgentServiceRes() { }
if (agentServiceRes == null) { return agentServiceRes;
agentServiceRes = MainContext.getContext().getBean(AgentServiceRepository.class); }
}
return agentServiceRes;
} }
}