|
|
@@ -20,10 +20,8 @@ import com.cyksj.config.corp.YHLXWxCorpConfig;
|
|
|
import com.cyksj.dto.CorpOauth2UserInfo;
|
|
|
import com.cyksj.mapper.OrderDonMapper;
|
|
|
import com.cyksj.mapper.corp.*;
|
|
|
-import com.cyksj.mapper.corp.kf.CorpKfAccountFollowMapper;
|
|
|
-import com.cyksj.mapper.corp.kf.CorpKfAccountMapper;
|
|
|
-import com.cyksj.mapper.corp.kf.CorpKfAccountSessionConfigMapper;
|
|
|
-import com.cyksj.mapper.corp.kf.CorpKfWaitingQueueUserMapper;
|
|
|
+import com.cyksj.mapper.corp.kf.*;
|
|
|
+import com.cyksj.model.dto.CorpKfServicerDto;
|
|
|
import com.cyksj.model.dto.WxCorpEncryptDto;
|
|
|
import com.cyksj.model.entity.*;
|
|
|
import com.cyksj.model.kf.CorpKfServicerResp;
|
|
|
@@ -52,10 +50,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
import java.io.File;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
-import java.util.Random;
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -121,6 +119,9 @@ public class CorpServiceImpl implements CorpService {
|
|
|
@Autowired
|
|
|
private CorpKfWaitingQueueUserMapper corpKfWaitingQueueUserMapper;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private CorpKfServicerSessionRecordMapper corpKfServicerSessionRecordMapper;
|
|
|
+
|
|
|
@PostConstruct
|
|
|
private void init() {
|
|
|
corpMessageRouter = new CorpMessageRouter(this)
|
|
|
@@ -532,13 +533,14 @@ public class CorpServiceImpl implements CorpService {
|
|
|
String openKfId = message.getOpenKfId();
|
|
|
WxCpKfMsgListResp wxCpKfMsgListResp = wxCorpOps.syncMsg(message.getToUserName(), null, message.getToken(), null, openKfId);
|
|
|
List<WxCpKfMsgListResp.WxCpKfMsgItem> msgList = wxCpKfMsgListResp.getMsgList();
|
|
|
- //欢迎语
|
|
|
+ //进入会话事件
|
|
|
enterSessionEvent(message, msgList);
|
|
|
+ //会话更变事件
|
|
|
+ sessionStatusChange(message, msgList);
|
|
|
//消息发送失败事件
|
|
|
//拒收客户消息变更事件
|
|
|
//同步客服聊天记录
|
|
|
syncChatMsg(message, msgList);
|
|
|
- //发送
|
|
|
} catch (Exception e) {
|
|
|
log.error("企业微信客服 事件消息回调 错误");
|
|
|
throw BusinessRuntimeException.getInstance(StringUtil.getErrorMsg(e));
|
|
|
@@ -546,8 +548,40 @@ public class CorpServiceImpl implements CorpService {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ private void sessionStatusChange(CorpXmlMessage message, List<WxCpKfMsgListResp.WxCpKfMsgItem> msgList) throws Exception {
|
|
|
+ String openKfId = message.getOpenKfId();
|
|
|
+ List<WxCpKfMsgListResp.WxCpKfMsgItem> sessionStatusChanges = msgList.stream()
|
|
|
+ .filter((item) -> item.getEvent() != null && item.getEvent().getEventType().equals("session_status_change")).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isNotEmpty(sessionStatusChanges)) {
|
|
|
+ WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem = sessionStatusChanges.get(sessionStatusChanges.size() - 1);
|
|
|
+ String externalUserId = wxCpKfMsgItem.getExternalUserId();
|
|
|
+ String oldServicerUserid = wxCpKfMsgItem.getOldServicerUserid();
|
|
|
+ CorpKfServicerSessionRecord corpKfServicerSessionRecord = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getOpenKfId, openKfId)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getServicerUserId, oldServicerUserid)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getExternalUserid, externalUserId)
|
|
|
+ .last("limit 1"));
|
|
|
+ if (corpKfServicerSessionRecord != null) {
|
|
|
+ corpKfServicerSessionRecord.setServiceState(2);
|
|
|
+ corpKfServicerSessionRecordMapper.updateById(corpKfServicerSessionRecord);
|
|
|
+ }
|
|
|
+ String newServicerUserid = wxCpKfMsgItem.getNewServicerUserid();
|
|
|
+
|
|
|
+ CorpKfServicerSessionRecord corpKfServicerSessionRecord1 = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getOpenKfId, openKfId)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getServicerUserId, newServicerUserid)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getExternalUserid, externalUserId)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getServiceState, 0)
|
|
|
+ .last("limit 1"));
|
|
|
+ if (corpKfServicerSessionRecord1 == null) {
|
|
|
+ //记录新的客服会话
|
|
|
+ transCorpKfSessionToServicer(message.getToUserName(), openKfId, newServicerUserid, externalUserId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
- * 微信客服欢迎语
|
|
|
+ * enter_session 会话事件
|
|
|
*/
|
|
|
public void enterSessionEvent(CorpXmlMessage message, List<WxCpKfMsgListResp.WxCpKfMsgItem> msgList) throws Exception {
|
|
|
String openKfId = message.getOpenKfId();
|
|
|
@@ -564,17 +598,16 @@ public class CorpServiceImpl implements CorpService {
|
|
|
CorpKfAccountSessionConfig corpKfAccountSessionConfig = corpKfAccountSessionConfigMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountSessionConfig.class)
|
|
|
.eq(CorpKfAccountSessionConfig::getOpenKfId, openKfId)
|
|
|
.last("limit 1"));
|
|
|
- //欢迎语
|
|
|
if (enterSessionList.size() > 0) {
|
|
|
WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem = enterSessionList.get(enterSessionList.size() - 1);
|
|
|
WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
|
|
|
String welcomeCode = event.getWelcomeCode();
|
|
|
- //如果满足发送欢迎语条件(条件为:用户在过去48小时里未收过欢迎语,且未向客服发过消息),会返回该字段。
|
|
|
- //可用该welcome_code调用发送事件响应消息接口给客户发送欢迎语。
|
|
|
if (corpKfAccountSessionConfig == null) {
|
|
|
log.info("openKfId:{}未设置会话设置", openKfId);
|
|
|
return;
|
|
|
}
|
|
|
+ //如果满足发送欢迎语条件(条件为:用户在过去48小时里未收过欢迎语,且未向客服发过消息),会返回该字段。
|
|
|
+ //可用该welcome_code调用发送事件响应消息接口给客户发送欢迎语。
|
|
|
if (StrUtil.isNotEmpty(welcomeCode)) {
|
|
|
WxCorpKfMsgSendRequest wxCpKfMsgSendRequest = new WxCorpKfMsgSendRequest();
|
|
|
wxCpKfMsgSendRequest.setMsgType("text");
|
|
|
@@ -590,6 +623,15 @@ public class CorpServiceImpl implements CorpService {
|
|
|
wxCpKfMsgSendRequest.setOpenKfid(event.getOpenKfid());
|
|
|
wxCorpOps.sendMsgOnEvent(message.getToUserName(), wxCpKfMsgSendRequest);
|
|
|
} else {
|
|
|
+ //用户是否已有会话
|
|
|
+ Integer selectCount = corpKfServicerSessionRecordMapper.selectCount(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getOpenKfId, openKfId)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getExternalUserid, event.getExternalUserId())
|
|
|
+ .eq(CorpKfServicerSessionRecord::getServiceState, 0));
|
|
|
+ if (selectCount > 0) {
|
|
|
+ log.info("external_userid:{}已有未结束的会话,无需分配", event.getExternalUserId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
//配置接待人员
|
|
|
//是否有空闲人员
|
|
|
int hour = DateTime.now().hour(true);
|
|
|
@@ -600,7 +642,15 @@ public class CorpServiceImpl implements CorpService {
|
|
|
//获取接待人员列表
|
|
|
CorpKfServicerResp corpKfServicerResp = wxCorpOps.getKfServicerList(message.getToUserName(), openKfId);
|
|
|
List<CorpKfServicerResp.CorpKfServicer> servicerList = corpKfServicerResp.getServicerList();
|
|
|
- List<CorpKfServicerResp.CorpKfServicer> corpKfServicers = servicerList.stream().filter(servicer -> servicer.getUserid() != null && servicer.getStatus() == 0).collect(Collectors.toList());
|
|
|
+ //目前值班客服id
|
|
|
+ List<String> corpKfServiceIds = new ArrayList<>();
|
|
|
+ List<CorpKfServicerResp.CorpKfServicer> corpKfServicers = servicerList.stream().filter(servicer ->{
|
|
|
+ if (servicer.getUserid() != null && servicer.getStatus() == 0) {
|
|
|
+ corpKfServiceIds.add(servicer.getUserid());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
if (CollUtil.isEmpty(corpKfServicers)) {
|
|
|
//非值班 移入等待池并发送非值班提示消息
|
|
|
moveWaitingQueue(message.getToUserName(), openKfId, event.getExternalUserId());
|
|
|
@@ -611,14 +661,47 @@ public class CorpServiceImpl implements CorpService {
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
- //未有可接待的客服 移入等待池并发送进入等待池消息
|
|
|
- moveWaitingQueue(message.getToUserName(), openKfId, event.getExternalUserId());
|
|
|
- String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
- sendCorpKfTextTips(message.getToUserName(), event.getExternalUserId(), openKfId, queueTips);
|
|
|
+ //是否有空闲接待人员
|
|
|
+ List<CorpKfServicerDto> corpKfServicerDtos = corpKfServicerSessionRecordMapper.getAvailableServicer(openKfId);
|
|
|
+ if (CollUtil.isEmpty(corpKfServicerDtos)) {
|
|
|
+ //暂无分配会话
|
|
|
+ //随机分配一个客服
|
|
|
+ CorpKfServicerResp.CorpKfServicer corpKfServicer = corpKfServicers.get(RandomUtil.randomInt(corpKfServicers.size()));
|
|
|
+ //变更会话状态
|
|
|
+ transCorpKfSessionToServicer(message.getToUserName(), openKfId, corpKfServicer.getUserid(), event.getExternalUserId());
|
|
|
+ }
|
|
|
+ //筛选符合条件的客服
|
|
|
+ //默认接入最少的优先分配 接待人最少的在集合前面
|
|
|
+ //最多接待人数
|
|
|
+ Integer maxNum = corpKfAccountSessionConfig.getMaxNum();
|
|
|
+ List<CorpKfServicerDto> filterKfCs = corpKfServicerDtos.stream().filter(kfCs -> corpKfServiceIds.contains(kfCs.getServicerUserid()) && kfCs.getNum() < maxNum).collect(Collectors.toList());
|
|
|
+ if (CollUtil.isEmpty(filterKfCs)) {
|
|
|
+ //未有可接待的客服 移入等待池并发送进入等待池消息
|
|
|
+ moveWaitingQueue(message.getToUserName(), openKfId, event.getExternalUserId());
|
|
|
+ String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
+ sendCorpKfTextTips(message.getToUserName(), event.getExternalUserId(), openKfId, queueTips);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //选择第一个分配接待
|
|
|
+ CorpKfServicerDto corpKfServicerDto = filterKfCs.get(0);
|
|
|
+ //变更会话状态
|
|
|
+ transCorpKfSessionToServicer(message.getToUserName(), openKfId, corpKfServicerDto.getServicerUserid(), event.getExternalUserId());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void transCorpKfSessionToServicer(String corpId, String openKfId, String userid, String externalUserId) throws Exception {
|
|
|
+ //记录接待人员会话
|
|
|
+ CorpKfServicerSessionRecord corpKfServicerSessionRecord = new CorpKfServicerSessionRecord();
|
|
|
+ corpKfServicerSessionRecord.setOpenKfId(openKfId);
|
|
|
+ corpKfServicerSessionRecord.setServiceState(0);
|
|
|
+ corpKfServicerSessionRecord.setServicerUserId(userid);
|
|
|
+ corpKfServicerSessionRecord.setExternalUserid(externalUserId);
|
|
|
+ corpKfServicerSessionRecordMapper.insert(corpKfServicerSessionRecord);
|
|
|
+ //调用微信客服接口 变更会话状态
|
|
|
+ wxCorpOps.transCorpKfSessionToServicer(corpId, openKfId, userid, externalUserId);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 发送微信客服会话文本消息
|
|
|
*/
|