|
@@ -1,28 +1,50 @@
|
|
|
package com.storlead.trade.service.impl;
|
|
package com.storlead.trade.service.impl;
|
|
|
|
|
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.storlead.framework.common.constant.CommonConstant;
|
|
import com.storlead.framework.common.constant.CommonConstant;
|
|
|
import com.storlead.framework.common.result.Result;
|
|
import com.storlead.framework.common.result.Result;
|
|
|
import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
|
|
import com.storlead.framework.mybatis.service.impl.MyBaseServiceImpl;
|
|
|
|
|
+import com.storlead.knowledge.pojo.dto.ChatDTO;
|
|
|
|
|
+import com.storlead.knowledge.service.ChatService;
|
|
|
import com.storlead.trade.dto.MarketEmailsDTO;
|
|
import com.storlead.trade.dto.MarketEmailsDTO;
|
|
|
-import com.storlead.trade.entity.MarketEmailsEntity;
|
|
|
|
|
|
|
+import com.storlead.trade.entity.*;
|
|
|
import com.storlead.trade.mapper.MarketEmailsMapper;
|
|
import com.storlead.trade.mapper.MarketEmailsMapper;
|
|
|
-import com.storlead.trade.service.MarketEmailsService;
|
|
|
|
|
|
|
+import com.storlead.trade.service.*;
|
|
|
|
|
+import com.storlead.trade.vo.MarketEmailsCustomerVO;
|
|
|
|
|
+import com.storlead.trade.vo.ScheduleStageVO;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
import org.springframework.util.CollectionUtils;
|
|
|
import org.springframework.util.ObjectUtils;
|
|
import org.springframework.util.ObjectUtils;
|
|
|
|
|
|
|
|
-import java.util.ArrayList;
|
|
|
|
|
-import java.util.List;
|
|
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
@Service
|
|
@Service
|
|
|
public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMapper, MarketEmailsEntity>
|
|
public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMapper, MarketEmailsEntity>
|
|
|
implements MarketEmailsService {
|
|
implements MarketEmailsService {
|
|
|
|
|
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private CustomerBaseEntityService customerBaseService;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private CustomerAnalysisResultEntityService customerAnalysisResultEntityService;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private CustomerEntityService customerEntityService;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private MarketingCampaignSopDetailService marketingCampaignSopDetailEntityService;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private SopDetailService sopDetailService;
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private ChatService chatService;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public Result<Object> getList(MarketEmailsDTO dto) {
|
|
public Result<Object> getList(MarketEmailsDTO dto) {
|
|
|
Page<MarketEmailsEntity> page = new Page<>(dto.getPageIndex(), dto.getPageSize());
|
|
Page<MarketEmailsEntity> page = new Page<>(dto.getPageIndex(), dto.getPageSize());
|
|
@@ -98,4 +120,173 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
|
|
|
}
|
|
}
|
|
|
return Result.ok();
|
|
return Result.ok();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void addSendTime(MarketingCampaignEntity marketingCampaignEntity) {
|
|
|
|
|
+ //获取营销活动对应的SopList
|
|
|
|
|
+ LambdaQueryWrapper<MarketingCampaignSopDetailEntity> markerSopDetailWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ markerSopDetailWrapper.eq(MarketingCampaignSopDetailEntity::getMarketingId, marketingCampaignEntity.getId());
|
|
|
|
|
+ markerSopDetailWrapper.eq(MarketingCampaignSopDetailEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
|
|
|
|
|
+ List<MarketingCampaignSopDetailEntity> marketingCampaignSopDetailEntityList = marketingCampaignSopDetailEntityService.list(markerSopDetailWrapper);
|
|
|
|
|
+ if (CollectionUtils.isEmpty(marketingCampaignSopDetailEntityList)){
|
|
|
|
|
+ return ;
|
|
|
|
|
+ }
|
|
|
|
|
+ //获取List sop_detail_id
|
|
|
|
|
+ List<Long> sopDetailIdList = marketingCampaignSopDetailEntityList.stream()
|
|
|
|
|
+ .map(MarketingCampaignSopDetailEntity::getSopDetailId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ List<SopDetailEntity> sopDetailEntityList = sopDetailService.listByIds(sopDetailIdList).stream().toList();
|
|
|
|
|
+ // 1. 查询营销关联的客户基础信息
|
|
|
|
|
+ LambdaQueryWrapper<CustomerBaseEntity> customerBaseWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ customerBaseWrapper.eq(CustomerBaseEntity::getMarketingCampaignId, marketingCampaignEntity.getId());
|
|
|
|
|
+ customerBaseWrapper.eq(CustomerBaseEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
|
|
|
|
|
+ List<CustomerBaseEntity> customerBaseList = customerBaseService.list(customerBaseWrapper);
|
|
|
|
|
+ if (CollectionUtils.isEmpty(customerBaseList)) {
|
|
|
|
|
+ return ;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 提取分析结果id列表
|
|
|
|
|
+ List<Long> customerAnalysisIdList = customerBaseList.stream()
|
|
|
|
|
+ .map(CustomerBaseEntity::getCustomerAnalysisId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 批量查询分析结果(取 customerId = customer.id)
|
|
|
|
|
+ LambdaQueryWrapper<CustomerAnalysisResultEntity> analysisWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ analysisWrapper.in(CustomerAnalysisResultEntity::getId, customerAnalysisIdList);
|
|
|
|
|
+ analysisWrapper.eq(CustomerAnalysisResultEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
|
|
|
|
|
+ List<CustomerAnalysisResultEntity> analysisList = customerAnalysisResultEntityService.list(analysisWrapper);
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 提取客户id列表,批量查询客户基本信息
|
|
|
|
|
+ List<Long> customerIdList = analysisList.stream()
|
|
|
|
|
+ .map(CustomerAnalysisResultEntity::getCustomerId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ Map<Long, CustomerEntity> customerMap = customerIdList.isEmpty()
|
|
|
|
|
+ ? Collections.emptyMap()
|
|
|
|
|
+ : customerEntityService.listByIds(customerIdList).stream()
|
|
|
|
|
+ .collect(Collectors.toMap(CustomerEntity::getId, c -> c));
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 构造返回结果
|
|
|
|
|
+ List<MarketEmailsCustomerVO> voList = new ArrayList<>();
|
|
|
|
|
+ for (CustomerAnalysisResultEntity analysis : analysisList) {
|
|
|
|
|
+ MarketEmailsCustomerVO vo = new MarketEmailsCustomerVO();
|
|
|
|
|
+ vo.setAnalysisResultId(analysis.getId());
|
|
|
|
|
+ vo.setCustomerId(analysis.getCustomerId());
|
|
|
|
|
+ vo.setCustomerLevel(analysis.getCustomerLevel());
|
|
|
|
|
+ vo.setPotentialScore(analysis.getPotentialScore());
|
|
|
|
|
+ vo.setConfidence(analysis.getConfidence());
|
|
|
|
|
+
|
|
|
|
|
+ CustomerEntity customer = customerMap.get(analysis.getCustomerId());
|
|
|
|
|
+ if (customer != null) {
|
|
|
|
|
+ vo.setCustomerName(customer.getCustomerName());
|
|
|
|
|
+ vo.setCountry(customer.getCountry());
|
|
|
|
|
+ vo.setContinent(customer.getContinent());
|
|
|
|
|
+ }
|
|
|
|
|
+ voList.add(vo);
|
|
|
|
|
+ }
|
|
|
|
|
+ //按照国家对voList进行分组
|
|
|
|
|
+ List<MarketEmailsEntity> marketEmailList = new ArrayList<>();
|
|
|
|
|
+ Map<String, List<MarketEmailsCustomerVO>> voListByCountry = voList.stream()
|
|
|
|
|
+ .collect(Collectors.groupingBy(MarketEmailsCustomerVO::getCountry));
|
|
|
|
|
+
|
|
|
|
|
+ for (Map.Entry<String, List<MarketEmailsCustomerVO>> entry : voListByCountry.entrySet()){
|
|
|
|
|
+ String country = entry.getKey();
|
|
|
|
|
+ List<MarketEmailsCustomerVO> customerVOList = entry.getValue();
|
|
|
|
|
+
|
|
|
|
|
+ Map sendMap = new HashMap();
|
|
|
|
|
+ sendMap.put("conuntry", country);
|
|
|
|
|
+ sendMap.put("steps", sopDetailEntityList);
|
|
|
|
|
+
|
|
|
|
|
+ ChatDTO chatDTO = new ChatDTO();
|
|
|
|
|
+ chatDTO.setInputs(sendMap);
|
|
|
|
|
+ chatDTO.setQuery("send_time");
|
|
|
|
|
+ chatDTO.setResponseMode("blocking");
|
|
|
|
|
+ chatDTO.setAppId("app-USCuwcmrJi3SwwSz64viUczH");
|
|
|
|
|
+ chatDTO.setUser("1");
|
|
|
|
|
+
|
|
|
|
|
+ //调取/router/rest/workflows/streaming接口获取时间
|
|
|
|
|
+ Result<Object> result = chatService.requestAnalysisToAi(chatDTO);
|
|
|
|
|
+ if (result == null || !result.isSuccess() || result.getResult() == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 解析 AI 返回的调度阶段(不同国家)
|
|
|
|
|
+ List<ScheduleStageVO> scheduleList = parseScheduleStages(result.getResult());
|
|
|
|
|
+ if (CollectionUtils.isEmpty(scheduleList)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 按 sequence 升序(1,2,3,4),与 sopDetailEntityList 按 step 顺次对齐
|
|
|
|
|
+ scheduleList.sort(Comparator.comparing(ScheduleStageVO::getSequence));
|
|
|
|
|
+ for (MarketEmailsCustomerVO customerVO : customerVOList) {
|
|
|
|
|
+ for (ScheduleStageVO scheduleStage : scheduleList){
|
|
|
|
|
+ //对比sopDetailEntityList和scheduleStage找到step和sequence相同的SopDetailEntity
|
|
|
|
|
+ SopDetailEntity sopDetail = sopDetailEntityList.stream()
|
|
|
|
|
+ .filter(detail -> detail.getStep().equals(scheduleStage.getSequence()))
|
|
|
|
|
+ .findFirst()
|
|
|
|
|
+ .orElse(null);
|
|
|
|
|
+ if (ObjectUtils.isEmpty(sopDetail)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ MarketEmailsEntity marketEmail = new MarketEmailsEntity();
|
|
|
|
|
+ marketEmail.setMarketingCampaignId(marketingCampaignEntity.getId());
|
|
|
|
|
+ marketEmail.setCustomerAnalysisId(customerVO.getAnalysisResultId());
|
|
|
|
|
+ marketEmail.setSopDetailId(sopDetail.getId());
|
|
|
|
|
+ marketEmail.setExpectSendTime(scheduleStage.getBeijingDatetime());
|
|
|
|
|
+ marketEmailList.add(marketEmail);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!marketEmailList.isEmpty()){
|
|
|
|
|
+ this.saveBatch(marketEmailList);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 解析 AI 返回的调度阶段。返回值可能是 Map / JSON 字符串 / 列表,均统一转为 List<ScheduleStageVO>。
|
|
|
|
|
+ */
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
|
+ private List<ScheduleStageVO> parseScheduleStages(Object aiResult) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 1) 已经是 List
|
|
|
|
|
+ if (aiResult instanceof List) {
|
|
|
|
|
+ return JSON.parseArray(JSON.toJSONString(aiResult), ScheduleStageVO.class);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 2) 是 Map(常见:Map.of("answer", jsonString) 或 Map.of("data", Map.of("answer",...)))
|
|
|
|
|
+ if (aiResult instanceof Map) {
|
|
|
|
|
+ Map<String, Object> map = (Map<String, Object>) aiResult;
|
|
|
|
|
+ Object answer = firstNonNull(map.get("answer"), map.get("data"));
|
|
|
|
|
+ if (answer instanceof Map) {
|
|
|
|
|
+ answer = firstNonNull(((Map<String, Object>) answer).get("answer"),
|
|
|
|
|
+ ((Map<String, Object>) answer).get("output"));
|
|
|
|
|
+ }
|
|
|
|
|
+ if (answer == null) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ String json = answer.toString();
|
|
|
|
|
+ return JSON.parseArray(json, ScheduleStageVO.class);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 3) 是 JSON 字符串
|
|
|
|
|
+ String s = aiResult.toString();
|
|
|
|
|
+ if (s.trim().startsWith("[")) {
|
|
|
|
|
+ return JSON.parseArray(s, ScheduleStageVO.class);
|
|
|
|
|
+ }
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static Object firstNonNull(Object... arr) {
|
|
|
|
|
+ for (Object o : arr) {
|
|
|
|
|
+ if (o != null) return o;
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|