diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDAgentService.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDAgentService.java index ea3e43f6..39db4d66 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDAgentService.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDAgentService.java @@ -56,14 +56,15 @@ public class ACDAgentService { /** * 查询条件,当前在线的 坐席,并且 未达到最大 服务人数的坐席 */ - List agentStatusList = acdAgentAllocatorMw.filterOutAvailableAgentStatus(agentUser, orgi); + final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi); + List agentStatusList = acdAgentAllocatorMw.filterOutAvailableAgentStatus( + agentUser, orgi, sessionConfig); /** * 处理ACD 的 技能组请求和 坐席请求 */ AgentStatus agentStatus = null; AgentService agentService = null; //放入缓存的对象 - SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi); if (agentStatusList.size() > 0) { agentStatus = agentStatusList.get(0); if (agentStatus.getUsers() >= sessionConfig.getMaxuser()) { diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDPolicyService.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDPolicyService.java index b110ceb0..e7e105eb 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDPolicyService.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDPolicyService.java @@ -16,6 +16,7 @@ package com.chatopera.cc.acd; +import com.chatopera.cc.basic.Constants; import com.chatopera.cc.basic.MainContext; import com.chatopera.cc.cache.Cache; import com.chatopera.cc.model.AgentStatus; @@ -74,6 +75,7 @@ public class ACDPolicyService { cache.putSessionConfigByOrgi(sessionConfig, orgi); } } + return sessionConfig; } @@ -104,7 +106,7 @@ public class ACDPolicyService { AgentStatus x = null; int min = 0; for (final AgentStatus o : agentStatuses) { - if (o.getUsers() <= min) { + if ((x == null) || (o.getUsers() < min)) { x = o; min = o.getUsers(); } diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDQueueService.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDQueueService.java index 306f6fe0..ab071aa6 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDQueueService.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDQueueService.java @@ -39,7 +39,7 @@ public class ACDQueueService { int queneUsers = 0; Map map = cache.getAgentUsersInQueByOrgi(orgi); - for (Map.Entry entry : map.entrySet()) { + for (final Map.Entry entry : map.entrySet()) { if (StringUtils.isNotBlank(skill)) { if (StringUtils.equals(entry.getValue().getSkill(), skill)) { queneUsers++; diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDServiceRouter.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDServiceRouter.java index 8dab33d9..1d1a6334 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDServiceRouter.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDServiceRouter.java @@ -30,6 +30,7 @@ import com.chatopera.cc.persistence.repository.*; import com.chatopera.cc.proxy.AgentUserProxy; import com.chatopera.cc.socketio.client.NettyClients; import com.chatopera.cc.socketio.message.Message; +import com.chatopera.cc.util.HashMapUtils; import com.chatopera.cc.util.IP; import com.chatopera.cc.util.SerializeUtil; import com.chatopera.compose4j.Composer; @@ -197,17 +198,31 @@ public class ACDServiceRouter { */ @SuppressWarnings("unchecked") public void allotVisitors(String agentno, String orgi) { + logger.info("[allotVisitors] agentno {}, orgi {}", agentno, orgi); // 获得目标坐席的状态 AgentStatus agentStatus = SerializeUtil.deserialize( redisCommand.getHashKV(RedisKey.getAgentStatusReadyHashKey(orgi), agentno)); if (agentStatus == null) { - logger.warn("[allotAgent] can not find AgentStatus for agentno {}", agentno); + logger.warn("[allotVisitors] can not find AgentStatus for agentno {}", agentno); + return; + } + logger.info("[allotVisitors] agentStatus id {}, status {}, service {}/{}, skills {}, busy {}", + agentStatus.getId(), agentStatus.getStatus(), agentStatus.getUsers(), agentStatus.getMaxusers(), + HashMapUtils.concatKeys(agentStatus.getSkills(), "|"), agentStatus.isBusy()); + + if ((!StringUtils.equals( + MainContext.AgentStatusEnum.READY.toString(), agentStatus.getStatus())) || agentStatus.isBusy()) { + // 该坐席处于非就绪状态,或该坐席处于置忙 + // 不分配坐席 return; } // 获得所有待服务访客的列表 Map pendingAgentUsers = cache.getAgentUsersInQueByOrgi(orgi); + final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi); + // 本次批量分配访客数目 + int assigned = 0; for (Map.Entry entry : pendingAgentUsers.entrySet()) { AgentUser agentUser = entry.getValue(); @@ -216,39 +231,37 @@ public class ACDServiceRouter { if ((StringUtils.equals(agentUser.getAgentno(), agentno))) { // 待服务的访客指定了该坐席 process = true; - } else { - if (agentStatus != null && - agentStatus.getSkills() != null && - agentStatus.getSkills().size() > 0) { - // 目标坐席有状态,并且坐席属于某技能组 - if ((StringUtils.isBlank(agentUser.getAgentno()) && - StringUtils.isBlank(agentUser.getSkill()))) { - // 待服务的访客还没有指定坐席,并且也没有绑定技能组 - process = true; - } else { - if (StringUtils.isBlank(agentUser.getAgentno()) && - agentStatus.getSkills().containsKey(agentUser.getSkill())) { - // 待服务的访客还没有指定坐席,并且指定的技能组和该坐席的技能组一致 - process = true; - } - } + } else if (agentStatus != null && + agentStatus.getSkills() != null && + agentStatus.getSkills().size() > 0) { + // 目标坐席有状态,并且坐席属于某技能组 + if ((StringUtils.isBlank(agentUser.getAgentno()) && + StringUtils.isBlank(agentUser.getSkill()))) { + // 待服务的访客还没有指定坐席,并且也没有绑定技能组 + process = true; } else { - // 目标坐席没有状态,或该目标坐席有状态但是没有属于任何一个技能组 if (StringUtils.isBlank(agentUser.getAgentno()) && - StringUtils.isBlank(agentUser.getSkill())) { - // 待服务访客没有指定坐席,并且没有指定技能组 + agentStatus.getSkills().containsKey(agentUser.getSkill())) { + // 待服务的访客还没有指定坐席,并且指定的技能组和该坐席的技能组一致 process = true; } } + } else { + // 目标坐席没有状态,或该目标坐席有状态但是没有属于任何一个技能组 + if (StringUtils.isBlank(agentUser.getAgentno()) && + StringUtils.isBlank(agentUser.getSkill())) { + // 待服务访客没有指定坐席,并且没有指定技能组 + process = true; + } } if (!process) { continue; } - SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi); - long maxusers = sessionConfig == null ? Constants.AGENT_STATUS_MAX_USER : sessionConfig.getMaxuser(); - if (agentStatus.getUsers() < maxusers) { //坐席未达到最大咨询访客数量 + // 坐席未达到最大咨询访客数量,并且单次批量分配小于坐席就绪时分配最大访客数量(initMaxuser) + if (((agentStatus.getUsers() + assigned) < sessionConfig.getMaxuser()) && (assigned < sessionConfig.getInitmaxuser())) { + assigned++; // 从排队队列移除 cache.deleteAgentUserInqueByAgentUserIdAndOrgi(agentUser.getUserid(), orgi); @@ -284,10 +297,13 @@ public class ACDServiceRouter { MainContext.MessageType.NEW, agentUser.getAgentno(), outMessage, true); } } catch (Exception ex) { - logger.warn("[allotAgent] fail to process service", ex); + logger.warn("[allotVisitors] fail to process service", ex); } } else { - logger.info("[allotAgent] agentno {} reach the max users limit", agentno); + logger.info( + "[allotVisitors] agentno {} reach the max users limit {}/{} or batch assign limit {}/{}", agentno, + (agentStatus.getUsers() + assigned), + sessionConfig.getMaxuser(), assigned, sessionConfig.getInitmaxuser()); break; } } @@ -303,6 +319,9 @@ public class ACDServiceRouter { */ public void serviceFinish(final AgentUser agentUser, final String orgi) { if (agentUser != null) { + /** + * 设置AgentUser + */ // 获得坐席状态 AgentStatus agentStatus = null; if (StringUtils.equals(MainContext.AgentUserStatusEnum.INSERVICE.toString(), agentUser.getStatus()) && @@ -321,7 +340,9 @@ public class ACDServiceRouter { final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi); - // 坐席服务 + /** + * 坐席服务 + */ AgentService service = null; if (StringUtils.isNotBlank(agentUser.getAgentserviceid())) { service = agentServiceRes.findByIdAndOrgi(agentUser.getAgentserviceid(), agentUser.getOrgi()); @@ -338,10 +359,9 @@ public class ACDServiceRouter { service.setSessiontimes(System.currentTimeMillis() - service.getServicetime().getTime()); } - final List agentUserTaskList = agentUserTaskRes.findByIdAndOrgi( - agentUser.getId(), agentUser.getOrgi()); - if (agentUserTaskList.size() > 0) { - final AgentUserTask agentUserTask = agentUserTaskList.get(0); + final AgentUserTask agentUserTask = agentUserTaskRes.findOne( + agentUser.getId()); + if (agentUserTask != null) { service.setAgentreplyinterval(agentUserTask.getAgentreplyinterval()); service.setAgentreplytime(agentUserTask.getAgentreplytime()); service.setAvgreplyinterval(agentUserTask.getAvgreplyinterval()); @@ -367,6 +387,15 @@ public class ACDServiceRouter { agentServiceRes.save(service); } + /** + * 更新AgentStatus + */ + if (agentStatus != null) { + agentStatus.setUsers( + cache.getInservAgentUsersSizeByAgentnoAndOrgi(agentStatus.getAgentno(), agentStatus.getOrgi())); + agentStatusRes.save(agentStatus); + } + /** * 发送到访客端的通知 */ @@ -423,8 +452,7 @@ public class ACDServiceRouter { // 当前访客服务已经结束,为坐席寻找新访客 if (agentStatus != null) { - long maxusers = sessionConfig != null ? sessionConfig.getMaxuser() : Constants.AGENT_STATUS_MAX_USER; - if ((agentStatus.getUsers() - 1) < maxusers) { + if ((agentStatus.getUsers() - 1) < sessionConfig.getMaxuser()) { allotVisitors(agentStatus.getAgentno(), orgi); } } @@ -513,6 +541,8 @@ public class ACDServiceRouter { Message outMessage = new Message(); outMessage.setAgentUser(agentUser); outMessage.setChannelMessage(agentUser); + + logger.info("[allotAgentForInvite] agentno {}, agentuser agentno {}", agentno, agentUser.getAgentno()); peerSyncIM.send(MainContext.ReceiverType.AGENT, MainContext.ChannelType.WEBIM, agentUser.getAppid(), MainContext.MessageType.NEW, agentUser.getAgentno(), outMessage, true); diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDWorkMonitor.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDWorkMonitor.java index fc8df5b8..1c988787 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDWorkMonitor.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/ACDWorkMonitor.java @@ -67,6 +67,7 @@ public class ACDWorkMonitor { AgentReport report = new AgentReport(); Map readys = cache.getAgentStatusReadyByOrig(orgi); + int readyNum = 0; int busyNum = 0; @@ -101,10 +102,10 @@ public class ACDWorkMonitor { report.setInquene(cache.getInqueAgentUsersSizeByOrgi(orgi)); // DEBUG -// logger.info( -// "[getAgentReport] orgi {}, organ {}, agents {}, busy {}, users {}, inqueue {}", orgi, organ, -// report.getAgents(), report.getBusy(), report.getUsers(), report.getInquene() -// ); + logger.info( + "[getAgentReport] orgi {}, organ {}, agents {}, busy {}, users {}, inqueue {}", orgi, organ, + report.getAgents(), report.getBusy(), report.getUsers(), report.getInquene() + ); return report; } diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisAllocatorMw.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisAllocatorMw.java index 395f32de..02a25c67 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisAllocatorMw.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisAllocatorMw.java @@ -74,7 +74,7 @@ public class ACDVisAllocatorMw implements Middleware { * 查询条件,当前在线的 坐席,并且 未达到最大 服务人数的坐席 */ final List agentStatuses = filterOutAvailableAgentStatus( - ctx.getAgentUser(), ctx.getOrgi()); + ctx.getAgentUser(), ctx.getOrgi(), ctx.getSessionConfig()); /** * 处理ACD 的 技能组请求和 坐席请求 @@ -108,6 +108,11 @@ public class ACDVisAllocatorMw implements Middleware { final boolean isInvite) { AgentStatus agentStatus = null; + // 过滤后没有就绪的满足条件的坐席 + if (agentStatuses.size() == 0) { + return agentStatus; + } + // 邀请功能 if (isInvite) { logger.info("[filterOutAgentStatusWithPolicies] is invited onlineUser."); @@ -131,10 +136,10 @@ public class ACDVisAllocatorMw implements Middleware { for (final AgentStatus o : agentStatuses) { if (StringUtils.equals( o.getAgentno(), report.getData()) && o.getUsers() < sessionConfig.getMaxuser()) { + agentStatus = o; logger.info( "[filterOutAgentStatusWithPolicies] choose agentno {} by chat history.", agentStatus.getAgentno()); - agentStatus = o; break; } } @@ -193,8 +198,8 @@ public class ACDVisAllocatorMw implements Middleware { */ public List filterOutAvailableAgentStatus( final AgentUser agentUser, - final String orgi - ) { + final String orgi, + final SessionConfig sessionConfig) { logger.info( "[filterOutAvailableAgentStatus] pre-conditions: agentUser.agentno {}, orgi {}, skill {}, onlineUser {}", agentUser.getAgentno(), orgi, agentUser.getSkill(), agentUser.getUserid() @@ -222,6 +227,7 @@ public class ACDVisAllocatorMw implements Middleware { if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentno())) { // 指定坐席 for (final Map.Entry entry : map.entrySet()) { + // 被指定的坐席,不检查是否忙,是否达到最大接待数量 if (StringUtils.equals( entry.getValue().getAgentno(), agentUser.getAgentno())) { agentStatuses.add(entry.getValue()); @@ -251,6 +257,7 @@ public class ACDVisAllocatorMw implements Middleware { // 指定技能组 for (final Map.Entry entry : map.entrySet()) { if ((!entry.getValue().isBusy()) && + (entry.getValue().getUsers() < sessionConfig.getMaxuser()) && (entry.getValue().getSkills() != null && entry.getValue().getSkills().containsKey(agentUser.getSkill()))) { logger.info( @@ -282,13 +289,21 @@ public class ACDVisAllocatorMw implements Middleware { */ // 对于该租户的所有客服 for (final Map.Entry entry : map.entrySet()) { - if (!entry.getValue().isBusy()) { + if ((!entry.getValue().isBusy()) && (entry.getValue().getUsers() < sessionConfig.getMaxuser())) { agentStatuses.add(entry.getValue()); logger.info( - "[filterOutAvailableAgentStatus] find ready agent {}, agentname {}, status {}, service {}/{}", + "[filterOutAvailableAgentStatus] find ready agent {}, agentname {}, status {}, service {}/{}, skills {}", entry.getValue().getAgentno(), entry.getValue().getUsername(), entry.getValue().getStatus(), entry.getValue().getUsers(), - entry.getValue().getMaxusers()); + entry.getValue().getMaxusers(), + HashMapUtils.concatKeys(entry.getValue().getSkills(), "|")); + } else { + logger.info( + "[filterOutAvailableAgentStatus] skip ready agent {}, name {}, status {}, service {}/{}, skills {}", + entry.getValue().getAgentno(), entry.getValue().getUsername(), entry.getValue().getStatus(), + entry.getValue().getUsers(), + entry.getValue().getMaxusers(), + HashMapUtils.concatKeys(entry.getValue().getSkills(), "|")); } } } @@ -303,11 +318,10 @@ public class ACDVisAllocatorMw implements Middleware { * 1. 在AgentUser服务结束并且还没有对应的AgentService * 2. 在新服务开始,安排坐席 * - * @param agentStatus 坐席状态 - * @param agentUser 坐席访客会话 - * @param orgi 租户ID - * @param finished 结束服务 - * @param sessionConfig 坐席配置 + * @param agentStatus 坐席状态 + * @param agentUser 坐席访客会话 + * @param orgi 租户ID + * @param finished 结束服务 * @return */ public AgentService processAgentService( diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBindingMw.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBindingMw.java index e324245c..c3610615 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBindingMw.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBindingMw.java @@ -17,7 +17,6 @@ package com.chatopera.cc.acd.visitor; import com.chatopera.cc.acd.ACDComposeContext; -import com.chatopera.cc.cache.Cache; import com.chatopera.cc.model.Organ; import com.chatopera.cc.model.User; import com.chatopera.cc.persistence.repository.OrganRepository; @@ -41,9 +40,6 @@ public class ACDVisBindingMw implements Middleware { @Autowired private OrganRepository organRes; - @Autowired - private Cache cache; - /** * 绑定技能组或坐席 * @@ -72,7 +68,7 @@ public class ACDVisBindingMw implements Middleware { } if (StringUtils.isNotBlank(ctx.getAgentno())) { - logger.info("[apply] bind agentno {}", ctx.getAgentno()); + logger.info("[apply] bind agentno {}, isInvite {}", ctx.getAgentno(), ctx.isInvite()); // 绑定坐席 // 绑定坐席有可能是因为前端展示了技能组和坐席 // 也有可能是坐席发送了邀请,该访客接收邀请 diff --git a/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBodyParserMw.java b/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBodyParserMw.java index 3f1dee49..fb73ba93 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBodyParserMw.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/acd/visitor/ACDVisBodyParserMw.java @@ -182,6 +182,7 @@ public class ACDVisBodyParserMw implements Middleware { } else { // TODO 什么是否返回 noAgentMessage, 是否在是 INQUENE 时 getQueneindex == 0 // 当前没有坐席,要留言 + ctx.setNoagent(true); ctx.setMessage(acdMessageHelper.getNoAgentMessage( ctx.getAgentService().getQueneindex(), ctx.getChannel(), diff --git a/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentStatusAspect.java b/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentStatusAspect.java new file mode 100644 index 00000000..60c45573 --- /dev/null +++ b/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentStatusAspect.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 Chatopera Inc, + * + * 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.aspect; + +import com.chatopera.cc.cache.Cache; +import com.chatopera.cc.model.AgentStatus; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Aspect; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * + */ +@Aspect +@Component +public class AgentStatusAspect { + private final static Logger logger = LoggerFactory.getLogger(AgentStatusAspect.class); + + @Autowired + private Cache cache; + + @After("execution(* com.chatopera.cc.persistence.repository.AgentStatusRepository.save(..))") + public void save(final JoinPoint joinPoint) { + final AgentStatus agentStatus = (AgentStatus) joinPoint.getArgs()[0]; + cache.putAgentStatusByOrgi(agentStatus, agentStatus.getOrgi()); + } + + @After("execution(* com.chatopera.cc.persistence.repository.AgentStatusRepository.delete(..))") + public void delete(final JoinPoint joinPoint) { + final AgentStatus agentStatus = (AgentStatus) joinPoint.getArgs()[0]; + cache.deleteAgentStatusByAgentnoAndOrgi(agentStatus.getAgentno(), agentStatus.getOrgi()); + } +} diff --git a/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentUserAspect.java b/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentUserAspect.java index 33dd85a5..5dcf38bd 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentUserAspect.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/aspect/AgentUserAspect.java @@ -59,12 +59,11 @@ public class AgentUserAspect { public void save(final JoinPoint joinPoint) { final AgentUser agentUser = (AgentUser) joinPoint.getArgs()[0]; logger.info( - "[save] agentUser id {}, agentno {}, userId {}", agentUser.getId(), agentUser.getAgentno(), - agentUser.getUserid()); + "[save] agentUser id {}, agentno {}, userId {}, status {}", agentUser.getId(), agentUser.getAgentno(), + agentUser.getUserid(), agentUser.getStatus()); if (StringUtils.isBlank(agentUser.getId()) - || StringUtils.isBlank(agentUser.getUserid()) - || StringUtils.isBlank(agentUser.getAgentno())) { + || StringUtils.isBlank(agentUser.getUserid())) { return; } @@ -82,7 +81,7 @@ public class AgentUserAspect { "[delete] agentUser id {}, agentno {}, userId {}", agentUser.getId(), agentUser.getAgentno(), agentUser.getUserid()); cache.deleteAgentUserAuditByOrgiAndId(agentUser.getOrgi(), agentUser.getId()); - cache.deleteAgentUserByUserIdAndOrgi(agentUser.getUserid(), agentUser.getOrgi()); + cache.deleteAgentUserByUserIdAndOrgi(agentUser, agentUser.getOrgi()); } /** diff --git a/contact-center/app/src/main/java/com/chatopera/cc/basic/Constants.java b/contact-center/app/src/main/java/com/chatopera/cc/basic/Constants.java index 643af7fe..dfc6274b 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/basic/Constants.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/basic/Constants.java @@ -65,8 +65,6 @@ public class Constants { public static final String CSKEFU_SYSTEM_ADV = "cskefu_system_adv"; // 系统广告位 - public static final int AGENT_STATUS_MAX_USER = 20; // 每个坐席 最大接待的 咨询数量 - public static final String SYSTEM_CACHE_CALLOUT_CONFIG = "callout_config"; /** diff --git a/contact-center/app/src/main/java/com/chatopera/cc/cache/Cache.java b/contact-center/app/src/main/java/com/chatopera/cc/cache/Cache.java index 970545c9..f3ada430 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/cache/Cache.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/cache/Cache.java @@ -57,37 +57,6 @@ public class Cache { return convertFromStringToAgentStatus(agentStatuses); } - /** - * 获得未就绪的坐席状态列表 - * - * @param orgi - * @return - */ - public Map getAgentStatusNotReadyByOrgi(final String orgi) { - Map agentStatuses = redisCommand.getHash(RedisKey.getAgentStatusNotReadyHashKey(orgi)); - return convertFromStringToAgentStatus(agentStatuses); - } - - /** - * 返回置忙的客服列表 - * - * @param orgi - * @return - */ - public Map getAgentStatusBusyByOrig(final String orgi) { - Map agentStatuses = redisCommand.getHash(RedisKey.getAgentStatusReadyHashKey(orgi)); - Map result = new HashMap<>(); - Map map = convertFromStringToAgentStatus(agentStatuses); - - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().isBusy()) { - result.put(entry.getKey(), entry.getValue()); - } - } - return result; - } - - /** * 通过访客ID和ORGI获得访客坐席关联关系 * @@ -124,8 +93,8 @@ public class Cache { public Map getAgentUsersInQueByOrgi(final String orgi) { Map agentUsers = redisCommand.getHash(RedisKey.getAgentUserInQueHashKey(orgi)); Map map = new HashMap<>(); - for (Map.Entry entry : agentUsers.entrySet()) { - AgentUser obj = SerializeUtil.deserialize(entry.getValue()); + for (final Map.Entry entry : agentUsers.entrySet()) { + final AgentUser obj = SerializeUtil.deserialize(entry.getValue()); map.put(obj.getId(), obj); } return map; @@ -421,17 +390,18 @@ public class Cache { /** * Delete agentUser * - * @param userId + * @param agentUser * @param orgi */ - public void deleteAgentUserByUserIdAndOrgi(String userId, String orgi) { - if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(orgi), userId)) { + @AgentUserAspect.LinkAgentUser + public void deleteAgentUserByUserIdAndOrgi(final AgentUser agentUser, String orgi) { + if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(orgi), agentUser.getUserid())) { // 排队等待中 - redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(orgi), userId); - } else if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(orgi), userId)) { - redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(orgi), userId); - } else if (redisCommand.hasHashKV(RedisKey.getAgentUserEndHashKey(orgi), userId)) { - redisCommand.delHashKV(RedisKey.getAgentUserEndHashKey(orgi), userId); + redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(orgi), agentUser.getUserid()); + } else if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(orgi), agentUser.getUserid())) { + redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(orgi), agentUser.getUserid()); + } else if (redisCommand.hasHashKV(RedisKey.getAgentUserEndHashKey(orgi), agentUser.getUserid())) { + redisCommand.delHashKV(RedisKey.getAgentUserEndHashKey(orgi), agentUser.getUserid()); } else { // TODO 考虑是否有其他状态保存 } @@ -539,7 +509,6 @@ public class Cache { } - /****************************** * Callcenter Agent 相关 ******************************/ diff --git a/contact-center/app/src/main/java/com/chatopera/cc/controller/LoginController.java b/contact-center/app/src/main/java/com/chatopera/cc/controller/LoginController.java index a4ffc710..af59ee0f 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/controller/LoginController.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/controller/LoginController.java @@ -207,11 +207,7 @@ public class LoginController extends Handler { final AgentStatus agentStatus = agentProxy.resolveAgentStatusByAgentnoAndOrgi( loginUser.getId(), orgi, loginUser.getSkills()); agentStatus.setBusy(false); - agentProxy.ready(loginUser, agentStatus); - - // 更新缓存和数据库 - cache.putAgentStatusByOrgi(agentStatus, loginUser.getOrgi()); - agentStatusRes.save(agentStatus); + agentProxy.ready(loginUser, agentStatus, false); // 工作状态记录 acdWorkMonitor.recordAgentStatus(agentStatus.getAgentno(), diff --git a/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiAgentUserController.java b/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiAgentUserController.java index 388447cd..e01330ef 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiAgentUserController.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiAgentUserController.java @@ -174,7 +174,9 @@ public class ApiAgentUserController extends Handler { // 当前访客的ID final String userId = agentUser.getUserid(); - logger.info("[transout] agentuserid {} \n target agent id {}, \n current agent id {}, onlineuserid {}", agentUserId, transAgentId, currentAgentno, userId); + logger.info( + "[transout] agentuserid {} \n target agent id {}, \n current agent id {}, onlineuserid {}", + agentUserId, transAgentId, currentAgentno, userId); // 检查权限 @@ -281,14 +283,15 @@ public class ApiAgentUserController extends Handler { } /** - * 结束坐席会话 + * 结束对话 + * 如果当前对话属于登录用户或登录用户为超级用户,则可以结束这个对话 * * @param request * @param payload * @return */ private JsonObject end(final HttpServletRequest request, final JsonObject payload) { - logger.info("[end] payload ", payload.toString()); + logger.info("[end] payload {}", payload.toString()); final String orgi = super.getOrgi(request); final User logined = super.getUser(request); JsonObject resp = new JsonObject(); diff --git a/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiServiceQueneController.java b/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiServiceQueneController.java index d3f13a1d..cec0ada6 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiServiceQueneController.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/controller/api/ApiServiceQueneController.java @@ -26,7 +26,6 @@ import com.chatopera.cc.model.AgentStatus; import com.chatopera.cc.model.SessionConfig; import com.chatopera.cc.model.User; import com.chatopera.cc.persistence.repository.AgentStatusRepository; -import com.chatopera.cc.persistence.repository.AgentUserRepository; import com.chatopera.cc.proxy.AgentUserProxy; import com.chatopera.cc.util.Menu; import com.chatopera.cc.util.RestResult; @@ -41,7 +40,6 @@ import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; -import java.nio.charset.CharacterCodingException; import java.util.Date; import java.util.List; @@ -63,14 +61,11 @@ public class ApiServiceQueneController extends Handler { private ACDPolicyService acdPolicyService; @Autowired - private AgentStatusRepository agentStatusRepository; + private AgentStatusRepository agentStatusRes; @Autowired private ACDServiceRouter acdServiceRouter; - @Autowired - private AgentUserRepository agentUserRepository; - @Autowired private Cache cache; @@ -98,104 +93,86 @@ public class ApiServiceQueneController extends Handler { @Menu(type = "apps", subtype = "user", access = true) public ResponseEntity agentStatus( HttpServletRequest request, - @Valid String status) throws CharacterCodingException { + @Valid String status) { User logined = super.getUser(request); AgentStatus agentStatus = null; if (StringUtils.isNotBlank(status) && status.equals(MainContext.AgentStatusEnum.READY.toString())) { - List agentStatusList = agentStatusRepository.findByAgentnoAndOrgi( - logined.getId(), super.getOrgi(request)); - if (agentStatusList.size() > 0) { - agentStatus = agentStatusList.get(0); - agentStatus.setSkills(logined.getSkills()); - } else { - agentStatus = new AgentStatus(); - agentStatus.setUserid(logined.getId()); - agentStatus.setUsername(logined.getUname()); - agentStatus.setAgentno(logined.getId()); - agentStatus.setLogindate(new Date()); - agentStatus.setSkills(logined.getSkills()); - SessionConfig sessionConfig = acdPolicyService.initSessionConfig(super.getOrgi(request)); + agentStatus = agentStatusRes.findOneByAgentnoAndOrgi(logined.getId(), logined.getOrgi()).orElseGet(() -> { + AgentStatus p = new AgentStatus(); + p.setUserid(logined.getId()); + p.setUsername(logined.getUname()); + p.setAgentno(logined.getId()); + p.setLogindate(new Date()); - agentStatus.setUsers(agentUserRepository.countByAgentnoAndStatusAndOrgi( - logined.getId(), - MainContext.AgentUserStatusEnum.INSERVICE.toString(), - super.getOrgi(request))); + SessionConfig sessionConfig = acdPolicyService.initSessionConfig(logined.getOrgi()); + p.setUpdatetime(new Date()); + p.setOrgi(super.getOrgi(request)); + p.setMaxusers(sessionConfig.getMaxuser()); + return p; + }); - agentStatus.setUpdatetime(new Date()); + /** + * 设置技能组 + */ + agentStatus.setSkills(logined.getSkills()); - agentStatus.setOrgi(super.getOrgi(request)); - agentStatus.setMaxusers(sessionConfig.getMaxuser()); - agentStatusRepository.save(agentStatus); + /** + * 更新当前用户状态 + */ + agentStatus.setUsers(cache.getInservAgentUsersSizeByAgentnoAndOrgi( + agentStatus.getAgentno(), + super.getOrgi(request))); + agentStatus.setStatus(MainContext.AgentStatusEnum.READY.toString()); + agentStatusRes.save(agentStatus); - } - if (agentStatus != null) { - /** - * 更新当前用户状态 - */ - agentStatus.setUsers(cache.getInservAgentUsersSizeByAgentnoAndOrgi( - agentStatus.getAgentno(), - super.getOrgi(request))); - agentStatus.setStatus(MainContext.AgentStatusEnum.READY.toString()); - cache.putAgentStatusByOrgi(agentStatus, super.getOrgi(request)); - - acdWorkMonitor.recordAgentStatus( - agentStatus.getAgentno(), agentStatus.getUsername(), agentStatus.getAgentno(), - logined.isAdmin(), agentStatus.getAgentno(), - MainContext.AgentStatusEnum.OFFLINE.toString(), MainContext.AgentStatusEnum.READY.toString(), - MainContext.AgentWorkType.MEIDIACHAT.toString(), agentStatus.getOrgi(), null); - acdServiceRouter.allotVisitors(agentStatus.getAgentno(), super.getOrgi(request)); - } + acdWorkMonitor.recordAgentStatus( + agentStatus.getAgentno(), agentStatus.getUsername(), agentStatus.getAgentno(), + logined.isAdmin(), agentStatus.getAgentno(), + MainContext.AgentStatusEnum.OFFLINE.toString(), MainContext.AgentStatusEnum.READY.toString(), + MainContext.AgentWorkType.MEIDIACHAT.toString(), agentStatus.getOrgi(), null); + acdServiceRouter.allotVisitors(agentStatus.getAgentno(), super.getOrgi(request)); } else if (StringUtils.isNotBlank(status)) { if (status.equals(MainContext.AgentStatusEnum.NOTREADY.toString())) { - List agentStatusList = agentStatusRepository.findByAgentnoAndOrgi( - logined.getId(), super.getOrgi(request)); - for (AgentStatus temp : agentStatusList) { + agentStatusRes.findOneByAgentnoAndOrgi( + logined.getId(), super.getOrgi(request)).ifPresent(p -> { acdWorkMonitor.recordAgentStatus( - temp.getAgentno(), temp.getUsername(), temp.getAgentno(), + p.getAgentno(), p.getUsername(), p.getAgentno(), logined.isAdmin(), - temp.getAgentno(), - temp.isBusy() ? MainContext.AgentStatusEnum.BUSY.toString() : MainContext.AgentStatusEnum.READY.toString(), + p.getAgentno(), + p.isBusy() ? MainContext.AgentStatusEnum.BUSY.toString() : MainContext.AgentStatusEnum.READY.toString(), MainContext.AgentStatusEnum.NOTREADY.toString(), - MainContext.AgentWorkType.MEIDIACHAT.toString(), temp.getOrgi(), temp.getUpdatetime()); - agentStatusRepository.delete(temp); - } - cache.deleteAgentStatusByAgentnoAndOrgi(super.getUser(request).getId(), super.getOrgi(request)); + MainContext.AgentWorkType.MEIDIACHAT.toString(), p.getOrgi(), p.getUpdatetime()); + agentStatusRes.delete(p); + }); } else if (StringUtils.isNotBlank(status) && status.equals(MainContext.AgentStatusEnum.BUSY.toString())) { - List agentStatusList = agentStatusRepository.findByAgentnoAndOrgi( - logined.getId(), super.getOrgi(request)); - if (agentStatusList.size() > 0) { - agentStatus = agentStatusList.get(0); - agentStatus.setBusy(true); + agentStatusRes.findOneByAgentnoAndOrgi( + logined.getId(), logined.getOrgi()).ifPresent(p -> { + p.setBusy(true); acdWorkMonitor.recordAgentStatus( - agentStatus.getAgentno(), agentStatus.getUsername(), agentStatus.getAgentno(), - logined.isAdmin(), agentStatus.getAgentno(), + p.getAgentno(), p.getUsername(), p.getAgentno(), + logined.isAdmin(), p.getAgentno(), MainContext.AgentStatusEnum.READY.toString(), MainContext.AgentStatusEnum.BUSY.toString(), - MainContext.AgentWorkType.MEIDIACHAT.toString(), agentStatus.getOrgi(), - agentStatus.getUpdatetime()); - agentStatus.setUpdatetime(new Date()); - - agentStatusRepository.save(agentStatus); - cache.putAgentStatusByOrgi(agentStatus, super.getOrgi(request)); - } + MainContext.AgentWorkType.MEIDIACHAT.toString(), p.getOrgi(), + p.getUpdatetime()); + p.setUpdatetime(new Date()); + agentStatusRes.save(p); + }); } else if (StringUtils.isNotBlank(status) && status.equals( MainContext.AgentStatusEnum.NOTBUSY.toString())) { - List agentStatusList = agentStatusRepository.findByAgentnoAndOrgi( - logined.getId(), super.getOrgi(request)); - if (agentStatusList.size() > 0) { - agentStatus = agentStatusList.get(0); - agentStatus.setBusy(false); + agentStatusRes.findOneByAgentnoAndOrgi( + logined.getId(), logined.getOrgi()).ifPresent(p -> { + p.setBusy(false); acdWorkMonitor.recordAgentStatus( - agentStatus.getAgentno(), agentStatus.getUsername(), agentStatus.getAgentno(), - logined.isAdmin(), agentStatus.getAgentno(), + p.getAgentno(), p.getUsername(), p.getAgentno(), + logined.isAdmin(), p.getAgentno(), MainContext.AgentStatusEnum.BUSY.toString(), MainContext.AgentStatusEnum.READY.toString(), - MainContext.AgentWorkType.MEIDIACHAT.toString(), agentStatus.getOrgi(), - agentStatus.getUpdatetime()); + MainContext.AgentWorkType.MEIDIACHAT.toString(), p.getOrgi(), + p.getUpdatetime()); - agentStatus.setUpdatetime(new Date()); - agentStatusRepository.save(agentStatus); - cache.putAgentStatusByOrgi(agentStatus, super.getOrgi(request)); - } + p.setUpdatetime(new Date()); + agentStatusRes.save(p); + }); acdServiceRouter.allotVisitors(agentStatus.getAgentno(), super.getOrgi(request)); } agentUserProxy.broadcastAgentsStatus( diff --git a/contact-center/app/src/main/java/com/chatopera/cc/controller/apps/AgentController.java b/contact-center/app/src/main/java/com/chatopera/cc/controller/apps/AgentController.java index c708d2be..ba8801ab 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/controller/apps/AgentController.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/controller/apps/AgentController.java @@ -17,17 +17,16 @@ package com.chatopera.cc.controller.apps; import com.alibaba.fastjson.JSONObject; - import com.chatopera.cc.acd.ACDAgentService; import com.chatopera.cc.acd.ACDPolicyService; - import com.chatopera.cc.acd.ACDWorkMonitor; import com.chatopera.cc.acd.ACDServiceRouter; + import com.chatopera.cc.acd.ACDWorkMonitor; import com.chatopera.cc.activemq.BrokerPublisher; import com.chatopera.cc.basic.Constants; import com.chatopera.cc.basic.MainContext; import com.chatopera.cc.basic.MainUtils; import com.chatopera.cc.cache.Cache; - import com.chatopera.cc.exception.CSKefuException; import com.chatopera.cc.controller.Handler; + import com.chatopera.cc.exception.CSKefuException; import com.chatopera.cc.model.*; import com.chatopera.cc.peer.PeerSyncIM; import com.chatopera.cc.persistence.blob.JpaBlobHelper; @@ -81,9 +80,6 @@ @Autowired private ACDPolicyService acdPolicyService; - @Autowired - private ACDAgentService acdAgentService; - @Autowired private ACDServiceRouter acdServiceRouter; @@ -543,14 +539,7 @@ logined.getId(), orgi, logined.getSkills()); // 缓存就绪状态 - agentProxy.ready(logined, agentStatus); - // TODO 对于busy的判断,其实可以和AgentStatus maxuser以及users结合 - // 现在为了配合前端的行为:从未就绪到就绪设置为置闲 - agentStatus.setBusy(false); - - // 更新数据库 - cache.putAgentStatusByOrgi(agentStatus, agentStatus.getOrgi()); - agentStatusRes.save(agentStatus); + agentProxy.ready(logined, agentStatus, false); // 为该坐席分配访客 acdServiceRouter.allotVisitors(agentStatus.getAgentno(), orgi); @@ -648,6 +637,7 @@ @Menu(type = "apps", subtype = "agent") public ModelAndView notbusy(HttpServletRequest request) { final User logined = super.getUser(request); + // 组织结构和权限数据 logger.info("[notbusy] set user {} as not busy", logined.getId()); AgentStatus agentStatus = agentProxy.resolveAgentStatusByAgentnoAndOrgi( @@ -717,6 +707,7 @@ @RequestMapping({"/end"}) @Menu(type = "apps", subtype = "agent") public ModelAndView end(HttpServletRequest request, @Valid String id) { + logger.info("[end] end id {}", id); final String orgi = super.getOrgi(request); final User logined = super.getUser(request); diff --git a/contact-center/app/src/main/java/com/chatopera/cc/model/AgentStatus.java b/contact-center/app/src/main/java/com/chatopera/cc/model/AgentStatus.java index 6a9bca9b..694a893a 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/model/AgentStatus.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/model/AgentStatus.java @@ -160,16 +160,24 @@ public class AgentStatus implements java.io.Serializable, Comparable { AgentStatus findByIdAndOrgi(String paramString, String orgi); - List findByAgentnoAndOrgi(String agentid, String orgi); - @Query(value = "SELECT * FROM uk_agentstatus WHERE agentno = ?1 AND orgi = ?2 ORDER BY createtime DESC LIMIT 1", nativeQuery = true) - AgentStatus findOneByAgentnoAndOrgi(final String agentid, final String orgi); + Optional findOneByAgentnoAndOrgi(final String agentid, final String orgi); AgentStatus findByAgentno(String agentid); diff --git a/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentProxy.java b/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentProxy.java index 91ef26fd..9efc19f5 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentProxy.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentProxy.java @@ -15,6 +15,7 @@ import com.chatopera.cc.persistence.repository.SNSAccountRepository; import com.chatopera.cc.persistence.repository.StreamingFileRepository; import com.chatopera.cc.socketio.message.ChatMessage; import com.chatopera.cc.socketio.message.Message; +import com.chatopera.cc.util.HashMapUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -70,7 +71,7 @@ public class AgentProxy { * @param user * @param agentStatus */ - public void ready(final User user, final AgentStatus agentStatus) { + public void ready(final User user, final AgentStatus agentStatus, final boolean busy) { agentStatus.setOrgi(user.getOrgi()); agentStatus.setUserid(user.getId()); agentStatus.setUsername(user.getUname()); @@ -79,6 +80,9 @@ public class AgentProxy { agentStatus.setOrgi(agentStatus.getOrgi()); agentStatus.setUpdatetime(new Date()); agentStatus.setSkills(user.getSkills()); + // TODO 对于busy的判断,其实可以和AgentStatus maxuser以及users结合 + // 现在为了配合前端的行为:从未就绪到就绪设置为置闲 + agentStatus.setBusy(busy); SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentStatus.getOrgi()); agentStatus.setMaxusers(sessionConfig.getMaxuser()); @@ -92,6 +96,9 @@ public class AgentProxy { logger.info( "[ready] set agent {}, status {}", agentStatus.getAgentno(), MainContext.AgentStatusEnum.READY.toString()); + + // 更新数据库 + agentStatusRes.save(agentStatus); } @@ -325,15 +332,13 @@ public class AgentProxy { * @return */ public AgentStatus resolveAgentStatusByAgentnoAndOrgi(final String agentno, final String orgi, final HashMap skills) { + logger.info( + "[resolveAgentStatusByAgentnoAndOrgi] agentno {}, skills {}", agentno, + HashMapUtils.concatKeys(skills, "|")); AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(agentno, orgi); if (agentStatus == null) { - final List ass = agentStatusRes.findByAgentnoAndOrgi(agentno, orgi); - if (ass.size() > 0) { - agentStatus = ass.get(0); - } else { - agentStatus = new AgentStatus(); - } + agentStatus = agentStatusRes.findOneByAgentnoAndOrgi(agentno, orgi).orElseGet(AgentStatus::new); } if (skills != null) { diff --git a/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentUserProxy.java b/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentUserProxy.java index fe6d7464..13effbb9 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentUserProxy.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/proxy/AgentUserProxy.java @@ -105,6 +105,8 @@ public class AgentUserProxy { @Autowired private Cache cache; + @Autowired + private AgentStatusRepository agentStatusRes; @Autowired private PeerSyncIM peerSyncIM; @@ -488,7 +490,7 @@ public class AgentUserProxy { int users = cache.getInservAgentUsersSizeByAgentnoAndOrgi(agentStatus.getAgentno(), orgi); agentStatus.setUsers(users); agentStatus.setUpdatetime(new Date()); - cache.putAgentStatusByOrgi(agentStatus, orgi); + agentStatusRes.save(agentStatus); } /** diff --git a/contact-center/app/src/main/java/com/chatopera/cc/proxy/UserProxy.java b/contact-center/app/src/main/java/com/chatopera/cc/proxy/UserProxy.java index c416669e..17246da2 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/proxy/UserProxy.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/proxy/UserProxy.java @@ -536,6 +536,8 @@ public class UserProxy { public void attachOrgansPropertiesForUser(final User user) { List organs = organUserRes.findByUserid(user.getId()); user.setOrgans(new HashMap<>()); + user.setAffiliates(new HashSet<>()); + final HashMap skills = new HashMap<>(); for (final OrganUser organ : organs) { diff --git a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java index 753bd420..a7ffb796 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/AgentEventHandler.java @@ -92,18 +92,13 @@ public class AgentEventHandler { client.set("connectid", connectid); // 更新AgentStatus到数据库 - List agentStatusList = getAgentStatusRes().findByAgentnoAndOrgi(userid, orgi); - if (agentStatusList.size() > 0) { - AgentStatus agentStatus = agentStatusList.get(0); - agentStatus.setUpdatetime(new Date()); - agentStatus.setConnected(true); - + getAgentStatusRes().findOneByAgentnoAndOrgi(userid, orgi).ifPresent(p -> { + p.setUpdatetime(new Date()); + p.setConnected(true); // 设置agentSkills - agentStatus.setSkills(getUserProxy().getSkillsMapByAgentno(userid)); - - getAgentStatusRes().save(agentStatus); - MainContext.getCache().putAgentStatusByOrgi(agentStatus, orgi); - } + p.setSkills(getUserProxy().getSkillsMapByAgentno(userid)); + getAgentStatusRes().save(p); + }); // 工作工作效率 InetSocketAddress address = (InetSocketAddress) client.getRemoteAddress(); @@ -190,7 +185,8 @@ public class AgentEventHandler { final String session = client.get("session"); final String connectid = client.get("connectid"); logger.info( - "[onIntervetionEvent] intervention: agentno {}, session {}, connectid {}, payload {}", agentno, session, connectid, + "[onIntervetionEvent] intervention: agentno {}, session {}, connectid {}, payload {}", agentno, session, + connectid, received.toJsonObject()); if (received.valid()) { diff --git a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java index e936b2b9..da49373e 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/socketio/handler/IMEventHandler.java @@ -156,8 +156,11 @@ public class IMEventHandler { /** * 发送消息给坐席 + * 如果没有AgentService或该AgentService没有坐席或AgentService在排队中,则不发送 */ - if (agentServiceMessage.getAgentService() != null) { + if (agentServiceMessage.getAgentService() != null && (!agentServiceMessage.isNoagent()) && !StringUtils.equals( + MainContext.AgentUserStatusEnum.INQUENE.toString(), + agentServiceMessage.getAgentService().getStatus())) { // 通知消息到坐席 MainContext.getPeerSyncIM().send(ReceiverType.AGENT, ChannelType.WEBIM, diff --git a/contact-center/app/src/main/java/com/chatopera/cc/socketio/util/HumanUtils.java b/contact-center/app/src/main/java/com/chatopera/cc/socketio/util/HumanUtils.java index 22f0b53e..9689929e 100644 --- a/contact-center/app/src/main/java/com/chatopera/cc/socketio/util/HumanUtils.java +++ b/contact-center/app/src/main/java/com/chatopera/cc/socketio/util/HumanUtils.java @@ -60,7 +60,7 @@ public class HumanUtils { protected static void processMessage(final ChatMessage chatMessage, final String msgtype, final String userid) { logger.info("[processMessage] userid {}, msgtype {}", userid, msgtype); AgentUser agentUser = MainContext.getCache().findOneAgentUserByUserIdAndOrgi( - userid, MainContext.SYSTEM_ORGI).orElseGet(null); + userid, MainContext.SYSTEM_ORGI).orElse(null); Message outMessage = new Message(); diff --git a/contact-center/app/src/main/resources/templates/apps/setting/agent/index.html b/contact-center/app/src/main/resources/templates/apps/setting/agent/index.html index bd7a33e4..adaa66e4 100644 --- a/contact-center/app/src/main/resources/templates/apps/setting/agent/index.html +++ b/contact-center/app/src/main/resources/templates/apps/setting/agent/index.html @@ -88,11 +88,11 @@
-
坐席分配最大访客数量
+
坐席同时服务最多访客数
-

