曜智外呼对接。

This commit is contained in:
haown 2026-01-05 15:15:23 +08:00
parent 0073751675
commit 870373970e
12 changed files with 588 additions and 66 deletions

View File

@ -7,7 +7,7 @@ spring:
# 主库数据源 # 主库数据源
master: master:
# url: jdbc:mysql://192.168.16.64:3306/post-discharge?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true # url: jdbc:mysql://192.168.16.64:3306/post-discharge?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
url: jdbc:mysql://8.131.93.145:54081/post-discharge?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true url: jdbc:mysql://8.131.93.145:54081/post-discharge-0331?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
# url: jdbc:mysql://182.92.166.109:8000/post-discharge?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true # url: jdbc:mysql://182.92.166.109:8000/post-discharge?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
username: root username: root
password: 1qaz!@#$ password: 1qaz!@#$

View File

@ -110,7 +110,7 @@ token:
# 令牌有效期默认30分钟 # 令牌有效期默认30分钟
expireTime: 120 expireTime: 120
# 请求拦截白名单 # 请求拦截白名单
ant-matchers: /postDischarge/**,/testMobile/**,/postDischargeApplet/**,/api/**,/manage/patientInfoimporttemp/** ant-matchers: /postDischarge/**,/testMobile/**,/postDischargeApplet/**,/api/**,/manage/patientInfoimporttemp/**,/yzapi/**
## MyBatis-Plus配置 ## MyBatis-Plus配置
mybatis-plus: mybatis-plus:
@ -302,6 +302,7 @@ yzaiobs:
# 请求地址 # 请求地址
url: http://47.109.194.76:8094/AIOBS url: http://47.109.194.76:8094/AIOBS
userId: 00447a7b-3174-4bc5-b917-8b72b29bc920 userId: 00447a7b-3174-4bc5-b917-8b72b29bc920
roleId: 1001
routeNum: 1 routeNum: 1
callPhone: 1234 callPhone: 1234
xinyilu-database: xinyilu-database:

View File

@ -0,0 +1,41 @@
package com.xinelu.manage.controller.yaiobs;
import com.alibaba.fastjson2.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.xinelu.manage.dto.aiob.DutyCallbackDto;
import com.xinelu.manage.service.yzaiobs.IYZAIOBSService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: 曜智·智能外呼平台控制器
* @author: haown
* @create: 2025-12-29 10:08
**/
@Api(tags = "曜智·智能外呼平台控制器")
@RestController
@RequestMapping("/yzapi")
public class YZAIOBSController {
@Resource
private IYZAIOBSService iyzaiobsService;
/**
* @description 任务回调
* @param dutyCallbackDto: 回调数据
* @return null
* @Author haown
* @Date 2024-8-29 11:15
*/
@ApiOperation("任务回调")
@PostMapping("/taskCallBack")
public JSONObject taskCallBack(@RequestBody DutyCallbackDto dutyCallbackDto) throws ClientException {
return iyzaiobsService.taskCallBack(dutyCallbackDto);
}
}

View File

@ -1,7 +1,7 @@
package com.xinelu.manage.dto.aiob; package com.xinelu.manage.dto.aiob;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson2.JSONObject;
import lombok.Data; import lombok.Data;
/** /**

View File

@ -101,7 +101,7 @@ public interface SignPatientManageRouteNodeMapper {
int updateDialStatus(SignPatientManageRouteNode signPatientManageRouteNode); int updateDialStatus(SignPatientManageRouteNode signPatientManageRouteNode);
/** /**
* 修改 拔打状态 * 修改 拔打状态第三方返回的任务ID
* @param signPatientManageRouteNode * @param signPatientManageRouteNode
* @return * @return
*/ */

View File

