From c5eaaf4bb1cad1fa626d083feff089fd3769a6b5 Mon Sep 17 00:00:00 2001 From: tanglong <842690096@qq.com> Date: Fri, 12 Jun 2026 10:55:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...stomerDashboardDailyCapabilityHandler.java | 37 ++++++++- .../integration/wecom/WecomClient.java | 20 +++++ .../wecom/WecomStudentContactStats.java | 8 +- .../WecomStudentContactStatsService.java | 75 ++++++++++++++++++- .../wecom/WecomUserBehaviorDataRequest.java | 11 +++ .../wecom/WecomUserBehaviorDataResponse.java | 26 +++++++ 6 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataRequest.java create mode 100644 src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataResponse.java diff --git a/src/main/java/com/company/agentfoundation/agent/capability/CustomerDashboardDailyCapabilityHandler.java b/src/main/java/com/company/agentfoundation/agent/capability/CustomerDashboardDailyCapabilityHandler.java index c3afe76..fe72299 100644 --- a/src/main/java/com/company/agentfoundation/agent/capability/CustomerDashboardDailyCapabilityHandler.java +++ b/src/main/java/com/company/agentfoundation/agent/capability/CustomerDashboardDailyCapabilityHandler.java @@ -41,9 +41,10 @@ public class CustomerDashboardDailyCapabilityHandler implements AgentCapabilityH 学员总数:暂未获取 今日新增:暂未获取 跟进成员数:暂未获取 + 统计管理:暂未获取 今日收款:暂未接入 """.trim(), - List.of("企业微信学员联系 API"), + List.of("企业微信学员联系 API", "企业微信统计管理 API"), Map.of("error", e.getMessage() == null ? "api forbidden" : e.getMessage()), Instant.now() ); @@ -60,15 +61,43 @@ public class CustomerDashboardDailyCapabilityHandler implements AgentCapabilityH 学员总数:%d 今日新增:%d 跟进成员数:%d + 今日咨询数:%d + 今日聊天数:%d + 今日发送消息数:%d + 今日回复率:%s + 平均首次回复时长:%s + 今日负反馈数:%d 今日收款:暂未接入 - """.formatted(stats.totalStudents(), stats.todayNewStudents(), stats.followUserCount()).trim(), - List.of("企业微信学员联系 API"), + """.formatted( + stats.totalStudents(), + stats.todayNewStudents(), + stats.followUserCount(), + stats.todayNewApplyCount(), + stats.todayChatCount(), + stats.todayMessageCount(), + percent(stats.todayReplyPercentage()), + seconds(stats.todayAvgReplySeconds()), + stats.todayNegativeFeedbackCount() + ).trim(), + List.of("企业微信学员联系 API", "企业微信统计管理 API"), Map.of( "totalStudents", stats.totalStudents(), "todayNewStudents", stats.todayNewStudents(), - "followUserCount", stats.followUserCount() + "followUserCount", stats.followUserCount(), + "todayNewApplyCount", stats.todayNewApplyCount(), + "todayChatCount", stats.todayChatCount(), + "todayMessageCount", stats.todayMessageCount(), + "todayNegativeFeedbackCount", stats.todayNegativeFeedbackCount() ), Instant.now() ); } + + private String percent(Integer value) { + return value == null ? "暂无数据" : value + "%"; + } + + private String seconds(Integer value) { + return value == null ? "暂无数据" : value + "秒"; + } } diff --git a/src/main/java/com/company/agentfoundation/integration/wecom/WecomClient.java b/src/main/java/com/company/agentfoundation/integration/wecom/WecomClient.java index 9fee554..6a0ac7f 100644 --- a/src/main/java/com/company/agentfoundation/integration/wecom/WecomClient.java +++ b/src/main/java/com/company/agentfoundation/integration/wecom/WecomClient.java @@ -89,6 +89,26 @@ public class WecomClient { return response; } + public WecomUserBehaviorDataResponse getStudentContactBehaviorData(List userIds, long startTime, long endTime) { + String token = getAccessToken(studentContactSecret()); + WecomUserBehaviorDataRequest request = new WecomUserBehaviorDataRequest(userIds, startTime, endTime); + WecomUserBehaviorDataResponse response = webClient.post() + .uri(uriBuilder -> uriBuilder.path("/cgi-bin/externalcontact/get_user_behavior_data") + .queryParam("access_token", token) + .build()) + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(request) + .retrieve() + .bodyToMono(WecomUserBehaviorDataResponse.class) + .block(); + + if (response == null || !response.success()) { + log.error("wecom student contact behavior data failed err={}", response == null ? "null" : response.errmsg()); + throw new IllegalStateException("WeCom student contact behavior data failed: " + (response == null ? "null" : response.errmsg())); + } + return response; + } + private String getAccessToken() { if (cachedToken != null && Instant.now().isBefore(tokenExpireAt)) { log.info("wecom gettoken use cached token expireAt={}", tokenExpireAt); diff --git a/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStats.java b/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStats.java index d7155b4..b265dcc 100644 --- a/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStats.java +++ b/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStats.java @@ -3,5 +3,11 @@ package com.company.agentfoundation.integration.wecom; public record WecomStudentContactStats( int totalStudents, int todayNewStudents, - int followUserCount + int followUserCount, + int todayNewApplyCount, + int todayChatCount, + int todayMessageCount, + int todayNegativeFeedbackCount, + Integer todayReplyPercentage, + Integer todayAvgReplySeconds ) {} diff --git a/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStatsService.java b/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStatsService.java index b9cce64..9327a99 100644 --- a/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStatsService.java +++ b/src/main/java/com/company/agentfoundation/integration/wecom/WecomStudentContactStatsService.java @@ -24,9 +24,11 @@ public class WecomStudentContactStatsService { public WecomStudentContactStats fetchTodayStats() { List followUsers = wecomClient.getStudentContactFollowUsers().followUser(); if (followUsers == null || followUsers.isEmpty()) { - return new WecomStudentContactStats(0, 0, 0); + return new WecomStudentContactStats(0, 0, 0, 0, 0, 0, 0, null, null); } + long todayStart = LocalDate.now(CHINA_ZONE).atStartOfDay(CHINA_ZONE).toEpochSecond(); + long tomorrowStart = LocalDate.now(CHINA_ZONE).plusDays(1).atStartOfDay(CHINA_ZONE).toEpochSecond(); Set allStudents = new HashSet<>(); Map earliestCreateTimeByStudent = new HashMap<>(); for (int start = 0; start < followUsers.size(); start += BATCH_SIZE) { @@ -34,13 +36,22 @@ public class WecomStudentContactStatsService { fetchBatch(batchUsers, allStudents, earliestCreateTimeByStudent); } - long todayStart = LocalDate.now(CHINA_ZONE).atStartOfDay(CHINA_ZONE).toEpochSecond(); - long tomorrowStart = LocalDate.now(CHINA_ZONE).plusDays(1).atStartOfDay(CHINA_ZONE).toEpochSecond(); int todayNew = (int) earliestCreateTimeByStudent.values().stream() .filter(createTime -> createTime != null && createTime >= todayStart && createTime < tomorrowStart) .count(); + BehaviorSummary behaviorSummary = fetchBehaviorSummary(followUsers, todayStart, tomorrowStart - 1); - return new WecomStudentContactStats(allStudents.size(), todayNew, followUsers.size()); + return new WecomStudentContactStats( + allStudents.size(), + todayNew, + followUsers.size(), + behaviorSummary.newApplyCount(), + behaviorSummary.chatCount(), + behaviorSummary.messageCount(), + behaviorSummary.negativeFeedbackCount(), + behaviorSummary.replyPercentage(), + behaviorSummary.avgReplySeconds() + ); } private void fetchBatch(List userIds, Set allStudents, Map earliestCreateTimeByStudent) { @@ -68,4 +79,60 @@ public class WecomStudentContactStatsService { } } } + + private BehaviorSummary fetchBehaviorSummary(List followUsers, long startTime, long endTime) { + int newApplyCount = 0; + int chatCount = 0; + int messageCount = 0; + int negativeFeedbackCount = 0; + int replyPercentageWeightedSum = 0; + int replyPercentageWeight = 0; + int avgReplyTimeWeightedSum = 0; + int avgReplyTimeWeight = 0; + + for (int start = 0; start < followUsers.size(); start += BATCH_SIZE) { + List batchUsers = followUsers.subList(start, Math.min(start + BATCH_SIZE, followUsers.size())); + WecomUserBehaviorDataResponse response = wecomClient.getStudentContactBehaviorData(batchUsers, startTime, endTime); + List behaviorData = response.behaviorData(); + if (behaviorData == null) { + continue; + } + for (WecomUserBehaviorDataResponse.BehaviorData item : behaviorData) { + if (item == null) { + continue; + } + int itemChatCount = value(item.chatCnt()); + int itemMessageCount = value(item.messageCnt()); + newApplyCount += value(item.newApplyCnt()); + chatCount += itemChatCount; + messageCount += itemMessageCount; + negativeFeedbackCount += value(item.negativeFeedbackCnt()); + if (item.replyPercentage() != null && itemChatCount > 0) { + replyPercentageWeightedSum += item.replyPercentage() * itemChatCount; + replyPercentageWeight += itemChatCount; + } + if (item.avgReplyTime() != null && itemMessageCount > 0) { + avgReplyTimeWeightedSum += item.avgReplyTime() * itemMessageCount; + avgReplyTimeWeight += itemMessageCount; + } + } + } + + Integer replyPercentage = replyPercentageWeight == 0 ? null : replyPercentageWeightedSum / replyPercentageWeight; + Integer avgReplySeconds = avgReplyTimeWeight == 0 ? null : avgReplyTimeWeightedSum / avgReplyTimeWeight; + return new BehaviorSummary(newApplyCount, chatCount, messageCount, negativeFeedbackCount, replyPercentage, avgReplySeconds); + } + + private int value(Integer value) { + return value == null ? 0 : value; + } + + private record BehaviorSummary( + int newApplyCount, + int chatCount, + int messageCount, + int negativeFeedbackCount, + Integer replyPercentage, + Integer avgReplySeconds + ) {} } diff --git a/src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataRequest.java b/src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataRequest.java new file mode 100644 index 0000000..cc64748 --- /dev/null +++ b/src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataRequest.java @@ -0,0 +1,11 @@ +package com.company.agentfoundation.integration.wecom; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public record WecomUserBehaviorDataRequest( + @JsonProperty("userid") List userIds, + @JsonProperty("start_time") Long startTime, + @JsonProperty("end_time") Long endTime +) {} diff --git a/src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataResponse.java b/src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataResponse.java new file mode 100644 index 0000000..d771db5 --- /dev/null +++ b/src/main/java/com/company/agentfoundation/integration/wecom/WecomUserBehaviorDataResponse.java @@ -0,0 +1,26 @@ +package com.company.agentfoundation.integration.wecom; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public record WecomUserBehaviorDataResponse( + Integer errcode, + String errmsg, + @JsonProperty("behavior_data") List behaviorData +) { + public boolean success() { + return errcode == null || errcode == 0; + } + + public record BehaviorData( + String statTime, + @JsonProperty("chat_cnt") Integer chatCnt, + @JsonProperty("message_cnt") Integer messageCnt, + @JsonProperty("reply_percentage") Integer replyPercentage, + @JsonProperty("avg_reply_time") Integer avgReplyTime, + @JsonProperty("negative_feedback_cnt") Integer negativeFeedbackCnt, + @JsonProperty("new_apply_cnt") Integer newApplyCnt, + @JsonProperty("new_contact_cnt") Integer newContactCnt + ) {} +}