|
|
@@ -573,36 +573,23 @@ public class CorpServiceImpl implements CorpService {
|
|
|
List<WxCpKfMsgListResp.WxCpKfMsgItem> msgList = wxCpKfMsgListResp.getMsgList();
|
|
|
List<WxCpKfMsgListResp.WxCpKfMsgItem> enterSessionList = null;
|
|
|
List<WxCpKfMsgListResp.WxCpKfMsgItem> sessionStatusChanges = null;
|
|
|
- List<WxCorpChatMsg> mergedMsgs = null;
|
|
|
for (WxCpKfMsgListResp.WxCpKfMsgItem item : msgList) {
|
|
|
if (item.getEvent() != null && item.getEvent().getEventType().equals("enter_session")) {
|
|
|
//会话事件
|
|
|
if (item.getEvent().getEventType().equals("enter_session")) {
|
|
|
- if (enterSessionList == null) {
|
|
|
- enterSessionList = new ArrayList<>();
|
|
|
- }
|
|
|
- enterSessionList.add(item);
|
|
|
+ //进入会话事件
|
|
|
+ enterSessionEvent(corpKfAccount, corpKfAccountSessionConfig, corpId, item);
|
|
|
}
|
|
|
//会话变更事件
|
|
|
if (item.getEvent().getEventType().equals("session_status_change")) {
|
|
|
- if (sessionStatusChanges == null) {
|
|
|
- sessionStatusChanges = new ArrayList<>();
|
|
|
- }
|
|
|
- sessionStatusChanges.add(item);
|
|
|
+ //会话更变事件
|
|
|
+ sessionStatusChange(corpId, openKfId, item, corpKfAccountSessionConfig);
|
|
|
}
|
|
|
}
|
|
|
- //同步客户聊天记录
|
|
|
+ //同步账号信息
|
|
|
syncKfChatMsg(item);
|
|
|
}
|
|
|
cursor = wxCpKfMsgListResp.getNextCursor();
|
|
|
- //进入会话事件
|
|
|
- enterSessionEvent(corpKfAccount, corpKfAccountSessionConfig, corpId, enterSessionList);
|
|
|
- //会话更变事件
|
|
|
- sessionStatusChange(corpId, openKfId, sessionStatusChanges, corpKfAccountSessionConfig);
|
|
|
- //同步客服聊天记录
|
|
|
- syncChatMsg(openKfId, mergedMsgs);
|
|
|
- //同步满意度
|
|
|
- syncSessionText(openKfId, textList, corpId, corpKfAccountSessionConfig);
|
|
|
corpKfAccountSyncMsgProgress.setNextCursor(cursor);
|
|
|
//同步信息
|
|
|
while (wxCpKfMsgListResp.getHasMore() == 1) {
|
|
|
@@ -732,35 +719,32 @@ public class CorpServiceImpl implements CorpService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void sessionStatusChange(String corpId, String openKfId, List<WxCpKfMsgListResp.WxCpKfMsgItem> sessionStatusChanges, CorpKfAccountSessionConfig corpKfAccountSessionConfig) throws Exception {
|
|
|
- if (CollUtil.isNotEmpty(sessionStatusChanges)) {
|
|
|
- WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem = sessionStatusChanges.get(sessionStatusChanges.size() - 1);
|
|
|
- CorpKfServicerSessionRecord corpKfServicerSessionRecord = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
|
|
|
- .eq(CorpKfServicerSessionRecord::getOpenKfId, openKfId)
|
|
|
- .eq(CorpKfServicerSessionRecord::getMsgId, wxCpKfMsgItem.getMsgId())
|
|
|
- .last("limit 1"));
|
|
|
- Integer changeType = null;
|
|
|
- if (corpKfServicerSessionRecord != null) {
|
|
|
- WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
|
|
|
- //变更类型,均为接待人员在企业微信客户端操作触发。1-从接待池接入会话 2-转接会话 3-结束会话 4-重新接入已结束/已转接会话
|
|
|
- changeType = event.getChangeType();
|
|
|
- //老会话已结束
|
|
|
- if (changeType != 1) {
|
|
|
- corpKfServicerSessionRecord.setServiceState(changeType == 3 ? 1 : 2);
|
|
|
- //关闭
|
|
|
- corpKfServicerSessionRecord.setCloseTime(DateTime.now());
|
|
|
- corpKfServicerSessionRecordMapper.updateById(corpKfServicerSessionRecord);
|
|
|
- //优先分配等待池中的用户
|
|
|
- assignWaitingQueueUser(corpId, openKfId, wxCpKfMsgItem.getServicerUserId(), corpKfAccountSessionConfig);
|
|
|
- }
|
|
|
- }
|
|
|
- //转接会话
|
|
|
- String newServicerUserid = wxCpKfMsgItem.getNewServicerUserid();
|
|
|
- if (StrUtil.isNotEmpty(newServicerUserid)) {
|
|
|
- //记录新的客服会话
|
|
|
- transCorpKfSessionToServicer(corpId, openKfId, newServicerUserid, wxCpKfMsgItem.getExternalUserId(), changeType, 3);
|
|
|
+ private void sessionStatusChange(String corpId, String openKfId, WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem, CorpKfAccountSessionConfig corpKfAccountSessionConfig) throws Exception {
|
|
|
+ CorpKfServicerSessionRecord corpKfServicerSessionRecord = corpKfServicerSessionRecordMapper.selectOne(Wrappers.lambdaQuery(CorpKfServicerSessionRecord.class)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getOpenKfId, openKfId)
|
|
|
+ .eq(CorpKfServicerSessionRecord::getMsgId, wxCpKfMsgItem.getMsgId())
|
|
|
+ .last("limit 1"));
|
|
|
+ Integer changeType = null;
|
|
|
+ if (corpKfServicerSessionRecord != null) {
|
|
|
+ WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
|
|
|
+ //变更类型,均为接待人员在企业微信客户端操作触发。1-从接待池接入会话 2-转接会话 3-结束会话 4-重新接入已结束/已转接会话
|
|
|
+ changeType = event.getChangeType();
|
|
|
+ //老会话已结束
|
|
|
+ if (changeType != 1) {
|
|
|
+ corpKfServicerSessionRecord.setServiceState(changeType == 3 ? 1 : 2);
|
|
|
+ //关闭
|
|
|
+ corpKfServicerSessionRecord.setCloseTime(DateTime.now());
|
|
|
+ corpKfServicerSessionRecordMapper.updateById(corpKfServicerSessionRecord);
|
|
|
+ //优先分配等待池中的用户
|
|
|
+ assignWaitingQueueUser(corpId, openKfId, wxCpKfMsgItem.getServicerUserId(), corpKfAccountSessionConfig);
|
|
|
}
|
|
|
}
|
|
|
+ //转接会话
|
|
|
+ String newServicerUserid = wxCpKfMsgItem.getNewServicerUserid();
|
|
|
+ if (StrUtil.isNotEmpty(newServicerUserid)) {
|
|
|
+ //记录新的客服会话
|
|
|
+ transCorpKfSessionToServicer(corpId, openKfId, newServicerUserid, wxCpKfMsgItem.getExternalUserId(), changeType, 3);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Transactional(rollbackFor = Throwable.class)
|
|
|
@@ -790,112 +774,109 @@ public class CorpServiceImpl implements CorpService {
|
|
|
/**
|
|
|
* enter_session 会话事件
|
|
|
*/
|
|
|
- public void enterSessionEvent(CorpKfAccount corpKfAccount, CorpKfAccountSessionConfig corpKfAccountSessionConfig, String corpId, List<WxCpKfMsgListResp.WxCpKfMsgItem> enterSessionList) throws Exception {
|
|
|
+ public void enterSessionEvent(CorpKfAccount corpKfAccount, CorpKfAccountSessionConfig corpKfAccountSessionConfig, String corpId, WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem) throws Exception {
|
|
|
String openKfId = corpKfAccount.getOpenKfId();
|
|
|
- if (enterSessionList != null && enterSessionList.size() > 0) {
|
|
|
- WxCpKfMsgListResp.WxCpKfMsgItem wxCpKfMsgItem = enterSessionList.get(enterSessionList.size() - 1);
|
|
|
- DateTime sendTime = DateTime.of(wxCpKfMsgItem.getSendTime() * 1000);
|
|
|
- WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
|
|
|
- String welcomeCode = event.getWelcomeCode();
|
|
|
- //如果满足发送欢迎语条件(条件为:用户在过去48小时里未收过欢迎语,且未向客服发过消息),会返回该字段。
|
|
|
- //可用该welcome_code调用发送事件响应消息接口给客户发送欢迎语。
|
|
|
- if (StrUtil.isNotEmpty(welcomeCode)) {
|
|
|
- WxCorpKfMsgSendRequest wxCpKfMsgSendRequest = new WxCorpKfMsgSendRequest();
|
|
|
- wxCpKfMsgSendRequest.setMsgType("text");
|
|
|
- wxCpKfMsgSendRequest.setCode(welcomeCode);
|
|
|
- WxCorpKfMsgSendRequest.WxCpKfTextMsg textMsg = new WxCorpKfMsgSendRequest.WxCpKfTextMsg();
|
|
|
- if (corpKfAccountSessionConfig != null && StrUtil.isNotEmpty(corpKfAccountSessionConfig.getWelcomeContent())) {
|
|
|
- textMsg.setContent(corpKfAccountSessionConfig.getWelcomeContent());
|
|
|
- wxCpKfMsgSendRequest.setText(textMsg);
|
|
|
- wxCpKfMsgSendRequest.setToUser(welcomeCode);
|
|
|
- wxCpKfMsgSendRequest.setOpenKfid(event.getOpenKfid());
|
|
|
- try {
|
|
|
- wxCorpOps.sendMsgOnEvent(corpId, wxCpKfMsgSendRequest);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("发送微信客服欢迎语失败:{}", StringUtil.getErrorText(e));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- //用户是否已有会话
|
|
|
- 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;
|
|
|
- }
|
|
|
- //是否设置非值班提示
|
|
|
- if (corpKfAccountSessionConfig != null && StrUtil.isNotEmpty(corpKfAccountSessionConfig.getNoDutyTips())) {
|
|
|
- DateTime now = DateTime.now();
|
|
|
- String thisHourDate = DateUtil.format(now, "HH:mm");
|
|
|
- //星期天为1
|
|
|
- int dayOfWeek = DateUtil.dayOfWeek(now);
|
|
|
- //是否值班期
|
|
|
- Integer dutyHourCount = corpKfAccountFollowMapper.selectCount(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
|
|
|
- .eq(CorpKfAccountFollow::getOpenKfId, openKfId)
|
|
|
- .le(CorpKfAccountFollow::getStartTime, thisHourDate)
|
|
|
- .ge(CorpKfAccountFollow::getEndTime, thisHourDate)
|
|
|
- .apply(String.format(" JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek)));
|
|
|
- //非值班时间 发送通知
|
|
|
- if (dutyHourCount == 0) {
|
|
|
- //非值班时间 移入等待池并发送进入等待池消息
|
|
|
- log.info("当前客服账号:{}处于非值班时间:{},将客服:{}移入等待池", openKfId, thisHourDate, event.getExternalUserId());
|
|
|
- String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
- sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
|
|
|
- moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
|
|
|
- return;
|
|
|
+ DateTime sendTime = DateTime.of(wxCpKfMsgItem.getSendTime() * 1000);
|
|
|
+ WxCpKfEventMsg event = wxCpKfMsgItem.getEvent();
|
|
|
+ String welcomeCode = event.getWelcomeCode();
|
|
|
+ //如果满足发送欢迎语条件(条件为:用户在过去48小时里未收过欢迎语,且未向客服发过消息),会返回该字段。
|
|
|
+ //可用该welcome_code调用发送事件响应消息接口给客户发送欢迎语。
|
|
|
+ if (StrUtil.isNotEmpty(welcomeCode)) {
|
|
|
+ WxCorpKfMsgSendRequest wxCpKfMsgSendRequest = new WxCorpKfMsgSendRequest();
|
|
|
+ wxCpKfMsgSendRequest.setMsgType("text");
|
|
|
+ wxCpKfMsgSendRequest.setCode(welcomeCode);
|
|
|
+ WxCorpKfMsgSendRequest.WxCpKfTextMsg textMsg = new WxCorpKfMsgSendRequest.WxCpKfTextMsg();
|
|
|
+ if (corpKfAccountSessionConfig != null && StrUtil.isNotEmpty(corpKfAccountSessionConfig.getWelcomeContent())) {
|
|
|
+ textMsg.setContent(corpKfAccountSessionConfig.getWelcomeContent());
|
|
|
+ wxCpKfMsgSendRequest.setText(textMsg);
|
|
|
+ wxCpKfMsgSendRequest.setToUser(welcomeCode);
|
|
|
+ wxCpKfMsgSendRequest.setOpenKfid(event.getOpenKfid());
|
|
|
+ try {
|
|
|
+ wxCorpOps.sendMsgOnEvent(corpId, wxCpKfMsgSendRequest);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("发送微信客服欢迎语失败:{}", StringUtil.getErrorText(e));
|
|
|
}
|
|
|
}
|
|
|
- //获取接待人员列表
|
|
|
- CorpKfServicerResp corpKfServicerResp = wxCorpOps.getKfServicerList(corpId, openKfId);
|
|
|
- List<CorpKfServicerResp.CorpKfServicer> servicerList = corpKfServicerResp.getServicerList();
|
|
|
- //目前值班客服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)) {
|
|
|
- if (corpKfAccountSessionConfig != null) {
|
|
|
- String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
- sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
|
|
|
- }
|
|
|
+ }
|
|
|
+ //用户是否已有会话
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ //是否设置非值班提示
|
|
|
+ if (corpKfAccountSessionConfig != null && StrUtil.isNotEmpty(corpKfAccountSessionConfig.getNoDutyTips())) {
|
|
|
+ DateTime now = DateTime.now();
|
|
|
+ String thisHourDate = DateUtil.format(now, "HH:mm");
|
|
|
+ //星期天为1
|
|
|
+ int dayOfWeek = DateUtil.dayOfWeek(now);
|
|
|
+ //是否值班期
|
|
|
+ Integer dutyHourCount = corpKfAccountFollowMapper.selectCount(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
|
|
|
+ .eq(CorpKfAccountFollow::getOpenKfId, openKfId)
|
|
|
+ .le(CorpKfAccountFollow::getStartTime, thisHourDate)
|
|
|
+ .ge(CorpKfAccountFollow::getEndTime, thisHourDate)
|
|
|
+ .apply(String.format(" JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek)));
|
|
|
+ //非值班时间 发送通知
|
|
|
+ if (dutyHourCount == 0) {
|
|
|
+ //非值班时间 移入等待池并发送进入等待池消息
|
|
|
+ log.info("当前客服账号:{}处于非值班时间:{},将客服:{}移入等待池", openKfId, thisHourDate, event.getExternalUserId());
|
|
|
+ String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
+ sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
|
|
|
moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
|
|
|
return;
|
|
|
}
|
|
|
- //是否有空闲接待人员
|
|
|
- List<CorpKfServicerDto> corpKfServicerDtos = corpKfServicerSessionRecordMapper.getAvailableServicer(openKfId);
|
|
|
- //暂无分配会话 初始化
|
|
|
- if (CollUtil.isEmpty(corpKfServicerDtos)) {
|
|
|
- //随机分配一个客服
|
|
|
- CorpKfServicerResp.CorpKfServicer corpKfServicer = corpKfServicers.get(RandomUtil.randomInt(corpKfServicers.size()));
|
|
|
- //变更会话状态
|
|
|
- transCorpKfSessionToServicer(corpId, openKfId, corpKfServicer.getUserid(), event.getExternalUserId(), null, 3);
|
|
|
- return;
|
|
|
+ }
|
|
|
+ //获取接待人员列表
|
|
|
+ CorpKfServicerResp corpKfServicerResp = wxCorpOps.getKfServicerList(corpId, openKfId);
|
|
|
+ List<CorpKfServicerResp.CorpKfServicer> servicerList = corpKfServicerResp.getServicerList();
|
|
|
+ //目前值班客服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;
|
|
|
}
|
|
|
- //筛选符合条件的客服
|
|
|
- //默认接入最少的优先分配 接待人最少的在集合前面
|
|
|
- //不超过最多接待人数
|
|
|
- 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)) {
|
|
|
+ return false;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ //客服是否已经开始值班
|
|
|
+ //没有值班人员 接入等待池
|
|
|
+ if (CollUtil.isEmpty(corpKfServicers)) {
|
|
|
+ if (corpKfAccountSessionConfig != null) {
|
|
|
String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
|
|
|
- //未有可接待的客服 移入等待池并发送进入等待池消息
|
|
|
- moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
|
|
|
- return;
|
|
|
}
|
|
|
- //选择第一个分配接待
|
|
|
- CorpKfServicerDto corpKfServicerDto = filterKfCs.get(0);
|
|
|
+ moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //是否有空闲接待人员
|
|
|
+ List<CorpKfServicerDto> corpKfServicerDtos = corpKfServicerSessionRecordMapper.getAvailableServicer(openKfId);
|
|
|
+ //暂无分配会话 初始化
|
|
|
+ if (CollUtil.isEmpty(corpKfServicerDtos)) {
|
|
|
+ //随机分配一个客服
|
|
|
+ CorpKfServicerResp.CorpKfServicer corpKfServicer = corpKfServicers.get(RandomUtil.randomInt(corpKfServicers.size()));
|
|
|
//变更会话状态
|
|
|
- transCorpKfSessionToServicer(corpId, openKfId, corpKfServicerDto.getServicerUserid(), event.getExternalUserId(), null, 3);
|
|
|
+ transCorpKfSessionToServicer(corpId, openKfId, corpKfServicer.getUserid(), event.getExternalUserId(), null, 3);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //筛选符合条件的客服
|
|
|
+ //默认接入最少的优先分配 接待人最少的在集合前面
|
|
|
+ //不超过最多接待人数
|
|
|
+ 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)) {
|
|
|
+ String queueTips = corpKfAccountSessionConfig.getQueueTips();
|
|
|
+ sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
|
|
|
+ //未有可接待的客服 移入等待池并发送进入等待池消息
|
|
|
+ moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
|
|
|
+ return;
|
|
|
}
|
|
|
+ //选择第一个分配接待
|
|
|
+ CorpKfServicerDto corpKfServicerDto = filterKfCs.get(0);
|
|
|
+ //变更会话状态
|
|
|
+ transCorpKfSessionToServicer(corpId, openKfId, corpKfServicerDto.getServicerUserid(), event.getExternalUserId(), null, 3);
|
|
|
}
|
|
|
|
|
|
/**
|