@ -10,6 +10,7 @@ import com.xinelu.manage.dto.aiob.CreateTaskDto;
import com.xinelu.manage.dto.aiob.ImportTaskDto; import com.xinelu.manage.dto.aiob.ImportTaskDto;
import com.xinelu.manage.dto.aiob.TaskCallbackDataDto; import com.xinelu.manage.dto.aiob.TaskCallbackDataDto;
import com.xinelu.manage.vo.aiob.ImportTaskVo; import com.xinelu.manage.vo.aiob.ImportTaskVo;
import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo;
import java.util.List; import java.util.List;
/** /**
@ -98,4 +99,8 @@ public interface IAIOBService {
void redialInfoSave(SignPatientManageRouteNode signPatientManageRouteNode, PatientVisitRecord patientVisitRecord); void redialInfoSave(SignPatientManageRouteNode signPatientManageRouteNode, PatientVisitRecord patientVisitRecord);
void parseQuestionInfo(JSONArray records, SignPatientManageRouteNode node, Long patientInfoId, Long taskExecuteRecordId); void parseQuestionInfo(JSONArray records, SignPatientManageRouteNode node, Long patientInfoId, Long taskExecuteRecordId);
String replaceQuestionName(String questionNameAlias, List<LabelFieldInfoContentVo> labelFieldContentList);
String videoPath(String downloadPath, String ccUuid);
} }

View File

@ -762,7 +762,8 @@ public class AIOBServiceImpl implements IAIOBService {
return null; return null;
} }
private String replaceQuestionName(String questionNameAlias, List<LabelFieldInfoContentVo> labelFieldContentList) { @Override
public String replaceQuestionName(String questionNameAlias, List<LabelFieldInfoContentVo> labelFieldContentList) {
Pattern pattern = Pattern.compile("\\{%\\s*&[\\s\\S]*?\\s*%}"); Pattern pattern = Pattern.compile("\\{%\\s*&[\\s\\S]*?\\s*%}");
Matcher matcher = pattern.matcher(questionNameAlias); Matcher matcher = pattern.matcher(questionNameAlias);
while (matcher.find()) { while (matcher.find()) {
@ -808,12 +809,16 @@ public class AIOBServiceImpl implements IAIOBService {
*/ */
@Override @Override
public String getPhoneDialRecord(String ccUuid) { public String getPhoneDialRecord(String ccUuid) {
String url = "";
String downLoadUrl = record(ccUuid); String downLoadUrl = record(ccUuid);
return videoPath(downLoadUrl, ccUuid);
}
@Override
public String videoPath(String downLoadUrl, String ccUuid) {
if (StringUtils.isBlank(downLoadUrl)) { if (StringUtils.isBlank(downLoadUrl)) {
throw new ServiceException("暂未获取到录音,请稍后再试!"); throw new ServiceException("暂未获取到录音,请稍后再试!");
} }
url = systemBusinessConfig.getProfile() + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + ccUuid + ".wav"; String url = systemBusinessConfig.getProfile() + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + ccUuid + ".wav";
File outputPath = new File(url); File outputPath = new File(url);
File dir = outputPath.getParentFile(); File dir = outputPath.getParentFile();
if (!dir.exists()){ if (!dir.exists()){

View File

@ -31,5 +31,12 @@ public interface IYZAIOBSService {
*/ */
JSONObject taskCallBack(DutyCallbackDto callbackDto) throws ClientException; JSONObject taskCallBack(DutyCallbackDto callbackDto) throws ClientException;
/**
* @description 单通电话数据回传接口
* @Param * @param null
* @return null
* @Author haown
* @Date 2025-12-26 15:59
*/
JSONObject phoneCallBack();
} }

View File

@ -27,13 +27,20 @@ import com.xinelu.manage.domain.questionsubjectoption.QuestionSubjectOption;
import com.xinelu.manage.domain.signpatientmanageroute.SignPatientManageRoute; import com.xinelu.manage.domain.signpatientmanageroute.SignPatientManageRoute;
import com.xinelu.manage.domain.signpatientmanageroutenode.SignPatientManageRouteNode; import com.xinelu.manage.domain.signpatientmanageroutenode.SignPatientManageRouteNode;
import com.xinelu.manage.domain.signpatientrecord.SignPatientRecord; import com.xinelu.manage.domain.signpatientrecord.SignPatientRecord;
import com.xinelu.manage.dto.aiob.AiobRecord;
import com.xinelu.manage.dto.aiob.CreateDutyDto; import com.xinelu.manage.dto.aiob.CreateDutyDto;
import com.xinelu.manage.dto.aiob.DutyCallbackDataDto; import com.xinelu.manage.dto.aiob.DutyCallbackDataDto;
import com.xinelu.manage.dto.aiob.DutyCallbackDto; import com.xinelu.manage.dto.aiob.DutyCallbackDto;
import com.xinelu.manage.mapper.labelfieldcontent.LabelFieldContentMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientquestionoptionresult.PatientQuestionOptionResultMapper;
import com.xinelu.manage.mapper.patientquestionsubjectresult.PatientQuestionSubjectResultMapper;
import com.xinelu.manage.mapper.patientquestionsubmitresult.PatientQuestionSubmitResultMapper;
import com.xinelu.manage.mapper.patienttaskexecuterecord.PatientTaskExecuteRecordMapper; import com.xinelu.manage.mapper.patienttaskexecuterecord.PatientTaskExecuteRecordMapper;
import com.xinelu.manage.mapper.patientvisitrecord.PatientVisitRecordMapper; import com.xinelu.manage.mapper.patientvisitrecord.PatientVisitRecordMapper;
import com.xinelu.manage.mapper.phonedialrecord.PhoneDialRecordMapper; import com.xinelu.manage.mapper.phonedialrecord.PhoneDialRecordMapper;
import com.xinelu.manage.mapper.questioninfo.QuestionInfoMapper;
import com.xinelu.manage.mapper.questionsubject.QuestionSubjectMapper;
import com.xinelu.manage.mapper.questionsubjectoption.QuestionSubjectOptionMapper;
import com.xinelu.manage.mapper.scriptinfotaskinfo.ScriptInfoTaskInfoMapper; import com.xinelu.manage.mapper.scriptinfotaskinfo.ScriptInfoTaskInfoMapper;
import com.xinelu.manage.mapper.signpatientmanageroute.SignPatientManageRouteMapper; import com.xinelu.manage.mapper.signpatientmanageroute.SignPatientManageRouteMapper;
import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper; import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper;
@ -43,23 +50,21 @@ import com.xinelu.manage.service.patienttaskstatistics.IPatientTaskStatisticsSer
import com.xinelu.manage.service.yzaiobs.IYZAIOBSService; import com.xinelu.manage.service.yzaiobs.IYZAIOBSService;
import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo; import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo;
import com.xinelu.manage.vo.questionsubject.QuestionSubjectVO; import com.xinelu.manage.vo.questionsubject.QuestionSubjectVO;
import com.xinelu.manage.vo.yzaiobs.CallRecord;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -76,6 +81,8 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
private String url; private String url;
@Value("${yzaiobs.userId}") @Value("${yzaiobs.userId}")
private String userId; private String userId;
@Value("${yzaiobs.roleId}")
private String roleId;
@Value("${yzaiobs.routeNum}") @Value("${yzaiobs.routeNum}")
private Integer routeNum; private Integer routeNum;
@Value("${yzaiobs.callPhone}") @Value("${yzaiobs.callPhone}")
@ -98,15 +105,52 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
private PatientTaskExecuteRecordMapper patientTaskExecuteRecordMapper; private PatientTaskExecuteRecordMapper patientTaskExecuteRecordMapper;
@Resource @Resource
private IPatientTaskStatisticsService patientTaskStatisticsService; private IPatientTaskStatisticsService patientTaskStatisticsService;
@Resource
private PatientInfoMapper patientInfoMapper;
@Resource
private QuestionInfoMapper questionInfoMapper;
@Resource
private PatientQuestionSubmitResultMapper questionSubmitResultMapper;
@Resource
private QuestionSubjectMapper questionSubjectMapper;
@Resource
private PatientQuestionSubjectResultMapper patientQuestionSubjectResultMapper;
@Resource
private QuestionSubjectOptionMapper questionSubjectOptionMapper;
@Resource
private PatientQuestionOptionResultMapper patientQuestionOptionResultMapper;
@Resource
private LabelFieldContentMapper labelFieldContentMapper;
@Override public JSONObject createDuty(CreateDutyDto createDutyDto) { @Override public JSONObject createDuty(CreateDutyDto createDutyDto) {
createDutyDto.setUserId(userId); createDutyDto.setUserId(userId);
createDutyDto.setRoleId(roleId);
createDutyDto.setRouteNum(routeNum); createDutyDto.setRouteNum(routeNum);
createDutyDto.setCallPhone(callPhone); createDutyDto.setCallPhone(callPhone);
HttpEntity<JSONObject> requestEntity = new HttpEntity<>((JSONObject) JSON.toJSON(createDutyDto)); //
RestTemplate restTemplate = new RestTemplate(); RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.exchange(url + "/createDuty", HttpMethod.POST, requestEntity, String.class); HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String requestBody = JSON.toJSONString(createDutyDto);
HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url + "/duty/createDuty", requestEntity, String.class);
JSONObject object = JSON.parseObject(responseEntity.getBody()); JSONObject object = JSON.parseObject(responseEntity.getBody());
/*try {
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json");
httpPost.setEntity(new StringEntity(JSON.toJSONString(createDutyDto)));
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse response = httpclient.execute(httpPost);
int status
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch (ClientProtocolException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}*/
/*{ /*{
"flag": true, "flag": true,
"message": "任务名已存在!!!", "message": "任务名已存在!!!",
@ -133,22 +177,22 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
throw new ServiceException("创建任务失败," + object.getString("message")); throw new ServiceException("创建任务失败," + object.getString("message"));
} }
JSONObject data = object.getJSONObject("value"); JSONObject data = object.getJSONObject("value");
Set<String> taskIds = data.keySet(); //Set<String> taskIds = data.keySet();
Iterator<String> iterator = taskIds.iterator(); //Iterator<String> iterator = taskIds.iterator();
String taskId = iterator.next(); //String taskId = iterator.next();
return data; return data;
} }
@Override public JSONObject taskCallBack(DutyCallbackDto callbackDto) throws ClientException { @Override public JSONObject taskCallBack(DutyCallbackDto callbackDto) throws ClientException {
// 根据第三方任务批次id查询任务列表
String accountId = callbackDto.getAccountId();
// 从data中获取任务id // 从data中获取任务id
JSONArray JSONArr = callbackDto.getData(); JSONArray JSONArr = callbackDto.getData();
if (!CollectionUtils.isEmpty(JSONArr)) { if (!CollectionUtils.isEmpty(JSONArr)) {
for (int i = 0; i < JSONArr.size(); i++) { for (int i = 0; i < JSONArr.size(); i++) {
JSONObject jsonObject = (JSONObject) JSONArr.get(i); JSONObject jsonObject = JSONArr.getJSONObject(i);
System.out.println("数据回调-----------------------");
System.out.println("数据" + i + ":"+jsonObject.toJSONString());
DutyCallbackDataDto dutyCallbackDataDto = JSON.parseObject(jsonObject.toJSONString(), DutyCallbackDataDto.class); DutyCallbackDataDto dutyCallbackDataDto = JSON.parseObject(jsonObject.toJSONString(), DutyCallbackDataDto.class);
System.out.println("数据转实体类" + i + ":" +dutyCallbackDataDto.toString());
// 是否发送短信标识 // 是否发送短信标识
boolean needSendSms = false; boolean needSendSms = false;
// 是否重拨 // 是否重拨
@ -258,7 +302,8 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
phoneDialRecord.setCreateTime(LocalDateTime.now()); phoneDialRecord.setCreateTime(LocalDateTime.now());
phoneDialRecord.setCtUuid(dutyCallbackDataDto.getCallid()); phoneDialRecord.setCtUuid(dutyCallbackDataDto.getCallid());
//phoneDialRecord.setPhoneDialRecordVideo(getPhoneDialRecord(data.getContactUUID())); // 通话录音地址
phoneDialRecord.setPhoneDialRecordVideo(iaiobService.videoPath(dutyCallbackDataDto.getMediaPath(), dutyCallbackDataDto.getCallid()));
phoneDialRecordMapper.insertPhoneDialRecord(phoneDialRecord); phoneDialRecordMapper.insertPhoneDialRecord(phoneDialRecord);
@ -272,7 +317,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
if (dutyCallbackDataDto.getIsAnswer() != null && dutyCallbackDataDto.getIsAnswer() == 1) { if (dutyCallbackDataDto.getIsAnswer() != null && dutyCallbackDataDto.getIsAnswer() == 1) {
// 问卷记录保存 // 问卷记录保存
if (StringUtils.equals(signPatientManageRouteNode.getTaskNodeType(), TaskNodeTypeEnum.QUESTIONNAIRE_SCALE.getInfo())) { if (StringUtils.equals(signPatientManageRouteNode.getTaskNodeType(), TaskNodeTypeEnum.QUESTIONNAIRE_SCALE.getInfo())) {
iaiobService.parseQuestionInfo(data.getRecord(), signPatientManageRouteNode, signPatientManageRoute.getPatientId(), patientTaskExecuteRecord.getId()); parseQuestionInfo(dutyCallbackDataDto.getCallResultType(), dutyCallbackDataDto.getInteractions(),signPatientManageRouteNode, signPatientManageRoute.getPatientId(), patientTaskExecuteRecord.getId());
} }
} }
@ -280,29 +325,38 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
} }
} }
JSONObject retObj = new JSONObject();
retObj.fluentPut("code", 200);
return retObj;
}
@Override public JSONObject phoneCallBack() {
return null; return null;
} }
private void parseQuestionInfo(String interactions, SignPatientManageRouteNode signPatientManageRouteNode, Long patientInfoId, String taskExecuteRecordId) { /**
* @description
List<AiobRecord> aiobRecords = records.toList(AiobRecord.class); * @Param callResultType: 命中的意向用,隔开
List<AiobRecord> speechList = aiobRecords.stream().filter(record -> StringUtils.equals("speech", record.getRole()) && !StringUtils.equals("抱歉,我不太理解您的意思", record.getContextText())) * @Param interactions: 通话内容文本
.collect(Collectors.toMap(AiobRecord::getContextText, p -> p, (p1, p2) -> p2)) * @return null
.values() * @Author haown
.stream() * @Date 2025-12-25 15:45
.sorted(Comparator.comparing(AiobRecord::getTimestamp)) */
.collect(Collectors.toList()); private void parseQuestionInfo(String callResultTypes, String interactions, SignPatientManageRouteNode node, Long patientInfoId, Long taskExecuteRecordId) {
speechList.forEach(s->{
if(StringUtils.isNull(s.getIntent())) s.setIntent("");
});
if(StringUtils.isBlank(interactions)) {
return;
}
List<String> callResultIntents = Arrays.asList(callResultTypes.split(","));
// 通话记录解析先用|分隔完整的问题与答案再用:分隔角色
List<CallRecord> recordList = parseRecord(interactions);
if (CollectionUtils.isEmpty(recordList)) {
return;
}
PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(patientInfoId);
// 查询患者画像信息 // 查询患者画像信息
List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfoId); List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfoId);
Map<String, String> contextMap = speechList.stream().collect(Collectors.toMap(AiobRecord::getContextText, AiobRecord::getIntent));
PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(patientInfoId);
QuestionInfo questionInfo = questionInfoMapper.selectQuestionInfoById(node.getQuestionInfoId()); QuestionInfo questionInfo = questionInfoMapper.selectQuestionInfoById(node.getQuestionInfoId());
// 1保存patient_question_submit_result // 1保存patient_question_submit_result
PatientQuestionSubmitResult patientQuestionSubmitResult = new PatientQuestionSubmitResult(); PatientQuestionSubmitResult patientQuestionSubmitResult = new PatientQuestionSubmitResult();
@ -332,21 +386,21 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
List<QuestionSubjectVO> questionSubjectList = questionSubjectMapper.selectQuestionSubjectBy(node.getQuestionInfoId()); List<QuestionSubjectVO> questionSubjectList = questionSubjectMapper.selectQuestionSubjectBy(node.getQuestionInfoId());
questionSubjectList.forEach(questionSubjectVO -> { questionSubjectList.forEach(questionSubjectVO -> {
// 判断问题中有无变量有变量替换变量 // 判断问题中有无变量有变量替换变量
String questionNameAlias = replaceQuestionName(questionSubjectVO.getQuestionNameAlias(), labelFieldContentList); String questionNameAlias = iaiobService.replaceQuestionName(questionSubjectVO.getQuestionNameAlias(), labelFieldContentList);
// 根据通话记录筛查是否询问该问题 // 根据通话记录筛查是否询问该问题
boolean hasQuestion = false; boolean hasQuestion = false;
String aiobQuestionName = ""; String aiobQuestionName = "";
for (String questionContent : contextMap.keySet()) { for (int i = 0; i < recordList.size(); i++) {
if (questionContent.replaceAll("\\p{P}", "").contains(questionNameAlias.replaceAll("\\p{P}", ""))) { if (recordList.get(i).getContent().contains(questionNameAlias.replaceAll("\\p{P}", ""))) {
hasQuestion = true; hasQuestion = true;
aiobQuestionName = questionContent; aiobQuestionName = recordList.get(i).getContent();
break; break;
} }
} }
if (hasQuestion) { if (hasQuestion) {
String finalAiobQuestionName = aiobQuestionName; String finalAiobQuestionName = aiobQuestionName;
AiobRecord nextRecord = getNextQuestion(speechList, finalAiobQuestionName);
PatientQuestionSubjectResult patientQuestionSubjectResult = new PatientQuestionSubjectResult(); PatientQuestionSubjectResult patientQuestionSubjectResult = new PatientQuestionSubjectResult();
BeanUtils.copyProperties(questionSubjectVO, patientQuestionSubjectResult); BeanUtils.copyProperties(questionSubjectVO, patientQuestionSubjectResult);
@ -354,7 +408,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
patientQuestionSubjectResult.setQuestionSubmitResultId(patientQuestionSubmitResult.getId()); patientQuestionSubjectResult.setQuestionSubmitResultId(patientQuestionSubmitResult.getId());
patientQuestionSubjectResult.setCreateTime(LocalDateTime.now()); patientQuestionSubjectResult.setCreateTime(LocalDateTime.now());
//不管是否是 填空题 写入回答 文本 //不管是否是 填空题 写入回答 文本
patientQuestionSubjectResult.setFillBlanksAnswer(nextRecord.getContent()); patientQuestionSubjectResult.setFillBlanksAnswer(getReply(recordList, finalAiobQuestionName));
patientQuestionSubjectResult.setQuestionSubjectId(questionSubjectVO.getId()); patientQuestionSubjectResult.setQuestionSubjectId(questionSubjectVO.getId());
patientQuestionSubjectResultMapper.insertPatientQuestionSubjectResult(patientQuestionSubjectResult); patientQuestionSubjectResultMapper.insertPatientQuestionSubjectResult(patientQuestionSubjectResult);
@ -368,42 +422,49 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
questionSubjectOptions.forEach(questionSubjectOption -> { questionSubjectOptions.forEach(questionSubjectOption -> {
PatientQuestionOptionResult patientQuestionOptionResult = new PatientQuestionOptionResult(); PatientQuestionOptionResult patientQuestionOptionResult = new PatientQuestionOptionResult();
BeanUtils.copyProperties(questionSubjectOption, patientQuestionOptionResult); BeanUtils.copyProperties(questionSubjectOption, patientQuestionOptionResult);
// 设置是否选中, 通过通话记录中下一个问题的intent字段查询QuestionSubjectOption
List<String> intents = Arrays.asList(questionSubjectOption.getIntent().split("\\|"));
if (ObjectUtils.isNotEmpty(nextRecord) && intents.contains(nextRecord.getIntent())) {
patientQuestionOptionResult.setOptionChooseSign(0); patientQuestionOptionResult.setOptionChooseSign(0);
} else { // 设置是否选中, 根据回调数据中命中的意向查询
List<String> intents = Arrays.asList(questionSubjectOption.getIntent().split("\\|"));
for (String intent : intents) {
if (callResultIntents.contains(intent)) {
patientQuestionOptionResult.setOptionChooseSign(1); patientQuestionOptionResult.setOptionChooseSign(1);
} }
}
patientQuestionOptionResult.setId(null); patientQuestionOptionResult.setId(null);
patientQuestionOptionResult.setCreateTime(LocalDateTime.now()); patientQuestionOptionResult.setCreateTime(LocalDateTime.now());
patientQuestionOptionResult.setQuestionSubjectResultId(patientQuestionSubjectResult.getId()); patientQuestionOptionResult.setQuestionSubjectResultId(patientQuestionSubjectResult.getId());
patientQuestionOptionResult.setQuestionSubjectOptionId(questionSubjectOption.getId()); patientQuestionOptionResult.setQuestionSubjectOptionId(questionSubjectOption.getId());
patientQuestionOptionResults.add(patientQuestionOptionResult); patientQuestionOptionResults.add(patientQuestionOptionResult);
}); });
//判断问卷 满意项与异常项
patientQuestionSubmitResult.setRemarkableFlag(ContentedAndRemarkableFlagEnum.ROUTINE.getInfo()); if (!CollectionUtils.isEmpty(patientQuestionOptionResults)) {
patientQuestionSubmitResult.setContentedFlag(ContentedAndRemarkableFlagEnum.CONTENTED.getInfo());
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(patientQuestionOptionResults)) {
List<PatientQuestionOptionResult> remarkableFlag = patientQuestionOptionResults.stream().filter(Objects::nonNull) List<PatientQuestionOptionResult> remarkableFlag = patientQuestionOptionResults.stream().filter(Objects::nonNull)
.filter(item -> org.apache.commons.lang3.StringUtils.isNotBlank(item.getRemarkableFlag()) .filter(item -> StringUtils.isNotBlank(item.getRemarkableFlag())
&& Objects.nonNull(item.getOptionChooseSign()) && item.getOptionChooseSign().equals(0) && Objects.nonNull(item.getOptionChooseSign()) && item.getOptionChooseSign().equals(0)
&& ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo().equals(item.getRemarkableFlag())) && ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo().equals(item.getRemarkableFlag()))
.collect(Collectors.toList()); .collect(Collectors.toList());
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(remarkableFlag)) { if (!CollectionUtils.isEmpty(remarkableFlag)) {
patientQuestionSubmitResult.setRemarkableFlag(ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo()); patientQuestionSubmitResult.setRemarkableFlag(ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo());
} }
List<PatientQuestionOptionResult> contentedFlag = patientQuestionOptionResults.stream().filter(Objects::nonNull).filter(item -> org.apache.commons.lang3.StringUtils.isNotBlank(item.getContentedFlag()) && Objects.nonNull(item.getOptionChooseSign()) && item.getOptionChooseSign().equals(0) && ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo().equals(item.getRemarkableFlag())).collect(Collectors.toList()); List<PatientQuestionOptionResult> contentedFlag = patientQuestionOptionResults.stream()
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(contentedFlag)) { .filter(Objects::nonNull)
.filter(item -> org.apache.commons.lang3.StringUtils.isNotBlank(item.getContentedFlag())
&& Objects.nonNull(item.getOptionChooseSign())
&& item.getOptionChooseSign().equals(0)
&& ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo().equals(item.getRemarkableFlag()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(contentedFlag)) {
patientQuestionSubmitResult.setContentedFlag(ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo()); patientQuestionSubmitResult.setContentedFlag(ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo());
} }
}
questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult);
if(patientQuestionOptionResults.size()>0) {
patientQuestionOptionResultMapper.saveQuestionOptionList(patientQuestionOptionResults);
} }
questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult);
patientQuestionOptionResultMapper.saveQuestionOptionList(patientQuestionOptionResults);
totalScore[0] = totalScore[0].add(questionSubjectVO.getQuestionScore() == null ? BigDecimal.ZERO : questionSubjectVO.getQuestionScore()); totalScore[0] = totalScore[0].add(questionSubjectVO.getQuestionScore() == null ? BigDecimal.ZERO : questionSubjectVO.getQuestionScore());
} else { } else {
// 没问到问卷中的问题则保存空问题+空选项 // 没问到问卷中的问题则保存空问题+空选项
@ -437,8 +498,43 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService {
}); });
// 4更新总得分 // 4更新总得分
patientQuestionSubmitResult.setTotalScore(totalScore[0]); //patientQuestionSubmitResult.setTotalScore(totalScore[0]);
questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult); //questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult);
}
private List<CallRecord> parseRecord(String interactions) {
// 先用|分隔完整的问题与答案再用:分隔角色
List<CallRecord> retList = new ArrayList<>();
List<String> records = Arrays.asList(interactions.split("\\|"));
if (CollectionUtils.isEmpty(records)) {
return null;
}
for (String record : records) {
CallRecord callRecord = new CallRecord();
String[] str1 = record.split(":");
callRecord.setRole(str1[0]);
callRecord.setContent(str1[1]);
retList.add(callRecord);
}
return retList;
}
/**
* @description 根据通话记录获取回复
* @Param callRecordList 通话记录列表
* @Param question: 问题名称
* @return 回复内容
* @Author haown
* @Date 2025-12-26 9:40
*/
private String getReply(List<CallRecord> callRecordList, String question) {
for (int i = 0; i < callRecordList.size(); i++) {
if (StringUtils.equals(callRecordList.get(i).getContent(), question)) {
if (StringUtils.equals("用户",callRecordList.get(i+1).getRole())) {
return callRecordList.get(i+1).getContent();
}
}
}
return null;
} }
} }

