|
|
@@ -0,0 +1,520 @@
|
|
|
+package com.fs.aiSipCall.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.fs.aiSipCall.RemoteCommon;
|
|
|
+import com.fs.aiSipCall.domain.AiSipCallOutboundCdr;
|
|
|
+import com.fs.aiSipCall.domain.CcCustInfo;
|
|
|
+import com.fs.aiSipCall.mapper.AiSipCallOutboundCdrMapper;
|
|
|
+import com.fs.aiSipCall.param.ApiCallRecordByUuidQueryParams;
|
|
|
+import com.fs.aiSipCall.param.ApiCallRecordQueryParams;
|
|
|
+import com.fs.aiSipCall.service.IAiSipCallOutboundCdrService;
|
|
|
+import com.fs.aiSipCall.utils.DateUtils;
|
|
|
+import com.fs.aiSipCall.vo.ApiCallRecordQueryVo;
|
|
|
+import com.fs.common.core.domain.AjaxResult;
|
|
|
+import com.fs.common.core.redis.RedisCache;
|
|
|
+import com.fs.company.domain.CompanyAiWorkflowExec;
|
|
|
+import com.fs.company.domain.CompanyVoiceRoboticCallLogCallphone;
|
|
|
+import com.fs.company.mapper.CompanyAiWorkflowExecMapper;
|
|
|
+import com.fs.company.mapper.CompanyVoiceRoboticCallLogCallphoneMapper;
|
|
|
+import com.fs.company.mapper.EasyCallMapper;
|
|
|
+import com.fs.company.param.ExecutionContext;
|
|
|
+import com.fs.company.vo.easycall.EasyCallCallPhoneVO;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.scheduling.annotation.Async;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * aiSIP手动外呼通话记录Service业务层处理
|
|
|
+ *
|
|
|
+ * @author fs
|
|
|
+ * @date 2026-03-19
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class AiSipCallOutboundCdrServiceImpl extends ServiceImpl<AiSipCallOutboundCdrMapper, AiSipCallOutboundCdr> implements IAiSipCallOutboundCdrService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CompanyVoiceRoboticCallLogCallphoneMapper companyVoiceRoboticCallLogCallphoneMapper;
|
|
|
+ @Autowired
|
|
|
+ private RedisCache redisCache;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EasyCallMapper easyCallMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CompanyAiWorkflowExecMapper currentExecutionMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ObjectMapper objectMapper;
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public AiSipCallOutboundCdr selectAiSipCallOutboundCdrById(String id) {
|
|
|
+ return baseMapper.selectAiSipCallOutboundCdrById(id);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 查询aiSIP手动外呼通话记录列表
|
|
|
+ *
|
|
|
+ * @param aiSipCallOutboundCdr aiSIP手动外呼通话记录
|
|
|
+ * @return aiSIP手动外呼通话记录
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<AiSipCallOutboundCdr> selectAiSipCallOutboundCdrList(AiSipCallOutboundCdr aiSipCallOutboundCdr)
|
|
|
+ {
|
|
|
+ if (aiSipCallOutboundCdr.getTimeLenStart() != null) {
|
|
|
+ aiSipCallOutboundCdr.setTimeLenStart(aiSipCallOutboundCdr.getTimeLenStart() * 60 * 1000L);
|
|
|
+ }
|
|
|
+ if (aiSipCallOutboundCdr.getTimeLenEnd() != null) {
|
|
|
+ aiSipCallOutboundCdr.setTimeLenEnd(aiSipCallOutboundCdr.getTimeLenEnd() * 60 * 1000L);
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(aiSipCallOutboundCdr.getStartTimeStart())) {
|
|
|
+ aiSipCallOutboundCdr.setStartTimeStartLong(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", aiSipCallOutboundCdr.getStartTimeStart()).getTime());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(aiSipCallOutboundCdr.getStartTimeEnd())) {
|
|
|
+ aiSipCallOutboundCdr.setStartTimeEndLong(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", aiSipCallOutboundCdr.getStartTimeEnd()).getTime());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(aiSipCallOutboundCdr.getAnsweredTimeStart())) {
|
|
|
+ aiSipCallOutboundCdr.setAnsweredTimeStartLong(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", aiSipCallOutboundCdr.getAnsweredTimeStart()).getTime());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(aiSipCallOutboundCdr.getAnsweredTimeEnd())) {
|
|
|
+ aiSipCallOutboundCdr.setAnsweredTimeEndLong(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", aiSipCallOutboundCdr.getAnsweredTimeEnd()).getTime());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StringUtils.isNotBlank(aiSipCallOutboundCdr.getEndTimeStart())) {
|
|
|
+ aiSipCallOutboundCdr.setEndTimeStartLong(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", aiSipCallOutboundCdr.getEndTimeStart()).getTime());
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(aiSipCallOutboundCdr.getEndTimeEnd())) {
|
|
|
+ aiSipCallOutboundCdr.setEndTimeEndLong(DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", aiSipCallOutboundCdr.getEndTimeEnd()).getTime());
|
|
|
+ }
|
|
|
+ return baseMapper.selectAiSipCallOutboundCdrList(aiSipCallOutboundCdr);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增aiSIP手动外呼通话记录
|
|
|
+ *
|
|
|
+ * @param aiSipCallOutboundCdr aiSIP手动外呼通话记录
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int insertAiSipCallOutboundCdr(AiSipCallOutboundCdr aiSipCallOutboundCdr)
|
|
|
+ {
|
|
|
+ return baseMapper.insertAiSipCallOutboundCdr(aiSipCallOutboundCdr);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 修改aiSIP手动外呼通话记录
|
|
|
+ *
|
|
|
+ * @param aiSipCallOutboundCdr aiSIP手动外呼通话记录
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int updateAiSipCallOutboundCdr(AiSipCallOutboundCdr aiSipCallOutboundCdr)
|
|
|
+ {
|
|
|
+ return baseMapper.updateAiSipCallOutboundCdr(aiSipCallOutboundCdr);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量删除aiSIP手动外呼通话记录
|
|
|
+ *
|
|
|
+ * @param ids 需要删除的aiSIP手动外呼通话记录主键
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int deleteAiSipCallOutboundCdrByIds(String[] ids)
|
|
|
+ {
|
|
|
+ return baseMapper.deleteAiSipCallOutboundCdrByIds(ids);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除aiSIP手动外呼通话记录信息
|
|
|
+ *
|
|
|
+ * @param id aiSIP手动外呼通话记录主键
|
|
|
+ * @return 结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public int deleteAiSipCallOutboundCdrById(String id)
|
|
|
+ {
|
|
|
+ return baseMapper.deleteAiSipCallOutboundCdrById(id);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public AjaxResult getCustCommunicationInfo(String phoneNum, Integer callType, String uuid) {
|
|
|
+ String paramStr = "?phoneNum=" + phoneNum + "&callType=" + callType + "&uuid=" + uuid;
|
|
|
+ String result = RemoteCommon.sendGet(RemoteCommon.REMOTE_ADDERSS_PREFIX + RemoteCommon.GET_CUST_COMMUNICATION_INFO_API + paramStr);
|
|
|
+ if (StringUtils.isNotBlank(result)) {
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(result);
|
|
|
+ if (jsonObject.getInteger("code") == 0) {
|
|
|
+ return JSONObject.parseObject(result, AjaxResult.class);
|
|
|
+ } else {
|
|
|
+ log.error("取手动外呼客户沟通信息失败:{}", jsonObject.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.error("取手动外呼客户沟通信息失败:{}", "接口返回为空");
|
|
|
+ }
|
|
|
+ return AjaxResult.error();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public AjaxResult addCustcallrecord(CcCustInfo ccCustInfo) {
|
|
|
+ String result = RemoteCommon.sendPost(RemoteCommon.REMOTE_ADDERSS_PREFIX + RemoteCommon.ADD_CUSTCALL_RECORD_API,JSONObject.toJSONString(ccCustInfo));
|
|
|
+ if (StringUtils.isNotBlank(result)) {
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(result);
|
|
|
+ if (jsonObject.getInteger("code") == 0) {
|
|
|
+ return JSONObject.parseObject(result, AjaxResult.class);
|
|
|
+ } else {
|
|
|
+ log.error("取手动外呼客户沟通信息失败:{}", jsonObject.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.error("取手动外呼客户沟通信息失败:{}", "接口返回为空");
|
|
|
+ }
|
|
|
+ return AjaxResult.error();
|
|
|
+ }
|
|
|
+
|
|
|
+ private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
|
|
+ @Override
|
|
|
+ @Async
|
|
|
+ public CompletableFuture<String> scheduledGetCallRecord() {
|
|
|
+ if (!isRunning.compareAndSet(false, true)) {
|
|
|
+ log.warn("scheduledGetCallRecord 任务正在执行中,请稍后再试");
|
|
|
+ return CompletableFuture.completedFuture("任务正在执行中,请稍后再试");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ log.info("开始执行 scheduledGetCallRecord 异步任务");
|
|
|
+ String todayStartStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date()) + " 00:00:00";
|
|
|
+ String now = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, new Date());
|
|
|
+ long startTime = System.currentTimeMillis();
|
|
|
+
|
|
|
+ // 构建查询参数
|
|
|
+ List<ApiCallRecordQueryParams> paramsList = buildDayQueryParams(todayStartStr,now);
|
|
|
+
|
|
|
+ // 获取远程数据
|
|
|
+ List<AiSipCallOutboundCdr> remoteList = fetchAllRemoteCallRecords(paramsList);
|
|
|
+ if (remoteList.isEmpty()) {
|
|
|
+ log.info("scheduledGetCallRecord 异步任务完成,耗时:{}ms, 结果:当天无最新数据", System.currentTimeMillis() - startTime);
|
|
|
+ return CompletableFuture.completedFuture("当天无最新数据");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取本地当天所有外呼记录
|
|
|
+ List<AiSipCallOutboundCdr> localList = baseMapper.selectCurrentDayCallRecords(DateUtils.toStartTime(), System.currentTimeMillis());
|
|
|
+
|
|
|
+ // 筛选并处理新增和更新数据
|
|
|
+ String result = processAndSaveData(remoteList, localList);
|
|
|
+ log.info("scheduledGetCallRecord 异步任务完成,耗时:{}ms, 结果:{}", System.currentTimeMillis() - startTime, result);
|
|
|
+ return CompletableFuture.completedFuture(result);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("scheduledGetCallRecord 异步任务执行失败", e);
|
|
|
+ return CompletableFuture.completedFuture("任务执行失败:" + e.getMessage());
|
|
|
+ } finally {
|
|
|
+ isRunning.set(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建当天查询参数 - 使用当天 00:00:00 到当前时间
|
|
|
+ * @return 查询参数对象列表(支持多时段查询)
|
|
|
+ */
|
|
|
+ private List<ApiCallRecordQueryParams> buildDayQueryParams(String todayStartStr,String now) {
|
|
|
+
|
|
|
+ List<ApiCallRecordQueryParams> paramsList = new ArrayList<>();
|
|
|
+
|
|
|
+ // 如果时间跨度超过 12 小时,分段查询避免遗漏
|
|
|
+ Date today = DateUtils.parseDate(todayStartStr);
|
|
|
+ long hoursDiff = (System.currentTimeMillis() - today.getTime()) / (1000 * 60 * 60);
|
|
|
+
|
|
|
+ if (hoursDiff > 12) {
|
|
|
+ // 分两段查询:00:00-12:00 和 12:00-当前时间
|
|
|
+ ApiCallRecordQueryParams params1 = createSingleParam(todayStartStr, todayStartStr.substring(0, 10) + " 12:00:00");
|
|
|
+ ApiCallRecordQueryParams params2 = createSingleParam(todayStartStr.substring(0, 10) + " 12:00:00", now);
|
|
|
+ paramsList.add(params1);
|
|
|
+ paramsList.add(params2);
|
|
|
+ } else {
|
|
|
+ // 单段查询:00:00-当前时间
|
|
|
+ paramsList.add(createSingleParam(todayStartStr, now));
|
|
|
+ }
|
|
|
+
|
|
|
+ return paramsList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建单个查询参数对象
|
|
|
+ */
|
|
|
+ private ApiCallRecordQueryParams createSingleParam(String startTime, String endTime) {
|
|
|
+ ApiCallRecordQueryParams params = new ApiCallRecordQueryParams();
|
|
|
+ params.setPageNum(1);
|
|
|
+ params.setPageSize(1000); // 减小单次请求量,提升响应速度
|
|
|
+ params.setCallType("03");
|
|
|
+ params.setCalloutTimeStart(startTime);
|
|
|
+ params.setCalloutTimeEnd(endTime);
|
|
|
+ return params;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分页轮询获取所有远程通话记录 (带去重和失败重试)
|
|
|
+ * @param paramsList 查询参数列表
|
|
|
+ * @return 通话记录列表 (已去重)
|
|
|
+ */
|
|
|
+ private List<AiSipCallOutboundCdr> fetchAllRemoteCallRecords(List<ApiCallRecordQueryParams> paramsList) {
|
|
|
+ List<AiSipCallOutboundCdr> allRecords = new ArrayList<>();
|
|
|
+ for (ApiCallRecordQueryParams params : paramsList) {
|
|
|
+ int currentPage = 1;
|
|
|
+ boolean hasMore = true;
|
|
|
+
|
|
|
+ while (hasMore) {
|
|
|
+ params.setPageNum(currentPage);
|
|
|
+ List<AiSipCallOutboundCdr> pageData = fetchSinglePageRecords(params);
|
|
|
+
|
|
|
+ // 失败时跳过该页,继续下一页
|
|
|
+ if (pageData == null) {
|
|
|
+ log.warn("分页查询第{}页失败,已丢弃该页数据", currentPage);
|
|
|
+ currentPage++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pageData.isEmpty()) {
|
|
|
+ log.info("第{}页无数据,查询结束", currentPage);
|
|
|
+ hasMore = false;
|
|
|
+ } else {
|
|
|
+ allRecords.addAll(pageData);
|
|
|
+ log.debug("第{}页数据:{},累计总数:{}", currentPage, pageData.size(), allRecords.size());
|
|
|
+
|
|
|
+ // 如果返回数据少于页大小,说明已是最后一页
|
|
|
+ if (pageData.size() < params.getPageSize()) {
|
|
|
+ hasMore = false;
|
|
|
+ }
|
|
|
+ currentPage++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 安全限制:最多拉取 50 页
|
|
|
+ if (currentPage > 50) {
|
|
|
+ log.warn("已达到最大页数限制 50 页,停止查询。已获取数据量:{}", allRecords.size());
|
|
|
+ hasMore = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("远程数据获取完成,总计:{} 条", allRecords.size());
|
|
|
+ return allRecords.isEmpty() ? Collections.emptyList() : allRecords;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取单页数据
|
|
|
+ * @param params 查询参数(需预先设置页码)
|
|
|
+ * @return 单页通话记录列表
|
|
|
+ */
|
|
|
+ private List<AiSipCallOutboundCdr> fetchSinglePageRecords(ApiCallRecordQueryParams params) {
|
|
|
+ try {
|
|
|
+ String result = RemoteCommon.sendPost(
|
|
|
+ RemoteCommon.REMOTE_ADDERSS_PREFIX + RemoteCommon.CALL_RECORDS_API,
|
|
|
+ JSONObject.toJSONString(params)
|
|
|
+ );
|
|
|
+
|
|
|
+ if (StringUtils.isBlank(result)) {
|
|
|
+ log.error("查询第{}页失败:接口返回为空", params.getPageNum());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(result);
|
|
|
+ Integer code = jsonObject.getInteger("code");
|
|
|
+
|
|
|
+ if (code == null || code != 0) {
|
|
|
+ String errorMsg = jsonObject.getString("msg") != null
|
|
|
+ ? jsonObject.getString("msg") : "未知错误";
|
|
|
+ log.error("查询第{}页失败:{}", params.getPageNum(), errorMsg);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ Long total = jsonObject.getLong("total");
|
|
|
+ if (total == null || total <= 0) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ String rows = jsonObject.getString("rows");
|
|
|
+ if (StringUtils.isBlank(rows)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ return JSONObject.parseArray(rows, AiSipCallOutboundCdr.class);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询第{}页异常", params.getPageNum(), e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理并保存数据 (新增和更新)
|
|
|
+ * @param remoteList 远程数据列表
|
|
|
+ * @param localList 本地数据列表
|
|
|
+ * @return 处理结果信息
|
|
|
+ */
|
|
|
+ private String processAndSaveData(List<AiSipCallOutboundCdr> remoteList, List<AiSipCallOutboundCdr> localList) {
|
|
|
+ if (remoteList == null || remoteList.isEmpty()) {
|
|
|
+ return "远程数据列表为空,无需处理";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (localList == null || localList.isEmpty()) {
|
|
|
+ log.warn("本地数据列表为空,所有远程数据都将作为新增处理");
|
|
|
+ return processDataWithStats(remoteList, "新增");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建本地数据的唯一标识映射
|
|
|
+ Set<String> localIdSet = localList.stream()
|
|
|
+ .map(AiSipCallOutboundCdr::getId)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ // 分类数据:新增和更新
|
|
|
+ List<AiSipCallOutboundCdr> insertList = new ArrayList<>();
|
|
|
+ List<AiSipCallOutboundCdr> updateList = new ArrayList<>();
|
|
|
+
|
|
|
+ for (AiSipCallOutboundCdr remote : remoteList) {
|
|
|
+ if (StringUtils.isBlank(remote.getId())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (localIdSet.contains(remote.getId())) {
|
|
|
+ updateList.add(remote);
|
|
|
+ } else {
|
|
|
+ insertList.add(remote);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("数据筛选完成 - 预计新增:{},预计更新:{}", insertList.size(), updateList.size());
|
|
|
+
|
|
|
+ StringBuilder resultMsg = new StringBuilder();
|
|
|
+ if (!insertList.isEmpty()) {
|
|
|
+ resultMsg.append(processDataWithStats(insertList, "新增"));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!updateList.isEmpty()) {
|
|
|
+ if (resultMsg.length() > 0) {
|
|
|
+ resultMsg.append(",");
|
|
|
+ }
|
|
|
+ resultMsg.append(processDataWithStats(updateList, "更新"));
|
|
|
+ }
|
|
|
+
|
|
|
+ return resultMsg.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理批量数据并统计成功失败信息
|
|
|
+ * @param dataList 数据列表
|
|
|
+ * @param operationType 操作类型:"新增" 或 "更新"
|
|
|
+ * @return 处理结果信息
|
|
|
+ */
|
|
|
+ private String processDataWithStats(List<AiSipCallOutboundCdr> dataList,String operationType) {
|
|
|
+ log.info("开始处理{}Ai 外呼记录数据,数量:{}", operationType, dataList.size());
|
|
|
+ if (dataList.isEmpty()) {
|
|
|
+ return "无有效数据,无需处理";
|
|
|
+ }
|
|
|
+
|
|
|
+ int batchSize = 500;
|
|
|
+ int totalSize = dataList.size();
|
|
|
+ int batchCount = (totalSize + batchSize - 1) / batchSize;
|
|
|
+ int successCount = 0;
|
|
|
+ int failCount = 0;
|
|
|
+ List<int[]> failedBatchRanges = new ArrayList<>();
|
|
|
+
|
|
|
+ for (int i = 0; i < batchCount; i++) {
|
|
|
+ int fromIndex = i * batchSize;
|
|
|
+ int toIndex = Math.min(fromIndex + batchSize, totalSize);
|
|
|
+ List<AiSipCallOutboundCdr> batchList = dataList.subList(fromIndex, toIndex);
|
|
|
+
|
|
|
+ try {
|
|
|
+ if ("新增".equals(operationType)) {
|
|
|
+ this.saveBatch(batchList);
|
|
|
+ } else if ("更新".equals(operationType)) {
|
|
|
+ this.updateBatchById(batchList);
|
|
|
+ }
|
|
|
+ successCount += batchList.size();
|
|
|
+ log.debug("第{}/{}批{}成功,本批数量:{}", i + 1, batchCount, operationType, batchList.size());
|
|
|
+ } catch (Exception e) {
|
|
|
+ failCount += batchList.size();
|
|
|
+ int[] range = {fromIndex, toIndex - 1};
|
|
|
+ failedBatchRanges.add(range);
|
|
|
+ log.error("第{}批数据{}失败,本批数量:{},起始位:{},结束位:{}",
|
|
|
+ i + 1, operationType, batchList.size(), fromIndex, toIndex - 1, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBuilder result = new StringBuilder();
|
|
|
+ result.append(operationType).append("数据处理完成,总计:").append(totalSize).append("条");
|
|
|
+ result.append(",成功:").append(successCount).append("条");
|
|
|
+
|
|
|
+ if (failCount > 0) {
|
|
|
+ result.append(",失败:").append(failCount).append("条");
|
|
|
+ result.append(",失败数据位置:");
|
|
|
+ for (int i = 0; i < failedBatchRanges.size(); i++) {
|
|
|
+ int[] range = failedBatchRanges.get(i);
|
|
|
+ if (i > 0) result.append(";");
|
|
|
+ result.append("[").append(range[0]).append("-").append(range[1]).append("]");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public int syncByUuid(ApiCallRecordByUuidQueryParams req) {
|
|
|
+ if (req == null || StringUtils.isBlank(req.getUuid())) {
|
|
|
+// throw new ServiceException("uuid不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ String callType = StringUtils.isBlank(req.getCallType()) ? "03" : req.getCallType();
|
|
|
+
|
|
|
+ EasyCallCallPhoneVO callPhoneRes = easyCallMapper.getCallPhoneInfoByUuid(req.getUuid());
|
|
|
+ String callBackUuid = UUID.randomUUID().toString();
|
|
|
+ CompanyAiWorkflowExec record = currentExecutionMapper.selectByWorkflowInstanceId(req.getWorkflowInstanceId());
|
|
|
+ try {
|
|
|
+ Map<String, Object> variablesMap;
|
|
|
+ if (record.getVariables() == null || record.getVariables().isEmpty()) {
|
|
|
+ variablesMap = new HashMap<>();
|
|
|
+ } else {
|
|
|
+ variablesMap = objectMapper.readValue(record.getVariables(), new TypeReference<Map<String, Object>>() {});
|
|
|
+ }
|
|
|
+ variablesMap.put("callBackUuid", callBackUuid);
|
|
|
+ record.setVariables(objectMapper.writeValueAsString(variablesMap));
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("反序列化上下文变量失败", e);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ CompanyVoiceRoboticCallLogCallphone companyVoiceRoboticCallLogCallphone = new CompanyVoiceRoboticCallLogCallphone();
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallbackUuid(callBackUuid);
|
|
|
+ companyVoiceRoboticCallLogCallphone.setRoboticId(req.getRoboticId());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallerId(null);
|
|
|
+ companyVoiceRoboticCallLogCallphone.setRunTime(null);
|
|
|
+ companyVoiceRoboticCallLogCallphone.setRunParam(null);
|
|
|
+ companyVoiceRoboticCallLogCallphone.setResult(null);
|
|
|
+ companyVoiceRoboticCallLogCallphone.setStatus(req.getStatus());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setRecordPath(callPhoneRes.getRecordServerUrl());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setContentList(callPhoneRes.getDialogue());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallerNum(callPhoneRes.getTelephone());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCalleeNum(callPhoneRes.getCallerNumber());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setUuid(req.getUuid());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallCreateTime(callPhoneRes.getCalloutTime());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallAnswerTime(callPhoneRes.getConnectedTime());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setIntention(callPhoneRes.getIntent());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCompanyId(req.getCompanyId());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCompanyUserId(req.getCompanyUserId());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallTime(Long.valueOf(callPhoneRes.getTimeLen()));
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCost(callPhoneRes.getTotalCost());
|
|
|
+ companyVoiceRoboticCallLogCallphone.setCallType(Integer.valueOf(callType));
|
|
|
+
|
|
|
+
|
|
|
+ return companyVoiceRoboticCallLogCallphoneMapper.insertCompanyVoiceRoboticCallLogCallphone(companyVoiceRoboticCallLogCallphone);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|