Ver Fonte

接待人员上下班

zoujiajian há 1 ano atrás
pai
commit
f1e0fae8b5

+ 21 - 0
netflix-dao/src/main/java/com/cyksj/model/request/CorpKfDutySetReq.java

@@ -0,0 +1,21 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfDutySetReq
+ * 创建者: JavaZou
+ * 创建时间:2025/1/3 17:44
+ */
+@Getter
+@Setter
+public class CorpKfDutySetReq {
+	private String openKfId;
+
+	/**
+	 * 1上班 1下班
+	 */
+	private Boolean status;
+}

+ 21 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CorpKfDutyServicersStatusView.java

@@ -0,0 +1,21 @@
+package com.cyksj.model.views;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfDutyServicers
+ * 创建者: JavaZou
+ * 创建时间:2025/1/3 17:30
+ */
+@Getter
+@Setter
+public class CorpKfDutyServicersStatusView {
+	private String nickname;
+
+	private Long cmsUserId;
+
+	//0未值班
+	private Integer status;
+}

+ 11 - 0
netflix-service/src/main/java/com/cyksj/service/corp/WxCorpOps.java

@@ -14,6 +14,7 @@ import com.cyksj.model.request.corp.message.WxCorpAgentMessage;
 import com.cyksj.model.response.corp.*;
 
 import java.util.List;
+import java.util.Set;
 
 /*
  *项目名: netflix
@@ -242,4 +243,14 @@ public interface WxCorpOps {
 	 * 获取微信客服账号链接
 	 */
 	String getUrl(String openKfId, String scene) throws Exception;
+
+	/**
+	 * 删除接待人员
+	 */
+	void delCorpKfServicer(String openKfId, List<String> delDutyFollowId) throws Exception;
+
+	/**
+	 * 添加接待人员
+	 */
+	void addCorpKfServicer(String openKfId, Set<String> dutyFollowIds) throws Exception;
 }

+ 46 - 5
netflix-service/src/main/java/com/cyksj/service/corp/impl/WxCorpOpsImpl.java