View File

@ -0,0 +1,22 @@
package com.xinelu.manage.vo.yzaiobs;
import lombok.Data;
/**
* @description: 曜智通话聊天记录视图类
* @author: haown
* @create: 2025-12-25 17:07
**/
@Data
public class CallRecord {
/**
* 角色
*/
private String role;
/**
* 说话内容
*/
private String content;
}

View File

@ -859,7 +859,7 @@
</update> </update>
<update id="updateDialStatusByNodeId" parameterType="SignPatientManageRouteNode"> <update id="updateDialStatusByNodeId" parameterType="SignPatientManageRouteNode">
update sign_patient_manage_route_node set dial_status = #{dialStatus} update sign_patient_manage_route_node set dial_status = #{dialStatus}, task_id_ext = #{taskIdExt}
where id = #{id} where id = #{id}
</update> </update>
<select id="selectPatientTaskList" parameterType="com.xinelu.manage.dto.signpatientmanageroutenode.PatientTaskDto" resultType="com.xinelu.manage.vo.signpatientmanageroutenode.PatientTaskVo"> <select id="selectPatientTaskList" parameterType="com.xinelu.manage.dto.signpatientmanageroutenode.PatientTaskDto" resultType="com.xinelu.manage.vo.signpatientmanageroutenode.PatientTaskVo">

