zoujiajian 1 an în urmă
părinte
comite
0a1a3cd8d5

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/kf/WxCorpKfMsgSendRequest.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.kf;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -10,6 +11,7 @@ import lombok.NoArgsConstructor;
  */
 @NoArgsConstructor
 @Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class WxCorpKfMsgSendRequest {
   /**
    * (发送欢迎语等事件响应消息) 事件响应消息对应的code。通过事件回调下发,仅可使用一次。

+ 8 - 1
netflix-service/src/main/java/com/cyksj/service/corp/WxCorpOps.java

@@ -230,7 +230,7 @@ public interface WxCorpOps {
 	/**
 	 * 变更微信客服会话状态
 	 */
-	void transCorpKfSessionToServicer(String toUserName, String openKfId, String userid, String externalUserId) throws Exception;
+	void transCorpKfSessionToServicer(String toUserName, String openKfId, String userid, String externalUserId, Integer serviceState) throws Exception;
 
 	/**
 	 * 发送满意度调查msg
@@ -253,4 +253,11 @@ public interface WxCorpOps {
 	 * 添加接待人员
 	 */
 	void addCorpKfServicer(String openKfId, Set<String> dutyFollowIds) throws Exception;
+
+	/**
+	 * 发送文本消息
+	 */
+	void sendTextMsg(String corpId, WxCorpKfMsgSendRequest wxCpKfMsgSendRequest) throws Exception;
+
+	Integer getCorpKfSessionStatus(String corpId, String openKfId, String externalUserid) throws Exception;
 }

+ 51 - 20
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpServiceImpl.java

