|
|
@@ -23,7 +23,6 @@ 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.util.RandomNameGeneratorUtil;
|
|
|
import com.fs.company.vo.*;
|
|
|
import com.fs.company.vo.easycall.EasyCallCallPhoneVO;
|
|
|
import com.fs.crm.domain.CrmCustomer;
|
|
|
@@ -33,14 +32,11 @@ import com.fs.crm.service.impl.CrmCustomerServiceImpl;
|
|
|
import com.fs.enums.ExecutionStatusEnum;
|
|
|
import com.fs.enums.NodeTypeEnum;
|
|
|
import com.fs.enums.TaskTypeEnum;
|
|
|
-import com.fs.his.config.CidPhoneConfig;
|
|
|
import com.fs.qw.domain.QwUser;
|
|
|
import com.fs.qw.mapper.QwUserMapper;
|
|
|
import com.fs.qw.service.impl.QwExternalContactServiceImpl;
|
|
|
-import com.fs.system.domain.SysConfig;
|
|
|
import com.fs.system.mapper.SysConfigMapper;
|
|
|
import com.fs.system.mapper.SysDictDataMapper;
|
|
|
-import com.fs.system.service.ISysConfigService;
|
|
|
import com.fs.system.service.impl.SysDictTypeServiceImpl;
|
|
|
import com.github.pagehelper.PageHelper;
|
|
|
import com.github.pagehelper.PageInfo;
|
|
|
@@ -49,11 +45,8 @@ import lombok.Synchronized;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
-
|
|
|
-import java.time.LocalDateTime;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
-
|
|
|
import static com.fs.company.service.impl.call.node.AiCallTaskNode.EASYCALL_WORKFLOW_REDIS_KEY;
|
|
|
|
|
|
|
|
|
@@ -75,7 +68,6 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
private final CompanyVoiceRoboticMapper companyVoiceRoboticMapper;
|
|
|
private final AiCallService aiCallService;
|
|
|
private final CrmCustomerServiceImpl crmCustomerService;
|
|
|
- private final CompanyVoiceRoboticCalleesMapper companyVoiceRoboticCalleesMapper;
|
|
|
|
|
|
private final CompanyVoiceRoboticCalleesServiceImpl companyVoiceRoboticCalleesService;
|
|
|
private final ICompanyWxAccountService companyWxAccountService;
|
|
|
@@ -90,8 +82,6 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
|
|
|
private final CompanyWxClientServiceImpl companyWxClientServiceImpl;
|
|
|
|
|
|
- private final ISysConfigService configService;
|
|
|
-
|
|
|
private final SysDictDataMapper sysDictDataMapper;
|
|
|
|
|
|
private final SmsServiceImpl smsService;
|
|
|
@@ -111,23 +101,24 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
private final CompanyWorkflowEngine companyWorkflowEngine;
|
|
|
private final CompanyAiWorkflowExecMapper companyAiWorkflowExecMapper;
|
|
|
private final CompanyAiWorkflowExecLogMapper companyAiWorkflowExecLogMapper;
|
|
|
+
|
|
|
+ private final CompanyVoiceRoboticCalleesMapper companyVoiceRoboticCalleesMapper;
|
|
|
private final RedisCache redisCache2;
|
|
|
private final CompanyAiWorkflowServerMapper companyAiWorkflowServerMapper;
|
|
|
private final QwUserMapper qwUserMapper;
|
|
|
private final EasyCallMapper easyCallMapper;
|
|
|
-
|
|
|
- private final SysConfigMapper sysConfigMapper;
|
|
|
- private final CompanyConfigMapper companyConfigMapper;
|
|
|
-
|
|
|
- private final CompanyWorkflowMapper companyWorkflowMapper;
|
|
|
-
|
|
|
- private final CompanyWorkflowEdgeMapper edgeMapper;
|
|
|
-
|
|
|
private final QwExternalContactServiceImpl qwExternalContactService;
|
|
|
|
|
|
private final SysDictTypeServiceImpl sysDictTypeService;
|
|
|
|
|
|
- final int BATCH_SIZE = 1500;
|
|
|
+ private final IAsyncCalleeProcessorService asyncCalleeProcessorService;
|
|
|
+
|
|
|
+ /** EasyCall intent 意向度重试队列 Redis key 前缀,value 为已重试次数 */
|
|
|
+ private static final String EASYCALL_INTENT_RETRY_KEY = "easycall:intent:retry:";
|
|
|
+ /** intent 意向度等待重试最大次数(每次间隔约30秒,最多等待 5*30=150秒) */
|
|
|
+ private static final int EASYCALL_INTENT_MAX_RETRY = 5;
|
|
|
+ /** 每次重试等待时长(毫秒) */
|
|
|
+ private static final long EASYCALL_INTENT_RETRY_INTERVAL_MS = 30000L;
|
|
|
|
|
|
/**
|
|
|
* 查询机器人外呼任务
|
|
|
@@ -153,10 +144,20 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
public List<CompanyVoiceRobotic> selectCompanyVoiceRoboticList(CompanyVoiceRobotic companyVoiceRobotic){
|
|
|
return companyVoiceRoboticMapper.selectCompanyVoiceRoboticList(companyVoiceRobotic);
|
|
|
}
|
|
|
+
|
|
|
@Override
|
|
|
@DataScope(deptAlias = "d", userAlias = "u")
|
|
|
- public List<CompanyVoiceRobotic> selectCompanyVoiceRoboticListCompany(CompanyVoiceRobotic companyVoiceRobotic){
|
|
|
- return companyVoiceRoboticMapper.selectCompanyVoiceRoboticListCompany(companyVoiceRobotic);
|
|
|
+ public List<CompanyVoiceRobotic> selectCompanyVoiceRoboticListCompany(CompanyVoiceRobotic companyVoiceRobotic) {
|
|
|
+ List<CompanyVoiceRobotic> companyVoiceRobotics = companyVoiceRoboticMapper.selectCompanyVoiceRoboticListCompany(companyVoiceRobotic);
|
|
|
+ List<SysDictData> taskSceneType = DictUtils.getDictCache("task_scene_type");
|
|
|
+ companyVoiceRobotics.forEach(a -> {
|
|
|
+ if (null != a.getSceneType()) {
|
|
|
+ taskSceneType.stream().filter(b -> b.getDictValue().equals(a.getSceneType().toString())).findFirst().ifPresent(c -> {
|
|
|
+ a.setSceneTypeName(c.getDictLabel());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return companyVoiceRobotics;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -762,6 +763,18 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
return companyVoiceRoboticMapper.deleteCompanyVoiceRoboticById(id);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 更新删除标志(逻辑删除)
|
|
|
+ *
|
|
|
+ * @param id 机器人外呼任务ID
|
|
|
+ * @param delFlag 删除标志 0正常 1删除
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int updateDelFlag(Long id, Integer delFlag) {
|
|
|
+ return companyVoiceRoboticMapper.updateDelFlag(id, delFlag);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public List<CompanyVoiceRoboticQwUserListVo> qwUserList() {
|
|
|
return companyVoiceRoboticMapper.qwUserList();
|
|
|
@@ -819,18 +832,90 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
return;
|
|
|
}
|
|
|
log.info("进入easyCall外呼结果查询结果callPhoneRes:{}", JSON.toJSONString(callPhoneRes));
|
|
|
+ // intent(意向度)由对方异步评估写入,回调时可能尚未赋值,进入延迟重试队列等待
|
|
|
+ if (StringUtils.isBlank(callPhoneRes.getIntent())) {
|
|
|
+ String retryKey = EASYCALL_INTENT_RETRY_KEY + result.getUuid();
|
|
|
+ Integer retryCount = redisCache2.getCacheObject(retryKey);
|
|
|
+ if (retryCount == null) {
|
|
|
+ retryCount = 0;
|
|
|
+ }
|
|
|
+ if (retryCount < EASYCALL_INTENT_MAX_RETRY) {
|
|
|
+ redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
|
|
|
+ log.info("easyCall外呼回调intent意向度暂未评估完成,uuid={},第{}次放入延迟重试队列", result.getUuid(), retryCount + 1);
|
|
|
+ doRetryCallerResult4EasyCall(result, retryCount + 1);
|
|
|
+ } else {
|
|
|
+ // 超过最大重试次数,以 intent 为空(意向未知)兜底继续处理
|
|
|
+ log.warn("easyCall外呼回调intent意向度在{}次重试后仍为空,uuid={},以意向未知兜底处理", EASYCALL_INTENT_MAX_RETRY, result.getUuid());
|
|
|
+ redisCache2.deleteObject(retryKey);
|
|
|
+ doHandleEasyCallResult(callPhoneRes);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // intent 已有值,直接正常处理
|
|
|
+ redisCache2.deleteObject(EASYCALL_INTENT_RETRY_KEY + result.getUuid());
|
|
|
+ doHandleEasyCallResult(callPhoneRes);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 延迟重试处理 EasyCall 外呼回调(等待 intent 意向度异步评估完成)
|
|
|
+ * 每次重试前等待 {@link #EASYCALL_INTENT_RETRY_INTERVAL_MS} 毫秒后重新拉取数据
|
|
|
+ */
|
|
|
+ @Async("cidWorkFlowExecutor")
|
|
|
+ public void doRetryCallerResult4EasyCall(CdrDetailVo result, int currentRetry) {
|
|
|
+ try {
|
|
|
+ Thread.sleep(EASYCALL_INTENT_RETRY_INTERVAL_MS);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ log.warn("easyCall intent重试等待被中断, uuid={}", result.getUuid());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ log.info("easyCall intent重试第{}次开始, uuid={}", currentRetry, result.getUuid());
|
|
|
+ EasyCallCallPhoneVO callPhoneRes = easyCallMapper.getCallPhoneInfoByUuid(result.getUuid());
|
|
|
+ if (null == callPhoneRes) {
|
|
|
+ log.error("easyCall intent重试时仍未查询到外呼结果, uuid={}", result.getUuid());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (StringUtils.isBlank(callPhoneRes.getIntent())) {
|
|
|
+ // intent 仍为空,继续判断是否还有剩余重试次数
|
|
|
+ String retryKey = EASYCALL_INTENT_RETRY_KEY + result.getUuid();
|
|
|
+ Integer retryCount = redisCache2.getCacheObject(retryKey);
|
|
|
+ if (retryCount == null) {
|
|
|
+ retryCount = currentRetry;
|
|
|
+ }
|
|
|
+ if (retryCount < EASYCALL_INTENT_MAX_RETRY) {
|
|
|
+ redisCache2.setCacheObject(retryKey, retryCount + 1, 10, java.util.concurrent.TimeUnit.MINUTES);
|
|
|
+ log.info("easyCall intent仍未评估完成,uuid={},第{}次继续延迟重试", result.getUuid(), retryCount + 1);
|
|
|
+ doRetryCallerResult4EasyCall(result, retryCount + 1);
|
|
|
+ } else {
|
|
|
+ log.warn("easyCall intent在{}次重试后仍为空,uuid={},以意向未知兜底处理", EASYCALL_INTENT_MAX_RETRY, result.getUuid());
|
|
|
+ redisCache2.deleteObject(retryKey);
|
|
|
+ doHandleEasyCallResult(callPhoneRes);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // intent 已评估完成,正常处理
|
|
|
+ log.info("easyCall intent重试第{}次成功获取到意向度={},uuid={}", currentRetry, callPhoneRes.getIntent(), result.getUuid());
|
|
|
+ redisCache2.deleteObject(EASYCALL_INTENT_RETRY_KEY + result.getUuid());
|
|
|
+ doHandleEasyCallResult(callPhoneRes);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 执行 EasyCall 外呼回调核心业务处理(推送对话内容、更新通话日志)
|
|
|
+ * 供 {@link #callerResult4EasyCall} 和重试逻辑统一调用
|
|
|
+ */
|
|
|
+ private void doHandleEasyCallResult(EasyCallCallPhoneVO callPhoneRes) {
|
|
|
//等待数据信息
|
|
|
JSONObject bizJson = JSONObject.parseObject(callPhoneRes.getBizJson());
|
|
|
String cacheString = (String) redisCache2.getCacheObject(EASYCALL_WORKFLOW_REDIS_KEY + bizJson.getString("callBackUuid"));
|
|
|
if (StringUtils.isBlank(cacheString)) {
|
|
|
- log.error("easyCall外呼回调缓存信息缺失:{}", JSON.toJSONString(result));
|
|
|
+ log.error("easyCall外呼回调缓存信息缺失, uuid={}", callPhoneRes.getUuid());
|
|
|
return;
|
|
|
}
|
|
|
JSONObject cacheInfo = JSONObject.parseObject(cacheString);
|
|
|
pushDialogContent4EasyCall(cacheInfo, callPhoneRes);
|
|
|
CompanyVoiceRoboticCallees callee = companyVoiceRoboticCalleesMapper.selectCompanyVoiceRoboticCalleesById(cacheInfo.getLong("calleeId"));
|
|
|
companyVoiceRoboticCallLogCallphoneService.asyncHandleCalleeCallBackResult4EasyCall(callPhoneRes, callee);
|
|
|
- System.out.println(callPhoneRes);
|
|
|
+ log.info("easyCall外呼回调业务处理完成, uuid={}, intent={}", callPhoneRes.getUuid(), callPhoneRes.getIntent());
|
|
|
}
|
|
|
|
|
|
public void pushDialogContent(PushIIntentionResult result) {
|
|
|
@@ -1054,6 +1139,9 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
if (robotic.getCompanyAiWorkflowId() == null) {
|
|
|
throw new RuntimeException("任务未配置工作流: " + id);
|
|
|
}
|
|
|
+ if(robotic.getDelFlag() == 1){
|
|
|
+ throw new RuntimeException("启动失败,当前任务已删除: " + id);
|
|
|
+ }
|
|
|
robotic.setTaskStatus(1);
|
|
|
updateById(robotic);
|
|
|
// 根据任务加微方式决定是否直接分配微信 平均时 直接分配用户 场景任务不做分配
|
|
|
@@ -1073,7 +1161,6 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
initAndExecuteWorkflows(robotic, roboticBusinesseList);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
/**
|
|
|
* 初始化场景任务客户流程
|
|
|
* @param robotic
|
|
|
@@ -1145,7 +1232,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
/**
|
|
|
* 添加用户到场景任务
|
|
|
*/
|
|
|
- public void addNewExec4Task(Long taskId, Long crmCustomerId) {
|
|
|
+ public void addNewExec4Task(Long taskId, Long crmCustomerId,String traceId) {
|
|
|
//保存callees表数据
|
|
|
CompanyVoiceRobotic companyVoiceRobotic = companyVoiceRoboticMapper.selectCompanyVoiceRoboticById(taskId);
|
|
|
CrmCustomer crmCustomer = crmCustomerService.selectCrmCustomerById(crmCustomerId);
|
|
|
@@ -1154,6 +1241,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
client.setRoboticId(taskId);
|
|
|
client.setCustomerId(crmCustomerId);
|
|
|
client.setIsWeCom(companyVoiceRobotic.getIsWeCom());
|
|
|
+ client.setTraceId(traceId);
|
|
|
companyWxClientServiceImpl.insertCompanyWxClient(client);
|
|
|
|
|
|
CompanyVoiceRoboticCallees callee = new CompanyVoiceRoboticCallees();
|
|
|
@@ -1203,7 +1291,7 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
}
|
|
|
//写入业务表数据
|
|
|
CompanyVoiceRoboticBusiness companyVoiceRoboticBusiness = buildTaskBussiness4SceneTask(companyVoiceRobotic, callee);
|
|
|
- //初始化流程表 todo
|
|
|
+ //初始化流程表
|
|
|
initWorkflows4SceneTask(companyVoiceRobotic,companyVoiceRoboticBusiness);
|
|
|
|
|
|
}
|
|
|
@@ -1337,42 +1425,12 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
}
|
|
|
public void buildTaskBussiness(CompanyVoiceRobotic robotic) {
|
|
|
List<CompanyVoiceRoboticCallees> calleesList = companyVoiceRoboticCalleesMapper.selectByRoboticId(robotic.getId());
|
|
|
- //获取电话生成配置
|
|
|
- CidPhoneConfig phoneConfig = null;
|
|
|
- //获取销售公司手机配置
|
|
|
- CompanyConfig companyConfig = companyConfigMapper.selectCompanyConfigByKey(robotic.getCompanyId(), "cid.config");
|
|
|
- //如果配置为空就获取总后台配置
|
|
|
- if(companyConfig == null){
|
|
|
- String json = configService.selectConfigByKey("his.store");
|
|
|
- if(StringUtils.isNotEmpty(json)){
|
|
|
- phoneConfig = JSONObject.parseObject(json,CidPhoneConfig.class);
|
|
|
- }
|
|
|
- } else {
|
|
|
- phoneConfig = JSONObject.parseObject(companyConfig.getConfigValue(), CidPhoneConfig.class);
|
|
|
- }
|
|
|
-
|
|
|
- //获取工作流主表信息
|
|
|
- CompanyWorkflow workflow = companyWorkflowMapper.selectCompanyWorkflowById(robotic.getCompanyAiWorkflowId());
|
|
|
-
|
|
|
- //获取相关节点信息
|
|
|
- CompanyNodeInfoVo nodeInfoVo = edgeMapper.slectNodeInfoByWorkflowId(workflow.getWorkflowId(), workflow.getStartNodeKey());
|
|
|
-
|
|
|
List<CompanyWxClient> companyWxClients = companyWxClientMapper.selectListByRoboticId(robotic.getId());
|
|
|
Map<String, CompanyWxClient> clientMp = companyWxClients.stream().collect(Collectors.toMap(e -> e.getRoboticId() + "-" + e.getCustomerId(), e -> e));
|
|
|
List<CompanyVoiceRoboticBusiness> addList = new ArrayList<>();
|
|
|
- List<CompanyVoiceRoboticCallees> batchToInsert = new LinkedList<>();
|
|
|
+ //异步生成列表日志
|
|
|
+ asyncCalleeProcessorService.generateCustomerInfo(calleesList,clientMp,robotic);
|
|
|
for (CompanyVoiceRoboticCallees callees : calleesList) {
|
|
|
- //根据配置随机生成电话号
|
|
|
- if (phoneConfig != null && phoneConfig.getEnablePhoneConfig()) {//配置不为空并且开启了
|
|
|
- List<CompanyVoiceRoboticCallees> roboticCallees = generatePhoneNumber(phoneConfig, callees);
|
|
|
- if (!roboticCallees.isEmpty()) {
|
|
|
- batchToInsert.addAll(roboticCallees);
|
|
|
- if (batchToInsert.size() >= BATCH_SIZE) {
|
|
|
- flushGeneratedCalleesBatch(new LinkedList<>(batchToInsert), clientMp, robotic, workflow, nodeInfoVo);
|
|
|
- batchToInsert.clear();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
CompanyVoiceRoboticBusiness companyVoiceRoboticBusiness = new CompanyVoiceRoboticBusiness();
|
|
|
companyVoiceRoboticBusiness.setRoboticId(robotic.getId());
|
|
|
companyVoiceRoboticBusiness.setCalleeId(callees.getId());
|
|
|
@@ -1383,13 +1441,6 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
companyVoiceRoboticBusiness.setCreateTime(new Date());
|
|
|
addList.add(companyVoiceRoboticBusiness);
|
|
|
}
|
|
|
-
|
|
|
- //处理剩余数据
|
|
|
- if (!batchToInsert.isEmpty()) {
|
|
|
- flushGeneratedCalleesBatch(new LinkedList<>(batchToInsert), clientMp, robotic, workflow, nodeInfoVo);
|
|
|
- batchToInsert.clear();
|
|
|
- }
|
|
|
-
|
|
|
companyVoiceRoboticBusinessMapper.insertBatch(addList);
|
|
|
|
|
|
}
|
|
|
@@ -1599,231 +1650,4 @@ public class CompanyVoiceRoboticServiceImpl extends ServiceImpl<CompanyVoiceRobo
|
|
|
return vo;
|
|
|
}).collect(Collectors.toList());
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- * 根据配置生成手机号
|
|
|
- *
|
|
|
- * @param config 配置对象(包含是否启用、生成数量、起始位置、结束位置)
|
|
|
- * @param callees 任务外呼电话对象
|
|
|
- * @return 生成的手机号列表
|
|
|
- */
|
|
|
- public static List<CompanyVoiceRoboticCallees> generatePhoneNumber(CidPhoneConfig config, CompanyVoiceRoboticCallees callees) {
|
|
|
- String basePhone = callees.getPhone();
|
|
|
- if (basePhone == null || basePhone.length() != 11) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- int start = config.getStartIndex();
|
|
|
- int end = config.getEndIndex();
|
|
|
- int count = config.getGenerateCount();
|
|
|
-
|
|
|
- // 校验索引范围
|
|
|
- if (start < 1 || start > 11 || end < 1 || end > 11 || start > end) {
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- int startIdx = start;
|
|
|
- int endIdx = end - 1;
|
|
|
-
|
|
|
- char[] baseChars = basePhone.toCharArray();
|
|
|
- //预加载随机
|
|
|
- List<String> nameList = RandomNameGeneratorUtil.generateBatch(count);
|
|
|
- Random random = new Random();
|
|
|
- List<CompanyVoiceRoboticCallees> result = new ArrayList<>(count);
|
|
|
- for (int i = 0; i < count; i++) {
|
|
|
- CompanyVoiceRoboticCallees roboticCallees = new CompanyVoiceRoboticCallees();
|
|
|
- // 克隆基础数组
|
|
|
- char[] newChars = baseChars.clone();
|
|
|
- for (int j = startIdx; j <= endIdx; j++) {
|
|
|
- // 生成0-9的随机数字字符
|
|
|
- newChars[j] = (char) ('0' + random.nextInt(10));
|
|
|
- }
|
|
|
- String phone = String.valueOf(newChars);
|
|
|
- roboticCallees.setPhone(phone);//电话
|
|
|
- roboticCallees.setRoboticId(callees.getRoboticId());//任务ID
|
|
|
- roboticCallees.setTaskFlow(callees.getTaskFlow());//任务流程
|
|
|
- roboticCallees.setRunTaskFlow(callees.getRunTaskFlow());//已执行流程
|
|
|
- roboticCallees.setIsWeCom(callees.getIsWeCom());
|
|
|
- roboticCallees.setUserId(0L);//用户ID
|
|
|
- roboticCallees.setUserName(nameList.get(i));//姓名
|
|
|
- roboticCallees.setIsGenerate(1);
|
|
|
- result.add(roboticCallees);
|
|
|
- }
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成外呼任务表
|
|
|
- *
|
|
|
- **/
|
|
|
- public void generateVoiceRoboticBusiness(List<CompanyVoiceRoboticCallees> calleesList,
|
|
|
- Map<String, CompanyWxClient> clientMp
|
|
|
- , CompanyVoiceRobotic robotic
|
|
|
- , CompanyWorkflow workflow
|
|
|
- , CompanyNodeInfoVo nodeInfoVo) {
|
|
|
- if (!calleesList.isEmpty()) {
|
|
|
- List<CompanyVoiceRoboticBusiness> addList = new LinkedList<>();
|
|
|
- Date date = new Date();
|
|
|
- for (CompanyVoiceRoboticCallees callees : calleesList) {
|
|
|
- CompanyVoiceRoboticBusiness companyVoiceRoboticBusiness = new CompanyVoiceRoboticBusiness();
|
|
|
- companyVoiceRoboticBusiness.setRoboticId(callees.getRoboticId());
|
|
|
- companyVoiceRoboticBusiness.setCalleeId(callees.getId());
|
|
|
- companyVoiceRoboticBusiness.setWxClientId(clientMp.getOrDefault(callees.getRoboticId() + "-" + callees.getUserId(), new CompanyWxClient()).getId());
|
|
|
- companyVoiceRoboticBusiness.setAddWxDone(0);
|
|
|
- companyVoiceRoboticBusiness.setCallPhoneDone(0);
|
|
|
- companyVoiceRoboticBusiness.setSendMsgDone(0);
|
|
|
- companyVoiceRoboticBusiness.setCreateTime(date);
|
|
|
- companyVoiceRoboticBusiness.setIsGenerate(1);
|
|
|
- addList.add(companyVoiceRoboticBusiness);
|
|
|
- }
|
|
|
-
|
|
|
- //批量插入ai外呼业务对象
|
|
|
- if (!addList.isEmpty()) {
|
|
|
- flushGeneratedBusinessBatch(addList, robotic, workflow, nodeInfoVo);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 刷新并批量插入生成的被叫数据,并生成对应的业务对象
|
|
|
- *
|
|
|
- * @param batchToInsert 待插入的被叫列表
|
|
|
- * @param clientMap 微信客户映射,用于关联客户ID
|
|
|
- */
|
|
|
- @Async("calleeTaskExecutor")
|
|
|
- public void flushGeneratedCalleesBatch(List<CompanyVoiceRoboticCallees> batchToInsert,
|
|
|
- Map<String, CompanyWxClient> clientMap,
|
|
|
- CompanyVoiceRobotic robotic,
|
|
|
- CompanyWorkflow workflow,
|
|
|
- CompanyNodeInfoVo nodeInfoVo) {
|
|
|
- if (batchToInsert.isEmpty()) {
|
|
|
- return;
|
|
|
- }
|
|
|
- int rows = companyVoiceRoboticCalleesMapper.batchInsertGenerateInfo(batchToInsert);
|
|
|
- if (rows > 0) {
|
|
|
- generateVoiceRoboticBusiness(batchToInsert, clientMap, robotic, workflow, nodeInfoVo);
|
|
|
- }
|
|
|
- batchToInsert.clear();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 批量插入业务对象,并创建工作流执行记录
|
|
|
- */
|
|
|
- private void flushGeneratedBusinessBatch(List<CompanyVoiceRoboticBusiness> batchToInsert,CompanyVoiceRobotic robotic,CompanyWorkflow workflow,CompanyNodeInfoVo nodeInfoVo){
|
|
|
- int rows = companyVoiceRoboticBusinessMapper.insertBatchGenerateInfo(batchToInsert);
|
|
|
- if(rows > 0){
|
|
|
- LocalDateTime now = LocalDateTime.now();
|
|
|
- List<CompanyAiWorkflowExec> startExecList = new LinkedList<>();//第一节点
|
|
|
- List<CompanyAiWorkflowExec> targetExecList = new LinkedList<>();//第二节点
|
|
|
- //插入执行流程代码
|
|
|
- for (CompanyVoiceRoboticBusiness business : batchToInsert){
|
|
|
- // 第一个节点(开始节点)
|
|
|
- CompanyAiWorkflowExec startExec = new CompanyAiWorkflowExec();
|
|
|
- startExec.setWorkflowInstanceId(generateInstanceId());
|
|
|
- startExec.setWorkflowId(robotic.getCompanyAiWorkflowId());
|
|
|
- startExec.setCurrentNodeKey(workflow.getStartNodeKey());
|
|
|
- startExec.setCurrentNodeType(NodeTypeEnum.START.getValue());
|
|
|
- startExec.setCurrentNodeName(NodeTypeEnum.START.getDescription());
|
|
|
- startExec.setStatus(ExecutionStatusEnum.SUCCESS.getValue()); // 开始节点执行成功
|
|
|
- startExec.setStartTime(now);
|
|
|
-
|
|
|
- JSONObject variables = new JSONObject();
|
|
|
- variables.put("roboticId", robotic.getId());
|
|
|
- variables.put("businessId", business.getId());
|
|
|
- variables.put("cidGroupNo", robotic.getCidGroupNo());
|
|
|
- variables.put("runtimeRangeStart", robotic.getRuntimeRangeStart());
|
|
|
- variables.put("runtimeRangeEnd", robotic.getRuntimeRangeEnd());
|
|
|
- startExec.setVariables(variables.toJSONString());
|
|
|
- startExec.setBusinessKey(business.getId().toString());
|
|
|
- startExec.setStartNodeKey(workflow.getStartNodeKey());
|
|
|
- startExec.setEndNodeKey(workflow.getEndNodeKey());
|
|
|
- startExec.setCidGroupNo(robotic.getCidGroupNo());
|
|
|
- startExec.setRuntimeRangeStart(robotic.getRuntimeRangeStart());
|
|
|
- startExec.setRuntimeRangeEnd(robotic.getRuntimeRangeEnd());
|
|
|
- startExec.setIsGenerate(1);
|
|
|
- startExecList.add(startExec);
|
|
|
-
|
|
|
- CompanyAiWorkflowExec targetExec = new CompanyAiWorkflowExec();
|
|
|
- // 复制公共字段
|
|
|
- targetExec.setWorkflowInstanceId(startExec.getWorkflowInstanceId());
|
|
|
- targetExec.setWorkflowId(startExec.getWorkflowId());
|
|
|
- targetExec.setCurrentNodeKey(nodeInfoVo.getTargetNodeKey());
|
|
|
- targetExec.setCurrentNodeName(nodeInfoVo.getNodeName());
|
|
|
- targetExec.setCurrentNodeType(NodeTypeEnum.fromCode(nodeInfoVo.getNodeType()).getValue());
|
|
|
- targetExec.setStatus(ExecutionStatusEnum.FAILURE.getValue());
|
|
|
- targetExec.setStartTime(now);
|
|
|
- targetExec.setVariables(variables.toJSONString());
|
|
|
- targetExec.setBusinessKey(startExec.getBusinessKey());
|
|
|
- targetExec.setStartNodeKey(startExec.getStartNodeKey());
|
|
|
- targetExec.setEndNodeKey(startExec.getEndNodeKey());
|
|
|
- targetExec.setCidGroupNo(startExec.getCidGroupNo());
|
|
|
- targetExec.setRuntimeRangeStart(startExec.getRuntimeRangeStart());
|
|
|
- targetExec.setRuntimeRangeEnd(startExec.getRuntimeRangeEnd());
|
|
|
- targetExec.setIsGenerate(1);
|
|
|
- targetExecList.add(targetExec);
|
|
|
-
|
|
|
- if(targetExecList.size() >= BATCH_SIZE){
|
|
|
- generateVoiceRoboticCurrentExecLogs(targetExecList, startExecList);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if(!targetExecList.isEmpty()){
|
|
|
- generateVoiceRoboticCurrentExecLogs(targetExecList, startExecList);
|
|
|
- }
|
|
|
- }
|
|
|
- batchToInsert.clear();
|
|
|
- }
|
|
|
-
|
|
|
- public void generateVoiceRoboticCurrentExecLogs(List<CompanyAiWorkflowExec> workflowExecs, List<CompanyAiWorkflowExec> startExecList){
|
|
|
- if (workflowExecs.isEmpty()) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- int rows = companyAiWorkflowExecMapper.insertBatchInfo(workflowExecs);
|
|
|
- if(rows > 0){
|
|
|
- workflowExecLogBatchInsert(startExecList);//第一节点
|
|
|
- workflowExecLogBatchInsert(workflowExecs);//第二节点
|
|
|
- }
|
|
|
- workflowExecs.clear();
|
|
|
- startExecList.clear();
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * AI外呼流程执行记录对象批量插入
|
|
|
- * **/
|
|
|
- private void workflowExecLogBatchInsert(List<CompanyAiWorkflowExec> workflowExecs){
|
|
|
- //插入日志记录表
|
|
|
- Date date =new Date();
|
|
|
- List<CompanyAiWorkflowExecLog> batch = new LinkedList<>();
|
|
|
- workflowExecs.forEach(w->{
|
|
|
- CompanyAiWorkflowExecLog execLog = new CompanyAiWorkflowExecLog();
|
|
|
- execLog.setWorkflowInstanceId(w.getWorkflowInstanceId());
|
|
|
- execLog.setNodeKey(w.getCurrentNodeKey());
|
|
|
- execLog.setNodeName(w.getCurrentNodeName());
|
|
|
- execLog.setNodeType(w.getCurrentNodeType());
|
|
|
- execLog.setInputData(w.getVariables());
|
|
|
- execLog.setStatus(w.getStatus());
|
|
|
- execLog.setOutputData("null");
|
|
|
- execLog.setStartTime(date);
|
|
|
- execLog.setEndTime(date);
|
|
|
- execLog.setIsGenerate(1);
|
|
|
- batch.add(execLog);
|
|
|
- });
|
|
|
- if(!batch.isEmpty()){
|
|
|
- companyAiWorkflowExecLogMapper.batchInsert(batch);
|
|
|
- batch.clear();
|
|
|
- }
|
|
|
- workflowExecs.clear();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成工作流实例ID
|
|
|
- */
|
|
|
- private String generateInstanceId() {
|
|
|
- return "wf_" + System.currentTimeMillis() + "_" +
|
|
|
- UUID.randomUUID().toString().replace("-", "");
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
}
|