mirror of
https://github.com/chatopera/cosin.git
synced 2025-06-16 18:30:03 +08:00
Closed #227 enable ACD Policies with configuration
This commit is contained in:
parent
26baf7a5d7
commit
f57bd54f56
@ -56,14 +56,15 @@ public class ACDAgentService {
|
||||
/**
|
||||
* 查询条件,当前在线的 坐席,并且 未达到最大 服务人数的坐席
|
||||
*/
|
||||
List<AgentStatus> agentStatusList = acdAgentAllocatorMw.filterOutAvailableAgentStatus(agentUser, orgi);
|
||||
final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi);
|
||||
List<AgentStatus> 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()) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ public class ACDQueueService {
|
||||
int queneUsers = 0;
|
||||
Map<String, AgentUser> map = cache.getAgentUsersInQueByOrgi(orgi);
|
||||
|
||||
for (Map.Entry<String, AgentUser> entry : map.entrySet()) {
|
||||
for (final Map.Entry<String, AgentUser> entry : map.entrySet()) {
|
||||
if (StringUtils.isNotBlank(skill)) {
|
||||
if (StringUtils.equals(entry.getValue().getSkill(), skill)) {
|
||||
queneUsers++;
|
||||
|
@ -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<String, AgentUser> pendingAgentUsers = cache.getAgentUsersInQueByOrgi(orgi);
|
||||
final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(orgi);
|
||||
// 本次批量分配访客数目
|
||||
int assigned = 0;
|
||||
|
||||
for (Map.Entry<String, AgentUser> 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<AgentUserTask> 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);
|
||||
|
@ -67,6 +67,7 @@ public class ACDWorkMonitor {
|
||||
AgentReport report = new AgentReport();
|
||||
|
||||
Map<String, AgentStatus> 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;
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ public class ACDVisAllocatorMw implements Middleware<ACDComposeContext> {
|
||||
* 查询条件,当前在线的 坐席,并且 未达到最大 服务人数的坐席
|
||||
*/
|
||||
final List<AgentStatus> agentStatuses = filterOutAvailableAgentStatus(
|
||||
ctx.getAgentUser(), ctx.getOrgi());
|
||||
ctx.getAgentUser(), ctx.getOrgi(), ctx.getSessionConfig());
|
||||
|
||||
/**
|
||||
* 处理ACD 的 技能组请求和 坐席请求
|
||||
@ -108,6 +108,11 @@ public class ACDVisAllocatorMw implements Middleware<ACDComposeContext> {
|
||||
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<ACDComposeContext> {
|
||||
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<ACDComposeContext> {
|
||||
*/
|
||||
public List<AgentStatus> 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<ACDComposeContext> {
|
||||
if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentno())) {
|
||||
// 指定坐席
|
||||
for (final Map.Entry<String, AgentStatus> entry : map.entrySet()) {
|
||||
// 被指定的坐席,不检查是否忙,是否达到最大接待数量
|
||||
if (StringUtils.equals(
|
||||
entry.getValue().getAgentno(), agentUser.getAgentno())) {
|
||||
agentStatuses.add(entry.getValue());
|
||||
@ -251,6 +257,7 @@ public class ACDVisAllocatorMw implements Middleware<ACDComposeContext> {
|
||||
// 指定技能组
|
||||
for (final Map.Entry<String, AgentStatus> 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<ACDComposeContext> {
|
||||
*/
|
||||
// 对于该租户的所有客服
|
||||
for (final Map.Entry<String, AgentStatus> entry : map.entrySet()) {
|
||||
if (!entry.getValue().isBusy()) {
|
||||
if ((!entry.getValue().isBusy()) && (entry.getValue().getUsers() < sessionConfig.getMaxuser())) {
|
||||
agentStatuses.add(entry.getValue());
|
||||
logger.info(
|
||||
"[filterOutAvailableAgentStatus] <Redundance> find ready agent {}, agentname {}, status {}, service {}/{}",
|
||||
"[filterOutAvailableAgentStatus] <Redundance> 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] <Redundance> 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<ACDComposeContext> {
|
||||
* 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(
|
||||
|
@ -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<ACDComposeContext> {
|
||||
@Autowired
|
||||
private OrganRepository organRes;
|
||||
|
||||
@Autowired
|
||||
private Cache cache;
|
||||
|
||||
/**
|
||||
* 绑定技能组或坐席
|
||||
*
|
||||
@ -72,7 +68,7 @@ public class ACDVisBindingMw implements Middleware<ACDComposeContext> {
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(ctx.getAgentno())) {
|
||||
logger.info("[apply] bind agentno {}", ctx.getAgentno());
|
||||
logger.info("[apply] bind agentno {}, isInvite {}", ctx.getAgentno(), ctx.isInvite());
|
||||
// 绑定坐席
|
||||
// 绑定坐席有可能是因为前端展示了技能组和坐席
|
||||
// 也有可能是坐席发送了邀请,该访客接收邀请
|
||||
|
@ -182,6 +182,7 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
|
||||
} else {
|
||||
// TODO 什么是否返回 noAgentMessage, 是否在是 INQUENE 时 getQueneindex == 0
|
||||
// 当前没有坐席,要留言
|
||||
ctx.setNoagent(true);
|
||||
ctx.setMessage(acdMessageHelper.getNoAgentMessage(
|
||||
ctx.getAgentService().getQueneindex(),
|
||||
ctx.getChannel(),
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.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());
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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";
|
||||
|
||||
/**
|
||||
|
@ -57,37 +57,6 @@ public class Cache {
|
||||
return convertFromStringToAgentStatus(agentStatuses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得未就绪的坐席状态列表
|
||||
*
|
||||
* @param orgi
|
||||
* @return
|
||||
*/
|
||||
public Map<String, AgentStatus> getAgentStatusNotReadyByOrgi(final String orgi) {
|
||||
Map<String, String> agentStatuses = redisCommand.getHash(RedisKey.getAgentStatusNotReadyHashKey(orgi));
|
||||
return convertFromStringToAgentStatus(agentStatuses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回置忙的客服列表
|
||||
*
|
||||
* @param orgi
|
||||
* @return
|
||||
*/
|
||||
public Map<String, AgentStatus> getAgentStatusBusyByOrig(final String orgi) {
|
||||
Map<String, String> agentStatuses = redisCommand.getHash(RedisKey.getAgentStatusReadyHashKey(orgi));
|
||||
Map<String, AgentStatus> result = new HashMap<>();
|
||||
Map<String, AgentStatus> map = convertFromStringToAgentStatus(agentStatuses);
|
||||
|
||||
for (Map.Entry<String, AgentStatus> 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<String, AgentUser> getAgentUsersInQueByOrgi(final String orgi) {
|
||||
Map<String, String> agentUsers = redisCommand.getHash(RedisKey.getAgentUserInQueHashKey(orgi));
|
||||
Map<String, AgentUser> map = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : agentUsers.entrySet()) {
|
||||
AgentUser obj = SerializeUtil.deserialize(entry.getValue());
|
||||
for (final Map.Entry<String, String> 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 相关
|
||||
******************************/
|
||||
|
@ -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(),
|
||||
|
@ -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();
|
||||
|
@ -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<RestResult> 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<AgentStatus> 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<AgentStatus> 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<AgentStatus> 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<AgentStatus> 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(
|
||||
|
@ -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);
|
||||
|
||||
|
@ -160,16 +160,24 @@ public class AgentStatus implements java.io.Serializable, Comparable<AgentStatus
|
||||
this.createtime = createtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同时服务最多的访客数
|
||||
* @return
|
||||
*/
|
||||
@Transient
|
||||
public int getMaxusers() {
|
||||
SessionConfig sessionConfig = MainContext.getACDServiceRouter().getAcdPolicyService().initSessionConfig(this.orgi);
|
||||
return sessionConfig != null ? sessionConfig.getMaxuser() : Constants.AGENT_STATUS_MAX_USER;
|
||||
return sessionConfig.getMaxuser();
|
||||
}
|
||||
|
||||
public void setMaxusers(int maxusers) {
|
||||
this.maxusers = maxusers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单次批量分配最大访客数目
|
||||
* @return
|
||||
*/
|
||||
@Transient
|
||||
public int getInitmaxusers() {
|
||||
SessionConfig sessionConfig = MainContext.getACDServiceRouter().getAcdPolicyService().initSessionConfig(this.orgi);
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.chatopera.cc.persistence.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.chatopera.cc.model.AgentStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
@ -28,10 +29,8 @@ public interface AgentStatusRepository extends
|
||||
JpaRepository<AgentStatus, String> {
|
||||
AgentStatus findByIdAndOrgi(String paramString, String orgi);
|
||||
|
||||
List<AgentStatus> 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<AgentStatus> findOneByAgentnoAndOrgi(final String agentid, final String orgi);
|
||||
|
||||
AgentStatus findByAgentno(String agentid);
|
||||
|
||||
|
@ -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<String, String> skills) {
|
||||
logger.info(
|
||||
"[resolveAgentStatusByAgentnoAndOrgi] agentno {}, skills {}", agentno,
|
||||
HashMapUtils.concatKeys(skills, "|"));
|
||||
AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(agentno, orgi);
|
||||
|
||||
if (agentStatus == null) {
|
||||
final List<AgentStatus> 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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,6 +536,8 @@ public class UserProxy {
|
||||
public void attachOrgansPropertiesForUser(final User user) {
|
||||
List<OrganUser> organs = organUserRes.findByUserid(user.getId());
|
||||
user.setOrgans(new HashMap<>());
|
||||
user.setAffiliates(new HashSet<>());
|
||||
|
||||
final HashMap<String, String> skills = new HashMap<>();
|
||||
|
||||
for (final OrganUser organ : organs) {
|
||||
|
@ -92,18 +92,13 @@ public class AgentEventHandler {
|
||||
client.set("connectid", connectid);
|
||||
|
||||
// 更新AgentStatus到数据库
|
||||
List<AgentStatus> 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()) {
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
||||
|
@ -88,11 +88,11 @@
|
||||
</div>
|
||||
|
||||
<div class="ukefu-webim-prop">
|
||||
<div class="ukefu-webim-tl" style="clear:both;">坐席分配最大访客数量</div>
|
||||
<div class="ukefu-webim-tl" style="clear:both;">坐席同时服务最多访客数</div>
|
||||
<div class="box-item">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<p>为每个人工坐席分配访客的最大数量</p>
|
||||
<p>为坐席分配的同时服务访客数量的最大限制</p>
|
||||
<p style="color:#888888;font-size:13px;margin-top:10px;">分配过多用户会导致客户满意度降低</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
@ -114,11 +114,11 @@
|
||||
</div>
|
||||
|
||||
<div class="ukefu-webim-prop">
|
||||
<div class="ukefu-webim-tl" style="clear:both;">坐席就绪时分配最大访客数量</div>
|
||||
<div class="ukefu-webim-tl" style="clear:both;">坐席批量分配最大访客数</div>
|
||||
<div class="box-item">
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<p>为每个人工坐席分配访客的最大数量</p>
|
||||
<p>单次分配访客的最大数量</p>
|
||||
<p style="color:#888888;font-size:13px;margin-top:10px;">为避免坐席就绪的时候突然涌入大量的咨询客户,设置此参数</p>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user