Просмотр исходного кода

微信客服会话通过用户id查询;客服变更记录

zoujiajian 1 год назад
Родитель
Сommit
02bed5bb18

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/kf/CorpKfFollowChangeRecordMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.corp.kf;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpKfFollowChangeRecord;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: CorpKfFollowChangeRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/1/15 11:20
+ */
+public interface CorpKfFollowChangeRecordMapper extends BaseMapper<CorpKfFollowChangeRecord> {
+}

+ 72 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/CorpKfChangeFollowLogDto.java

@@ -0,0 +1,72 @@
+package com.cyksj.model.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbIgnore;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: CorpKfChangeFollowLogDto
+ * 创建者: JavaZou
+ * 创建时间:2025/1/15 16:37
+ */
+@Getter
+@Setter
+public class CorpKfChangeFollowLogDto {
+	/**
+	 * 值班星期
+	 * 1星期天 2星期一 ....
+	 */
+	private Integer dutyWeek;
+
+	@DbIgnore
+	@TableField(exist = false)
+	private List<String> beforeSelect;
+
+	@DbIgnore
+	@TableField(exist = false)
+	private List<String> afterSelect;
+
+
+	public String toChangeString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append(getDutyWeekName(this.dutyWeek));
+		if (beforeSelect.size() > 0) {
+			sb.append(" - 移除 - ");
+			String beforeCollect = beforeSelect.stream().collect(Collectors.joining("、"));
+			sb.append(beforeCollect);
+		}
+
+		if (afterSelect.size() > 0) {
+			sb.append(" - 增加 - ");
+			String afterCollect = afterSelect.stream().collect(Collectors.joining("、"));
+			sb.append(afterCollect);
+		}
+		return sb.toString();
+	}
+
+	public String getDutyWeekName(Integer week) {
+		switch (week) {
+			case 1:
+				return "周日";
+			case 2:
+				return "周一";
+			case 3:
+				return "周二";
+			case 4:
+				return "周三";
+			case 5:
+				return "周四";
+			case 6:
+				return "周五";
+			case 7:
+				return "周六";
+			default:
+				return null;
+		}
+	}
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpKfFollowChangeRecord.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj
+ * 文件名: CorpKfFollowChangeRecord
+ * 创建者: JavaZou
+ * 创建时间:2025/1/15 11:18
+ */
+@Getter
+@Setter
+public class CorpKfFollowChangeRecord extends BaseEntity{
+	private String openKfId;
+
+	private String preValue;
+
+	private String backValue;
+
+	private String changeStr;
+
+	private String operator;
+}

+ 2 - 0
netflix-dao/src/main/java/com/cyksj/model/request/corp/kf/CorpKfDutyReq.java

@@ -28,4 +28,6 @@ public class CorpKfDutyReq {
 	 * 删除ids
 	 */
 	private List<Long> delIds;
+
+	private Long adminId;
 }

+ 3 - 4
netflix-dao/src/main/java/com/cyksj/model/views/CorpKfUserChatRecordView.java

@@ -1,6 +1,5 @@
 package com.cyksj.model.views;
 
