|
|
@@ -0,0 +1,1840 @@
|
|
|
+package com.fs.app.service;
|
|
|
+
|
|
|
+import cn.hutool.core.util.RandomUtil;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.fs.common.constant.Constants;
|
|
|
+import com.fs.common.core.domain.R;
|
|
|
+import com.fs.common.core.redis.RedisCache;
|
|
|
+import com.fs.common.core.redis.RedisCacheT;
|
|
|
+import com.fs.common.utils.PubFun;
|
|
|
+import com.fs.common.utils.StringUtils;
|
|
|
+import com.fs.company.domain.*;
|
|
|
+import com.fs.company.mapper.*;
|
|
|
+import com.fs.company.param.ExecutionContext;
|
|
|
+import com.fs.company.service.*;
|
|
|
+import com.fs.company.service.impl.*;
|
|
|
+import com.fs.company.service.impl.call.node.AiAddWxTaskNode;
|
|
|
+import com.fs.company.service.impl.call.node.AiQwAddWxTaskNode;
|
|
|
+import com.fs.company.service.impl.call.node.WorkflowNodeFactory;
|
|
|
+import com.fs.company.vo.CompanyWxClient4WorkFlowVO;
|
|
|
+import com.fs.course.config.RedisKeyScanner;
|
|
|
+import com.fs.crm.param.SmsSendBatchParam;
|
|
|
+import com.fs.enums.ExecutionStatusEnum;
|
|
|
+import com.fs.enums.NodeTypeEnum;
|
|
|
+import com.fs.company.util.ObjectPlaceholderResolver;
|
|
|
+import com.fs.company.vo.SendMsgVo;
|
|
|
+import com.fs.course.config.WxConfig;
|
|
|
+import com.fs.crm.domain.CrmCustomer;
|
|
|
+import com.fs.crm.service.ICrmCustomerService;
|
|
|
+import com.fs.qw.domain.QwExternalContact;
|
|
|
+import com.fs.qw.domain.QwUser;
|
|
|
+import com.fs.qw.mapper.QwExternalContactMapper;
|
|
|
+import com.fs.qw.mapper.QwUserMapper;
|
|
|
+import com.fs.qwApi.domain.QwLinkCreateResult;
|
|
|
+import com.fs.qwApi.param.QwLinkCreateParam;
|
|
|
+import com.fs.qwApi.service.QwApiService;
|
|
|
+import com.fs.system.service.ISysConfigService;
|
|
|
+import com.fs.voice.utils.StringUtil;
|
|
|
+import com.fs.wxcid.dto.friend.AddContactParam;
|
|
|
+import com.fs.wxcid.service.FriendService;
|
|
|
+import com.fs.wxcid.vo.AddContactVo;
|
|
|
+import com.fs.wxwork.dto.WxAddSearchDTO;
|
|
|
+import com.fs.wxwork.dto.WxSearchContactDTO;
|
|
|
+import com.fs.wxwork.dto.WxSearchContactResp;
|
|
|
+import com.fs.wxwork.dto.WxWorkResponseDTO;
|
|
|
+import com.fs.wxwork.service.WxWorkService;
|
|
|
+import com.google.gson.JsonObject;
|
|
|
+import com.google.gson.JsonParser;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.redisson.api.RLock;
|
|
|
+import org.redisson.api.RedissonClient;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.*;
|
|
|
+import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class WxTaskService {
|
|
|
+
|
|
|
+
|
|
|
+ @Value("${cid-group-no:0}")
|
|
|
+ private Integer cidGroupNo;
|
|
|
+
|
|
|
+ private final ICompanyWxAccountService companyWxAccountService;
|
|
|
+ private final ISysConfigService sysConfigService;
|
|
|
+ private final ICompanyWxClientService companyWxClientService;
|
|
|
+ private final ICompanyWxDialogService companyWxDialogService;
|
|
|
+ private final ICompanyVoiceRoboticService companyVoiceRoboticService;
|
|
|
+ private final ObjectPlaceholderResolver objectPlaceholderResolver;
|
|
|
+ private final ICrmCustomerService crmCustomerService;
|
|
|
+ private final FriendService friendService;
|
|
|
+ private final CompanyVoiceRoboticMapper companyVoiceRoboticMapper;
|
|
|
+ private final RedisCacheT<String> redisCache;
|
|
|
+ private final CompanyVoiceRoboticCalleesMapper companyVoiceRoboticCalleesMapper;
|
|
|
+ private final CompanyVoiceRoboticWxMapper companyVoiceRoboticWxMapper;
|
|
|
+ private final CompanyWxClientMapper companyWxClientMapper;
|
|
|
+ private final CompanyVoiceRoboticWxServiceImpl companyVoiceRoboticWxServiceImpl;
|
|
|
+ private final CompanyWxAccountMapper companyWxAccountMapper;
|
|
|
+ private final CompanyVoiceRoboticCalleesServiceImpl companyVoiceRoboticCalleesServiceImpl;
|
|
|
+ private RedissonClient redissonClient;
|
|
|
+ private final CompanyVoiceRoboticServiceImpl companyVoiceRoboticServiceImpl;
|
|
|
+ private final CompanyVoiceRoboticCallLogCallphoneServiceImpl companyVoiceRoboticCallLogCallphoneService;
|
|
|
+ private final CompanyAiWorkflowExecMapper companyAiWorkflowExecMapper;
|
|
|
+ private final CompanyWorkflowEngine companyWorkflowEngine;
|
|
|
+ private final CompanyVoiceRoboticBusinessMapper companyVoiceRoboticBusinessMapper;
|
|
|
+ private final WorkflowNodeFactory workflowNodeFactory;
|
|
|
+ private final CompanySmsTempServiceImpl smsTempService;
|
|
|
+ private final ICompanySmsService companySmsService;
|
|
|
+ private final ICompanyUserService companyUserService;
|
|
|
+ private final CompanyVoiceRoboticCallLogSendmsgServiceImpl companyVoiceRoboticCallLogSendmsgService;
|
|
|
+ private final QwApiService qwApiService;
|
|
|
+ private final RedisCache redisCache2;
|
|
|
+ private final ExecutorService cidExcutor = new ThreadPoolExecutor(
|
|
|
+ 32,
|
|
|
+ 64,
|
|
|
+ 60L,
|
|
|
+ TimeUnit.SECONDS,
|
|
|
+ new LinkedBlockingQueue<>(1000),
|
|
|
+ r -> new Thread(r, "callPool-" + System.currentTimeMillis()),
|
|
|
+ new ThreadPoolExecutor.CallerRunsPolicy()
|
|
|
+ );
|
|
|
+ private final RedisKeyScanner redisKeyScanner;
|
|
|
+ private final QwUserMapper qwUserMapper;
|
|
|
+ private final WxWorkService wxWorkService;
|
|
|
+ private final QwExternalContactMapper qwExternalContactMapper;
|
|
|
+ private final CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper;
|
|
|
+
|
|
|
+ public void addWx(List<Long> accountIdList) {
|
|
|
+ log.info("==========执行加微信任务开始==========");
|
|
|
+ String json = sysConfigService.selectConfigByKey("wx.config");
|
|
|
+ WxConfig config = JSONUtil.toBean(json, WxConfig.class);
|
|
|
+ // 需要添加微信的列表
|
|
|
+ List<CompanyWxClient> list = companyWxClientService.getAddWxList(accountIdList,1);
|
|
|
+ //排除掉没到达加微步骤的人
|
|
|
+ List<CompanyVoiceRoboticCallees> exList = companyVoiceRoboticCalleesMapper.selectExcludeList(list, 1);
|
|
|
+ List<CompanyVoiceRoboticCallees> collect =
|
|
|
+ exList.stream().filter(e -> !Constants.ADD_WX.equals(getNextTaskOptimized(e.getTaskFlow(), e.getRunTaskFlow())))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ Set<String> existingKeys = collect.stream()
|
|
|
+ .map(callee -> callee.getRoboticId() + "_" + callee.getUserId())
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ list = list.stream()
|
|
|
+ .filter(client -> {
|
|
|
+ String key = client.getRoboticId() + "_" + client.getCustomerId();
|
|
|
+ return !existingKeys.contains(key);
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ log.info("需要添加微信的数量:{}", list.size());
|
|
|
+ if (list.isEmpty()) return;
|
|
|
+ List<CompanyWxClient> addList = new ArrayList<>();
|
|
|
+ Map<Long, CompanyWxClient> clientMap = PubFun.listToMapByGroupObject(list, CompanyWxClient::getAccountId);
|
|
|
+ List<CompanyWxAccount> accountList = new ArrayList<>(companyWxAccountService.listByIds(clientMap.keySet()));
|
|
|
+ log.info("查询加微的账号数量:{}", list.size());
|
|
|
+ List<CompanyWxAccount> addAccountList = accountList.stream().filter(e -> {
|
|
|
+ int newAddWxMinute = RandomUtil.randomInt(config.getNewAccountAddWxMin(), config.getNewAccountAddWxMax());
|
|
|
+ int addWxMinute = RandomUtil.randomInt(config.getAccountAddWxMin(), config.getAccountAddWxMax());
|
|
|
+ if (e.getLastAddWxTime() == null) {
|
|
|
+ log.info("加微时间为空,可以加微:{}", e.getWxNickName());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ int minute = addWxMinute;
|
|
|
+ if (e.getIsNew() == 0) {
|
|
|
+ minute = newAddWxMinute;
|
|
|
+ }
|
|
|
+ long until = e.getLastAddWxTime().until(LocalDateTime.now(), ChronoUnit.MINUTES);
|
|
|
+ log.info("判断{}是否达到最低加微时间:上次加微时间:{},时间间隔:{},当前时间:{}", e.getWxNickName(), e.getLastAddWxTime(), until, LocalDateTime.now());
|
|
|
+ return until > minute;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ log.info("实际加微的账号数量:{}", addAccountList.size());
|
|
|
+ addAccountList.forEach(e -> {
|
|
|
+ CompanyWxClient client = clientMap.get(e.getId());
|
|
|
+ if (client != null) {
|
|
|
+ String task = redisCache.getCacheObject(Constants.TASK_ID + client.getRoboticId());
|
|
|
+ log.info("ROBOTIC-ID:{},CLIENT-ID:{},当前任务执行状态:{}", client.getRoboticId(), client.getId(), task);
|
|
|
+ if (StringUtils.isNotEmpty(task) && Constants.ADD_WX.equals(task)) {
|
|
|
+ CompanyWxDialog dialog = companyWxDialogService.getById(client.getDialogId());
|
|
|
+ CrmCustomer crmCustomer = crmCustomerService.selectCrmCustomerById(client.getCustomerId());
|
|
|
+ String newTxt = objectPlaceholderResolver.resolvePlaceholders(crmCustomer, dialog.getTemplateDetails());
|
|
|
+ AddContactParam addParam = new AddContactParam();
|
|
|
+ addParam.setAccountId(e.getId());
|
|
|
+ addParam.setMobile(crmCustomer.getMobile());
|
|
|
+ addParam.setTxt(newTxt);
|
|
|
+ addParam.setClientId(client.getId());
|
|
|
+ AddContactVo vo = friendService.addContact(addParam);
|
|
|
+ JSONObject runParam = new JSONObject();
|
|
|
+ runParam.put("id", e.getId());
|
|
|
+ runParam.put("mobile", crmCustomer.getMobile());
|
|
|
+ runParam.put("txt", newTxt);
|
|
|
+ runParam.put("clientId", client.getId());
|
|
|
+ CompanyVoiceRoboticCallLogAddwx addLog = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+ runParam.toJSONString(), client.getId(), client.getRoboticId(), e.getId(), e.getCompanyId(),0);
|
|
|
+ log.info("ROBOTIC-ID:{},CLIENT-ID:{},执行加微:{},客户:{}-{},使用话术:{}", client.getRoboticId(), client.getId(), e.getId(), client.getCustomerId(), crmCustomer.getCustomerName(), dialog.getName());
|
|
|
+ if (vo.isSuccess()) {
|
|
|
+ e.setLastAddWxTime(LocalDateTime.now());
|
|
|
+ e.setIsAddNum(e.getIsAddNum() + 1);
|
|
|
+ client.setIsAdd(2);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+ client.setWxV3(vo.getV3());
|
|
|
+ client.setWxV4(vo.getV4());
|
|
|
+ addList.add(client);
|
|
|
+ addLog.setStatus(2);
|
|
|
+ addLog.setResult(JSON.toJSONString(vo));
|
|
|
+ } else {
|
|
|
+ log.error("ROBOTIC-ID:{},加微失败:{}", client.getRoboticId(), vo);
|
|
|
+ addLog.setStatus(3);
|
|
|
+ addLog.setResult(JSON.toJSONString(vo));
|
|
|
+ }
|
|
|
+ asyncSaveCompanyVoiceRoboticCallLog(addLog);
|
|
|
+ } else {
|
|
|
+ log.error("ROBOTIC-ID:{},当前任务没有执行加微任务", client.getRoboticId());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.error("当前账号暂无需要添加微信:{}-{}", e.getId(), e.getWxNickName());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (!addList.isEmpty()) {
|
|
|
+ companyWxClientService.updateBatchById(addList);
|
|
|
+ //根据加微成功的用户,判定是否加入延时执行下一步任务
|
|
|
+ Set<Long> roboticIdSet = addList.stream().map(CompanyWxClient::getRoboticId).collect(Collectors.toSet());
|
|
|
+ Set<Long> userIdSet = addList.stream().map(CompanyWxClient::getCustomerId).collect(Collectors.toSet());
|
|
|
+
|
|
|
+ //找到任务
|
|
|
+ List<CompanyVoiceRobotic> companyVoiceRobotics = companyVoiceRoboticMapper.selectBatchIds(roboticIdSet);
|
|
|
+ Map<Long, CompanyVoiceRobotic> roboticsMp = companyVoiceRobotics.stream().collect(Collectors.toMap(CompanyVoiceRobotic::getId, Function.identity(), (existing, replacement) -> existing));
|
|
|
+ //找到callees数据
|
|
|
+ List<CompanyVoiceRoboticCallees> companyVoiceRoboticCallees = companyVoiceRoboticCalleesMapper.selectCalleesListByRoboticIdsAndUserIds(userIdSet, roboticIdSet);
|
|
|
+ Map<String, CompanyVoiceRoboticCallees> calleesMp = companyVoiceRoboticCallees.stream().collect(Collectors.toMap(e -> e.getUserId() + "-" + e.getRoboticId(), Function.identity(), (existing, replacement) -> existing));
|
|
|
+
|
|
|
+ long l = System.currentTimeMillis();
|
|
|
+
|
|
|
+ //根据加微成功
|
|
|
+ for (CompanyWxClient client : addList) {
|
|
|
+ CompanyVoiceRobotic clientRobotic = roboticsMp.getOrDefault(client.getRoboticId(), null);
|
|
|
+ if (null == clientRobotic) {
|
|
|
+ log.error("ROBOTIC-ID:{},CLIENT-ID:{},没有找到任务", client.getRoboticId(), client.getId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ CompanyVoiceRoboticCallees callees = calleesMp.getOrDefault(client.getCustomerId() + "-" + client.getRoboticId(), null);
|
|
|
+ if (null == callees) {
|
|
|
+ log.error("ROBOTIC-ID:{},CLIENT-ID:{},没有找到任务", client.getRoboticId(), client.getId());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ Integer addWxTime = clientRobotic.getAddWxTime();
|
|
|
+ if (null == addWxTime) {
|
|
|
+ log.error("ROBOTIC-ID:{},CLIENT-ID:{},没有设置加微后置等待时间", client.getRoboticId(), client.getId());
|
|
|
+ } else {
|
|
|
+ long endT = System.currentTimeMillis() + addWxTime * 60 * 1000;
|
|
|
+ StringBuilder sb = new StringBuilder(Constants.CID_NEXT_TASK_ID).append(callees.getRoboticId()).append(":").append(callees.getId());
|
|
|
+ redisCache.setCacheObject(sb.toString(), String.valueOf(endT));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ companyVoiceRoboticCallees.forEach(robotic ->
|
|
|
+ robotic.setRunTaskFlow(
|
|
|
+ StringUtils.isBlank(robotic.getRunTaskFlow()) ?
|
|
|
+ Constants.ADD_WX : robotic.getRunTaskFlow() + "," + Constants.ADD_WX
|
|
|
+ )
|
|
|
+ );
|
|
|
+ companyVoiceRoboticCalleesServiceImpl.updateBatchById(companyVoiceRoboticCallees);
|
|
|
+ companyVoiceRoboticServiceImpl.finishAddWxByCallees(roboticIdSet);
|
|
|
+ }
|
|
|
+ if (!addAccountList.isEmpty()) {
|
|
|
+ companyWxAccountService.updateBatchById(addAccountList);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addWx4Workflow(List<Long> accountIdList) {
|
|
|
+ log.info("==========执行加微信任务开始==========");
|
|
|
+ String json = sysConfigService.selectConfigByKey("wx.config");
|
|
|
+ WxConfig config = JSONUtil.toBean(json, WxConfig.class);
|
|
|
+ // 需要添加微信的列表
|
|
|
+ List<CompanyWxClient4WorkFlowVO> list = companyWxClientService.getAddWxList4Workflow(accountIdList,cidGroupNo);
|
|
|
+ log.info("需要添加微信的数量:{}", list.size());
|
|
|
+ if (list.isEmpty()) return;
|
|
|
+ List<CompanyWxClient> addList = new ArrayList<>();
|
|
|
+ Map<Long, CompanyWxClient4WorkFlowVO> clientMap = PubFun.listToMapByGroupObject(list, CompanyWxClient4WorkFlowVO::getAccountId);
|
|
|
+ List<CompanyWxAccount> accountList = new ArrayList<>(companyWxAccountService.listByIds(clientMap.keySet()));
|
|
|
+ log.info("查询加微的账号数量:{}", list.size());
|
|
|
+ List<CompanyWxAccount> addAccountList = accountList.stream().filter(e -> {
|
|
|
+ int newAddWxMinute = RandomUtil.randomInt(config.getNewAccountAddWxMin(), config.getNewAccountAddWxMax());
|
|
|
+ int addWxMinute = RandomUtil.randomInt(config.getAccountAddWxMin(), config.getAccountAddWxMax());
|
|
|
+ if (e.getLastAddWxTime() == null) {
|
|
|
+ log.info("加微时间为空,可以加微:{}", e.getWxNickName());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ int minute = addWxMinute;
|
|
|
+ if (e.getIsNew() == 0) {
|
|
|
+ minute = newAddWxMinute;
|
|
|
+ }
|
|
|
+ long until = e.getLastAddWxTime().until(LocalDateTime.now(), ChronoUnit.MINUTES);
|
|
|
+ log.info("判断{}是否达到最低加微时间:上次加微时间:{},时间间隔:{},当前时间:{}", e.getWxNickName(), e.getLastAddWxTime(), until, LocalDateTime.now());
|
|
|
+ return until > minute;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ log.info("实际加微的账号数量:{}", addAccountList.size());
|
|
|
+ addAccountList.forEach(e -> {
|
|
|
+ CompanyWxClient4WorkFlowVO client = clientMap.get(e.getId());
|
|
|
+ if (client != null) {
|
|
|
+ CompanyWxDialog dialog = companyWxDialogService.getById(client.getDialogId());
|
|
|
+ CrmCustomer crmCustomer = crmCustomerService.selectCrmCustomerById(client.getCustomerId());
|
|
|
+ String newTxt = objectPlaceholderResolver.resolvePlaceholders(crmCustomer, dialog.getTemplateDetails());
|
|
|
+ AddContactParam addParam = new AddContactParam();
|
|
|
+ addParam.setAccountId(e.getId());
|
|
|
+ addParam.setMobile(crmCustomer.getMobile());
|
|
|
+ addParam.setTxt(newTxt);
|
|
|
+ addParam.setClientId(client.getId());
|
|
|
+ AddContactVo vo = friendService.addContact(addParam);
|
|
|
+ JSONObject runParam = new JSONObject();
|
|
|
+ runParam.put("id", e.getId());
|
|
|
+ runParam.put("mobile", crmCustomer.getMobile());
|
|
|
+ runParam.put("txt", newTxt);
|
|
|
+ runParam.put("clientId", client.getId());
|
|
|
+ CompanyVoiceRoboticCallLogAddwx addLog = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+ runParam.toJSONString(), client.getId(), client.getRoboticId(), e.getId(), e.getCompanyId(),0);
|
|
|
+ log.info("ROBOTIC-ID:{},CLIENT-ID:{},执行加微:{},客户:{}-{},使用话术:{}", client.getRoboticId(), client.getId(), e.getId(), client.getCustomerId(), crmCustomer.getCustomerName(), dialog.getName());
|
|
|
+ if (vo.isSuccess()) {
|
|
|
+ e.setLastAddWxTime(LocalDateTime.now());
|
|
|
+// todo 删除还原 以下为测试所用
|
|
|
+ e.setLastAddWxTime(LocalDateTime.now().plus(-1, ChronoUnit.DAYS));
|
|
|
+ e.setIsAddNum(e.getIsAddNum() + 1);
|
|
|
+ client.setIsAdd(2);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+ client.setWxV3(vo.getV3());
|
|
|
+ client.setWxV4(vo.getV4());
|
|
|
+ CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+ BeanUtils.copyProperties(client, addItem);
|
|
|
+ addList.add(addItem);
|
|
|
+ addLog.setStatus(2);
|
|
|
+ addLog.setResult(JSON.toJSONString(vo));
|
|
|
+ } else {
|
|
|
+ log.error("ROBOTIC-ID:{},加微失败:{}", client.getRoboticId(), vo);
|
|
|
+ addLog.setStatus(3);
|
|
|
+ addLog.setResult(JSON.toJSONString(vo));
|
|
|
+ }
|
|
|
+ asyncSaveCompanyVoiceRoboticCallLog(addLog);
|
|
|
+ } else {
|
|
|
+ log.error("当前账号暂无需要添加微信:{}-{}", e.getId(), e.getWxNickName());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (!addList.isEmpty()) {
|
|
|
+ companyWxClientService.updateBatchById(addList);
|
|
|
+ long l = System.currentTimeMillis();
|
|
|
+ //根据加微成功
|
|
|
+ for (CompanyWxClient client : addList) {
|
|
|
+ CompanyWxClient4WorkFlowVO vo = clientMap.get(client.getAccountId());
|
|
|
+ IWorkflowNode node = workflowNodeFactory.createNode(vo.getCurrentNodeKey(),
|
|
|
+ NodeTypeEnum.fromValue(vo.getCurrentNodeType()),
|
|
|
+ vo.getCurrentNodeName(), null);
|
|
|
+ if (node instanceof AiAddWxTaskNode) {
|
|
|
+ CompletableFuture.runAsync(() -> {
|
|
|
+ AiAddWxTaskNode addWxNode = (AiAddWxTaskNode) node;
|
|
|
+ addWxNode.doneAddwx(vo.getWorkflowInstanceId());
|
|
|
+ }, cidExcutor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!addAccountList.isEmpty()) {
|
|
|
+ companyWxAccountService.updateBatchById(addAccountList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void initAccountNum() {
|
|
|
+ LocalDateTime now = LocalDateTime.now();
|
|
|
+ String json = sysConfigService.selectConfigByKey("wx.config");
|
|
|
+ WxConfig config = JSONUtil.toBean(json, WxConfig.class);
|
|
|
+ List<CompanyWxAccount> list = companyWxAccountService.list();
|
|
|
+ list.forEach(e -> {
|
|
|
+ if (e.getAccountCreateTime() != null) {
|
|
|
+ long until = e.getAccountCreateTime().until(now.toLocalDate(), ChronoUnit.DAYS);
|
|
|
+ if (until > config.getNewAccountTime()) {
|
|
|
+ e.setIsNew(1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (e.getIsNew() == 0) {
|
|
|
+ e.setAddNum(config.getNewAccountAddNum());
|
|
|
+ } else {
|
|
|
+ e.setAddNum(RandomUtil.randomInt(config.getAccountAddMax(), config.getAccountAddMin()));
|
|
|
+ }
|
|
|
+ e.setIsAddNum(0);
|
|
|
+ e.setAllocateNum(0);
|
|
|
+ });
|
|
|
+ companyWxAccountService.updateBatchById(list);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public void initAccountMsg() {
|
|
|
+ String json = sysConfigService.selectConfigByKey("wx.config");
|
|
|
+ WxConfig config = JSONUtil.toBean(json, WxConfig.class);
|
|
|
+ List<CompanyWxAccount> list = companyWxAccountService.list();
|
|
|
+ list.forEach(e -> {
|
|
|
+ int txtNum = RandomUtil.randomInt(config.getTxtMsgMinNum(), config.getTxtMsgMaxNum());
|
|
|
+ int imgNum = RandomUtil.randomInt(config.getImgMsgMinNum(), config.getImgMsgMaxNum());
|
|
|
+ e.setSendMsgJson(JSON.toJSONString(SendMsgVo.builder().txt(txtNum).img(imgNum).build()));
|
|
|
+ });
|
|
|
+ companyWxAccountService.updateBatchById(list);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void cellRun() {
|
|
|
+ log.info("===========CID任务开始执行===========");
|
|
|
+ List<CompanyVoiceRobotic> list = companyVoiceRoboticMapper.selectList(new QueryWrapper<CompanyVoiceRobotic>().eq("task_status", 1));
|
|
|
+ List<CompanyVoiceRobotic> successList = list.stream().filter(e -> StringUtils.isNotEmpty(e.getRunTaskFlow()) && e.getTaskFlow().length() == e.getRunTaskFlow().length()).collect(Collectors.toList());
|
|
|
+ List<CompanyVoiceRobotic> waitList = list.stream().filter(e -> StringUtils.isEmpty(e.getRunTaskFlow()) || e.getTaskFlow().length() != e.getRunTaskFlow().length()).collect(Collectors.toList());
|
|
|
+ successList.forEach(e -> e.setTaskStatus(3));
|
|
|
+ if (!successList.isEmpty()) {
|
|
|
+ log.info("已经完成任务:{}", successList.size());
|
|
|
+ companyVoiceRoboticService.updateBatchById(successList);
|
|
|
+ }
|
|
|
+ waitList.forEach(e -> {
|
|
|
+ log.info("ROBOTIC-ID:{},开始执行小任务:{}", e.getId(), e.getName());
|
|
|
+ List<String> taskFlow = new ArrayList<>(Arrays.asList(e.getTaskFlow().split(",")));
|
|
|
+ log.info("ROBOTIC-ID:{},当前任务顺序:{}", e.getId(), e.getTaskFlow());
|
|
|
+ String runTaskFlow = e.getRunTaskFlow();
|
|
|
+ log.info("ROBOTIC-ID:{},已有任务:{}", e.getId(), e.getRunTaskFlow());
|
|
|
+ if (StringUtils.isNotEmpty(runTaskFlow)) {
|
|
|
+ Arrays.asList(runTaskFlow.split(",")).forEach(taskFlow::remove);
|
|
|
+ }
|
|
|
+ log.info("ROBOTIC-ID:{},当前还剩余任务:{}", e.getId(), taskFlow);
|
|
|
+ e.setNowTask(taskFlow.get(0));
|
|
|
+ log.info("ROBOTIC-ID:{},当前需要执行任务:{}", e.getId(), e.getNowTask());
|
|
|
+ });
|
|
|
+ Function<CompanyVoiceRobotic, String> getKey = e -> Constants.TASK_ID + e.getId();
|
|
|
+ waitList.forEach(e -> {
|
|
|
+ if (redisCache.getCacheObject(getKey.apply(e)) != null) {
|
|
|
+ log.info("ROBOTIC-ID:{},已有正在执行任务", e.getId());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ redisCache.setCacheObject(getKey.apply(e), e.getNowTask());
|
|
|
+ try {
|
|
|
+ switch (e.getNowTask()) {
|
|
|
+ case Constants.CELL_PHONE:
|
|
|
+ companyVoiceRoboticService.addTask(e);
|
|
|
+ log.info("ROBOTIC-ID:{},打电话任务创建完成", e.getId());
|
|
|
+ break;
|
|
|
+ case Constants.ADD_WX:
|
|
|
+ //第一步是调用添加微信步骤
|
|
|
+ if (StringUtils.isBlank(e.getRunTaskFlow()) && StringUtils.isNotBlank(e.getTaskFlow()) && e.getTaskFlow().startsWith(Constants.ADD_WX)) {
|
|
|
+ companyVoiceRoboticServiceImpl.allocateWx(e);
|
|
|
+// CompletableFuture.supplyAsync(()->{
|
|
|
+// //分配个微账号
|
|
|
+// return allocateWx(e);
|
|
|
+// },cidExcutor).thenApply(result->{
|
|
|
+// //逐条添加微信,且判定是否任务
|
|
|
+// for (CompanyWxClient client : result) {
|
|
|
+// ArrayList<Long> addWxParamList = new ArrayList<>();
|
|
|
+// addWxParamList.add(client.getAccountId());
|
|
|
+// //添加微信 todo 暂时注释掉 不在添加微信 发布时需要开放
|
|
|
+//// addWx(addWxParamList);
|
|
|
+// //判定任务是否有加微后等待时间设定,加入到待执行任务redis
|
|
|
+// if(null != e.getAddWxTime() && e.getAddWxTime() > 0){
|
|
|
+// long endT = System.currentTimeMillis() + e.getAddWxTime() * 60 * 1000;
|
|
|
+// //通过任务+用户id找到calles记录
|
|
|
+// CompanyVoiceRoboticCallees callees = companyVoiceRoboticCalleesMapper.getCalleesByUserIdAndTaskId(client.getCustomerId(), e.getId());
|
|
|
+// if(null != callees && !ObjectUtil.isEmpty(callees)){
|
|
|
+// Long calleesId = callees.getId();
|
|
|
+// StringBuilder sb = new StringBuilder(Constants.CID_NEXT_TASK_ID).append(e.getId()).append(":").append(calleesId);
|
|
|
+// redisCache.setCacheObject(sb.toString(), String.valueOf(endT),e.getAddWxTime() + 5, TimeUnit.MINUTES);
|
|
|
+// if(StringUtils.isNotBlank(callees.getRunTaskFlow())){
|
|
|
+// callees.setRunTaskFlow(callees.getRunTaskFlow() + "," + Constants.ADD_WX);
|
|
|
+// }else{
|
|
|
+// callees.setRunTaskFlow(Constants.ADD_WX);
|
|
|
+// }
|
|
|
+// companyVoiceRoboticCalleesMapper.updateById(callees);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// e.setRunTaskFlow(Constants.ADD_WX);
|
|
|
+// //更新任务 已跑任务值
|
|
|
+// companyVoiceRoboticMapper.updateById(e);
|
|
|
+// }
|
|
|
+// return null;
|
|
|
+// }).exceptionally(ex -> {
|
|
|
+// log.error("ROBOTIC-ID:{},任务执行异常:{}", e.getId(), e.getNowTask(), ex);
|
|
|
+// return null;
|
|
|
+// });
|
|
|
+ } else {
|
|
|
+ //todo 接入原有加微逻辑
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case Constants.SEND_MSG:
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (Exception exception) {
|
|
|
+ log.error("ROBOTIC-ID:{},任务执行失败:{}", e.getId(), e.getNowTask(), exception);
|
|
|
+ redisCache.deleteObject(getKey.apply(e));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ log.info("===========CID任务执行完成===========");
|
|
|
+ }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 分配账号
|
|
|
+// * @param robotic
|
|
|
+// */
|
|
|
+// @Transactional
|
|
|
+// @Deprecated
|
|
|
+// public List<CompanyWxClient> allocateWx(CompanyVoiceRobotic robotic) {
|
|
|
+// List<CompanyWxClient> resArr = new ArrayList<>();
|
|
|
+// //找到任务指定的微信用户
|
|
|
+// List<CompanyVoiceRoboticWx> companyVoiceRoboticWxes = companyVoiceRoboticWxMapper.selectByRoboticIdWithGroupBy(robotic.getId());
|
|
|
+// Integer totalSize = 0;
|
|
|
+// if (null != companyVoiceRoboticWxes && !companyVoiceRoboticWxes.isEmpty()) {
|
|
|
+// totalSize = companyVoiceRoboticWxes.size();
|
|
|
+// } else {
|
|
|
+// log.error("分配对象空,数据异常");
|
|
|
+// throw new RuntimeException("没有找到任务指定的微信用户");
|
|
|
+// }
|
|
|
+// List<CompanyWxAccount> accountIds = companyWxAccountMapper.selectBatchIds(PubFun.listToNewList(companyVoiceRoboticWxes, CompanyVoiceRoboticWx::getAccountId));
|
|
|
+// Map<Long, CompanyWxAccount> accountMap = PubFun.listToMapByGroupObject(accountIds, CompanyWxAccount::getId);
|
|
|
+// List<CompanyWxClient> companyWxClients = companyWxClientMapper.selectListByRoboticId(robotic.getId());
|
|
|
+// List<Long> ids = PubFun.listToNewList(companyWxClients, CompanyWxClient::getCustomerId);
|
|
|
+// List<CrmCustomer> crmCustomerList = crmCustomerService.selectCrmCustomerListByIds(ids.stream().map(e -> e + "").collect(Collectors.joining(",")));
|
|
|
+// Map<Long, CrmCustomer> customerMap = PubFun.listToMapByGroupObject(crmCustomerList, CrmCustomer::getCustomerId);
|
|
|
+// if (null == companyWxClients || companyWxClients.isEmpty()) {
|
|
|
+// log.error("分配个微空,数据异常");
|
|
|
+// throw new RuntimeException("没有找到需要分配微信用户");
|
|
|
+// }
|
|
|
+// Integer allocateIndex = 0;
|
|
|
+// List<CompanyVoiceRoboticWx> updateCompanyVoiceRoboticWxList = new ArrayList<>();
|
|
|
+// //分配客户
|
|
|
+// for (CompanyWxClient companyWxClient : companyWxClients) {
|
|
|
+// new CompanyVoiceRoboticWx();
|
|
|
+// CompanyVoiceRoboticWx wx = companyVoiceRoboticWxes.get(allocateIndex++ % totalSize);
|
|
|
+// CompanyWxAccount account = accountMap.get(wx.getAccountId());
|
|
|
+// CrmCustomer crmCustomer = customerMap.get(companyWxClient.getCustomerId());
|
|
|
+// companyWxClient.setRoboticWxId(wx.getId());
|
|
|
+// companyWxClient.setAccountId(wx.getAccountId());
|
|
|
+// companyWxClient.setDialogId(wx.getWxDialogId());
|
|
|
+// companyWxClient.setCompanyUserId(account.getCompanyUserId());
|
|
|
+// companyWxClient.setNickName(crmCustomer.getCustomerName());
|
|
|
+// companyWxClient.setPhone(crmCustomer.getMobile());
|
|
|
+// resArr.add(companyWxClient);
|
|
|
+// if (wx.getNum() == null) {
|
|
|
+// wx.setNum(1);
|
|
|
+// } else {
|
|
|
+// wx.setNum(wx.getNum() + 1);
|
|
|
+// }
|
|
|
+// updateCompanyVoiceRoboticWxList.add(wx);
|
|
|
+// }
|
|
|
+// //保存数据库
|
|
|
+// companyWxClientService.updateBatchById(companyWxClients);
|
|
|
+// companyVoiceRoboticWxServiceImpl.updateBatchById(updateCompanyVoiceRoboticWxList);
|
|
|
+// return resArr;
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 单任务加微
|
|
|
+ *
|
|
|
+ * @param roboticId
|
|
|
+ * @param callerId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Boolean addWxOne(Long roboticId, Long callerId) {
|
|
|
+
|
|
|
+ return Boolean.TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 单个任务执行且为单条执行对象
|
|
|
+ *
|
|
|
+ * @param roboticId
|
|
|
+ * @param callerId
|
|
|
+ */
|
|
|
+ public String cellRunOne(Long roboticId, Long callerId) {
|
|
|
+
|
|
|
+ //查询任务执行情况
|
|
|
+ CompanyVoiceRoboticCallees data = companyVoiceRoboticCalleesMapper.selectDataByCalleesId(callerId);
|
|
|
+ CompanyVoiceRobotic robotic = companyVoiceRoboticMapper.selectCompanyVoiceRoboticById(roboticId);
|
|
|
+ String taskFlow = data.getTaskFlow();
|
|
|
+ if (null == data || null == robotic) {
|
|
|
+ log.error("没有查询到任务执行数据,roboticId:{},callerId:{}", roboticId, callerId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if (Integer.valueOf(3).equals(robotic.getTaskStatus())) {
|
|
|
+ log.error("执行任务已经完成了,roboticId:{}", roboticId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String nextTask;
|
|
|
+ if (StringUtils.isNotBlank(data.getRunTaskFlow()) && StringUtils.isNotBlank(taskFlow)) {
|
|
|
+ nextTask = getNextTaskOptimized(taskFlow, data.getRunTaskFlow());
|
|
|
+ } else {
|
|
|
+ //如果个人任务流程没有维护,执行当前个人在任务流程中的任务流程节点
|
|
|
+ nextTask = getNextTaskOptimized(robotic.getTaskFlow(), robotic.getRunTaskFlow());
|
|
|
+ taskFlow = robotic.getTaskFlow();
|
|
|
+ data.setRunTaskFlow(robotic.getRunTaskFlow());
|
|
|
+// return null;
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(nextTask)) {
|
|
|
+ log.error("任务没有下个执行任务,标记完成,roboticId:{}", roboticId);
|
|
|
+ companyVoiceRoboticMapper.finishRobotic(roboticId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ log.info("单人单任务执行ROBOTIC-ID:{},caller_id:{},当前需要执行任务:{}", roboticId, callerId, nextTask);
|
|
|
+ String nextTaskOptimized = null;
|
|
|
+ try {
|
|
|
+ switch (nextTask) {
|
|
|
+ case Constants.CELL_PHONE:
|
|
|
+ companyVoiceRoboticService.callPhoneOne(roboticId, callerId);
|
|
|
+ nextTaskOptimized = getNextTaskOptimized(taskFlow, data.getRunTaskFlow() + "," + Constants.CELL_PHONE);
|
|
|
+ break;
|
|
|
+ case Constants.ADD_WX:
|
|
|
+ Boolean success = addWxOne(roboticId, callerId);
|
|
|
+ break;
|
|
|
+ case Constants.SEND_MSG:
|
|
|
+ if (Integer.valueOf(0).equals(data.getIsSendMsg())) {
|
|
|
+ //发送短信前一个任务如果是打电话 等待电话打完以后再执行发送
|
|
|
+ String lastTaskOptimized = getLastTaskOptimized(taskFlow);
|
|
|
+ if (Constants.CELL_PHONE.equals(lastTaskOptimized)) {
|
|
|
+ //是否打电话结束有回调值 完成电话动作以后执行下一步
|
|
|
+ CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone = companyVoiceRoboticCallLogCallphoneService.selectLogByRoboticIdAndCallerId(roboticId, callerId);
|
|
|
+ if (null != companyVoiceRoboticCallLogCallphone && companyVoiceRoboticCallLogCallphone.getStatus() == 1) {
|
|
|
+ nextTaskOptimized = "wait callPhone";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+// todo AI电话执行失败了 是否执行发送短信
|
|
|
+// if(null != companyVoiceRoboticCallLogCallphone && companyVoiceRoboticCallLogCallphone.getStatus() == 3){
|
|
|
+// nextTaskOptimized = "error callPhone";
|
|
|
+// break;
|
|
|
+// }
|
|
|
+ }
|
|
|
+ companyVoiceRoboticService.sendMsgOne(roboticId, callerId);
|
|
|
+ nextTaskOptimized = getNextTaskOptimized(taskFlow, data.getRunTaskFlow() + "," + Constants.SEND_MSG);
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ log.info("不再需要发送短信处理,roboticId:{},callerId:{}", roboticId, callerId);
|
|
|
+ nextTaskOptimized = getNextTaskOptimized(taskFlow, data.getRunTaskFlow() + "," + Constants.SEND_MSG);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("执行任务异常,roboticId:{},callerId:{},nextTask:{}", roboticId, callerId, nextTask, ex);
|
|
|
+ nextTaskOptimized = "exception";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(nextTaskOptimized)) {
|
|
|
+ return nextTaskOptimized;
|
|
|
+ } else {
|
|
|
+ //任务执行完了 没有下一步 直接完成任务
|
|
|
+// companyVoiceRoboticMapper.finishRobotic(roboticId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取下一个任务
|
|
|
+ *
|
|
|
+ * @param taskFlow
|
|
|
+ * @param runTaskFlow
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String getNextTaskOptimized(String taskFlow, String runTaskFlow) {
|
|
|
+ if (StringUtils.isBlank(taskFlow)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String[] allTasks = taskFlow.split(",");
|
|
|
+ Set<String> executedTasks = new HashSet<>();
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(runTaskFlow)) {
|
|
|
+ executedTasks.addAll(Arrays.asList(runTaskFlow.split(",")));
|
|
|
+ }
|
|
|
+ for (String task : allTasks) {
|
|
|
+ if (!executedTasks.contains(task.trim())) {
|
|
|
+ return task.trim();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取最后一个执行的任务
|
|
|
+ *
|
|
|
+ * @param taskFlow
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String getLastTaskOptimized(String taskFlow) {
|
|
|
+ return taskFlow.substring(taskFlow.lastIndexOf(",") + 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 调用下一个任务
|
|
|
+ */
|
|
|
+ public void callNextTask() {
|
|
|
+ //
|
|
|
+ RLock lock = redissonClient.getLock("CID_CALL_NEXT_TASK");
|
|
|
+ try {
|
|
|
+ lock.lock();
|
|
|
+ log.info("===========CID扫描执行下一个任务任务执行开始===========");
|
|
|
+ long l = System.currentTimeMillis();
|
|
|
+ Collection<String> keys = redisCache.keys(Constants.CID_NEXT_TASK_ID + "*");
|
|
|
+ keys.parallelStream().forEach(key -> {
|
|
|
+ String[] keyArr = key.split(":");
|
|
|
+ String taskId = keyArr[keyArr.length - 2];
|
|
|
+ String callerId = keyArr[keyArr.length - 1];
|
|
|
+ Long runTime = Long.valueOf(redisCache.getCacheObject(key));
|
|
|
+ log.info("任务执行时间:{},当前时间:{}", runTime, l);
|
|
|
+ //到了该执行时间
|
|
|
+ if (runTime.compareTo(l) <= 0) {
|
|
|
+ log.info("开始执行任务:{},callerId:{}", taskId, callerId);
|
|
|
+ //得到待执行任务
|
|
|
+ CompletableFuture.supplyAsync(() -> this.cellRunOne(Long.valueOf(taskId), Long.valueOf(callerId)), cidExcutor).thenApply(res -> {
|
|
|
+ if (StringUtils.isBlank(res)) {
|
|
|
+ redisCache.deleteObject(key);
|
|
|
+ redisCache.deleteObject(Constants.TASK_ID + taskId);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }).exceptionally(throwable -> {
|
|
|
+ log.error("单项任务执行或删除失败,taskId: {},callerId:{}", taskId, callerId, throwable);
|
|
|
+ return null;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // todo 加入新逻辑 没有到执行时间的待执行任务 检查上一个任务的执行状态
|
|
|
+ // 如果是已经完成的状态 修改待执行时间为现在 下次进入任务会直接执行对应的下个任务
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("CID任务自动调用调用下一个任务失败", ex);
|
|
|
+ } finally {
|
|
|
+ if (lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ CompanyVoiceRoboticCallLogServiceImpl companyVoiceRoboticCallLogService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ CompanyVoiceRoboticCallLogAddwxServiceImpl companyVoiceRoboticCallLogAddwxService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录任务执行日志 addWx
|
|
|
+ *
|
|
|
+ * @param logAddwx
|
|
|
+ */
|
|
|
+ public void asyncSaveCompanyVoiceRoboticCallLog(CompanyVoiceRoboticCallLogAddwx logAddwx) {
|
|
|
+ try {
|
|
|
+ companyVoiceRoboticCallLogAddwxService.asyncInsertCompanyVoiceRoboticCallLog(logAddwx);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("记录任务执行日志失败:失败数据:{}", logAddwx, ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 工作流加微超时检测
|
|
|
+ * 扫描Redis中的加微超时检测Key,如果超时则触发工作流继续执行
|
|
|
+ */
|
|
|
+ public void checkWorkflowAddWxTimeout() {
|
|
|
+ RLock lock = redissonClient.getLock("WORKFLOW_ADD_WX_TIMEOUT_CHECK");
|
|
|
+ try {
|
|
|
+ lock.lock();
|
|
|
+ log.info("===========工作流加微超时检测开始===========");
|
|
|
+ long currentTime = System.currentTimeMillis();
|
|
|
+
|
|
|
+ // 扫描所有加微超时检测Key
|
|
|
+ Collection<String> keys = redisCache.keys(Constants.WORKFLOW_ADD_WX_TIMEOUT + "*");
|
|
|
+ if (keys == null || keys.isEmpty()) {
|
|
|
+ log.info("没有待检测的加微超时Key");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("找到 {} 个待检测的加微超时Key", keys.size());
|
|
|
+
|
|
|
+ keys.parallelStream().forEach(key -> {
|
|
|
+ try {
|
|
|
+ // 解析Key: workflow:addwx:timeout:{workflowInstanceId}:{wxClientId}
|
|
|
+ String[] keyParts = key.split(":");
|
|
|
+ if (keyParts.length < 5) {
|
|
|
+ log.warn("无效的加微超时Key格式: {}", key);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String workflowInstanceId = keyParts[keyParts.length - 2];
|
|
|
+ Long wxClientId = Long.parseLong(keyParts[keyParts.length - 1]);
|
|
|
+
|
|
|
+ // 获取超时时间戳
|
|
|
+ String timeoutStr = redisCache.getCacheObject(key);
|
|
|
+ if (StringUtils.isBlank(timeoutStr)) {
|
|
|
+ log.warn("加微超时Key值为空: {}", key);
|
|
|
+ redisCache.deleteObject(key);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ long timeoutTimestamp = Long.parseLong(timeoutStr);
|
|
|
+
|
|
|
+ // 检查是否超时
|
|
|
+ if (currentTime < timeoutTimestamp) {
|
|
|
+ // 还没到超时时间
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("加微超时,准备触发工作流继续执行 - workflowInstanceId: {}, wxClientId: {}",
|
|
|
+ workflowInstanceId, wxClientId);
|
|
|
+
|
|
|
+ // 互斥检查:如果已经被执行过(回调成功路径),则不再执行
|
|
|
+ if (!AiAddWxTaskNode.tryMarkAsExecuted(workflowInstanceId, wxClientId)) {
|
|
|
+ log.info("工作流已被其他路径执行,跳过超时处理 - workflowInstanceId: {}, wxClientId: {}",
|
|
|
+ workflowInstanceId, wxClientId);
|
|
|
+ // 清除超时Key
|
|
|
+ redisCache.deleteObject(key);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除超时Key
|
|
|
+ redisCache.deleteObject(key);
|
|
|
+
|
|
|
+ // 查找等待中的加微工作流实例
|
|
|
+ CompanyAiWorkflowExec waitingExec = companyAiWorkflowExecMapper.selectWaitingAddWxWorkflowByWxClientId(
|
|
|
+ wxClientId,
|
|
|
+ ExecutionStatusEnum.WAITING.getValue(),
|
|
|
+ NodeTypeEnum.AI_ADD_WX_TASK.getValue());
|
|
|
+
|
|
|
+ if (waitingExec == null) {
|
|
|
+ log.info("未找到等待中的加微工作流实例 - wxClientId: {}", wxClientId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ String currentNodeKey = waitingExec.getCurrentNodeKey();
|
|
|
+
|
|
|
+ // 触发工作流继续执行(超时路径)
|
|
|
+ Map<String, Object> inputData = new HashMap<>();
|
|
|
+ inputData.put("addWxSuccess", false); // 超时意味着加微未成功
|
|
|
+ inputData.put("wxClientId", wxClientId);
|
|
|
+ inputData.put("triggerType", "timeout"); // 超时触发
|
|
|
+
|
|
|
+ companyWorkflowEngine.resumeFromBlockingNode(workflowInstanceId, currentNodeKey, inputData);
|
|
|
+
|
|
|
+ log.info("加微超时触发工作流继续执行完成 - workflowInstanceId: {}, wxClientId: {}",
|
|
|
+ workflowInstanceId, wxClientId);
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("处理加微超时检测异常 - key: {}", key, ex);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ log.info("===========工作流加微超时检测结束===========");
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("工作流加微超时检测任务异常", ex);
|
|
|
+ } finally {
|
|
|
+ if (lock.isHeldByCurrentThread()) {
|
|
|
+ lock.unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 扫描工作流延时任务
|
|
|
+ */
|
|
|
+ public void cidWorkflowAddWxRun() {
|
|
|
+ log.info("===========工作流延时任务开始扫描===========");
|
|
|
+ String delayAddWxKeyPrefix = AiAddWxTaskNode.getDelayAddWxKeyPrefix(cidGroupNo,null) + "*";
|
|
|
+ Set<String> keys = redisKeyScanner.scanMatchKey(delayAddWxKeyPrefix);
|
|
|
+ log.info("共扫描到 {} 个待处理键", keys.size());
|
|
|
+ keys.parallelStream().forEach(key -> {
|
|
|
+ try {
|
|
|
+ //doExec
|
|
|
+ CompletableFuture.runAsync(()->{
|
|
|
+ try {
|
|
|
+ ExecutionContext context = redisCache2.getCacheObject(key);
|
|
|
+ context.setVariable("callRedisKey",key);
|
|
|
+ context.setVariable("callSource","addWxTimer");
|
|
|
+ companyWorkflowEngine.timeDoExecute(context.getWorkflowInstanceId(),context.getCurrentNodeKey(),context.getVariables());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理工作流延时任务异常 - key: {}", key, e);
|
|
|
+ }
|
|
|
+ }, cidExcutor).thenRun(()->{
|
|
|
+ redisCache2.deleteObject(key);
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("处理工作流延时任务异常 - key: {}", key, ex);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ log.info("===========工作流延时任务扫描结束===========");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 企微加微信任务
|
|
|
+ *
|
|
|
+ * @param accountIdList 企微成员id
|
|
|
+ */
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 企微加微方式:主动申请
|
|
|
+ */
|
|
|
+ private static final int QW_ADD_WX_TYPE_APPLY = 1;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 企微加微方式:短信获客链接
|
|
|
+ */
|
|
|
+ private static final int QW_ADD_WX_TYPE_SMS_LINK = 2;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 默认加微方式 ID
|
|
|
+ */
|
|
|
+ private static final int DEFAULT_QW_WX_ADD_WAY_ID = 1;
|
|
|
+
|
|
|
+ public void qwAddWx(List<Long> accountIdList) {
|
|
|
+ log.info("==========执行申请企微加好友任务开始==========");
|
|
|
+ try {
|
|
|
+ // 获取需要添加微信的列表
|
|
|
+ List<CompanyWxClient4WorkFlowVO> list = companyWxClientService.getQwAddWxList4Workflow(accountIdList);
|
|
|
+ log.info("申请企微加好友任务需要添加微信的数量:{}", list.size());
|
|
|
+ if (list.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建客户映射
|
|
|
+ Map<Long, CompanyWxClient4WorkFlowVO> clientMap = PubFun.listToMapByGroupObject(
|
|
|
+ list, CompanyWxClient4WorkFlowVO::getAccountId);
|
|
|
+
|
|
|
+ // 获取有效的企微用户列表
|
|
|
+ List<QwUser> addAccountList = qwUserMapper.selectBatchIds(clientMap.keySet()).stream()
|
|
|
+ .filter(this::isValidQwUser)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ log.info("企微申请加好友任务需要企微的账号数量:{}", addAccountList.size());
|
|
|
+ if (addAccountList.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理每个企微用户的加微请求
|
|
|
+ List<CompanyWxClient> updateList = processQwAddWxRequests(addAccountList, clientMap);
|
|
|
+
|
|
|
+ // 批量更新并触发后续流程
|
|
|
+ if (!updateList.isEmpty()) {
|
|
|
+ companyWxClientService.updateBatchById(updateList);
|
|
|
+ triggerNextWorkflowSteps(updateList, clientMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("企微申请加好友任务执行异常", e);
|
|
|
+ }
|
|
|
+ log.info("==========执行企微申请加好友任务结束==========");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理所有企微用户的加微请求
|
|
|
+ */
|
|
|
+ private List<CompanyWxClient> processQwAddWxRequests(
|
|
|
+ List<QwUser> addAccountList,
|
|
|
+ Map<Long, CompanyWxClient4WorkFlowVO> clientMap) {
|
|
|
+
|
|
|
+ List<CompanyWxClient> updateList = new ArrayList<>();
|
|
|
+
|
|
|
+ for (QwUser qwUser : addAccountList) {
|
|
|
+ CompanyWxClient4WorkFlowVO client = clientMap.get(qwUser.getId());
|
|
|
+ if (client == null) {
|
|
|
+ log.error("企微申请加好友任务当前账号暂无需要添加微信:{}-{}",
|
|
|
+ qwUser.getId(), qwUser.getQwUserName());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 解析配置参数
|
|
|
+ NodeConfig config = parseNodeConfig(client.getNodeConfig());
|
|
|
+
|
|
|
+ // 根据加微方式处理
|
|
|
+ CompanyWxClient result = handleQwAddWxByType(qwUser, client, config);
|
|
|
+ if (result != null) {
|
|
|
+ updateList.add(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理企微加微请求失败 - accountId: {}, qwUserId: {}",
|
|
|
+ client.getAccountId(), qwUser.getId(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return updateList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析节点配置
|
|
|
+ */
|
|
|
+ private NodeConfig parseNodeConfig(String nodeConfigStr) {
|
|
|
+ NodeConfig config = new NodeConfig();
|
|
|
+ config.qwWxAddWayId = DEFAULT_QW_WX_ADD_WAY_ID;
|
|
|
+ config.smsTempId = DEFAULT_QW_WX_ADD_WAY_ID;
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(nodeConfigStr)) {
|
|
|
+ return config;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ JsonObject configJson = JsonParser.parseString(nodeConfigStr).getAsJsonObject();
|
|
|
+ if (configJson.has("qwWxAddWayId") && !configJson.get("qwWxAddWayId").isJsonNull()) {
|
|
|
+ config.qwWxAddWayId = configJson.get("qwWxAddWayId").getAsInt();
|
|
|
+ }
|
|
|
+ if (configJson.has("smsTempId") && !configJson.get("smsTempId").isJsonNull()) {
|
|
|
+ config.smsTempId = configJson.get("smsTempId").getAsInt();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("解析配置出错,使用默认值:{}", e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return config;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据加微方式类型处理
|
|
|
+ */
|
|
|
+ private CompanyWxClient handleQwAddWxByType(
|
|
|
+ QwUser qwUser,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ NodeConfig config) {
|
|
|
+
|
|
|
+ switch (config.qwWxAddWayId) {
|
|
|
+ case QW_ADD_WX_TYPE_APPLY:
|
|
|
+ return handleApplyAddWx(qwUser, client, config);
|
|
|
+ case QW_ADD_WX_TYPE_SMS_LINK:
|
|
|
+ return handleSmsLinkAddWx(qwUser, client, config);
|
|
|
+ default:
|
|
|
+ log.warn("未知的加微方式:{}", config.qwWxAddWayId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理主动申请加微
|
|
|
+ */
|
|
|
+ private CompanyWxClient handleApplyAddWx(
|
|
|
+ QwUser qwUser,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ NodeConfig config) {
|
|
|
+
|
|
|
+ CrmCustomer crmCustomer = crmCustomerService.selectCrmCustomerById(client.getCustomerId());
|
|
|
+
|
|
|
+ // 发起加微申请
|
|
|
+ WxWorkResponseDTO<String> resp = qwAddWxInvokeIpad(
|
|
|
+ crmCustomer.getMobile(),
|
|
|
+ qwUser.getUid(),
|
|
|
+ qwUser.getServerId(),
|
|
|
+ qwUser.getVid(),
|
|
|
+ qwUser.getQwUserName()
|
|
|
+ );
|
|
|
+
|
|
|
+ // 准备日志参数
|
|
|
+ JSONObject runParam = buildAddWxRunParam(qwUser, client, crmCustomer.getMobile());
|
|
|
+ CompanyVoiceRoboticCallLogAddwx addLog = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+ runParam.toJSONString(),
|
|
|
+ client.getId(),
|
|
|
+ client.getRoboticId(),
|
|
|
+ qwUser.getId(),
|
|
|
+ qwUser.getCompanyId(),
|
|
|
+ config.qwWxAddWayId
|
|
|
+ );
|
|
|
+
|
|
|
+ // 处理结果
|
|
|
+ if (resp != null && resp.getErrcode() == 0) {
|
|
|
+ // 加微成功
|
|
|
+ client.setIsAdd(2);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+
|
|
|
+ CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+ BeanUtils.copyProperties(client, addItem);
|
|
|
+
|
|
|
+ addLog.setStatus(2);
|
|
|
+ addLog.setResult(JSON.toJSONString(resp));
|
|
|
+ addLog.setIsWeCom(2);
|
|
|
+ log.info("ROBOTIC-ID:{},企微申请加好友任务申请成功", client.getRoboticId());
|
|
|
+
|
|
|
+ asyncSaveCompanyVoiceRoboticCallLog(addLog);
|
|
|
+ return addItem;
|
|
|
+ } else {
|
|
|
+ // 加微失败
|
|
|
+ client.setIsAdd(3);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+
|
|
|
+
|
|
|
+ CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+ BeanUtils.copyProperties(client, addItem);
|
|
|
+
|
|
|
+
|
|
|
+ addLog.setStatus(3);
|
|
|
+ addLog.setResult(JSON.toJSONString(runParam));
|
|
|
+ log.error("ROBOTIC-ID:{},企微申请加好友任务加微失败:{}",
|
|
|
+ client.getRoboticId(), runParam);
|
|
|
+
|
|
|
+ asyncSaveCompanyVoiceRoboticCallLog(addLog);
|
|
|
+ return addItem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理短信获客链接加微
|
|
|
+ */
|
|
|
+ private CompanyWxClient handleSmsLinkAddWx(
|
|
|
+ QwUser qwUser,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ NodeConfig config) {
|
|
|
+
|
|
|
+ // 查询短信模板
|
|
|
+ CompanySmsTemp temp = smsTempService.selectCompanySmsTempById((long) config.smsTempId);
|
|
|
+ if (temp == null || !temp.getStatus().equals(1) || !temp.getIsAudit().equals(1)) {
|
|
|
+ log.error("短信模板无效或未审核:{}", temp);
|
|
|
+ throw new RuntimeException("短信模板无效或未审核");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询公司短信信息
|
|
|
+ CompanySms sms = companySmsService.selectCompanySmsByCompanyId(qwUser.getCompanyId());
|
|
|
+ if (sms == null) {
|
|
|
+ log.error("公司短信信息不存在:companyId: {}", qwUser.getCompanyId());
|
|
|
+ throw new RuntimeException("公司短信信息不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sms.getRemainSmsCount() <= 0) {
|
|
|
+ log.error("剩余短信数量不足:companyId: {}", qwUser.getCompanyId());
|
|
|
+ throw new RuntimeException("剩余短信数量不足,请充值");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ String linkUrl = getLinkUrl(qwUser);
|
|
|
+
|
|
|
+ if (StringUtil.strIsNullOrEmpty(linkUrl)) {
|
|
|
+ return handleLinkGenerationFailure(client, qwUser, config);
|
|
|
+ }
|
|
|
+
|
|
|
+ return handleSmsSendAndAddWx(qwUser, client, temp, linkUrl, config);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 处理链接生成失败
|
|
|
+ */
|
|
|
+ private CompanyWxClient handleLinkGenerationFailure(
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ QwUser qwUser,
|
|
|
+ NodeConfig config) {
|
|
|
+
|
|
|
+ client.setIsAdd(3);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+
|
|
|
+ CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+ BeanUtils.copyProperties(client, addItem);
|
|
|
+
|
|
|
+ CompanyVoiceRoboticCallLogAddwx addLogAddWx = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+ "获客链接生成失败",
|
|
|
+ client.getId(),
|
|
|
+ client.getRoboticId(),
|
|
|
+ qwUser.getId(),
|
|
|
+ qwUser.getCompanyId(),
|
|
|
+ config.qwWxAddWayId
|
|
|
+ );
|
|
|
+
|
|
|
+ addLogAddWx.setStatus(3);
|
|
|
+ addLogAddWx.setResult(JSON.toJSONString(R.ok()));
|
|
|
+ addLogAddWx.setIsWeCom(2);
|
|
|
+
|
|
|
+ asyncSaveCompanyVoiceRoboticCallLog(addLogAddWx);
|
|
|
+ return addItem;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理短信发送和加微
|
|
|
+ */
|
|
|
+ private CompanyWxClient handleSmsSendAndAddWx(
|
|
|
+ QwUser qwUser,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ CompanySmsTemp temp,
|
|
|
+ String linkUrl,
|
|
|
+ NodeConfig config) {
|
|
|
+
|
|
|
+ SmsSendBatchParam smsSendBatchParam = buildSmsSendParam(qwUser, client, temp, linkUrl);
|
|
|
+ JSONObject runParamSms = (JSONObject) JSON.toJSON(smsSendBatchParam);
|
|
|
+ runParamSms.put("temp", temp);
|
|
|
+
|
|
|
+ //发送短信并记录日志
|
|
|
+ sendSmsWithLog(smsSendBatchParam, runParamSms, client, qwUser, temp);
|
|
|
+
|
|
|
+ //保存加微日志
|
|
|
+ saveAddWxLog(runParamSms, client, qwUser, config);
|
|
|
+
|
|
|
+ client.setIsAdd(2);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+
|
|
|
+
|
|
|
+ CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+ BeanUtils.copyProperties(client, addItem);
|
|
|
+
|
|
|
+ return addItem;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送短信并记录日志
|
|
|
+ */
|
|
|
+ private void sendSmsWithLog(
|
|
|
+ SmsSendBatchParam smsSendBatchParam,
|
|
|
+ JSONObject runParamSms,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ QwUser qwUser,
|
|
|
+ CompanySmsTemp temp) {
|
|
|
+
|
|
|
+ CompanyVoiceRoboticCallLogSendmsg addLogSms = CompanyVoiceRoboticCallLogSendmsg.initCallLog(
|
|
|
+ runParamSms.toJSONString(),
|
|
|
+ client.getCalleeId(),
|
|
|
+ client.getRoboticId(),
|
|
|
+ qwUser.getCompanyId(),
|
|
|
+ qwUser.getCompanyUserId(),
|
|
|
+ temp.getTempId()
|
|
|
+ );
|
|
|
+
|
|
|
+ try {
|
|
|
+ String callbackUuid = UUID.randomUUID().toString();
|
|
|
+ int smsContentLen = getSmsContentLen(smsSendBatchParam);
|
|
|
+
|
|
|
+ addLogSms.setContentLen(smsContentLen);
|
|
|
+ companyVoiceRoboticServiceImpl.sendMsgBatch(temp, smsSendBatchParam);
|
|
|
+
|
|
|
+ addLogSms.setStatus(2);
|
|
|
+ addLogSms.setCallbackUuid(callbackUuid);
|
|
|
+ } catch (Exception ex) {
|
|
|
+ addLogSms.setStatus(3);
|
|
|
+ addLogSms.setResult(ex.getMessage());
|
|
|
+ log.error("sendMsgBatch 异常:", ex);
|
|
|
+ } finally {
|
|
|
+ companyVoiceRoboticCallLogSendmsgService.asyncInsertCompanyVoiceRoboticCallLog(addLogSms);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存加微日志
|
|
|
+ */
|
|
|
+ private void saveAddWxLog(
|
|
|
+ JSONObject runParamSms,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ QwUser qwUser,
|
|
|
+ NodeConfig config) {
|
|
|
+
|
|
|
+ CompanyVoiceRoboticCallLogAddwx addLogAddWx = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+ runParamSms.toJSONString(),
|
|
|
+ client.getId(),
|
|
|
+ client.getRoboticId(),
|
|
|
+ qwUser.getId(),
|
|
|
+ qwUser.getCompanyId(),
|
|
|
+ config.qwWxAddWayId
|
|
|
+ );
|
|
|
+
|
|
|
+ addLogAddWx.setStatus(1);
|
|
|
+ addLogAddWx.setResult(JSON.toJSONString(R.ok()));
|
|
|
+ addLogAddWx.setIsWeCom(2);
|
|
|
+
|
|
|
+ asyncSaveCompanyVoiceRoboticCallLog(addLogAddWx);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取获客链接
|
|
|
+ */
|
|
|
+ private String getLinkUrl(QwUser qwUser){
|
|
|
+
|
|
|
+ String link = redisCache2.getCacheObject("customerLink:"+qwUser.getId());
|
|
|
+ if (link!=null && !StringUtil.strIsNullOrEmpty(link)){
|
|
|
+ return link;
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取获客链接
|
|
|
+ QwLinkCreateParam createParam=new QwLinkCreateParam();
|
|
|
+ createParam.setLink_name(qwUser.getQwUserName()+"的获客链接");
|
|
|
+
|
|
|
+ QwLinkCreateParam.Range range=new QwLinkCreateParam.Range();
|
|
|
+ range.setUser_list(Collections.singletonList(qwUser.getQwUserId()));
|
|
|
+ createParam.setRange(range);
|
|
|
+
|
|
|
+ QwLinkCreateResult result = qwApiService.linkCreate(createParam, qwUser.getCorpId());
|
|
|
+
|
|
|
+ if (result.getErrcode()==0){
|
|
|
+
|
|
|
+ redisCache2.setCacheObject("customerLink:"+qwUser.getId(),result.getUrl());
|
|
|
+
|
|
|
+ return result.getUrl();
|
|
|
+ }else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建加微请求参数
|
|
|
+ */
|
|
|
+ private JSONObject buildAddWxRunParam(QwUser qwUser, CompanyWxClient4WorkFlowVO client, String mobile) {
|
|
|
+ JSONObject runParam = new JSONObject();
|
|
|
+ runParam.put("qwId", qwUser.getId());
|
|
|
+ runParam.put("mobile", mobile);
|
|
|
+ runParam.put("qwUid", qwUser.getUid());
|
|
|
+ runParam.put("clientId", client.getId());
|
|
|
+ return runParam;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建短信发送参数
|
|
|
+ */
|
|
|
+ private SmsSendBatchParam buildSmsSendParam(
|
|
|
+ QwUser qwUser,
|
|
|
+ CompanyWxClient4WorkFlowVO client,
|
|
|
+ CompanySmsTemp temp,
|
|
|
+ String cardUrl) {
|
|
|
+
|
|
|
+ SmsSendBatchParam param = new SmsSendBatchParam();
|
|
|
+ param.setCompanyId(qwUser.getCompanyId());
|
|
|
+ param.setCompanyUserId(qwUser.getCompanyUserId());
|
|
|
+ param.setSmsType(temp.getTempType());
|
|
|
+ param.setTempCode(temp.getTempCode());
|
|
|
+ param.setContent(temp.getContent());
|
|
|
+ param.setSenderName(qwUser.getQwUserName());
|
|
|
+ param.setCustomerIds(new Long[]{client.getCustomerId()});
|
|
|
+ if (!StringUtil.strIsNullOrEmpty(client.getTraceId())){
|
|
|
+ param.setCardUrl(cardUrl+"?customer_channel="+client.getTraceId());
|
|
|
+ }else {
|
|
|
+ param.setCardUrl(cardUrl);
|
|
|
+ }
|
|
|
+
|
|
|
+ return param;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 触发后续工作流步骤
|
|
|
+ */
|
|
|
+ private void triggerNextWorkflowSteps(
|
|
|
+ List<CompanyWxClient> updateList,
|
|
|
+ Map<Long, CompanyWxClient4WorkFlowVO> clientMap) {
|
|
|
+
|
|
|
+ for (CompanyWxClient client : updateList) {
|
|
|
+ CompanyWxClient4WorkFlowVO vo = clientMap.get(client.getAccountId());
|
|
|
+ IWorkflowNode node = workflowNodeFactory.createNode(
|
|
|
+ vo.getCurrentNodeKey(),
|
|
|
+ NodeTypeEnum.fromValue(vo.getCurrentNodeType()),
|
|
|
+ vo.getCurrentNodeName(),
|
|
|
+ null
|
|
|
+ );
|
|
|
+
|
|
|
+ if (node instanceof AiQwAddWxTaskNode) {
|
|
|
+ CompletableFuture.runAsync(() -> {
|
|
|
+ AiQwAddWxTaskNode qwAddWxNode = (AiQwAddWxTaskNode) node;
|
|
|
+ qwAddWxNode.doneQwAddWx(vo.getWorkflowInstanceId());
|
|
|
+ }, cidExcutor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 节点配置内部类
|
|
|
+ */
|
|
|
+ private static class NodeConfig {
|
|
|
+ private int qwWxAddWayId;
|
|
|
+ private int smsTempId;
|
|
|
+ }
|
|
|
+
|
|
|
+// ... existing code ...
|
|
|
+
|
|
|
+// public void qwAddWx(List<Long> accountIdList) {
|
|
|
+// log.info("==========执行申请企微加好友任务开始==========");
|
|
|
+// try {
|
|
|
+// // 需要添加微信的列表
|
|
|
+// List<CompanyWxClient4WorkFlowVO> list = companyWxClientService.getQwAddWxList4Workflow(accountIdList);
|
|
|
+// log.info("申请企微加好友任务需要添加微信的数量:{}", list.size());
|
|
|
+// if (list.isEmpty()) return;
|
|
|
+// List<CompanyWxClient> addList = new ArrayList<>();
|
|
|
+// Map<Long, CompanyWxClient4WorkFlowVO> clientMap = PubFun.listToMapByGroupObject(list, CompanyWxClient4WorkFlowVO::getAccountId);
|
|
|
+// // 获取实际企微用户信息
|
|
|
+// List<QwUser> addAccountList = qwUserMapper.selectBatchIds(clientMap.keySet()).stream()
|
|
|
+// .filter(this::isValidQwUser)
|
|
|
+// .collect(Collectors.toList());
|
|
|
+// log.info("企微申请加好友任务需要企微的账号数量:{}", addAccountList.size());
|
|
|
+// addAccountList.forEach(qwUser -> {
|
|
|
+// CompanyWxClient4WorkFlowVO client = clientMap.get(qwUser.getId());
|
|
|
+// if (client != null) {
|
|
|
+// CrmCustomer crmCustomer = crmCustomerService.selectCrmCustomerById(client.getCustomerId());
|
|
|
+//
|
|
|
+// int qwWxAddWayId = 1; // 先固定为1
|
|
|
+// int smsTempId= 1; // 先固定为1
|
|
|
+// try {
|
|
|
+// String nodeConfig = client.getNodeConfig();
|
|
|
+// if (nodeConfig != null && !nodeConfig.trim().isEmpty()) {
|
|
|
+// JsonObject configJson = JsonParser.parseString(nodeConfig).getAsJsonObject();
|
|
|
+// if (configJson.has("qwWxAddWayId") && !configJson.get("qwWxAddWayId").isJsonNull()) {
|
|
|
+// qwWxAddWayId = configJson.get("qwWxAddWayId").getAsInt();
|
|
|
+// }
|
|
|
+// smsTempId = configJson.get("smsTempId").getAsInt();
|
|
|
+// }
|
|
|
+// } catch (Exception e) {
|
|
|
+// // 报错了也不处理,继续使用1
|
|
|
+// log.error("解析配置出错,但保持加微使用默认值1: " + e.getMessage());
|
|
|
+// }
|
|
|
+//
|
|
|
+// switch (qwWxAddWayId){
|
|
|
+// case 1:
|
|
|
+// // 开始主动申请加微
|
|
|
+// WxWorkResponseDTO<String> resp = qwAddWxInvokeIpad(crmCustomer.getMobile(), qwUser.getUid(),qwUser.getServerId(),qwUser.getVid(),qwUser.getQwUserName());
|
|
|
+// JSONObject runParam = new JSONObject();
|
|
|
+// runParam.put("qwId", qwUser.getId());
|
|
|
+// runParam.put("mobile", crmCustomer.getMobile());
|
|
|
+// runParam.put("qwUid", qwUser.getUid());
|
|
|
+// runParam.put("clientId", client.getId());
|
|
|
+//
|
|
|
+// CompanyVoiceRoboticCallLogAddwx addLog = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+// runParam.toJSONString(), client.getId(), client.getRoboticId(), qwUser.getId(), qwUser.getCompanyId(),qwWxAddWayId);
|
|
|
+// if (resp != null && resp.getErrcode() == 0) {
|
|
|
+// // 加微消息已发送成功
|
|
|
+// client.setIsAdd(2);
|
|
|
+// client.setAddTime(LocalDateTime.now());
|
|
|
+// CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+// BeanUtils.copyProperties(client, addItem);
|
|
|
+// addList.add(addItem);
|
|
|
+// addLog.setStatus(1);
|
|
|
+// addLog.setResult(JSON.toJSONString(resp));
|
|
|
+// addLog.setIsWeCom(2);
|
|
|
+// log.info("ROBOTIC-ID:{},企微申请加好友任务申请成功", client.getRoboticId());
|
|
|
+// } else {
|
|
|
+// log.error("ROBOTIC-ID:{},企微申请加好友任务加微失败:{}", client.getRoboticId(), runParam);
|
|
|
+// addLog.setStatus(3);
|
|
|
+// addLog.setResult(JSON.toJSONString(runParam));
|
|
|
+//
|
|
|
+// client.setIsAdd(3);
|
|
|
+// client.setAddTime(LocalDateTime.now());
|
|
|
+// CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+// BeanUtils.copyProperties(client, addItem);
|
|
|
+// addList.add(addItem);
|
|
|
+// }
|
|
|
+// asyncSaveCompanyVoiceRoboticCallLog(addLog);
|
|
|
+// break;
|
|
|
+// case 2:
|
|
|
+// //短信-获客链接
|
|
|
+//
|
|
|
+// CompanySmsTemp temp = smsTempService.selectCompanySmsTempById((long) smsTempId);
|
|
|
+//
|
|
|
+// if (temp != null && temp.getStatus().equals(1) && temp.getIsAudit().equals(1)) {
|
|
|
+//
|
|
|
+// CompanySms sms=companySmsService.selectCompanySmsByCompanyId(qwUser.getCompanyId());
|
|
|
+// if(sms!=null){
|
|
|
+// if(sms.getRemainSmsCount()>0){
|
|
|
+// SmsSendBatchParam smsSendBatchParam = new SmsSendBatchParam();
|
|
|
+// smsSendBatchParam.setCompanyId(qwUser.getCompanyId());
|
|
|
+// smsSendBatchParam.setCompanyUserId(qwUser.getCompanyUserId());
|
|
|
+// smsSendBatchParam.setSmsType(temp.getTempType());
|
|
|
+// smsSendBatchParam.setTempCode(temp.getTempCode());
|
|
|
+// smsSendBatchParam.setContent(temp.getContent());
|
|
|
+// smsSendBatchParam.setSenderName(client.getWxNickName());
|
|
|
+// smsSendBatchParam.setCustomerIds(new Long[]{client.getCustomerId()});
|
|
|
+// //记录工作流级短信日志
|
|
|
+// JSONObject runParamSms = (JSONObject) JSON.toJSON(smsSendBatchParam);
|
|
|
+// runParamSms.put("temp", temp);
|
|
|
+// CompanyVoiceRoboticCallLogSendmsg addLogSms = CompanyVoiceRoboticCallLogSendmsg.initCallLog(
|
|
|
+// runParamSms.toJSONString(),
|
|
|
+// null,
|
|
|
+// null,
|
|
|
+// qwUser.getCompanyId(),
|
|
|
+// qwUser.getCompanyUserId(),
|
|
|
+// temp.getTempId()
|
|
|
+// );
|
|
|
+//
|
|
|
+// addLogSms.setStatus(1);
|
|
|
+// try{
|
|
|
+// String callbackUuid = UUID.randomUUID().toString();
|
|
|
+// int smsContentLen = getSmsContentLen(smsSendBatchParam);
|
|
|
+// addLogSms.setContentLen(smsContentLen);
|
|
|
+// companyVoiceRoboticServiceImpl.sendMsgBatch(temp,smsSendBatchParam);
|
|
|
+// addLogSms.setStatus(2);
|
|
|
+// addLogSms.setCallbackUuid(callbackUuid);
|
|
|
+// } catch(Exception ex){
|
|
|
+// addLogSms.setStatus(3);
|
|
|
+// addLogSms.setResult(ex.getMessage());
|
|
|
+// log.error("sendMsgOne异常:",ex);
|
|
|
+// } finally {
|
|
|
+// //短信记录表
|
|
|
+// companyVoiceRoboticCallLogSendmsgService.asyncInsertCompanyVoiceRoboticCallLog(addLogSms);
|
|
|
+// }
|
|
|
+//
|
|
|
+// CompanyVoiceRoboticCallLogAddwx addLogAddWx = CompanyVoiceRoboticCallLogAddwx.initCallLog(
|
|
|
+// runParamSms.toJSONString(), client.getId(), client.getRoboticId(), qwUser.getId(), qwUser.getCompanyId(),qwWxAddWayId);
|
|
|
+//
|
|
|
+// // 加微中
|
|
|
+// client.setIsAdd(2);
|
|
|
+// client.setAddTime(LocalDateTime.now());
|
|
|
+// CompanyWxClient addItem = new CompanyWxClient();
|
|
|
+// BeanUtils.copyProperties(client, addItem);
|
|
|
+// addList.add(addItem);
|
|
|
+//
|
|
|
+// addLogAddWx.setStatus(1);
|
|
|
+// addLogAddWx.setResult(JSON.toJSONString(R.ok()));
|
|
|
+// addLogAddWx.setIsWeCom(2);
|
|
|
+//
|
|
|
+// asyncSaveCompanyVoiceRoboticCallLog(addLogAddWx);
|
|
|
+//
|
|
|
+// }
|
|
|
+// else{
|
|
|
+// log.error("qw剩余短信数量不足,请充值:{}",client.getCompanyId());
|
|
|
+// throw new RuntimeException("剩余短信数量不足,请充值");
|
|
|
+// }
|
|
|
+// }
|
|
|
+// else{
|
|
|
+// log.error("qw请充值:companyId:{}",client.getCompanyId());
|
|
|
+// throw new RuntimeException("请充值");
|
|
|
+// }
|
|
|
+//
|
|
|
+// } else {
|
|
|
+// log.error("模板未审核:smsTemp:{}", temp);
|
|
|
+// throw new RuntimeException("模板未审核");
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+// break;
|
|
|
+// default:
|
|
|
+// break;
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+// } else {
|
|
|
+// log.error("企微申请加好友任务当前账号暂无需要添加微信:{}-{}", qwUser.getId(), qwUser.getQwUserName());
|
|
|
+// }
|
|
|
+// });
|
|
|
+// if (!addList.isEmpty()) {
|
|
|
+// companyWxClientService.updateBatchById(addList);
|
|
|
+// for (CompanyWxClient client : addList) {
|
|
|
+// CompanyWxClient4WorkFlowVO vo = clientMap.get(client.getAccountId());
|
|
|
+// IWorkflowNode node = workflowNodeFactory.createNode(vo.getCurrentNodeKey(),
|
|
|
+// NodeTypeEnum.fromValue(vo.getCurrentNodeType()),
|
|
|
+// vo.getCurrentNodeName(), null);
|
|
|
+// if (node instanceof AiQwAddWxTaskNode) {
|
|
|
+// CompletableFuture.runAsync(() -> {
|
|
|
+// AiQwAddWxTaskNode qwAddWxNode = (AiQwAddWxTaskNode) node;
|
|
|
+// qwAddWxNode.doneQwAddWx(vo.getWorkflowInstanceId());
|
|
|
+// }, cidExcutor);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// } catch (Exception e) {
|
|
|
+// log.error("企微申请加好友任务执行异常", e);
|
|
|
+// }
|
|
|
+// log.info("==========执行企微申请加好友任务结束==========");
|
|
|
+// }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public int getSmsContentLen(SmsSendBatchParam param){
|
|
|
+ CompanyUser companyUser=companyUserService.selectCompanyUserById(param.getCompanyUserId());
|
|
|
+
|
|
|
+ CrmCustomer crmCustomer=crmCustomerService.selectCrmCustomerById(param.getCustomerIds()[0].longValue());
|
|
|
+ String content=param.getContent();
|
|
|
+ if(StringUtils.isNotEmpty(crmCustomer.getCustomerName())){
|
|
|
+ content=content.replace("${sms.csName}",crmCustomer.getCustomerName());
|
|
|
+ }
|
|
|
+ if(companyUser!=null&& StringUtils.isNotEmpty(companyUser.getPhonenumber())){
|
|
|
+ content=content.replace("${sms.phoneNumber}",companyUser.getPhonenumber());
|
|
|
+ }
|
|
|
+ if(StringUtils.isNotEmpty(param.getCardUrl())){
|
|
|
+ content=content.replace("${sms.cardUrl}",param.getCardUrl());
|
|
|
+ }
|
|
|
+ if(StringUtils.isNotEmpty(param.getSenderName())){
|
|
|
+ content=content.replace("${sms.senderName}",param.getSenderName());
|
|
|
+ }
|
|
|
+
|
|
|
+ return content.length();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 企微加微结果处理
|
|
|
+ */
|
|
|
+ public void qwAddWxResult(List<Long> accountIdList) {
|
|
|
+ log.info("==========执行企微申请加微结果查询任务开始==========");
|
|
|
+ try {
|
|
|
+ //is_add = 2,状态为加微中且是企微类型
|
|
|
+ List<CompanyWxClient> clients = companyWxClientService.getQwAddWxList(accountIdList, 2);
|
|
|
+ log.info("企微申请加微结果查询任务需要查询的数量:{}", clients.size());
|
|
|
+
|
|
|
+ if (clients.isEmpty()) return;
|
|
|
+ // 处理每个客户的加微结果
|
|
|
+ List<CompanyWxClient> upClientList = new ArrayList<>();
|
|
|
+ clients.parallelStream().forEach(client -> {
|
|
|
+ try {
|
|
|
+ processSingleClientResult(client, upClientList);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("企微申请加微结果查询任务处理客户{}加微结果异常", client.getId(), e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 批量更新和后续处理
|
|
|
+ if (!upClientList.isEmpty()) {
|
|
|
+ batchUpdateClients(upClientList);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("企微申请加微结果查询任务处理异常", e);
|
|
|
+ }
|
|
|
+ log.info("==========执行企微申请加微结果查询任务结束==========");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 扫描企微加微工作流延时任务
|
|
|
+ */
|
|
|
+ public void cidWorkflowQwAddWxRun() {
|
|
|
+ log.info("===========企微加微工作流延时任务开始扫描===========");
|
|
|
+ String delayAddWxKeyPrefix = AiQwAddWxTaskNode.getDelayAddWxKeyPrefix(cidGroupNo,null) + "*";
|
|
|
+ Set<String> keys = redisKeyScanner.scanMatchKey(delayAddWxKeyPrefix);
|
|
|
+ log.info("企微加微共扫描到 {} 个待处理键", keys.size());
|
|
|
+ keys.parallelStream().forEach(key -> {
|
|
|
+ try {
|
|
|
+ //doExec
|
|
|
+ CompletableFuture.runAsync(()->{
|
|
|
+ try {
|
|
|
+ ExecutionContext context = redisCache2.getCacheObject(key);
|
|
|
+ context.setVariable("callRedisKey",key);
|
|
|
+ context.setVariable("callSource","qwAddWxTimer");
|
|
|
+ companyWorkflowEngine.timeDoExecute(context.getWorkflowInstanceId(),context.getCurrentNodeKey(),context.getVariables());
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理工作流延时任务异常 - key: {}", key, e);
|
|
|
+ }
|
|
|
+ }, cidExcutor).thenRun(()->{
|
|
|
+ redisCache2.deleteObject(key);
|
|
|
+ });
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("处理工作流延时任务异常 - key: {}", key, ex);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ log.info("===========工作流延时任务扫描结束===========");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证企微用户有效性
|
|
|
+ */
|
|
|
+ private boolean isValidQwUser(QwUser qwUser) {
|
|
|
+ if (StringUtils.isBlank(qwUser.getUid()) || qwUser.getServerId() == null) {
|
|
|
+ log.info("企微账号{}的uid或serverId为空,跳过执行", qwUser.getQwUserName());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 企微加个微调用ipad端
|
|
|
+ * @param mobile 手机号
|
|
|
+ * @param qwUid 企微uid
|
|
|
+ * @param serverId 服务器id
|
|
|
+ * @return String 结果
|
|
|
+ */
|
|
|
+ private WxWorkResponseDTO<String> qwAddWxInvokeIpad(String mobile, String qwUid, Long serverId,String vid,String qwUserName) {
|
|
|
+ if (StringUtils.isBlank(mobile) || StringUtils.isBlank(qwUid) || serverId == null) {
|
|
|
+ log.warn("企微申请加好友任务参数校验失败: mobile={}, qwUid={}, serverId={}", mobile, qwUid, serverId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ WxAddSearchDTO wxAddSearchDTO = new WxAddSearchDTO();
|
|
|
+ wxAddSearchDTO.setUuid(qwUid);
|
|
|
+ wxAddSearchDTO.setVid(Long.valueOf(vid));
|
|
|
+ wxAddSearchDTO.setPhone(mobile);
|
|
|
+
|
|
|
+ WxSearchContactDTO contactDTO=new WxSearchContactDTO();
|
|
|
+ contactDTO.setUuid(qwUid);
|
|
|
+ contactDTO.setPhoneNumber(mobile);
|
|
|
+
|
|
|
+
|
|
|
+ WxWorkResponseDTO<WxSearchContactResp> respWxWorkResponseDTO = wxWorkService.searchContact(contactDTO, serverId);
|
|
|
+ WxSearchContactResp.UserList user = respWxWorkResponseDTO.getData().getUserList().stream()
|
|
|
+ .filter(u -> u.getState().equals("2"))
|
|
|
+ .findFirst()
|
|
|
+ .orElse(null); // 或者 .orElseThrow(() -> new RuntimeException("未找到指定用户"))
|
|
|
+
|
|
|
+ wxAddSearchDTO.setOptionid(user.getOpenid());
|
|
|
+ wxAddSearchDTO.setTicket(user.getTicket());
|
|
|
+ wxAddSearchDTO.setContent("你好,我是你的专属助手:"+qwUserName+",有什么问题都可以问我哦~");
|
|
|
+
|
|
|
+ WxWorkResponseDTO<String> response = wxWorkService.addSearch(wxAddSearchDTO, serverId);
|
|
|
+ log.debug("企微加微接口调用结果: errcode={}, errmsg={}",
|
|
|
+ response != null ? response.getErrcode() : "null",
|
|
|
+ response != null ? response.getErrmsg() : "null");
|
|
|
+
|
|
|
+ return response;
|
|
|
+
|
|
|
+ // 测试代码
|
|
|
+// WxWorkResponseDTO<String> response = new WxWorkResponseDTO<>();
|
|
|
+// response.setErrcode(0);
|
|
|
+// return response;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("企微申请加好友任务请求接口异常: mobile={}, qwUid={}, serverId={}", mobile, qwUid, serverId, e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理单个客户加微结果
|
|
|
+ */
|
|
|
+ private void processSingleClientResult(CompanyWxClient client, List<CompanyWxClient> upClientList) {
|
|
|
+ if (StringUtils.isBlank(client.getPhone())) {
|
|
|
+ handleFailedAddWx(client, upClientList, "无电话号码",0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询外部联系人表是否有数据
|
|
|
+ QwExternalContact qwExternalContact = qwExternalContactMapper.queryQwUserIdIsAddContact(
|
|
|
+ client.getAccountId(), client.getPhone(), 2);
|
|
|
+
|
|
|
+ if (qwExternalContact != null && qwExternalContact.getId() > 0) {
|
|
|
+ handleSuccessfulAddWx(client, upClientList);
|
|
|
+ } else {
|
|
|
+ handleFailedAddWxWithRetry(client, upClientList);
|
|
|
+ }
|
|
|
+
|
|
|
+ //测试代码
|
|
|
+// handleSuccessfulAddWx(client, upClientList);
|
|
|
+// handleFailedAddWx(client, upClientList, "无电话号码",0);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理加微成功的情况
|
|
|
+ */
|
|
|
+ private void handleSuccessfulAddWx(CompanyWxClient client, List<CompanyWxClient> upClientList) {
|
|
|
+ // 更新记录状态
|
|
|
+ companyVoiceRoboticCallLogAddwxService.lambdaUpdate()
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getRoboticId, client.getRoboticId())
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getWxClientId, client.getId())
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getWxAccountId, client.getAccountId())
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getIsWeCom, 2)
|
|
|
+ .set(CompanyVoiceRoboticCallLogAddwx::getStatus, 2)
|
|
|
+ .update();
|
|
|
+
|
|
|
+ client.setIsAdd(1);
|
|
|
+ client.setAddTime(LocalDateTime.now());
|
|
|
+ upClientList.add(client);
|
|
|
+ redisCache.deleteObject("qwAddWx_" + client.getId());
|
|
|
+ log.info("ROBOTIC-ID:{},企微申请加微结果查询任务加微成功:{}", client.getRoboticId(), client.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理加微失败的情况
|
|
|
+ */
|
|
|
+ private void handleFailedAddWx(CompanyWxClient client, List<CompanyWxClient> upClientList, String reason,Integer isAdd) {
|
|
|
+ String taskName = isAdd == 1 ? "企微申请加好友任务" : "加微结果查询任务";
|
|
|
+ log.error("ROBOTIC-ID:{},{}:{},clientId={}", client.getRoboticId(),taskName, reason, client.getId());
|
|
|
+ client.setIsAdd(3);
|
|
|
+ client.setUpdateTime(new Date());
|
|
|
+ upClientList.add(client);
|
|
|
+ // 更新日志记录
|
|
|
+ companyVoiceRoboticCallLogAddwxService.lambdaUpdate()
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getRoboticId, client.getRoboticId())
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getWxClientId, client.getId())
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getWxAccountId, client.getAccountId())
|
|
|
+ .eq(CompanyVoiceRoboticCallLogAddwx::getIsWeCom, 2)
|
|
|
+ .set(CompanyVoiceRoboticCallLogAddwx::getStatus, 3)
|
|
|
+ .set(CompanyVoiceRoboticCallLogAddwx::getResult, reason)
|
|
|
+ .update();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理加微失败并重试计数
|
|
|
+ */
|
|
|
+ private void handleFailedAddWxWithRetry(CompanyWxClient client, List<CompanyWxClient> upClientList) {
|
|
|
+ String taskName = 0 == 1 ? "企微申请加好友任务" : "加微结果查询任务";
|
|
|
+ log.error("ROBOTIC-ID:{},{}失败:{}", client.getRoboticId(),taskName, client.getId());
|
|
|
+ String failCountStr = redisCache.getCacheObject("qwAddWx_" + client.getId());
|
|
|
+ int failCount = 1;
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(failCountStr)) {
|
|
|
+ if (Integer.parseInt(failCountStr) >= 60 * 24) { // 超过一天
|
|
|
+ handleFailedAddWx(client, upClientList, "超过最大重试次数", 0);
|
|
|
+ redisCache.deleteObject("qwAddWx_" + client.getId());
|
|
|
+ } else {
|
|
|
+ failCount += Integer.parseInt(failCountStr);
|
|
|
+ redisCache.setCacheObject("qwAddWx_" + client.getId(), String.valueOf(failCount-1));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ redisCache.setCacheObject("qwAddWx_" + client.getId(), String.valueOf(failCount), 25, TimeUnit.HOURS);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量更新客户和相关数据
|
|
|
+ */
|
|
|
+ private void batchUpdateClients(List<CompanyWxClient> upClientList) {
|
|
|
+ companyWxClientService.updateBatchById(upClientList);
|
|
|
+ // 从 upClientList 中筛选出 isAdd=1和3加微失败的数据
|
|
|
+ List<CompanyWxClient> successClients = upClientList.stream()
|
|
|
+ .filter(client -> client.getIsAdd() != null && (client.getIsAdd() == 1 || client.getIsAdd() == 3))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ if(!successClients.isEmpty()){
|
|
|
+ successClients.forEach(client -> {
|
|
|
+ triggerWorkflowOnAddWxSuccess(client.getId());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加微结果触发工作流继续执行
|
|
|
+ * @param wxClientId 加微客户ID
|
|
|
+ */
|
|
|
+ private void triggerWorkflowOnAddWxSuccess(Long wxClientId) {
|
|
|
+ try {
|
|
|
+ // 查找等待中的加微工作流实例
|
|
|
+ CompanyAiWorkflowExec waitingExec = companyAiWorkflowExecMapper.selectWaitingAddWxWorkflowByWxClientId(
|
|
|
+ wxClientId,
|
|
|
+ ExecutionStatusEnum.WAITING.getValue(),
|
|
|
+ NodeTypeEnum.AI_QW_ADD_WX_TASK.getValue());
|
|
|
+ if (waitingExec == null) {
|
|
|
+ log.info("未找到等待中的加微工作流实例 - wxClientId: {}", wxClientId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //查询工作流加微执行日志是否未更新状态
|
|
|
+ CompanyAiWorkflowExecLog queryP = new CompanyAiWorkflowExecLog();
|
|
|
+ queryP.setWorkflowInstanceId(waitingExec.getWorkflowInstanceId());
|
|
|
+ queryP.setNodeType(NodeTypeEnum.AI_QW_ADD_WX_TASK.getValue());
|
|
|
+ queryP.setStatus(ExecutionStatusEnum.WAITING.getValue());
|
|
|
+ List<CompanyAiWorkflowExecLog> companyAiWorkflowExecLogs = companyAiWorkflowExecLogMapper.selectCompanyAiWorkflowExecLogList(queryP);
|
|
|
+ companyAiWorkflowExecLogs.forEach(log -> {
|
|
|
+ log.setStatus(ExecutionStatusEnum.SUCCESS.getValue());
|
|
|
+ companyAiWorkflowExecLogMapper.updateById(log);
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ String workflowInstanceId = waitingExec.getWorkflowInstanceId();
|
|
|
+ String currentNodeKey = waitingExec.getCurrentNodeKey();
|
|
|
+
|
|
|
+ log.info("加微成功回调,尝试触发工作流继续执行 - workflowInstanceId: {}, nodeKey: {}, wxClientId: {}",
|
|
|
+ workflowInstanceId, currentNodeKey, wxClientId);
|
|
|
+
|
|
|
+ // 互斥检查:如果已经被执行过(超时路径或其他回调),则不再执行
|
|
|
+ if (!AiQwAddWxTaskNode.tryMarkAsExecuted(workflowInstanceId, wxClientId)) {
|
|
|
+ log.info("企微申请加微结果查询任务工作流已被其他路径执行,跳过 - workflowInstanceId: {}, wxClientId: {}",
|
|
|
+ workflowInstanceId, wxClientId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除超时检测Key(回调成功了,不需要超时检测了)
|
|
|
+ AiQwAddWxTaskNode.clearTimeoutKey(workflowInstanceId, wxClientId);
|
|
|
+
|
|
|
+ // 触发工作流继续执行
|
|
|
+ Map<String, Object> inputData = new HashMap<>();
|
|
|
+ inputData.put("addWxSuccess", true);
|
|
|
+ inputData.put("wxClientId", wxClientId);
|
|
|
+ inputData.put("triggerType", "callback"); // 回调触发
|
|
|
+
|
|
|
+ companyWorkflowEngine.resumeFromBlockingNode(workflowInstanceId, currentNodeKey, inputData);
|
|
|
+
|
|
|
+ log.info("企微申请加微结果查询任务加微成功回调触发工作流继续执行完成 - workflowInstanceId: {}, wxClientId: {}",
|
|
|
+ workflowInstanceId, wxClientId);
|
|
|
+
|
|
|
+ } catch (Exception ex) {
|
|
|
+ log.error("企微申请加微结果查询任务加微成功回调触发工作流异常 - wxClientId: {}", wxClientId, ex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|