Kaynağa Gözat

修改统计

YPZ 3 hafta önce
ebeveyn
işleme
30fa2e415a

+ 79 - 31
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketEmailsServiceImpl.java

@@ -165,8 +165,7 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
         if (dto == null) {
             dto = new MarketEmailsDTO();
         }
-        // 打开邮件的客户 = hasReader=1 且 recipient 不为空
-        // 字段都可直接从 market_emails 查出,无需聚合,直接 DB 分页
+        // 打开邮件的客户 = hasReader=1 且 recipient / customerId 不为空
         LambdaQueryWrapper<MarketEmailsEntity> wrapper = new LambdaQueryWrapper<>();
         wrapper.eq(MarketEmailsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
         wrapper.eq(MarketEmailsEntity::getHasReader, 1);
@@ -178,23 +177,70 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
         }
         wrapper.isNotNull(MarketEmailsEntity::getRecipient);
         wrapper.ne(MarketEmailsEntity::getRecipient, "");
-        // DB 层直接分页 + 按首次打开时间倒序
+        wrapper.isNotNull(MarketEmailsEntity::getCustomerId);
         wrapper.orderByDesc(MarketEmailsEntity::getFirstOpenTime);
-        Page<MarketEmailsEntity> page = new Page<>(dto.getPageIndex(), dto.getPageSize());
-        IPage<MarketEmailsEntity> entityPage = this.page(page, wrapper);
 
-        // 实体 → VO(字段直接映射,openCount 来自 entity.openCount,无需 clickCount)
-        List<MarketEmailsOpenVO> voList = entityPage.getRecords().stream().map(e -> {
-            MarketEmailsOpenVO vo = new MarketEmailsOpenVO();
-            vo.setRecipient(e.getRecipient());
-            vo.setId(e.getId());
-            vo.setCustomerId(e.getCustomerId());
-            vo.setOpenCount(e.getOpenCount());
-            vo.setFirstOpenTime(e.getFirstOpenTime());
-            vo.setHasProtect(e.getHasProtect());
-            vo.setHasSuspend(e.getHasSuspend());
-            return vo;
-        }).collect(Collectors.toList());
+        List<MarketEmailsEntity> all = this.list(wrapper);
+
+        // 按 customerId 聚合(同一客户多封已打开邮件合并为一张卡片):
+        //   firstOpenTime 取最新,openCount 求和(总点击数),recipient 取最新打开时间那条,
+        //   hasProtect / hasSuspend 取 MAX
+        Map<Long, MarketEmailsOpenVO> aggMap = new LinkedHashMap<>();
+        if (!CollectionUtils.isEmpty(all)) {
+            for (MarketEmailsEntity e : all) {
+                Long cid = e.getCustomerId();
+                if (cid == null) continue;
+                MarketEmailsOpenVO vo = aggMap.computeIfAbsent(cid, k -> {
+                    MarketEmailsOpenVO v = new MarketEmailsOpenVO();
+                    v.setCustomerId(k);
+                    v.setHasProtect(0);
+                    v.setHasSuspend(0);
+                    v.setOpenCount(0);
+                    return v;
+                });
+                // id: 取第一条(后续护/暂停操作以 customerId 为准)
+                if (vo.getId() == null) {
+                    vo.setId(e.getId());
+                }
+                // 比较 firstOpenTime:isLater = 当前记录更新
+                Date eFirstOpen = e.getFirstOpenTime();
+                Date voFirstOpen = vo.getFirstOpenTime();
+                boolean isLater = eFirstOpen != null && (voFirstOpen == null || eFirstOpen.after(voFirstOpen));
+                // firstOpenTime / recipient: 取最新打开时间那条的
+                if (isLater) {
+                    vo.setFirstOpenTime(eFirstOpen);
+                    if (e.getRecipient() != null && !e.getRecipient().isEmpty()) {
+                        vo.setRecipient(e.getRecipient());
+                    }
+                } else if ((vo.getRecipient() == null || vo.getRecipient().isEmpty())
+                        && e.getRecipient() != null && !e.getRecipient().isEmpty()) {
+                    // firstOpenTime 没更新,但 vo.recipient 仍为空 → 补齐
+                    vo.setRecipient(e.getRecipient());
+                }
+                // openCount: 累加(总点击数)
+                if (e.getOpenCount() != null) {
+                    vo.setOpenCount((vo.getOpenCount() == null ? 0 : vo.getOpenCount()) + e.getOpenCount());
+                }
+                // hasProtect / hasSuspend: MAX
+                if (e.getHasProtect() != null && e.getHasProtect() == 1) {
+                    vo.setHasProtect(1);
+                }
+                if (e.getHasSuspend() != null && e.getHasSuspend() == 1) {
+                    vo.setHasSuspend(1);
+                }
+            }
+        }
+
+        // 按 firstOpenTime DESC 排序
+        List<MarketEmailsOpenVO> voList = new ArrayList<>(aggMap.values());
+        voList.sort((a, b) -> {
+            Date at = a.getFirstOpenTime();
+            Date bt = b.getFirstOpenTime();
+            if (at == null && bt == null) return 0;
+            if (at == null) return 1;
+            if (bt == null) return -1;
+            return bt.compareTo(at);
+        });
 
         // 回填客户名称(批量查 customer 表)
         Set<Long> customerIdSet = new LinkedHashSet<>();