@@ -40,10 +40,7 @@ import java.io.File;
 import java.net.URLEncoder;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
 
 /*
  *项目名: netflix
@@ -82,7 +79,7 @@ public class WxCorpOpsImpl implements WxCorpOps {
 	@Override
 	public String getAccessToken(String corpId) throws Exception {
 		corpId = Optional.ofNullable(corpId).orElse(yhlXWxCorpConfig.getCorpId());
-		String accessToken = redisService.getStr(RedisKey.CORP_ACCESS_TOKEN_KEY + corpId);
+		String accessToken = "-FDM4JMpcGcupd99Hqf5I2Q-hN7TJp53e_AE3eLr-JeM2nHV2TvHG7tVa134p-vm1P-l6NxURDuuR9D8_J5R4GhYw2-Yig36HNg_14sS5gM6M_gldKmLttFjlUDuz39n7DhNbK3CYbLJxZHSPG_ZMmKdx6hsmrkld0IysGmpgnUTcQ457OJkZ1Vdf36htq88gvq-vpyeSj3LYV5USVtEog";
 		if (StringUtils.isNotBlank(accessToken)) {
 			return accessToken;
 		}
@@ -1056,4 +1053,48 @@ public class WxCorpOpsImpl implements WxCorpOps {
 		}
 		return re.getStr("url");
 	}
+
+	@Override
+	public void delCorpKfServicer(String openKfId, List<String> delDutyFollowId) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/servicer/del?access_token=" + getAccessToken(yhlXWxCorpConfig.getCorpId());
+		JSONObject params = new JSONObject();
+		params.putOpt("open_kfid", openKfId);
+		params.putOpt("userid_list", delDutyFollowId);
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(params), 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"));
+		}
+	}
+
+	@Override
+	public void addCorpKfServicer(String openKfId, Set<String> dutyFollowIds) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/kf/servicer/add?access_token=" + getAccessToken(yhlXWxCorpConfig.getCorpId());
+		JSONObject params = new JSONObject();
+		params.putOpt("open_kfid", openKfId);
+		params.putOpt("userid_list", dutyFollowIds);
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(Jsons.toJson(params), 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"));
+		}
+	}
 }

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

@@ -1,9 +1,9 @@
 package com.cyksj.service.corp.kf;
 
 import com.cyksj.model.entity.CorpKfAccount;
-import com.cyksj.model.entity.CorpKfAccountFollowDutyStatus;
 import com.cyksj.model.entity.CorpKfAccountSessionConfig;
 import com.cyksj.model.request.corp.kf.CorpKfDutyReq;
+import com.cyksj.model.views.CorpKfDutyServicersStatusView;
 
 import java.util.List;
 
@@ -24,9 +24,9 @@ public interface CorpKfService {
 
 	void setKfDuty(CorpKfDutyReq dutyReq);
 
-	void servicerCommute(long cmsUserId, String openKfId);
+	void servicerCommute(long cmsUserId, String openKfId, Boolean status) throws Exception;
 
-	List<CorpKfAccountFollowDutyStatus> getDutyFollowByOpenKfId(long cmsUserId, String openKfId) throws Exception;
+	List<CorpKfDutyServicersStatusView> getDutyFollowByOpenKfId(long cmsUserId, String openKfId) throws Exception;
 
 	String getUrl(String openKfId, String scene) throws Exception;
 }

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

@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.config.corp.YHLXWxCorpConfig;
 import com.cyksj.mapper.corp.CorpFollowMapper;
@@ -12,12 +13,13 @@ import com.cyksj.mapper.corp.kf.CorpKfAccountFollowDutyStatusMapper;
 import com.cyksj.mapper.corp.kf.CorpKfAccountFollowMapper;
 import com.cyksj.mapper.corp.kf.CorpKfAccountMapper;
 import com.cyksj.mapper.corp.kf.CorpKfAccountSessionConfigMapper;
-import com.cyksj.model.entity.*;
-import com.cyksj.model.kf.WxCpKfAccountAdd;
-import com.cyksj.model.kf.WxCpKfAccountAddResp;
-import com.cyksj.model.kf.WxCpKfAccountDel;
-import com.cyksj.model.kf.WxCpKfAccountUpd;
+import com.cyksj.model.entity.CorpFollow;
+import com.cyksj.model.entity.CorpKfAccount;
+import com.cyksj.model.entity.CorpKfAccountFollow;
+import com.cyksj.model.entity.CorpKfAccountSessionConfig;
+import com.cyksj.model.kf.*;
 import com.cyksj.model.request.corp.kf.CorpKfDutyReq;
+import com.cyksj.model.views.CorpKfDutyServicersStatusView;
 import com.cyksj.service.corp.WxCorpOps;
 import com.cyksj.service.corp.kf.CorpKfService;
 import com.cyksj.service.mange.cms.service.CmsUserService;
@@ -25,9 +27,11 @@ import com.google.common.collect.Lists;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * 项目名: yhlxj2
@@ -95,13 +99,19 @@ public class CorpKfServiceImpl implements CorpKfService {
 	}
 
 	@Override
-	public void setKfAccountRuleOrAutoReply(CorpKfAccountSessionConfig CorpKfAccountSessionConfig) {
-		Long id = CorpKfAccountSessionConfig.getId();
+	public void setKfAccountRuleOrAutoReply(CorpKfAccountSessionConfig corpKfAccountSessionConfig) {
+		CorpKfAccountSessionConfig db = corpKfAccountSessionConfigMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountSessionConfig.class)
+				.eq(CorpKfAccountSessionConfig::getOpenKfId, corpKfAccountSessionConfig.getOpenKfId())
+				.last("limit 1"));
+		if (db != null) {
+			corpKfAccountSessionConfig.setId(db.getId());
+		}
+		Long id = corpKfAccountSessionConfig.getId();
 		if (id == null) {
-			corpKfAccountSessionConfigMapper.insert(CorpKfAccountSessionConfig);
+			corpKfAccountSessionConfigMapper.insert(corpKfAccountSessionConfig);
 			return;
 		}
-		corpKfAccountSessionConfigMapper.updateById(CorpKfAccountSessionConfig);
+		corpKfAccountSessionConfigMapper.updateById(corpKfAccountSessionConfig);
 	}
 
 	@Override
@@ -120,24 +130,74 @@ public class CorpKfServiceImpl implements CorpKfService {
 	}
 
 	@Override
-	public void servicerCommute(long cmsUserId, String openKfId) {
-		String thisHourDate = DateUtil.format(DateTime.now(), "HH:mm:ss");
-		corpKfAccountFollowMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
+	public void servicerCommute(long cmsUserId, String openKfId, Boolean status) throws Exception {
+		CorpKfServicerResp corpKfServicerResp = wxCorpOps.getKfServicerList(yhlxWxCorpConfig.getCorpId(), openKfId);
+		List<String> followIds = corpFollowMapper.selectList(Wrappers.lambdaQuery(CorpFollow.class)
+				.eq(CorpFollow::getCmsUserId, cmsUserId)).stream().map(CorpFollow::getUserid).collect(Collectors.toList());
+		if (followIds.isEmpty()) {
+			throw BusinessRuntimeException.getInstance("未关联企业微信成员");
+		}
+		//接待人员列表
+		List<CorpKfServicerResp.CorpKfServicer> servicerList = corpKfServicerResp.getServicerList();
+		List<String> delDutyFollowId = new ArrayList<>();
+		//下班
+		if (!status) {
+			for (CorpKfServicerResp.CorpKfServicer servicer : servicerList) {
+				if (servicer.getUserid() != null) {
+					if (followIds.contains(servicer.getUserid())) {
+						delDutyFollowId.add(servicer.getUserid());
+					}
+				}
+			}
+			if (!delDutyFollowId.isEmpty()) {
+				wxCorpOps.delCorpKfServicer(openKfId, delDutyFollowId);
+			}
+			return;
+		}
+		//上班
+		DateTime now = DateTime.now();
+		String thisHourDate = DateUtil.format(now, "HH:mm:ss");
+		//星期天为1
+		int dayOfWeek = DateUtil.dayOfWeek(now);
+		//是否值班期
+		List<CorpKfAccountFollow> corpKfAccountFollows = corpKfAccountFollowMapper.selectList(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
 				.eq(CorpKfAccountFollow::getOpenKfId, openKfId)
 				.le(CorpKfAccountFollow::getStartTime, thisHourDate)
 				.ge(CorpKfAccountFollow::getEndTime, thisHourDate)
-				.apply(""));
-		CorpKfAccountFollowDutyStatus corpKfAccountFollowDutyStatus = corpKfAccountFollowDutyStatusMapper.selectOne(Wrappers.lambdaQuery(CorpKfAccountFollowDutyStatus.class)
-				.eq(CorpKfAccountFollowDutyStatus::getCmsUserId, cmsUserId)
-				.eq(CorpKfAccountFollowDutyStatus::getOpenKfId, openKfId)
-				.last("limit 1"));
-		if (corpKfAccountFollowDutyStatus == null) {
-			corpKfAccountFollowDutyStatus = new CorpKfAccountFollowDutyStatus();
+				.apply(" and JSON_CONTAINS(duty_week,'\"%s\"')", dayOfWeek));
+		//无需值班
+		if (corpKfAccountFollows.isEmpty()) {
+			throw BusinessRuntimeException.getInstance("非值班时间");
 		}
+		//目前时间段需要值班的客服
+		Set<String> thisHourDutyFollows = new HashSet<>();
+		for (CorpKfAccountFollow corpKfAccountFollow : corpKfAccountFollows) {
+			thisHourDutyFollows.addAll(Jsons.parseList(corpKfAccountFollow.getUserIdList(), String.class));
+		}
+		String dutyFollowId = null;
+		for (String followId : followIds) {
+			if (thisHourDutyFollows.contains(followId)) {
+				dutyFollowId = followId;
+				break;
+			}
+		}
+		if (dutyFollowId == null) {
+			throw BusinessRuntimeException.getInstance("无关联企业成员");
+		}
+		Set<String> dutyFollowIds = new HashSet<>();
+		for (CorpKfServicerResp.CorpKfServicer corpKfServicer : servicerList) {
+			String userid = corpKfServicer.getUserid();
+			if (userid != null) {
+				dutyFollowIds.add(userid);
+			}
+		}
+		dutyFollowIds.add(dutyFollowId);
+		wxCorpOps.addCorpKfServicer(openKfId, dutyFollowIds);
 	}
 
 	@Override
-	public List<CorpKfAccountFollowDutyStatus> getDutyFollowByOpenKfId(long cmsUserId, String openKfId) throws Exception {
+	public List<CorpKfDutyServicersStatusView> getDutyFollowByOpenKfId(long cmsUserId, String openKfId) throws Exception {
+		Boolean isRoot = cmsUserService.isRootRole(cmsUserId);
 		DateTime now = DateTime.now();
 		String thisHourDate = DateUtil.format(now, "HH:mm:ss");
 		//星期天为1
@@ -153,23 +213,46 @@ public class CorpKfServiceImpl implements CorpKfService {
 			return Lists.newArrayList();
 		}
 		//目前时间段需要值班的客服
-		Set<String> follows = new HashSet<>();
+		Set<String> thisHourDutyFollows = new HashSet<>();
 		for (CorpKfAccountFollow corpKfAccountFollow : corpKfAccountFollows) {
-			follows.addAll(Jsons.parseList(corpKfAccountFollow.getUserIdList(), String.class));
+			thisHourDutyFollows.addAll(Jsons.parseList(corpKfAccountFollow.getUserIdList(), String.class));
 		}
-		List<CorpFollow> cmsUserFollows = corpFollowMapper.selectList(Wrappers.lambdaQuery(CorpFollow.class)
-				.in(CorpFollow::getUserid, follows)
-				.eq(CorpFollow::getCmsUserId, cmsUserId));
-
-
-
-		LambdaQueryWrapper<CorpKfAccountFollowDutyStatus> queryWrapper = Wrappers.lambdaQuery(CorpKfAccountFollowDutyStatus.class)
-				.eq(CorpKfAccountFollowDutyStatus::getOpenKfId, openKfId);
-		if (!cmsUserService.isRootRole(cmsUserId)) {
-			queryWrapper.eq(CorpKfAccountFollowDutyStatus::getCmsUserId, cmsUserId);
+		CorpKfServicerResp corpKfServicerResp = wxCorpOps.getKfServicerList(yhlxWxCorpConfig.getCorpId(), openKfId);
+		List<CorpKfServicerResp.CorpKfServicer> servicerList = corpKfServicerResp.getServicerList();
+		//目前值班客服id
+		List<String> corpKfDutyServiceIds = new ArrayList<>();
+		for (CorpKfServicerResp.CorpKfServicer servicer : servicerList) {
+			if (servicer.getUserid() != null && servicer.getStatus() == 0) {
+				corpKfDutyServiceIds.add(servicer.getUserid());
+			}
+		}
+		List<CorpKfDutyServicersStatusView> views = new ArrayList<>();
+		CorpKfDutyServicersStatusView corpKfDutyServicersStatusView = null;
+		//查看目前时间段值班人员情况
+		for (String thisHourDutyFollow : thisHourDutyFollows) {
+			LambdaQueryWrapper<CorpFollow> wrapper = Wrappers.lambdaQuery(CorpFollow.class)
+					.eq(CorpFollow::getUserid, thisHourDutyFollow);
+			//非root 只查询当前用户当前时间段值班情况
+			if (!isRoot) {
+				wrapper.eq(CorpFollow::getCmsUserId, cmsUserId);
+			}
+			CorpFollow corpFollow = corpFollowMapper.selectOne(wrapper
+					.last("limit 1"));
+			if (corpFollow == null) {
+				continue;
+			}
+			corpKfDutyServicersStatusView = new CorpKfDutyServicersStatusView();
+			corpKfDutyServicersStatusView.setNickname(corpFollow.getName());
+			corpKfDutyServicersStatusView.setCmsUserId(corpFollow.getCmsUserId());
+			if (!corpKfDutyServiceIds.contains(thisHourDutyFollow)) {
+				//未值班
+				corpKfDutyServicersStatusView.setStatus(0);
+			} else {
+				corpKfDutyServicersStatusView.setStatus(1);
+			}
+			views.add(corpKfDutyServicersStatusView);
 		}
-		List<CorpKfAccountFollowDutyStatus> dutyStatuses = corpKfAccountFollowDutyStatusMapper.selectList(queryWrapper);
-		return dutyStatuses;
+		return views;
 	}
 
 	@Override

+ 9 - 4
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/wxkf/CorpKfController.java

@@ -2,11 +2,15 @@ package com.cyksj.web.controller.manage.corp.wxkf;
 
 import cn.dev33.satoken.stp.StpUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.annotation.Log;
 import com.cyksj.dto.Result;
+import com.cyksj.enums.BusinessType;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.corp.CorpFollowMapper;
 import com.cyksj.model.entity.*;
+import com.cyksj.model.request.CorpKfDutySetReq;
 import com.cyksj.model.request.corp.kf.CorpKfDutyReq;
+import com.cyksj.model.views.CorpKfDutyServicersStatusView;
 import com.cyksj.model.views.CorpKfServicerSessionRecordView;
 import com.cyksj.service.corp.kf.CorpKfService;
 import com.cyksj.service.mange.cms.service.CmsUserService;
@@ -182,9 +186,10 @@ public class CorpKfController {
 	 * 客服上下班
 	 */
 	@PutMapping("/servicer/commute/{openKfId}")
