|
|
@@ -26,8 +26,11 @@ import com.storlead.trade.mapper.MarketEmailsMapper;
|
|
|
import com.storlead.trade.service.*;
|
|
|
import com.storlead.trade.vo.*;
|
|
|
import org.apache.commons.lang.time.DateUtils;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
@@ -62,6 +65,9 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
|
|
|
@Resource
|
|
|
private CustomerTradeService customerTradeService;
|
|
|
+ @Resource
|
|
|
+ private CustomerCompanyTradeService customerCompanyTradeService;
|
|
|
+
|
|
|
@Resource
|
|
|
@Lazy
|
|
|
private MarketingCampaignSopDetailService marketingCampaignSopDetailEntityService;
|
|
|
@@ -79,6 +85,12 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
|
|
|
@Resource
|
|
|
private MktMailRemoteClient mktMailRemoteClient;
|
|
|
+ @Resource
|
|
|
+ private LiaisonTradeService liaisonTradeService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ @Lazy
|
|
|
+ private RedissonClient redissonClient;
|
|
|
|
|
|
|
|
|
@Override
|
|
|
@@ -312,10 +324,14 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
|
|
|
|
|
|
// 如果是开启保护 且 前端传了保护原因 -> 一并写入
|
|
|
- if (Integer.valueOf(1).equals(dto.getHasProtect()) && !ObjectUtils.isEmpty(dto.getProtectReason())) {
|
|
|
- wrapper.set(MarketEmailsEntity::getProtectReason, dto.getProtectReason());
|
|
|
+ if (Integer.valueOf(1).equals(dto.getHasProtect())) {
|
|
|
wrapper.set(MarketEmailsEntity::getProtectTime, new Date());
|
|
|
+ if (!ObjectUtils.isEmpty(dto.getProtectReason())) {
|
|
|
+ wrapper.set(MarketEmailsEntity::getProtectReason, dto.getProtectReason());
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
// 如果是移除保护 -> 清空保护原因
|
|
|
if (Integer.valueOf(0).equals(dto.getHasProtect())) {
|
|
|
wrapper.set(MarketEmailsEntity::getProtectReason, null);
|
|
|
@@ -450,11 +466,21 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
if (vo.getId() == null && e.getId() != null) {
|
|
|
vo.setId(e.getId());
|
|
|
}
|
|
|
- // 取最早的 firstReplyTime + 同时记录主题/emailId
|
|
|
+ // 取最早的 firstReplyTime
|
|
|
if (e.getFirstReplyTime() != null) {
|
|
|
if (vo.getFirstReplyTime() == null || e.getFirstReplyTime().before(vo.getFirstReplyTime())) {
|
|
|
vo.setFirstReplyTime(e.getFirstReplyTime());
|
|
|
- vo.setReplyContent(e.getFirstReplyTheme());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 取最新且非空的回复主题(bestReplyContent 聚合)
|
|
|
+ String theme = e.getFirstReplyTheme();
|
|
|
+ if (theme != null && !theme.trim().isEmpty()) {
|
|
|
+ if (vo.getBestReplyContent() == null) {
|
|
|
+ vo.setBestReplyContent(theme);
|
|
|
+ } else if (e.getFirstReplyTime() != null
|
|
|
+ && (vo.getFirstReplyTime() == null || e.getFirstReplyTime().after(vo.getFirstReplyTime()))) {
|
|
|
+ // 当前记录的 firstReplyTime 比已记录的 firstReplyTime 更新时,更新 bestReplyContent
|
|
|
+ vo.setBestReplyContent(theme);
|
|
|
}
|
|
|
}
|
|
|
// MAX(has_protect) / MAX(has_suspend) 语义
|
|
|
@@ -466,10 +492,12 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- // 默认未保护/未暂停为 0
|
|
|
+ // 默认未保护/未暂停为 0;bestReplyContent 写回 replyContent
|
|
|
for (com.storlead.trade.vo.MarketEmailsReplyVO vo : aggMap.values()) {
|
|
|
if (vo.getHasProtect() == null) vo.setHasProtect(0);
|
|
|
if (vo.getHasSuspend() == null) vo.setHasSuspend(0);
|
|
|
+ vo.setReplyContent(vo.getBestReplyContent());
|
|
|
+ vo.setBestReplyContent(null);
|
|
|
}
|
|
|
// 按首次回复时间倒序(最近回复的排前)
|
|
|
List<com.storlead.trade.vo.MarketEmailsReplyVO> voList = new java.util.ArrayList<>(aggMap.values());
|
|
|
@@ -483,7 +511,7 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
// 批量回填:客户名 / 客户等级 / 核心标签
|
|
|
if (!voList.isEmpty()) {
|
|
|
java.util.Set<Long> customerIdSet = new java.util.LinkedHashSet<>();
|
|
|
- for (com.storlead.trade.vo.MarketEmailsReplyVO v : voList) {
|
|
|
+ for (MarketEmailsReplyVO v : voList) {
|
|
|
if (v.getCustomerId() != null) customerIdSet.add(v.getCustomerId());
|
|
|
}
|
|
|
if (!customerIdSet.isEmpty()) {
|
|
|
@@ -520,6 +548,7 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
}
|
|
|
CustomerAnalysisResultEntity a = analysisMap.get(v.getCustomerId());
|
|
|
if (a != null) {
|
|
|
+ v.setCustomerAnalysisResult(a);
|
|
|
v.setCustomerLevel(a.getCustomerLevel());
|
|
|
v.setCoreTags(a.getCoreTags());
|
|
|
if (a.getCustomerLevel() != null) {
|
|
|
@@ -995,6 +1024,41 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
marketEmail.setIsDelete(CommonConstant.DEL_FLAG_0);
|
|
|
}
|
|
|
);
|
|
|
+ //查询其他营销活动关联客户的暂停和取消状态,同步写入到当前客户
|
|
|
+ for (MarketEmailsEntity marketEmail : marketEmailList){
|
|
|
+ LambdaQueryWrapper<MarketEmailsEntity> queryOtherWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryOtherWrapper.eq(MarketEmailsEntity::getCustomerId, marketEmail.getCustomerId());
|
|
|
+ queryOtherWrapper.eq(MarketEmailsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
|
|
|
+ queryOtherWrapper.ne(MarketEmailsEntity::getMarketingCampaignId, marketEmail.getMarketingCampaignId());
|
|
|
+ queryOtherWrapper.last("limit 1");
|
|
|
+ MarketEmailsEntity marketOtherEmail = this.getOne(queryOtherWrapper);
|
|
|
+ if (marketOtherEmail != null){
|
|
|
+ marketEmail.setHasSuspend(marketOtherEmail.getHasSuspend());
|
|
|
+ marketEmail.setHasProtect(marketOtherEmail.getHasProtect());
|
|
|
+ marketEmail.setProtectReason(marketOtherEmail.getProtectReason());
|
|
|
+ marketEmail.setProtectTime(marketOtherEmail.getProtectTime());
|
|
|
+ marketEmail.setSuspendTime(marketOtherEmail.getSuspendTime());
|
|
|
+ }
|
|
|
+
|
|
|
+ //通过客户id写入企业关联邮箱
|
|
|
+ String email = "";
|
|
|
+ CustomerCompanyEntity customerCompany = customerCompanyTradeService.getOne(new LambdaQueryWrapper<CustomerCompanyEntity>()
|
|
|
+ .eq(CustomerCompanyEntity::getCustomerId, marketEmail.getCustomerId())
|
|
|
+ .eq(CustomerCompanyEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
|
|
|
+ .last("limit 1"));
|
|
|
+ if (!ObjectUtils.isEmpty(customerCompany)){
|
|
|
+ email = customerCompany.getEmail();
|
|
|
+ if (ObjectUtils.isEmpty(email)){
|
|
|
+ LiaisonEntity liaison = liaisonTradeService.getOne(new LambdaQueryWrapper<LiaisonEntity>()
|
|
|
+ .eq(LiaisonEntity::getCustomerId, marketEmail.getCustomerId())
|
|
|
+ .eq(LiaisonEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
|
|
|
+ .eq(LiaisonEntity::getHasPrimaryLialison,1)
|
|
|
+ .last("limit 1"));
|
|
|
+ email = liaison.getEmail();
|
|
|
+ }
|
|
|
+ marketEmail.setRecipient(email);
|
|
|
+ }
|
|
|
+ }
|
|
|
this.saveBatch(marketEmailList);
|
|
|
|
|
|
}
|
|
|
@@ -1085,6 +1149,28 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
|
|
|
@Override
|
|
|
public void sendAgain() {
|
|
|
+ String lockKey = "market-emails:send-again:lock";
|
|
|
+ RLock lock = redissonClient.getLock(lockKey);
|
|
|
+ boolean acquired = false;
|
|
|
+ try {
|
|
|
+ // 尝试获取锁,最多等 0 秒(抢不到直接放弃,避免当前执行实例被阻塞)
|
|
|
+ acquired = lock.tryLock(0, 2, java.util.concurrent.TimeUnit.MINUTES);
|
|
|
+ if (!acquired) {
|
|
|
+ log.info("[sendAgain] 锁未获取到,当前有其他实例在执行,跳过本次");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ doSendAgain(lockKey);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ log.warn("[sendAgain] 获取锁被中断: {}", e.getMessage());
|
|
|
+ } finally {
|
|
|
+ if (acquired && lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void doSendAgain(String lockKey) {
|
|
|
LambdaQueryWrapper<MarketEmailsEntity> marketEmailHasFirstQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
marketEmailHasFirstQueryWrapper.eq(MarketEmailsEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
|
|
|
marketEmailHasFirstQueryWrapper.eq(MarketEmailsEntity::getHasFirst, 2);
|
|
|
@@ -1149,6 +1235,9 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
Date expectSendTime = DateUtils.addMinutes(new Date(), 30);
|
|
|
newMarketEmail.setExpectSendTime(expectSendTime);
|
|
|
newMarketEmail.setHasFirst(2);
|
|
|
+ newMarketEmail.setHasProtect(0);
|
|
|
+ newMarketEmail.setHasReader(0);
|
|
|
+ newMarketEmail.setHasReply(0);
|
|
|
|
|
|
newMarketEmailList.add(newMarketEmail);
|
|
|
}
|