@@ -617,7 +617,7 @@ public class CorpServiceImpl implements CorpService {
 		//同步客服聊天记录
 		syncChatMsg(openKfId, mergedMsgs);
 		//同步满意度
-		syncSessionSatisfaction(openKfId, textList);
+		syncSessionSatisfaction(openKfId, textList, corpId, corpKfAccountSessionConfig);
 		corpKfAccountSyncMsgProgress.setNextCursor(cursor);
 		//同步信息
 		while (wxCpKfMsgListResp.getHasMore() == 1) {
@@ -625,7 +625,7 @@ public class CorpServiceImpl implements CorpService {
 		}
 	}
 
-	private void syncSessionSatisfaction(String openKfId, List<WxCpKfMsgListResp.WxCpKfMsgItem> textList) {
+	private void syncSessionSatisfaction(String openKfId, List<WxCpKfMsgListResp.WxCpKfMsgItem> textList, String corpId, CorpKfAccountSessionConfig corpKfAccountSessionConfig) throws Exception {
 		if (textList == null) {
 			return;
 		}
@@ -633,7 +633,7 @@ public class CorpServiceImpl implements CorpService {
 		for (WxCpKfMsgListResp.WxCpKfMsgItem item : textList) {
 			WxCorpTextMsg text = item.getText();
 			//自定义菜单id
-			if (text.getMenu_id()!=null) {
+			if (text.getMenu_id() != null) {
 				//满意
 				if ("101".equals(text.getMenu_id())) {
 					satisfaction = 1;
@@ -653,6 +653,20 @@ public class CorpServiceImpl implements CorpService {
 							.eq(CorpKfServicerSessionRecord::getMsgId, item.getMsgId()));
 				}
 			}
+			try {
+				//查询用户是否有会话 无会话发文本消息 分配会话
+				Integer state = wxCorpOps.getCorpKfSessionStatus(corpId, openKfId, item.getExternalUserId());
+				if (state == 0) {
+					//接入等待池 分配会话
+					if (corpKfAccountSessionConfig != null) {
+						String queueTips = corpKfAccountSessionConfig.getQueueTips();
+						sendCorpKfTextTips(corpId, item.getExternalUserId(), openKfId, queueTips);
+					}
+					moveWaitingQueue(corpId, openKfId, item.getExternalUserId());
+				}
+			} catch (Exception e) {
+
+			}
 		}
 	}
 
@@ -706,7 +720,7 @@ public class CorpServiceImpl implements CorpService {
 			String newServicerUserid = wxCpKfMsgItem.getNewServicerUserid();
 			if (StrUtil.isNotEmpty(newServicerUserid)) {
 				//记录新的客服会话
-				transCorpKfSessionToServicer(corpId, openKfId, newServicerUserid, wxCpKfMsgItem.getExternalUserId(), changeType);
+				transCorpKfSessionToServicer(corpId, openKfId, newServicerUserid, wxCpKfMsgItem.getExternalUserId(), changeType, 3);
 			}
 		}
 	}
@@ -728,7 +742,7 @@ public class CorpServiceImpl implements CorpService {
 						.eq(CorpKfServicerSessionRecord::getServiceState, 0));
 				if (maxNum < corpKfAccountSessionConfig.getMaxNum()) {
 					//记录新的客服会话
-					transCorpKfSessionToServicer(corpId, openKfId, servicerUserid, externalUserid, null);
+					transCorpKfSessionToServicer(corpId, openKfId, servicerUserid, externalUserid, null, 3);
 					corpKfWaitingQueueUserMapper.deleteById(corpKfWaitingQueueUser.getId());
 				}
 			}
@@ -756,7 +770,11 @@ public class CorpServiceImpl implements CorpService {
 					wxCpKfMsgSendRequest.setText(textMsg);
 					wxCpKfMsgSendRequest.setToUser(welcomeCode);
 					wxCpKfMsgSendRequest.setOpenKfid(event.getOpenKfid());
-					wxCorpOps.sendMsgOnEvent(corpId, wxCpKfMsgSendRequest);
+					try {
+						wxCorpOps.sendMsgOnEvent(corpId, wxCpKfMsgSendRequest);
+					} catch (Exception e) {
+						log.error("发送微信客服欢迎语失败:{}", StringUtil.getErrorText(e));
+					}
 				}
 			}
 			//用户是否已有会话
@@ -771,7 +789,7 @@ public class CorpServiceImpl implements CorpService {
 			//是否设置非值班提示
 			if (corpKfAccountSessionConfig != null && StrUtil.isNotEmpty(corpKfAccountSessionConfig.getNoDutyTips())) {
 				DateTime now = DateTime.now();
-				String thisHourDate = DateUtil.format(now, "HH:mm:ss");
+				String thisHourDate = DateUtil.format(now, "HH:mm");
 				//星期天为1
 				int dayOfWeek = DateUtil.dayOfWeek(now);
 				//是否值班期
@@ -779,14 +797,14 @@ public class CorpServiceImpl implements CorpService {
 						.eq(CorpKfAccountFollow::getOpenKfId, openKfId)
 						.le(CorpKfAccountFollow::getStartTime, thisHourDate)
 						.ge(CorpKfAccountFollow::getEndTime, thisHourDate)
-						.apply(" and JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek));
+						.apply(String.format(" JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek)));
 				//非值班时间 发送通知
 				if (dutyHourCount == 0) {
 					//非值班时间 移入等待池并发送进入等待池消息
 					log.info("当前客服账号:{}处于非值班时间:{},将客服:{}移入等待池", openKfId, thisHourDate, event.getExternalUserId());
-					moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
 					String queueTips = corpKfAccountSessionConfig.getQueueTips();
 					sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
+					moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
 					return;
 				}
 			}
@@ -805,11 +823,11 @@ public class CorpServiceImpl implements CorpService {
 			//客服是否已经开始值班
 			//没有值班人员 接入等待池
 			if (CollUtil.isEmpty(corpKfServicers)) {
-				moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
 				if (corpKfAccountSessionConfig != null) {
 					String queueTips = corpKfAccountSessionConfig.getQueueTips();
 					sendCorpKfTextTips(corpId, event.getExternalUserId(), openKfId, queueTips);
 				}
+				moveWaitingQueue(corpId, openKfId, event.getExternalUserId());
 				return;
 			}
 			//是否有空闲接待人员
@@ -819,7 +837,7 @@ public class CorpServiceImpl implements CorpService {
 				//随机分配一个客服
 				CorpKfServicerResp.CorpKfServicer corpKfServicer = corpKfServicers.get(RandomUtil.randomInt(corpKfServicers.size()));
 				//变更会话状态
-				transCorpKfSessionToServicer(corpId, openKfId, corpKfServicer.getUserid(), event.getExternalUserId(), null);
+				transCorpKfSessionToServicer(corpId, openKfId, corpKfServicer.getUserid(), event.getExternalUserId(), null, 3);
 				return;
 			}
 			//筛选符合条件的客服
@@ -828,23 +846,25 @@ public class CorpServiceImpl implements CorpService {
 			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(corpId, openKfId, event.getExternalUserId());
 				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);
+			transCorpKfSessionToServicer(corpId, openKfId, corpKfServicerDto.getServicerUserid(), event.getExternalUserId(), null, 3);
 		}
 	}
 
 	/**
 	 * 变更用户会话状态
+	 * serviceState 0未处理 1由智能助手接待 2待接入池排队中 3由人工接待 4 已结束/未开始
+	 *
 	 */
-	private void transCorpKfSessionToServicer(String corpId, String openKfId, String userid, String externalUserId, Integer changeType) throws Exception {
+	private void transCorpKfSessionToServicer(String corpId, String openKfId, String userid, String externalUserId, Integer changeType, Integer serviceState) throws Exception {
 		try {
 			//记录接待人员会话
 			CorpKfServicerSessionRecord corpKfServicerSessionRecord = new CorpKfServicerSessionRecord();
@@ -855,7 +875,7 @@ public class CorpServiceImpl implements CorpService {
 			corpKfServicerSessionRecord.setChangeType(changeType);
 			corpKfServicerSessionRecordMapper.insert(corpKfServicerSessionRecord);
 			//调用微信客服接口 变更会话状态
-			wxCorpOps.transCorpKfSessionToServicer(corpId, openKfId, userid, externalUserId);
+			wxCorpOps.transCorpKfSessionToServicer(corpId, openKfId, userid, externalUserId, serviceState);
 		} catch (DuplicateKeyException e) {
 		}
 
@@ -868,6 +888,13 @@ public class CorpServiceImpl implements CorpService {
 		if (StrUtil.isEmpty(content)) {
 			return;
 		}
+		//查询会话状态
+		Integer state = wxCorpOps.getCorpKfSessionStatus(corpId, openKfId, externalUserid);
+		//0.未处理 1.人工智能接待 可调用api发送消息
+		if (state == null || state != 0 || state != 1) {
+			log.info("目前openKfId:{}用户eid:{}会话处于状态中state:{},无法发送消息", openKfId, externalUserid, state);
+			return;
+		}
 		WxCorpKfMsgSendRequest wxCpKfMsgSendRequest = new WxCorpKfMsgSendRequest();
 		wxCpKfMsgSendRequest.setMsgType("text");
 		wxCpKfMsgSendRequest.setToUser(externalUserid);
@@ -875,15 +902,19 @@ public class CorpServiceImpl implements CorpService {
 		WxCorpKfMsgSendRequest.WxCpKfTextMsg textMsg = new WxCorpKfMsgSendRequest.WxCpKfTextMsg();
 		textMsg.setContent(content);
 		wxCpKfMsgSendRequest.setText(textMsg);
-		wxCorpOps.sendMsgOnEvent(corpId, wxCpKfMsgSendRequest);
+		wxCorpOps.sendTextMsg(corpId, wxCpKfMsgSendRequest);
 	}
 
 	private void moveWaitingQueue(String corpId, String openKfId, String externalUserId) throws Exception {
 		CorpKfWaitingQueueUser corpKfWaitingQueueUser = new CorpKfWaitingQueueUser();
 		corpKfWaitingQueueUser.setOpenKfId(openKfId);
 		corpKfWaitingQueueUser.setExternalUserid(externalUserId);
-		corpKfWaitingQueueUserMapper.insert(corpKfWaitingQueueUser);
-		//移入等待池
-		wxCorpOps.moveWaitingQueue(corpId, openKfId, externalUserId);
+		try {
+			corpKfWaitingQueueUserMapper.insert(corpKfWaitingQueueUser);
+			//移入等待池
+			wxCorpOps.moveWaitingQueue(corpId, openKfId, externalUserId);
+		} catch (DuplicateKeyException e) {
+
+		}
 	}
 }

+ 70 - 2
netflix-service/src/main/java/com/cyksj/service/corp/impl/WxCorpOpsImpl.java

@@ -957,7 +957,7 @@ public class WxCorpOpsImpl implements WxCorpOps {
 	}
 
 	@Override
-	public void transCorpKfSessionToServicer(String corpId, String openKfId, String userid, String externalUserId) throws Exception {
+	public void transCorpKfSessionToServicer(String corpId, String openKfId, String userid, String externalUserId, Integer serviceState) throws Exception {
 		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/trans?access_token=" + getAccessToken(corpId);
 		JSONObject request = new JSONObject();
 		request.putOpt("open_kfid", openKfId);
@@ -984,7 +984,7 @@ public class WxCorpOpsImpl implements WxCorpOps {
 
 	@Override
 	public void sendSatisfactionMsg(String msgId) throws Exception {
-		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg_on_event?access_token=" + getAccessToken(yhlXWxCorpConfig.getCorpId());
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=" + getAccessToken(yhlXWxCorpConfig.getCorpId());
 		CorpKfSatisfactionMsg corpKfSatisfactionMsg = new CorpKfSatisfactionMsg();
 		corpKfSatisfactionMsg.setCode(msgId);
 		corpKfSatisfactionMsg.setMsgtype("msgtype");
@@ -1097,4 +1097,72 @@ public class WxCorpOpsImpl implements WxCorpOps {
 			throw BusinessRuntimeException.getInstance("添加接待人员信息错误: " + re.getStr("errmsg"));
 		}
 	}
+
+	@Override
+	public void sendTextMsg(String corpId, WxCorpKfMsgSendRequest request) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=" + getAccessToken(corpId);
+
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(request), IoKit.Charsets.UTF_8.getCharset()))
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("发送文本事件响应消息: " + res.body());
+		}
+
+		WxCpKfMsgSendResp resp = Jsons.parseObject(res.body(), WxCpKfMsgSendResp.class);
+		if (resp.getErrcode() != 0) {
+			throw BusinessRuntimeException.getInstance("发送文本事件响应消息错误: " + resp.getErrmsg());
+		}
+	}
+
+
+	@Override
+	public Integer getCorpKfSessionStatus(String corpId, String openKfId, String externalUserid) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/get?access_token=" + getAccessToken(corpId);
+		JSONObject jsonObject = new JSONObject();
+		jsonObject.putOpt("open_kfid", openKfId);
+		jsonObject.putOpt("external_userid", externalUserid);
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(jsonObject), IoKit.Charsets.UTF_8.getCharset()))
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("用户会话状态消息: " + res.body());
+		}
+		JSONObject re = Jsons.parseObject(res.body(), JSONObject.class);
+		if (re.getInt("errcode") != 0) {
+			throw BusinessRuntimeException.getInstance("添加接待人员信息错误: " + re.getStr("errmsg"));
+		}
+		return re.getInt("service_state");
+	}
+
+	public static void main(String[] args) throws Exception {
+		String accessToken = "cLKd5cAJOW_0OW2Dv0Lk91_cbYBhUrKDfk-DOwdf2395J6yxoshl9BEpVIq0s4vXunYLDA8IU6-fz8ZN4yZRAARFdXEhcS8Hi9LdXhjYLqD8fGtCr2AV7ZkXOGAMzbyWDbPUERRcERE9Zp3nWnIl4xS7IBJx3AHcujPVDyqxocKRrvtBP3Rv-7QH6yU81p-VF-AdteZMrCkLC_kjFiloQg";
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/service_state/get?access_token=" + accessToken;
+		JSONObject jsonObject = new JSONObject();
+		jsonObject.putOpt("open_kfid", "wkvj2DPQAAS0g4Ik06VjeqGL2VTUGggg");
+		jsonObject.putOpt("external_userid", "wmvj2DPQAAWBEnCK39MVr7EO3eoxIgg");
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(jsonObject), IoKit.Charsets.UTF_8.getCharset()))
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("用户会话状态消息: " + res.body());
+		}
+		JSONObject re = Jsons.parseObject(res.body(), JSONObject.class);
+		if (re.getInt("errcode") != 0) {
+			throw BusinessRuntimeException.getInstance("添加接待人员信息错误: " + re.getStr("errmsg"));
+		}
+		System.out.println(re.getInt("service_state"));
+	}
 }