-import com.baomidou.mybatisplus.annotation.TableField;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Getter;
@@ -38,7 +37,6 @@ public class CorpKfUserChatRecordView {
 	 * 成员名称
 	 */
 	@DbField("cf.name")
-	@TableField(exist = false)
 	private String followName;
 
 	@DbField("cr.external_userid")
@@ -48,11 +46,12 @@ public class CorpKfUserChatRecordView {
 	 * 用户昵称
 	 */
 	@DbField("cu.nickname")
-	@TableField(exist = false)
 	private String name;
 
+	@DbField("cu.unionid")
+	private String unionid;
+
 	@DbField("cu.avatar")
-	@TableField(exist = false)
 	private String avatar;
 
 	/**

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

@@ -14,13 +14,17 @@ import com.cyksj.config.corp.YHLXWxCorpConfig;
 import com.cyksj.mapper.corp.CorpFollowMapper;
 import com.cyksj.mapper.corp.kf.*;
 import com.cyksj.mapper.manage.cms.CmsUserMapper;
+import com.cyksj.model.dto.CorpKfChangeFollowLogDto;
 import com.cyksj.model.entity.*;
 import com.cyksj.model.kf.*;
 import com.cyksj.model.request.corp.kf.CorpKfDutyReq;
 import com.cyksj.model.views.CorpKfDutyServicersStatusView;
+import com.cyksj.model.views.SysCorpFollowView;
 import com.cyksj.service.corp.WxCorpOps;
 import com.cyksj.service.corp.kf.CorpKfService;
 import com.cyksj.service.mange.cms.service.CmsUserService;
+import com.ejlchina.searcher.BeanSearcher;
+import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
@@ -54,6 +58,10 @@ public class CorpKfServiceImpl implements CorpKfService {
 
 	private final CmsUserMapper cmsUserMapper;
 
+	private final BeanSearcher beanSearcher;
+
+	private final CorpKfFollowChangeRecordMapper corpKfFollowChangeRecordMapper;
+
 	@Override
 	public void addKfAccount(CorpKfAccount corpKfAccount) throws Exception {
 		WxCpKfAccountAdd wxCpKfAccountAdd = new WxCpKfAccountAdd();
@@ -113,6 +121,9 @@ public class CorpKfServiceImpl implements CorpKfService {
 	@Override
 	public void setKfDuty(CorpKfDutyReq dutyReq) throws Exception {
 		String openKfId = dutyReq.getOpenKfId();
+		//记录变更记录
+		List<CorpKfAccountFollow> before = corpKfAccountFollowMapper.selectList(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
+				.eq(CorpKfAccountFollow::getOpenKfId, openKfId));
 		List<CorpKfAccountFollow> dutyList = Optional.ofNullable(dutyReq.getDutyList()).orElse(new ArrayList<>());
 		//非单个 删除其他设置
 		if (!dutyReq.getIsUpdateSingle()) {
@@ -167,6 +178,58 @@ public class CorpKfServiceImpl implements CorpKfService {
 		if (delDutyFollowIds.size() > 0) {
 			wxCorpOps.delCorpKfServicer(openKfId, delDutyFollowIds);
 		}
+		List<CorpKfAccountFollow> after = corpKfAccountFollowMapper.selectList(Wrappers.lambdaQuery(CorpKfAccountFollow.class)
+				.eq(CorpKfAccountFollow::getOpenKfId, openKfId));
+		CmsUser cmsUser = cmsUserMapper.selectById(dutyReq.getAdminId());
+		recordChangeKfFollows(openKfId, cmsUser, before, after);
+	}
+
+	private void recordChangeKfFollows(String openKfId, CmsUser cmsUser, List<CorpKfAccountFollow> before, List<CorpKfAccountFollow> after) throws Exception {
+		String operator = null;
+		if (cmsUser != null) {
+			operator = cmsUser.getNickname();
+		}
+		//客服关联
+		List<SysCorpFollowView> sysCorpFollowViews = beanSearcher.searchAll(SysCorpFollowView.class, MapUtils.builder().build());
+		Map<String, List<SysCorpFollowView>> followMap = sysCorpFollowViews.stream().collect(Collectors.groupingBy(SysCorpFollowView::getFollowId));
+		Map<Integer, List<CorpKfAccountFollow>> bfDutyWeekFollowMap = before.stream().collect(Collectors.groupingBy(CorpKfAccountFollow::getDutyWeek));
+		Map<Integer, List<CorpKfAccountFollow>> afDutyWeekFollowMap = after.stream().collect(Collectors.groupingBy(CorpKfAccountFollow::getDutyWeek));
+
+		StringBuilder changeStr = new StringBuilder();
+		for (Integer dutyWeek : bfDutyWeekFollowMap.keySet()) {
+			List<CorpKfAccountFollow> bfFollow = bfDutyWeekFollowMap.get(dutyWeek);
+			List<CorpKfAccountFollow> afFollow = Optional.ofNullable(afDutyWeekFollowMap.get(dutyWeek)).orElse(new ArrayList<>());
+			CorpKfChangeFollowLogDto corpKfWeekChange = getCorpKfWeekChange(bfFollow, afFollow, dutyWeek, followMap);
+			if (corpKfWeekChange != null) {
+				if (changeStr.length() > 0) {
+					changeStr.append(";");
+				}
+				changeStr.append(corpKfWeekChange.toChangeString());
+			}
+		}
+		for (Integer dutyWeek : afDutyWeekFollowMap.keySet()) {
+			List<CorpKfAccountFollow> afFollow = afDutyWeekFollowMap.get(dutyWeek);
+			List<CorpKfAccountFollow> bfFollow = Optional.ofNullable(bfDutyWeekFollowMap.get(dutyWeek)).orElse(new ArrayList<>());
+			if (bfFollow.size() > 0) {
+				continue;
+			}
+			CorpKfChangeFollowLogDto corpKfWeekChange = getCorpKfWeekChange(bfFollow, afFollow, dutyWeek, followMap);
+			if (corpKfWeekChange != null) {
+				if (changeStr.length() > 0) {
+					changeStr.append(";");
+				}
+				changeStr.append(corpKfWeekChange.toChangeString());
+			}
+		}
+		if (changeStr.length() > 0) {
+			CorpKfFollowChangeRecord corpKfFollowChangeRecord = new CorpKfFollowChangeRecord();
+			corpKfFollowChangeRecord.setOpenKfId(openKfId);
+			corpKfFollowChangeRecord.setPreValue(Jsons.toJson(before));
+			corpKfFollowChangeRecord.setBackValue(Jsons.toJson(after));
+			corpKfFollowChangeRecord.setOperator(operator);
+			corpKfFollowChangeRecord.setChangeStr(changeStr.toString());
+			corpKfFollowChangeRecordMapper.insert(corpKfFollowChangeRecord);
+		}
 	}
 
 	@Override
@@ -368,4 +431,47 @@ public class CorpKfServiceImpl implements CorpKfService {
 		}
 		return thisHourDutyFollows;
 	}
+
+	public CorpKfChangeFollowLogDto getCorpKfWeekChange(List<CorpKfAccountFollow> bfFollow, List<CorpKfAccountFollow> afFollow, Integer dutyWeek, Map<String, List<SysCorpFollowView>> followMap) {
+		List<String> beforeSelect = new ArrayList<>();
+		List<String> afterSelect = new ArrayList<>();
+
+		Set<String> bfFollowSet = new HashSet<>();
+		bfFollow.forEach(bf -> {
+			try {
+				bfFollowSet.addAll(Jsons.parseList(bf.getUserIdList(), String.class));
+			} catch (Exception e) {
+			}
+		});
+
+		Set<String> afFollowSet = new HashSet<>();
+		afFollow.forEach(af -> {
+			try {
+				afFollowSet.addAll(Jsons.parseList(af.getUserIdList(), String.class));
+			} catch (Exception e) {
+			}
+		});
+		//移除
+		for (String bfUserId : bfFollowSet) {
+			if (!afFollowSet.contains(bfUserId)) {
+				SysCorpFollowView sysCorpFollowView = followMap.get(bfUserId).get(0);
+				beforeSelect.add(String.format("%s(%s)", sysCorpFollowView.getName(), sysCorpFollowView.getFollowName()));
+			}
+		}
+		//增加
+		for (String afUserId : afFollowSet) {
+			if (!bfFollowSet.contains(afUserId)) {
+				SysCorpFollowView sysCorpFollowView = followMap.get(afUserId).get(0);
+				afterSelect.add(String.format("%s(%s)", sysCorpFollowView.getName(), sysCorpFollowView.getFollowName()));
+			}
+		}
+		if (beforeSelect.size() > 0 || afterSelect.size() > 0) {
+			CorpKfChangeFollowLogDto corpKfChangeFollowLogDto = new CorpKfChangeFollowLogDto();
+			corpKfChangeFollowLogDto.setDutyWeek(dutyWeek);
+			corpKfChangeFollowLogDto.setBeforeSelect(beforeSelect);
+			corpKfChangeFollowLogDto.setAfterSelect(afterSelect);
+			return corpKfChangeFollowLogDto;
+		}
+		return null;
+	}
 }

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

@@ -1,12 +1,14 @@
 package com.cyksj.web.controller.manage.corp.wxkf;
 
 import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 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.UserMapper;
 import com.cyksj.mapper.corp.CorpFollowMapper;
 import com.cyksj.mapper.corp.kf.CorpKfAccountUserChangeRecordMapper;
 import com.cyksj.model.entity.*;
@@ -18,6 +20,7 @@ import com.cyksj.model.views.CorpKfUserChatRecordView;
 import com.cyksj.model.views.SysCorpFollowView;
 import com.cyksj.service.corp.kf.CorpKfService;
 import com.cyksj.service.mange.cms.service.CmsUserService;
+import com.cyksj.service.user.UserBindRelationService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
 import com.ejlchina.searcher.param.Operator;
@@ -57,6 +60,10 @@ public class CorpKfController {
 
 	private final CorpKfAccountUserChangeRecordMapper corpKfAccountUserChangeRecordMapper;
 
+	private final UserBindRelationService userBindRelationService;
+
+	private final UserMapper userMapper;
+
 
 	/**
 	 * 添加客服账号
@@ -150,10 +157,21 @@ public class CorpKfController {
 	 */
 	@PostMapping("/set/duty")
 	public Result<String> setKfDuty(@RequestBody CorpKfDutyReq dutyReq) throws Exception {
+		long adminId = StpUtil.getLoginIdAsLong();
+		dutyReq.setAdminId(adminId);
 		corpKfService.setKfDuty(dutyReq);
 		return GatewayResponse.SUCCESS.newBuilder().toResult();
 	}
 
+	/**
+	 * 客服变更记录
+	 */
+	@GetMapping("/get/follow/change/logs")
+	public Result<SearchResult<CorpKfFollowChangeRecord>> getChangeLogs() {
+		SearchResult<CorpKfFollowChangeRecord> search = beanSearcher.search(CorpKfFollowChangeRecord.class, MapUtils.flatBuilder(request.getParameterMap()).orderBy(CorpKfFollowChangeRecord::getId).desc().build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
 	/**
 	 * 获取账号值班设置
 	 */
@@ -205,8 +223,12 @@ public class CorpKfController {
 	 * 会话记录
 	 */
 	@GetMapping("/get/session")
-	public Result<SearchResult<CorpKfUserChatRecordView>> getSession(String keyword) {
+	public Result<SearchResult<CorpKfUserChatRecordView>> getSession(Long userId, String keyword) {
+		String unionId = getUnionid(userId);
 		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		if (unionId != null) {
+			builder.field(CorpKfUserChatRecordView::getUnionid, unionId);
+		}
 		if (StringUtils.isNotBlank(keyword)) {
 			builder.put("keyword", String.format(" and exist (select 1 from corp_kf_account_session_chat ct where ct.session_id = cr.id and ct.msg_content like '%s%%')", keyword));
 		}
@@ -291,4 +313,25 @@ public class CorpKfController {
 		return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfAccountUserChangeRecord);
 	}
 
+	public String getUnionid(Long userId) {
+		String unionId = null;
+		if (userId != null) {
+			try {
+				unionId = StrUtil.COLON;
+				List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+				if (CollUtil.isNotEmpty(userIdList)) {
+					User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
+							.in(User::getId, userIdList)
+							.ne(User::getUnionid, StrUtil.EMPTY)
+							.last("limit 1"));
+					if (user != null) {
+						unionId = user.getUnionid();
+					}
+				}
+			} catch (Exception e) {
+			}
+		}
+		return unionId;
+	}
+
 }