zoujiajian 1 рік тому
батько
коміт
fc15174a35

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.corp.kf;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpKfServicerStatistic;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfServicerStatisticMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/1/2 16:29
+ */
+public interface CorpKfServicerStatisticMapper extends BaseMapper<CorpKfServicerStatistic> {
+}

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

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.corp.kf;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpKfUser;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfUserMapper
+ * 创建者: JavaZou
+ * 创建时间:2025/1/2 17:03
+ */
+public interface CorpKfUserMapper extends BaseMapper<CorpKfUser> {
+}

+ 56 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpKfServicerStatistic.java

@@ -0,0 +1,56 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+public class CorpKfServicerStatistic extends BaseEntity {
+
+	/** 主键 ID */
+	private Long id;
+
+	/** openkfid */
+	private String openKfId;
+
+	/** 客服人员 ID */
+	private String servicerUserId;
+
+	/** 接入人工会话数 */
+	private Integer sessionCnt;
+
+	/** 咨询客户数 */
+	private Integer customerCnt;
+
+	/** 咨询消息总数 */
+	private Integer customerMsgCnt;
+
+	/** 人工回复率 */
+	private BigDecimal replyRate;
+
+	/** 平均首次响应时长(秒) */
+	private BigDecimal firstReplyAverageSec;
+
+	/** 满意度评价发送数 */
+	private Integer satisfactionInvestgateCnt;
+
+	/** 满意度参评率 */
+	private BigDecimal satisfactionParticipationRate;
+
+	/** 满意评价占比 */
+	private BigDecimal satisfiedRate;
+
+	/** 一般评价占比 */
+	private BigDecimal middlingRate;
+
+	/** 不满意评价占比 */
+	private BigDecimal dissatisfiedRate;
+
+	/** 被拒收消息的客户数 */
+	private Integer msgRejectedCustomerCnt;
+
+	/** 统计日期 */
+	private String statisticsDate;
+}

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

@@ -0,0 +1,24 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfUser
+ * 创建者: JavaZou
+ * 创建时间:2025/1/2 17:02
+ */
+@Getter
+@Setter
+public class CorpKfUser extends BaseEntity{
+	private String externalUserid;
+
+	private String unionid;
+
+	private String nickname;
+
+	private Integer gender;
+
+	private String avatar;
+}

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/kf/CorpKfUserInfo.java