+ 3 - 3
netflix-service/src/main/java/com/cyksj/service/corp/kf/impl/CorpKfServiceImpl.java

@@ -160,7 +160,7 @@ public class CorpKfServiceImpl implements CorpKfService {
 				.eq(CorpKfAccountFollow::getOpenKfId, openKfId)
 				.le(CorpKfAccountFollow::getStartTime, thisHourDate)
 				.ge(CorpKfAccountFollow::getEndTime, thisHourDate)
-				.apply(" and JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek));
+				.apply(String.format(String.format(" JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek))));
 		//无需值班
 		if (corpKfAccountFollows.isEmpty()) {
 			throw BusinessRuntimeException.getInstance("非值班时间");
@@ -203,7 +203,7 @@ public class CorpKfServiceImpl implements CorpKfService {
 				.eq(CorpKfAccountFollow::getOpenKfId, openKfId)
 				.le(CorpKfAccountFollow::getStartTime, thisHourDate)
 				.ge(CorpKfAccountFollow::getEndTime, thisHourDate)
-				.apply(" and JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek));
+				.apply(String.format(" JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek)));
 
 		if (corpKfAccountFollows.isEmpty()) {
 			return Lists.newArrayList();
@@ -297,7 +297,7 @@ public class CorpKfServiceImpl implements CorpKfService {
 		}
 		for (CorpKfServicerSessionRecord corpKfServicerSessionRecord : corpKfServicerSessionRecords) {
 			//调用微信客服接口 变更会话状态
-			wxCorpOps.transCorpKfSessionToServicer(corpId, corpKfServicerSessionRecord.getOpenKfId(), toFollowId, corpKfServicerSessionRecord.getExternalUserid());
+			wxCorpOps.transCorpKfSessionToServicer(corpId, corpKfServicerSessionRecord.getOpenKfId(), toFollowId, corpKfServicerSessionRecord.getExternalUserid(), 3);
 		}
 	}
 }