Pārlūkot izejas kodu

账号邮箱统计

18118724055@163.com 6 stundas atpakaļ
vecāks
revīzija
e4c9c139cb

+ 0 - 1
java/storlead-mail/storlead-mail-api/src/main/java/com/storlead/mail/controller/mkt/MktEmailAccountApiController.java

@@ -83,7 +83,6 @@ public class MktEmailAccountApiController {
     @PostMapping("/personal_mail_account")
     @ApiOperation("营销邮箱账户(含未读数)")
     public Result<?> personalMailAccount() {
-
         return mktAccountRemoteClient.personalMailAccount();
     }
 

+ 7 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/controller/MarketEmailsController.java

@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
+import java.util.Map;
 
 import javax.annotation.Resource;
 
@@ -164,6 +165,12 @@ public class MarketEmailsController {
         return marketEmailsService.getLast7DaysSendTrend();
     }
 
+    @GetMapping("/account-total")
+    @ApiOperation("营销: 按发件箱 id 批量统计,返回 Map<outboxId, 统计>(总发送量、回复数、回复率、最新发送时间;outboxIds=1,2 或 outboxIds=1&outboxIds=2)")
+    public Result<Map<Long, Object>> accountStats(@RequestParam("outboxIds") List<Long> outboxIds) {
+        return marketEmailsService.getAccountStats(outboxIds);
+    }
+
     @PostMapping("/test")
     @ApiOperation("获取邮件信息(form 传 ids,多个用逗号分隔或重复 key:ids=1,2 或 ids=1&ids=2)")
     public Result<?> emailList(@RequestParam("ids") List<Long> ids) {

+ 8 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/MarketEmailsService.java

@@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.springframework.scheduling.annotation.Async;
 
 import java.util.List;
+import java.util.Map;
 
 public interface MarketEmailsService extends MyBaseService<MarketEmailsEntity> {
 
@@ -109,6 +110,13 @@ public interface MarketEmailsService extends MyBaseService<MarketEmailsEntity> {
      */
     Result<Object> getLast7DaysSendTrend();
 
+    /**
+     * 按发件箱 id 批量聚合:总发送量、回复数、回复率、最新发送时间。
+     * 口径与今日发送一致:is_delete=0 且 status=1;回复数再叠加 has_reply=1。
+     * 返回 Map&lt;outboxId, 统计&gt;;入参只接受账号 id,无数据的 id 补 0。
+     */
+    Result<Map<Long, Object>> getAccountStats(List<Long> outboxIds);
+
     /***
       * @Description: 通过id/marketingCampaignId/客户id关联的邮件状态
       * @Param:

+ 91 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketEmailsServiceImpl.java

@@ -39,6 +39,8 @@ import org.springframework.util.CollectionUtils;
 import org.springframework.util.ObjectUtils;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -1052,6 +1054,64 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
         return Result.result(list);
     }
 
+    @Override
+    public Result<Map<Long, Object>> getAccountStats(List<Long> outboxIds) {
+        Map<Long, Object> result = new LinkedHashMap<>();
+        if (CollectionUtils.isEmpty(outboxIds)) {
+            return Result.result(result);
+        }
+        List<Long> ids = outboxIds.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());
+        if (ids.isEmpty()) {
+            return Result.result(result);
+        }
+        for (Long id : ids) {
+            result.put(id, emptyAccountStats(id));
+        }
+
+        QueryWrapper<MarketEmailsEntity> qw = new QueryWrapper<>();
+        qw.select(
+                "outbox_id",
+                "COUNT(*) AS send_count",
+                "COUNT(CASE WHEN IFNULL(has_reply, 0) = 1 THEN 1 END) AS reply_count",
+                "MAX(expect_send_time) AS last_send_time");
+        qw.eq("is_delete", CommonConstant.DEL_FLAG_0);
+        qw.eq("status", 1);
+        qw.in("outbox_id", ids);
+        qw.groupBy("outbox_id");
+        List<Map<String, Object>> rows = this.listMaps(qw);
+        if (CollectionUtils.isEmpty(rows)) {
+            return Result.result(result);
+        }
+        for (Map<String, Object> row : rows) {
+            if (row == null) {
+                continue;
+            }
+            Long id = toLongOrNull(row.get("outbox_id"));
+            if (id == null || !result.containsKey(id)) {
+                continue;
+            }
+            MarketEmailsAccountStatsVO vo = new MarketEmailsAccountStatsVO();
+            int sendCount = toInteger(row.get("send_count"));
+            int replyCount = toInteger(row.get("reply_count"));
+            vo.setOutboxId(id);
+            vo.setSendCount(sendCount);
+            vo.setReplyCount(replyCount);
+            vo.setReplyRate(toReplyRate(sendCount, replyCount));
+            vo.setLastSendTime(toDate(row.get("last_send_time")));
+            result.put(id, vo);
+        }
+        return Result.result(result);
+    }
+
+    private MarketEmailsAccountStatsVO emptyAccountStats(Long outboxId) {
+        MarketEmailsAccountStatsVO vo = new MarketEmailsAccountStatsVO();
+        vo.setOutboxId(outboxId);
+        vo.setSendCount(0);
+        vo.setReplyCount(0);
+        vo.setReplyRate(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));
+        return vo;
+    }
+
     /**
      * 分组键转 yyyy-MM-dd:JDBC 可能返回 java.sql.Date / java.sql.Timestamp / 字符串。
      * java.sql.Date#toInstant 会抛 UnsupportedOperationException,必须优先判断。
@@ -1087,6 +1147,37 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
         }
     }
 
+    /** 聚合字段转 Long,空值保持 null。 */
+    private Long toLongOrNull(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        try {
+            return Long.valueOf(value.toString().trim());
+        } catch (NumberFormatException e) {
+            return null;
+        }
+    }
+
+    private Date toDate(Object value) {
+        if (value instanceof Date) {
+            return (Date) value;
+        }
+        return null;
+    }
+
+    private BigDecimal toReplyRate(int sendCount, int replyCount) {
+        if (sendCount <= 0) {
+            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
+        }
+        return BigDecimal.valueOf(replyCount)
+                .multiply(BigDecimal.valueOf(100))
+                .divide(BigDecimal.valueOf(sendCount), 2, RoundingMode.HALF_UP);
+    }
+
     @Override
     public void updateCustomerEmailStatus(MarketEmailsCustomerVO marketEmailsCustomerVO) {
         LambdaQueryWrapper<MarketEmailsEntity> queryWrapper = new LambdaQueryWrapper<>();

+ 40 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/vo/MarketEmailsAccountStatsVO.java

@@ -0,0 +1,40 @@
+package com.storlead.trade.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 营销邮件-按发件箱账号聚合统计
+ */
+@Data
+@ApiModel(value = "MarketEmailsAccountStatsVO", description = "营销邮件-按邮箱账号统计(发送量/回复数/回复率/最近发送时间)")
+public class MarketEmailsAccountStatsVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "发件箱id")
+    private Long outboxId;
+
+    @ApiModelProperty(value = "总发送量(status=1 发送成功)")
+    private Integer sendCount = 0;
+
+    @ApiModelProperty(value = "回复数(发送成功且 has_reply=1)")
+    private Integer replyCount = 0;
+
+    @ApiModelProperty(value = "回复率(百分比,保留 2 位小数;sendCount=0 时为 0.00)")
+    private BigDecimal replyRate = BigDecimal.ZERO.setScale(2);
+
+    @ApiModelProperty(value = "最新发送时间(该账号下 expect_send_time 最大值)")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
+    private Date lastSendTime;
+}