View File

@ -0,0 +1,345 @@
package com.xinelu.quartz.task;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.common.constant.AiobTaskTypeContant;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.entity.SysDictData;
import com.xinelu.common.enums.DialStatusEnum;
import com.xinelu.common.enums.NodeExecuteStatusEnum;
import com.xinelu.common.enums.PhoneDialMethodEnum;
import com.xinelu.common.enums.PhoneRedialTimesEnum;
import com.xinelu.common.enums.TaskExcuteTypeEnum;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.common.utils.regex.RegexUtil;
import com.xinelu.common.utils.uuid.UUID;
import com.xinelu.manage.domain.dialtime.DialTime;
import com.xinelu.manage.domain.patientinfo.PatientInfo;
import com.xinelu.manage.domain.patientvisitrecord.PatientVisitRecord;
import com.xinelu.manage.domain.scriptInfo.ScriptInfo;
import com.xinelu.manage.domain.scriptinfotaskinfo.ScriptInfoTaskInfo;
import com.xinelu.manage.domain.signpatientmanageroute.SignPatientManageRoute;
import com.xinelu.manage.domain.signpatientmanageroutenode.SignPatientManageRouteNode;
import com.xinelu.manage.domain.signpatientrecord.SignPatientRecord;
import com.xinelu.manage.dto.aiob.CreateDutyDto;
import com.xinelu.manage.dto.signpatientmanageroutenode.SignPatientManageRouteNodeDto;
import com.xinelu.manage.mapper.labelfieldcontent.LabelFieldContentMapper;
import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
import com.xinelu.manage.mapper.patientinfoimportmain.PatientInfoImportMainMapper;
import com.xinelu.manage.mapper.patientvisitrecord.PatientVisitRecordMapper;
import com.xinelu.manage.mapper.scriptInfo.ScriptInfoMapper;
import com.xinelu.manage.mapper.scriptinfotaskinfo.ScriptInfoTaskInfoMapper;
import com.xinelu.manage.mapper.signpatientmanageroute.SignPatientManageRouteMapper;
import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper;
import com.xinelu.manage.mapper.signpatientrecord.SignPatientRecordMapper;
import com.xinelu.manage.service.signpatientmanageroutenode.ISignPatientManageRouteNodeService;
import com.xinelu.manage.service.yzaiobs.IYZAIOBSService;
import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo;
import com.xinelu.system.service.ISysDictTypeService;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Component;
/**
* @description: 曜智智能外呼任务
* @author: haown
* @create: 2025-12-26 09:57
**/
@Slf4j
@Component("YZAIOBSTask")
public class YZAIOBSTask {
@Resource private SignPatientManageRouteNodeMapper signPatientManageRouteNodeMapper;
@Resource private ISignPatientManageRouteNodeService signPatientManageRouteNodeService;
@Resource private SignPatientManageRouteMapper signPatientManageRouteMapper;
@Resource private SignPatientRecordMapper signPatientRecordMapper;
@Resource private PatientVisitRecordMapper patientVisitRecordMapper;
@Resource private ScriptInfoTaskInfoMapper scriptInfoTaskInfoMapper;
@Resource private IYZAIOBSService iyzaiobsService;
@Resource private ScriptInfoMapper scriptInfoMapper;
@Resource private PatientInfoMapper patientInfoMapper;
@Resource private LabelFieldContentMapper labelFieldContentMapper;
@Resource private RegexUtil regexUtil;
@Resource private ISysDictTypeService iSysDictTypeService;
@Resource private PatientInfoImportMainMapper patientInfoImportMainMapper;
public void uploadRobotPublishTask() {
log.info("开始执行曜智智能外呼创建任务定时任务......");
// 查找需要当天执行的AI打电话任务问卷或电话外呼类型
SignPatientManageRouteNodeDto signPatientManageRouteNodeDto = new SignPatientManageRouteNodeDto();
//signPatientManageRouteNodeDto.setTaskNodeType(TaskNodeTypeEnum.PHONE_OUTBOUND.getInfo());
signPatientManageRouteNodeDto.setNodeExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
signPatientManageRouteNodeDto.setPhoneDialMethod(PhoneDialMethodEnum.AI.getInfo());
//只获取 任务执行类型为 批量执行的
signPatientManageRouteNodeDto.setTaskExcuteType(TaskExcuteTypeEnum.BATCH_TASK.getInfo());
//查询未拨打的
signPatientManageRouteNodeDto.setDialStatus(DialStatusEnum.NODIALED.getInfo());
List<SignPatientManageRouteNode> nodeList = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeList(signPatientManageRouteNodeDto);
List<SignPatientManageRouteNode> executeNodeList = new ArrayList<>();
nodeList.forEach(node -> {
LocalDateTime executeTime;
if (Objects.nonNull(node.getNodePlanTime()) && org.apache.commons.lang3.StringUtils.isNotBlank(node.getNodePlanTime().toString())) {
executeTime = node.getNodePlanTime();
} else {
SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
SignPatientRecord signPatientRecord = signPatientRecordMapper.selectByPrimaryKey(signPatientManageRoute.getSignPatientRecordId());
PatientVisitRecord patientVisitRecord = patientVisitRecordMapper.selectPatientVisitRecordById(signPatientRecord.getPatientVisitRecordId());
executeTime = signPatientManageRouteNodeService.getExecuteTime(node.getExecuteTime(), node.getRouteNodeName(), node.getRouteNodeDay(), patientVisitRecord);
}
//只处理 流水号不为空的
if (node.getSn() != null &&
//精确到秒
node.getScriptInfoId() != null && (executeTime.isBefore(LocalDateTime.now()) || executeTime.isEqual(LocalDateTime.now()))) {
//精确到天
// node.getScriptInfoId() != null && (executeTime.toLocalDate().isBefore(LocalDate.now()) || executeTime.toLocalDate().isEqual(LocalDate.now()))) {
executeNodeList.add(node);
}
});
if (executeNodeList.isEmpty()) return;
//1最外层按照导入流水号分组
Map<String, List<SignPatientManageRouteNode>> routeNodeGroupListBySn = executeNodeList.stream().collect(Collectors.groupingBy(SignPatientManageRouteNode::getSn));
// 开始遍历
routeNodeGroupListBySn.keySet().forEach(sn -> {
//2次外层按照话术ID分组
Map<Long, List<SignPatientManageRouteNode>> routeNodeGroupListByScriptInfoId =
routeNodeGroupListBySn.get(sn).stream().collect(Collectors.groupingBy(SignPatientManageRouteNode::getScriptInfoId));
//开始遍历生成任务
routeNodeGroupListByScriptInfoId.keySet().forEach(scriptInfoId -> {
// 同一分组下的任务节点配置属性 应该是 是相同的所以取第0项节点 来使用
SignPatientManageRouteNode nodeFirstTemp = routeNodeGroupListByScriptInfoId.get(scriptInfoId).get(0);
//话术
ScriptInfo scriptInfo = scriptInfoMapper.selectScriptInfoById(scriptInfoId);
if (ObjectUtils.isNotEmpty(scriptInfo)) {
// 查询机构拨打时间设置
Long hospitalId = patientInfoImportMainMapper.selectHospitalAgencyId(sn);
DialTime dialTime = patientInfoImportMainMapper.selectDialTimeById(hospitalId);
LocalTime localStartTime = LocalTime.parse(dialTime.getDialStartTime());
LocalTime localEndTime = LocalTime.parse(dialTime.getDialEndTime());
LocalTime dateStartTime;
LocalTime dateEndTime;
List<SysDictData> sysDictDataList = iSysDictTypeService.selectDictDataByType(Constants.DIAL_TIME);
if (CollectionUtils.isEmpty(sysDictDataList) || sysDictDataList.size() != 2) {
dateStartTime = LocalTime.parse("08:00");
dateEndTime = LocalTime.parse("19:00");
} else {
dateStartTime = LocalTime.parse(sysDictDataList.get(0).getDictValue());
dateEndTime = LocalTime.parse(sysDictDataList.get(1).getDictValue());
}
if (dateStartTime.isAfter(localStartTime)) {
localStartTime = dateStartTime;
}
if (dateEndTime.isBefore(localEndTime)) {
localEndTime = dateEndTime;
}
log.info("创建任务......");
CreateDutyDto createDutyDto = new CreateDutyDto();
//临时重复测试用
String taskName = "T_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + scriptInfo.getScriptName() + "(" + sn + ")";
log.info("任务名称:" + taskName);
createDutyDto.setAccountId(taskName);
createDutyDto.setDutyName(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + scriptInfo.getScriptName() + "(" + nodeFirstTemp.getManageRouteId() + ")");
createDutyDto.setDutyType(scriptInfo.getRobotPublishId());
createDutyDto.setDutySceneId(Integer.parseInt(scriptInfo.getRobotPublishId()));
createDutyDto.setOutboundPeriods("[" + localStartTime.format(DateTimeFormatter.ofPattern("HH:mm")) + "~" + localEndTime.format(DateTimeFormatter.ofPattern("HH:mm")) + "]");
createDutyDto.setStartDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
createDutyDto.setNoticeSwitch(1);
createDutyDto.setDeduplicationSwitch(true);
//3开始组装本任务下的客户变量
//遍历最内层任务节点
JSONArray dataArr = new JSONArray();
routeNodeGroupListByScriptInfoId.get(scriptInfoId).forEach(node -> {
SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(signPatientManageRoute.getPatientId());
//校验手机号
if (StringUtils.isNotBlank(patientInfo.getPatientPhone())) {
if (regexUtil.regexPhone(patientInfo.getPatientPhone())) {
// 查询患者画像信息
List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId());
// 处理变量
JSONObject jsonObject = new JSONObject();
//TODO 需要验证是任务id还是患者id
jsonObject.fluentPut("手机号", patientInfo.getPatientPhone()).fluentPut("custId", node.getId());
if (StringUtils.isNotBlank(scriptInfo.getVariables())) {
List<String> variables = Arrays.asList(scriptInfo.getVariables().split("\\|"));
variables.forEach(variable -> {
LabelFieldInfoContentVo labelFieldContent =
labelFieldContentList.stream().filter(s -> Objects.equals(s.getFieldCode(), variable.replaceAll("_", "").toUpperCase())).findFirst().orElse(null);
jsonObject.fluentPut(variable, ObjectUtils.isEmpty(labelFieldContent) ? "" : labelFieldContent.getFieldValue());
});
}
dataArr.add(jsonObject);
}
}
});
createDutyDto.setDataArr(dataArr);
JSONObject taskObj = iyzaiobsService.createDuty(createDutyDto);
String taskId = taskObj.keySet().iterator().next();
routeNodeGroupListByScriptInfoId.get(scriptInfoId).forEach(nodeForTask -> {
ScriptInfoTaskInfo scriptInfoTaskInfo = new ScriptInfoTaskInfo();
scriptInfoTaskInfo.setScriptInfoId(scriptInfoId);
scriptInfoTaskInfo.setTaskId(taskId);
scriptInfoTaskInfo.setRobotId(scriptInfo.getRobotPublishId());
scriptInfoTaskInfo.setCreateTime(LocalDateTime.now());
scriptInfoTaskInfo.setSn(sn);
scriptInfoTaskInfo.setSignPatientManageRouteNodeId(nodeForTask.getId());
scriptInfoTaskInfo.setSignPatientManageRouteId(nodeForTask.getManageRouteId());
scriptInfoTaskInfo.setAiobTaskType(AiobTaskTypeContant.BATCHTASK);
//进入拔打记录表用于后续重拨处理等判断)----有时间再优化为批量插入
scriptInfoTaskInfoMapper.insertScriptInfoTaskInfo(scriptInfoTaskInfo);
//设置拨打状态
SignPatientManageRouteNode signPatientManageRouteNode_DialStatus = new SignPatientManageRouteNode();
// signPatientManageRouteNode_DialStatus.setManageRouteId(routeId);
signPatientManageRouteNode_DialStatus.setId(nodeForTask.getId());
signPatientManageRouteNode_DialStatus.setDialStatus(DialStatusEnum.DIALED.getInfo());
signPatientManageRouteNode_DialStatus.setTaskIdExt(taskId);
signPatientManageRouteNodeMapper.updateDialStatusByNodeId(signPatientManageRouteNode_DialStatus);
});
}
});
});
log.info("曜智智能外呼创建任务定时任务执行完成......");
}
/**
* @return null
* @description 创建实时任务
* @Author haown
* @Date 2024-9-23 10:41
*/
public void actualTimeTask() {
log.info("开始执行曜智智能外呼创建实时任务定时任务......");
// 查找需要当天执行的AI打电话任务问卷或电话外呼类型
SignPatientManageRouteNodeDto signPatientManageRouteNodeDto = new SignPatientManageRouteNodeDto();
signPatientManageRouteNodeDto.setNodeExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
signPatientManageRouteNodeDto.setPhoneDialMethod(PhoneDialMethodEnum.AI.getInfo());
//只获取 任务执行类型为 单个执行的
signPatientManageRouteNodeDto.setTaskExcuteType(TaskExcuteTypeEnum.ACTUAL_TIME_TASK.getInfo());
//查询未拨打的
signPatientManageRouteNodeDto.setDialStatus(DialStatusEnum.NODIALED.getInfo());
List<SignPatientManageRouteNode> nodeList = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeList(signPatientManageRouteNodeDto);
List<SignPatientManageRouteNode> executeNodeList = new ArrayList<>();
nodeList.forEach(node -> {
LocalDateTime executeTime;
//如果有计划执行时间则直接获取
if (node.getNodePlanTime() != null) {
executeTime = node.getNodePlanTime();
}
// 否则 则根据诊后/院后 第几天 计算
else {
SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
SignPatientRecord signPatientRecord = signPatientRecordMapper.selectByPrimaryKey(signPatientManageRoute.getSignPatientRecordId());
PatientVisitRecord patientVisitRecord = patientVisitRecordMapper.selectPatientVisitRecordById(signPatientRecord.getPatientVisitRecordId());
executeTime = signPatientManageRouteNodeService.getExecuteTime(node.getExecuteTime(), node.getRouteNodeName(), node.getRouteNodeDay(), patientVisitRecord);
}
//精确到天
// if (node.getScriptInfoId() != null && (executeTime.toLocalDate().isBefore(LocalDate.now()) || executeTime.toLocalDate().isEqual(LocalDate.now()))) {
//精确到秒
if (node.getScriptInfoId() != null && (executeTime.isBefore(LocalDateTime.now()) || executeTime.isEqual(LocalDateTime.now()))) {
executeNodeList.add(node);
}
});
// 查询需要重拨的任务
ScriptInfoTaskInfo scriptInfoTaskInfo = new ScriptInfoTaskInfo();
scriptInfoTaskInfo.setExecuteStatus(NodeExecuteStatusEnum.UNEXECUTED.getInfo());
scriptInfoTaskInfo.setAiobTaskType(AiobTaskTypeContant.ACTUALTIMETASK);
List<ScriptInfoTaskInfo> scriptInfoTaskInfoList = scriptInfoTaskInfoMapper.selectList(scriptInfoTaskInfo);
scriptInfoTaskInfoList.forEach(taskInfo -> {
SignPatientManageRouteNode node = signPatientManageRouteNodeMapper.selectSignPatientManageRouteNodeById(taskInfo.getSignPatientManageRouteNodeId());
if (taskInfo.getExecuteTime().isBefore(LocalDateTime.now()) || taskInfo.getExecuteTime().isEqual(LocalDateTime.now())) {
executeNodeList.add(node);
}
});
if (CollectionUtils.isNotEmpty(executeNodeList)) {
// 根据机器人id查询智能外呼系统的任务id
executeNodeList.forEach(node -> {
log.info("创建任务......");
//话术
ScriptInfo scriptInfo = scriptInfoMapper.selectScriptInfoById(node.getScriptInfoId());
if (scriptInfo == null) {
return;
}
CreateDutyDto createDutyDto = new CreateDutyDto();
//临时重复测试用
String dutyName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +"NODE" + node.getId();
log.info("任务名称:" + dutyName);
String accountId = UUID.randomUUID().toString().replace("-", "").substring(0, 11);
createDutyDto.setAccountId(accountId);
createDutyDto.setDutyName(dutyName);
createDutyDto.setDutyType(scriptInfo.getRobotPublishId());
createDutyDto.setDutySceneId(Integer.parseInt(scriptInfo.getRobotPublishId()));
createDutyDto.setOutboundPeriods("[\"09:00~11:35\",\"15:55~23:30\"]");
createDutyDto.setStartDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
if (StringUtils.isNotBlank(node.getPhoneRedialTimes())) {
createDutyDto.setDuplication(PhoneRedialTimesEnum.getValueByInfo(node.getPhoneRedialTimes()).getValue());
} else {
createDutyDto.setDuplication(0);
}
createDutyDto.setPeriod(node.getPhoneTimeInterval());
createDutyDto.setNoticeSwitch(1);
createDutyDto.setDeduplicationSwitch(true);
JSONObject repStrategy = new JSONObject();
repStrategy.fluentPut("hangState", "").fluentPut("state", "1,2,4,5,6,7,8").fluentPut("intention", "");
createDutyDto.setRepStrategy(repStrategy);
//遍历最内层任务节点
JSONArray dataArr = new JSONArray();
SignPatientManageRoute signPatientManageRoute = signPatientManageRouteMapper.selectSignPatientManageRouteById(node.getManageRouteId());
PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(signPatientManageRoute.getPatientId());
//校验手机号
if (StringUtils.isNotBlank(patientInfo.getPatientPhone())) {
if (regexUtil.regexPhone(patientInfo.getPatientPhone())) {
// 查询患者画像信息
List<LabelFieldInfoContentVo> labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId());
// 处理变量
JSONObject jsonObject = new JSONObject();
//TODO 需要验证是任务id还是患者id
jsonObject.fluentPut("custId", node.getId()).fluentPut("手机号", patientInfo.getPatientPhone());
if (StringUtils.isNotBlank(scriptInfo.getVariables())) {
List<String> variables = Arrays.asList(scriptInfo.getVariables().split("\\|"));
variables.forEach(variable -> {
LabelFieldInfoContentVo labelFieldContent =
labelFieldContentList.stream().filter(s -> Objects.equals(s.getFieldCode(), variable.replaceAll("_", "").toUpperCase())).findFirst().orElse(null);
jsonObject.fluentPut(variable, ObjectUtils.isEmpty(labelFieldContent) ? "" : labelFieldContent.getFieldValue());
});
}
dataArr.add(jsonObject);
}
}
createDutyDto.setDataArr(dataArr);
JSONObject taskObj = iyzaiobsService.createDuty(createDutyDto);
//设置拨打状态
SignPatientManageRouteNode signPatientManageRouteNode_DialStatus = new SignPatientManageRouteNode();
signPatientManageRouteNode_DialStatus.setId(node.getId());
signPatientManageRouteNode_DialStatus.setDialStatus(DialStatusEnum.DIALED.getInfo());
signPatientManageRouteNodeMapper.updateDialStatusByNodeId(signPatientManageRouteNode_DialStatus);
});
}
log.info("曜智智能外呼创建实时任务定时任务执行完成......");
}
}