-	public Result<String> servicerCommute(@PathVariable String openKfId) {
+	@Log(module = "微信客服/客服上下班", businessType = BusinessType.PUT, isSaveRequestData = true)
+	public Result<String> servicerCommute(@RequestBody CorpKfDutySetReq corpKfDutySetReq) throws Exception {
 		long cmsUserId = StpUtil.getLoginIdAsLong();
-		corpKfService.servicerCommute(cmsUserId, openKfId);
+		corpKfService.servicerCommute(cmsUserId, corpKfDutySetReq.getOpenKfId(), corpKfDutySetReq.getStatus());
 		return GatewayResponse.SUCCESS.newBuilder().toResult();
 	}
 
@@ -192,9 +197,9 @@ public class CorpKfController {
 	 * 目前值班人员变化
 	 */
 	@GetMapping("/get/duty/{openKfId}")
-	public Result<List<CorpKfAccountFollowDutyStatus>> getDutyFollowByOpenKfId(@PathVariable String openKfId) throws Exception {
+	public Result<List<CorpKfDutyServicersStatusView>> getDutyFollowByOpenKfId(@PathVariable String openKfId) throws Exception {
 		long cmsUserId = StpUtil.getLoginIdAsLong();
-		List<CorpKfAccountFollowDutyStatus> dutyStatuses= corpKfService.getDutyFollowByOpenKfId(cmsUserId, openKfId);
+		List<CorpKfDutyServicersStatusView> dutyStatuses= corpKfService.getDutyFollowByOpenKfId(cmsUserId, openKfId);
 		return GatewayResponse.SUCCESS.newBuilder().toResult(dutyStatuses);
 	}