@@ -16,7 +16,7 @@ public class CorpKfUserInfo {
 	@JsonProperty("external_userid")
 	private String externalUserid;
 
-	private String ncikname;
+	private String nickname;
 
 	private String avatar;
 

+ 67 - 0
netflix-dao/src/main/java/com/cyksj/model/views/CorpKfServicerSessionRecordView.java

@@ -0,0 +1,67 @@
+package com.cyksj.model.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: CorpKfServicerSessionRecordView
+ * 创建者: JavaZou
+ * 创建时间:2025/1/2 16:41
+ */
+@Getter
+@Setter
+@SearchBean(tables = "(SELECT external_userid userid, q.servicer_userid follow_id, MAX(id) msgId " +
+		"FROM corp_kf_servicer_session_reocrd q " +
+		" :keyword: " +
+		"GROUP BY q.external_userid , q.follow_id " +
+		"ORDER BY MAX(q.id) desc limit 1) t " +
+		"LEFT JOIN corp_kf_account_session_chat qm on qm.id = t.msgId " +
+		"LEFT JOIN corp_kf_user ku on ku.external_userid = t.userid "
+)
+public class CorpKfServicerSessionRecordView {
+	/**
+	 * 用户名称
+	 */
+	@DbField("ifnull(ku.nickname,qm.sender_name)")
+	private String nickname;
+
+	/**
+	 * 用户头像
+	 */
+	@DbField("ku.avatar")
+	private String avatar;
+
+	/**
+	 * 成员id
+	 */
+	@DbField("t.follow_id")
+	private String followId;
+
+	/**
+	 * 用户id
+	 */
+	@DbField("t.userid")
+	private String userid;
+
+	/**
+	 * 最近消息文本内容
+	 */
+	@DbField("qm.msg_content")
+	private String msgContent;
+
+	/**
+	 * 最近消息类型
+	 */
+	@DbField("qm.msg_type")
+	private String msgType;
+
+	/**
+	 * 最近消息时间
+	 */
+	@DbField("qm.send_time")
+	private String sendTime;
+
+}

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

@@ -1,19 +1,27 @@
 package com.cyksj.web.controller.manage.corp.wxkf;
 
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
-import com.cyksj.model.entity.CorpKfAccount;
-import com.cyksj.model.entity.CorpKfAccountFollow;
-import com.cyksj.model.entity.CorpKfAccountSessionConfig;
+import com.cyksj.mapper.corp.CorpFollowMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.views.CorpKfServicerSessionRecordView;
 import com.cyksj.service.corp.kf.CorpKfService;
+import com.cyksj.service.mange.cms.service.CmsUserService;
 import com.ejlchina.searcher.BeanSearcher;
 import com.ejlchina.searcher.SearchResult;
+import com.ejlchina.searcher.param.Operator;
+import com.ejlchina.searcher.util.MapBuilder;
 import com.ejlchina.searcher.util.MapUtils;
 import lombok.RequiredArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 项目名: yhlxj2
@@ -31,6 +39,10 @@ public class CorpKfController {
 
 	private final HttpServletRequest request;
 
+	private final CmsUserService cmsUserService;
+
+	private final CorpFollowMapper corpFollowMapper;
+
 
 	/**
 	 * 添加客服账号
@@ -95,4 +107,51 @@ public class CorpKfController {
 		corpKfService.setKfAccountDuty(corpKfAccountFollows);
 		return GatewayResponse.SUCCESS.newBuilder().toResult();
 	}
+
+	//===============================================数据统计========================================================================
+
+	/**
+	 * 数据统计
+	 */
+	@GetMapping("/get/statistics")
+	public Result<SearchResult<CorpKfServicerStatistic>> getStatisticsData() {
+		long adminId = StpUtil.getLoginIdAsLong();
+		Boolean rootRole = cmsUserService.isRootRole(adminId);
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		if (!rootRole) {
+			List<String> userids = corpFollowMapper.selectList(Wrappers.lambdaQuery(CorpFollow.class)
+					.eq(CorpFollow::getCmsUserId, adminId)).stream().map(CorpFollow::getUserid).collect(Collectors.toList());
+			builder.field(CorpKfServicerStatistic::getServicerUserId, userids).op(Operator.InList);
+		}
+		SearchResult<CorpKfServicerStatistic> search = beanSearcher.search(CorpKfServicerStatistic.class, builder.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+	//===============================================聊天记录========================================================================
+
+	/**
+	 * 会话记录
+	 */
+	@GetMapping("/get/session")
+	public Result<SearchResult<CorpKfServicerSessionRecordView>> getSession(String keyword) {
+		MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+		if(StringUtils.isNotBlank(keyword)){
+			builder.put("keyword", String.format("where q.msg_content like '%s%%')",keyword));
+		}
+		SearchResult<CorpKfServicerSessionRecordView> search = beanSearcher.search(CorpKfServicerSessionRecordView.class, builder.build());
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
+
+
+	/**
+	 * 获取聊天记录
+	 */
+	@GetMapping("/get/session/chat")
+	public Result<SearchResult<CorpKfAccountSessionChat>> getSessionChat(){
+		Map<String, Object> build = MapUtils.flatBuilder(request.getParameterMap()).build();
+		SearchResult<CorpKfAccountSessionChat> search = beanSearcher.search(CorpKfAccountSessionChat.class, build);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(search);
+	}
+
 }

+ 20 - 0
netflix-web/src/main/java/com/cyksj/web/controller/manage/corp/wxkf/CorpKfMsgController.java

@@ -1,10 +1,13 @@
 package com.cyksj.web.controller.manage.corp.wxkf;
 
+import cn.hutool.core.bean.BeanUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.corp.kf.CorpKfServicerSessionRecordMapper;
+import com.cyksj.mapper.corp.kf.CorpKfUserMapper;
 import com.cyksj.model.entity.CorpKfServicerSessionRecord;
+import com.cyksj.model.entity.CorpKfUser;
 import com.cyksj.model.kf.CorpKfUserInfo;
 import com.cyksj.service.corp.WxCorpOps;
 import lombok.RequiredArgsConstructor;
@@ -27,6 +30,8 @@ public class CorpKfMsgController {
 
 	private final CorpKfServicerSessionRecordMapper corpKfServicerSessionRecordMapper;
 
+	private final CorpKfUserMapper corpKfUserMapper;
+
 	/**
 	 * 发送满意度调查消息
 	 */
@@ -49,6 +54,21 @@ public class CorpKfMsgController {
 	@GetMapping("/get/user/info")
 	public Result<CorpKfUserInfo> getUserInfo(String externalUserid) throws Exception {
 		CorpKfUserInfo corpKfUserInfo = wxCorpOps.getCorpKfUserInfo(externalUserid);
+		CorpKfUser corpKfUser = corpKfUserMapper.selectOne(Wrappers.lambdaQuery(CorpKfUser.class)
+				.eq(CorpKfUser::getExternalUserid, externalUserid)
+				.last("limit 1"));
+		if (corpKfUser == null) {
+			try {
+				BeanUtil.copyProperties(corpKfUserInfo, corpKfUser);
+				corpKfUserMapper.insert(corpKfUser);
+			} catch (Exception e) {
+			}
+		} else {
+			corpKfUser.setAvatar(corpKfUserInfo.getAvatar());
+			corpKfUser.setNickname(corpKfUserInfo.getNickname());
+			corpKfUser.setGender(corpKfUserInfo.getGender());
+			corpKfUserMapper.updateById(corpKfUser);
+		}
 		return GatewayResponse.SUCCESS.newBuilder().toResult(corpKfUserInfo);
 	}