@@ -225,7 +271,8 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
             }
         }
 
-        IPage<MarketEmailsOpenVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
+        // 包装为 IPage(保持 API 契约;total = 客户数,size = 总数)
+        IPage<MarketEmailsOpenVO> voPage = new Page<>(1, voList.size(), voList.size());
         voPage.setRecords(voList);
         return Result.result(voPage);
     }
@@ -516,25 +563,26 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
 //                MarketEmailsEntity::getUpdateTime);
         List<MarketEmailsEntity> all = this.list(wrapper);
 
-        // 按 recipient 聚合(同一客户多个保护/暂停记录合并为一张卡片)
-        Map<String, MarketEmailsProtectVO> aggMap = new HashMap<>();
+        // 按 customerId 聚合(同一客户多个邮箱合并为一张卡片)
+        Map<Long, MarketEmailsProtectVO> aggMap = new LinkedHashMap<>();
         if (!CollectionUtils.isEmpty(all)) {
             for (MarketEmailsEntity e : all) {
-                String r = e.getRecipient();
-                if (r == null || r.isEmpty()) continue;
-                MarketEmailsProtectVO vo = aggMap.computeIfAbsent(r, k -> {
+                Long cid = e.getCustomerId();
+                if (cid == null) continue;
+                MarketEmailsProtectVO vo = aggMap.computeIfAbsent(cid, k -> {
                     MarketEmailsProtectVO v = new MarketEmailsProtectVO();
-                    v.setRecipient(k);
+                    v.setCustomerId(k);
                     v.setHasProtect(0);
                     v.setHasSuspend(0);
                     return v;
                 });
-                // 记下第一条(最早设置保护/暂停的那一条)
+                // 记下第一条记录的 id 和 recipient
                 if (vo.getId() == null) {
                     vo.setId(e.getId());
                 }
-                if (vo.getCustomerId() == null && e.getCustomerId() != null) {
-                    vo.setCustomerId(e.getCustomerId());
+                if ((vo.getRecipient() == null || vo.getRecipient().isEmpty())
+                        && e.getRecipient() != null && !e.getRecipient().isEmpty()) {
+                    vo.setRecipient(e.getRecipient());
                 }
                 if (e.getHasProtect() != null && e.getHasProtect() == 1) {
                     vo.setHasProtect(1);
@@ -542,11 +590,11 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
                 if (e.getHasSuspend() != null && e.getHasSuspend() == 1) {
                     vo.setHasSuspend(1);
                 }
-                // 取最早的 updateTime 作为保护/暂停时间
-                if (e.getProtectTime() != null) {
+                // 保护/暂停时间取第一条非空的(同一客户多邮箱一般是同时设置)
+                if (vo.getProtectTime() == null && e.getProtectTime() != null) {
                     vo.setProtectTime(e.getProtectTime());
                 }
-                if (e.getSuspendTime() != null) {
+                if (vo.getSuspendTime() == null && e.getSuspendTime() != null) {
                     vo.setSuspendTime(e.getSuspendTime());
                 }
 //                if (e.getUpdateTime() != null) {
@@ -554,7 +602,7 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
 //                        vo.setProtectTime(e.getUpdateTime());
 //                    }
 //                }
-                // 保护原因:取该 recipient 下任意一条非空的(多条一致时取最先写入的)
+                // 保护原因:取该 customerId 下第一条非空的(多条同时设置时取先进入循环的)
                 if (vo.getProtectReason() == null && e.getProtectReason() != null && !e.getProtectReason().isEmpty()) {
                     vo.setProtectReason(e.getProtectReason());
                 }

+ 2 - 2
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignServiceImpl.java

@@ -134,9 +134,9 @@ public class MarketingCampaignServiceImpl
             Map<Long, Long> repliedMap = countEmailsByCampaign(marketingCampaignIdList,
                     "count(distinct customer_id) as cnt", qw -> qw.eq("has_reply", 1));
             Map<Long, Long> protectMap = countEmailsByCampaign(marketingCampaignIdList,
-                    "count(distinct customer_id) as cnt", qw -> qw.eq("has_protect", 1));
+                    "count(distinct customer_id) as cnt", qw -> qw.eq("has_protect", 1).isNotNull("recipient").ne("recipient", ""));
             Map<Long, Long> suspendMap = countEmailsByCampaign(marketingCampaignIdList,
-                    "count(distinct customer_id) as cnt", qw -> qw.eq("has_suspend", 1));
+                    "count(distinct customer_id) as cnt", qw -> qw.eq("has_suspend", 1).isNotNull("recipient").ne("recipient", ""));
             Map<Long, Long> pendingMap = countEmailsByCampaign(marketingCampaignIdList,
                     "count(*) as cnt", qw -> qw.eq("status", -1));
             Map<Long, Long> sentMap = countEmailsByCampaign(marketingCampaignIdList,