为每个人工坐席分配访客的最大数量

+

为坐席分配的同时服务访客数量的最大限制

分配过多用户会导致客户满意度降低

@@ -114,11 +114,11 @@
-
坐席就绪时分配最大访客数量
+
坐席批量分配最大访客数
-

为每个人工坐席分配访客的最大数量

+

单次分配访客的最大数量

为避免坐席就绪的时候突然涌入大量的咨询客户,设置此参数

diff --git a/public/plugins/chatbot/classes/ChatbotEventHandler.java b/public/plugins/chatbot/classes/ChatbotEventHandler.java index 970cecf5..8434311f 100644 --- a/public/plugins/chatbot/classes/ChatbotEventHandler.java +++ b/public/plugins/chatbot/classes/ChatbotEventHandler.java @@ -237,7 +237,7 @@ public class ChatbotEventHandler { MainContext.getCache().findOneAgentUserByUserIdAndOrgi(user, orgi).ifPresent(p -> { MainContext.getACDServiceRouter().getAcdChatbotService().processChatbotService(null, p, orgi); - MainContext.getCache().deleteAgentUserByUserIdAndOrgi(user, orgi); + MainContext.getCache().deleteAgentUserByUserIdAndOrgi(p, orgi); MainContext.getCache().deleteOnlineUserByIdAndOrgi(user, orgi); p.setStatus(MainContext.OnlineUserStatusEnum.OFFLINE.toString());