From 0153f17aa4a984840a586b8199d4b9524fcdebed Mon Sep 17 00:00:00 2001 From: haown <454902499@qq.com> Date: Thu, 15 Jan 2026 14:46:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9B=9C=E6=99=BA=E5=A4=96?= =?UTF-8?q?=E5=91=BC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 9 +- .../common/config/SystemBusinessConfig.java | 10 + ...SignPatientManageRouteNodeServiceImpl.java | 108 ++++++-- .../service/yzaiobs/IYZAIOBSService.java | 11 +- .../yzaiobs/impl/YZAIOBSServiceImpl.java | 243 +++++++++++++----- .../xinelu/manage/vo/yzaiobs/CallRecord.java | 2 +- .../com/xinelu/quartz/task/YZAIOBSTask.java | 84 +++--- 7 files changed, 337 insertions(+), 130 deletions(-) diff --git a/postdischarge-admin/src/main/resources/application.yml b/postdischarge-admin/src/main/resources/application.yml index 881442f9..30e02dac 100644 --- a/postdischarge-admin/src/main/resources/application.yml +++ b/postdischarge-admin/src/main/resources/application.yml @@ -31,8 +31,10 @@ xinelu: rich-text-picture-url: /richTextPictureUrl # 资讯富文本的上传路径 info-rich-text-picture-url: /infoRichTextPictureUrl - # 资讯富文本的上传路径 + # 百度外呼通话录音地址 phone-dial-record-video: /phoneDialRecordVideo + # 曜智外呼通话录音地址 + yz-phone-dial-record-video: /yzPhoneDialRecordVideo # 开发环境配置 server: @@ -305,6 +307,11 @@ yzaiobs: roleId: 1001 routeNum: 1 callPhone: 1234 + +# 外呼选项 +outboundCall: + type: yzaiobs + xinyilu-database: # 公共机构ID(新医路,用于宣教库公共库查询) id: 46 diff --git a/postdischarge-common/src/main/java/com/xinelu/common/config/SystemBusinessConfig.java b/postdischarge-common/src/main/java/com/xinelu/common/config/SystemBusinessConfig.java index 9f711fef..a28508eb 100644 --- a/postdischarge-common/src/main/java/com/xinelu/common/config/SystemBusinessConfig.java +++ b/postdischarge-common/src/main/java/com/xinelu/common/config/SystemBusinessConfig.java @@ -91,6 +91,8 @@ public class SystemBusinessConfig { */ private String phoneDialRecordVideo; + private String yzPhoneDialRecordVideo; + public String getName() { return name; } @@ -245,4 +247,12 @@ public class SystemBusinessConfig { public void setPhoneDialRecordVideo(String phoneDialRecordVideo) { this.phoneDialRecordVideo = phoneDialRecordVideo; } + + public String getYzPhoneDialRecordVideo() { + return yzPhoneDialRecordVideo; + } + + public void setYzPhoneDialRecordVideo(String yzPhoneDialRecordVideo) { + this.yzPhoneDialRecordVideo = yzPhoneDialRecordVideo; + } } diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/service/signpatientmanageroutenode/impl/SignPatientManageRouteNodeServiceImpl.java b/postdischarge-manage/src/main/java/com/xinelu/manage/service/signpatientmanageroutenode/impl/SignPatientManageRouteNodeServiceImpl.java index 2cf26633..7837e001 100644 --- a/postdischarge-manage/src/main/java/com/xinelu/manage/service/signpatientmanageroutenode/impl/SignPatientManageRouteNodeServiceImpl.java +++ b/postdischarge-manage/src/main/java/com/xinelu/manage/service/signpatientmanageroutenode/impl/SignPatientManageRouteNodeServiceImpl.java @@ -1,5 +1,6 @@ package com.xinelu.manage.service.signpatientmanageroutenode.impl; +import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.xinelu.common.annotation.DataScope; @@ -13,7 +14,13 @@ import com.xinelu.common.constant.TemplateTypeConstants; import com.xinelu.common.constant.TriggerConditionOperatorConstants; import com.xinelu.common.constant.TriggerLogicConstants; import com.xinelu.common.constant.VisitMethodConstants; -import com.xinelu.common.enums.*; +import com.xinelu.common.enums.MessageStatusEnum; +import com.xinelu.common.enums.NodeExecuteResultStatusEnum; +import com.xinelu.common.enums.NodeExecuteStatusEnum; +import com.xinelu.common.enums.PhoneDialMethodEnum; +import com.xinelu.common.enums.QuestionTypeEnum; +import com.xinelu.common.enums.RouteCheckStatusEnum; +import com.xinelu.common.enums.RouteNodeNameEnum; import com.xinelu.common.exception.ServiceException; import com.xinelu.common.utils.SecurityUtils; import com.xinelu.common.utils.StringUtils; @@ -38,7 +45,11 @@ import com.xinelu.manage.domain.specialdiseasetriggercondition.SpecialDiseaseTri import com.xinelu.manage.domain.textmessage.TextMessage; import com.xinelu.manage.domain.wechattemplate.WechatTemplate; import com.xinelu.manage.dto.patientinfo.PatientInfoDto; -import com.xinelu.manage.dto.signpatientmanageroutenode.*; +import com.xinelu.manage.dto.signpatientmanageroutenode.AppletPatientTaskDto; +import com.xinelu.manage.dto.signpatientmanageroutenode.PatientTaskDto; +import com.xinelu.manage.dto.signpatientmanageroutenode.RouteNodeCheckDto; +import com.xinelu.manage.dto.signpatientmanageroutenode.SignPatientManageRouteNodeDto; +import com.xinelu.manage.dto.signpatientmanageroutenode.UploadRobotPublishRecordDto; import com.xinelu.manage.mapper.labelfieldcontent.LabelFieldContentMapper; import com.xinelu.manage.mapper.patientinfo.PatientAllInfoViewMapper; import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper; @@ -62,13 +73,23 @@ import com.xinelu.manage.service.propagandainfo.IPropagandaInfoService; import com.xinelu.manage.service.questioninfo.IQuestionInfoService; import com.xinelu.manage.service.signpatientmanageroutenode.ISignPatientManageRouteNodeService; import com.xinelu.manage.service.specialdiseaseroute.ISpecialDiseaseRouteService; +import com.xinelu.manage.service.yzaiobs.IYZAIOBSService; import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo; import com.xinelu.manage.vo.patientinfo.PatientInfoVo; import com.xinelu.manage.vo.patientinfo.PatientNextTaskVo; import com.xinelu.manage.vo.patientquestionsubmitresult.PatientQuestionSubmitResultVO; import com.xinelu.manage.vo.propagandainfo.PropagandaMaterialsVo; import com.xinelu.manage.vo.questionInfo.QuestionVO; -import com.xinelu.manage.vo.signpatientmanageroutenode.*; +import com.xinelu.manage.vo.signpatientmanageroutenode.AIDialRecordVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.AppletRouteNodeListVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.PatientManageNodeInfoVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.PatientManageNodeListVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.PatientTaskVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.SignPatientManageNodeAuditVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.SignPatientManageRouteNodeInfoVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.SignPatientManageRouteNodeVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.SignPatientTaskVo; +import com.xinelu.manage.vo.signpatientmanageroutenode.UploadRobotPublishRecordVo; import com.xinelu.manage.vo.specialdiseasenode.PatientSpecialDiseaseNodeVo; import com.xinelu.manage.vo.specialdiseasenode.SpecialDiseaseNodeVO; import com.xinelu.manage.vo.specialdiseaseroute.SpecialDiseaseRouteVO; @@ -93,6 +114,7 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -148,8 +170,12 @@ public class SignPatientManageRouteNodeServiceImpl implements ISignPatientManage private PhoneDialRecordMapper phoneDialRecordMapper; @Resource private IAIOBService aiobService; + @Resource + private IYZAIOBSService iyzaiobsService; + @Value("${outboundCall.type}") + private String callType; - /** + /** * 查询签约患者管理任务路径节点 * * @param id 签约患者管理任务路径节点主键 @@ -587,31 +613,65 @@ public class SignPatientManageRouteNodeServiceImpl implements ISignPatientManage PhoneDialRecord phoneDialRecord = phoneDialRecordMapper.getLastRecord(id); - String phoneResultJson = signPatientManageRouteNode.getPhoneResultJson(); - if (StringUtils.isNotBlank(phoneResultJson)) { - JSONObject resultJson = JSONObject.parseObject(phoneResultJson); - JSONArray record = resultJson.getJSONArray("record"); - recordVo.setRecord(record); + if (StringUtils.equals("yzaiobs", callType)) { + String phoneResultJson = signPatientManageRouteNode.getPhoneResultJson(); + if (StringUtils.isNotBlank(phoneResultJson)) { + JSONObject resultJson = JSONObject.parseObject(phoneResultJson); - if(ObjectUtils.isEmpty(phoneDialRecord) || StringUtils.isBlank(phoneDialRecord.getCtUuid())) { - // 从任务中解析ctuuid - String ctuuid = resultJson.getString("contactUUID"); - if (StringUtils.isNotBlank(ctuuid)) { - String videoUrl = aiobService.getPhoneDialRecord(ctuuid); - recordVo.setPhoneDialRecordVideo(videoUrl); + // 通话记录文字 + String interactions = resultJson.getString("interactions"); + // 解析 + if (StringUtils.isNotBlank(interactions)) { + recordVo.setRecord(JSONArray.parseArray(JSON.toJSONString(iyzaiobsService.parseRecord(interactions)))); + } else { + recordVo.setRecord(new JSONArray()); } - return recordVo; + + if(ObjectUtils.isEmpty(phoneDialRecord) || StringUtils.isBlank(phoneDialRecord.getPhoneDialRecordVideo())) { + // 从任务中解析ctuuid + String mediaPath = resultJson.getString("mediaPath"); + if (StringUtils.isNotBlank(mediaPath)) { + String videoUrl = iyzaiobsService.saveVideo(mediaPath, signPatientManageRouteNode.getId() + ""); + recordVo.setPhoneDialRecordVideo(videoUrl); + if (ObjectUtils.isNotEmpty(phoneDialRecord)) { + phoneDialRecord.setPhoneDialRecordVideo(videoUrl); + phoneDialRecordMapper.updatePhoneDialRecord(phoneDialRecord); + } + } + return recordVo; + } else { + recordVo.setPhoneDialRecordVideo(phoneDialRecord.getPhoneDialRecordVideo()); + return recordVo; + } + } + } else if (StringUtils.equals("aiobs", callType)) { + String phoneResultJson = signPatientManageRouteNode.getPhoneResultJson(); + if (StringUtils.isNotBlank(phoneResultJson)) { + JSONObject resultJson = JSONObject.parseObject(phoneResultJson); + JSONArray record = resultJson.getJSONArray("record"); + recordVo.setRecord(record); + + if(ObjectUtils.isEmpty(phoneDialRecord) || StringUtils.isBlank(phoneDialRecord.getCtUuid())) { + // 从任务中解析ctuuid + String ctuuid = resultJson.getString("contactUUID"); + if (StringUtils.isNotBlank(ctuuid)) { + String videoUrl = aiobService.getPhoneDialRecord(ctuuid); + recordVo.setPhoneDialRecordVideo(videoUrl); + } + return recordVo; + } + } + + if (StringUtils.isBlank(phoneDialRecord.getPhoneDialRecordVideo())) { + String videoUrl = aiobService.getPhoneDialRecord(phoneDialRecord.getCtUuid()); + phoneDialRecord.setPhoneDialRecordVideo(videoUrl); + phoneDialRecordMapper.updatePhoneDialRecord(phoneDialRecord); + recordVo.setPhoneDialRecordVideo(videoUrl); + } else { + recordVo.setPhoneDialRecordVideo(phoneDialRecord.getPhoneDialRecordVideo()); } } - if (StringUtils.isBlank(phoneDialRecord.getPhoneDialRecordVideo())) { - String videoUrl = aiobService.getPhoneDialRecord(phoneDialRecord.getCtUuid()); - phoneDialRecord.setPhoneDialRecordVideo(videoUrl); - phoneDialRecordMapper.updatePhoneDialRecord(phoneDialRecord); - recordVo.setPhoneDialRecordVideo(videoUrl); - } else { - recordVo.setPhoneDialRecordVideo(phoneDialRecord.getPhoneDialRecordVideo()); - } return recordVo; } diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/IYZAIOBSService.java b/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/IYZAIOBSService.java index 776d49bf..18c38da0 100644 --- a/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/IYZAIOBSService.java +++ b/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/IYZAIOBSService.java @@ -4,6 +4,8 @@ import com.alibaba.fastjson2.JSONObject; import com.aliyuncs.exceptions.ClientException; import com.xinelu.manage.dto.aiob.CreateDutyDto; import com.xinelu.manage.dto.aiob.DutyCallbackDto; +import com.xinelu.manage.vo.yzaiobs.CallRecord; +import java.util.List; /** * 曜智·智能外呼平台Service接口 @@ -20,7 +22,7 @@ public interface IYZAIOBSService { * @Author haown * @Date 2025-12-17 16:27 */ - JSONObject createDuty(CreateDutyDto createDutyDto); + String createDuty(CreateDutyDto createDutyDto); /** * @description 任务执行回调方法 @@ -32,11 +34,12 @@ public interface IYZAIOBSService { JSONObject taskCallBack(DutyCallbackDto callbackDto) throws ClientException; /** - * @description 单通电话数据回传接口 - * @Param * @param null + * @description 通话录音保存到本地 * @return null * @Author haown * @Date 2025-12-26 15:59 */ - JSONObject phoneCallBack(); + String saveVideo(String downloadPath, String nodeId); + + List parseRecord(String interactions); } diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/impl/YZAIOBSServiceImpl.java b/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/impl/YZAIOBSServiceImpl.java index 882c5b4f..5387c9af 100644 --- a/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/impl/YZAIOBSServiceImpl.java +++ b/postdischarge-manage/src/main/java/com/xinelu/manage/service/yzaiobs/impl/YZAIOBSServiceImpl.java @@ -1,9 +1,12 @@ package com.xinelu.manage.service.yzaiobs.impl; +import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.aliyuncs.exceptions.ClientException; +import com.xinelu.common.config.SystemBusinessConfig; +import com.xinelu.common.constant.Constants; import com.xinelu.common.constant.PhoneMessageRemindConstants; import com.xinelu.common.constant.TaskCreateTypeConstant; import com.xinelu.common.constant.TaskStatisticsTypeConstants; @@ -51,14 +54,24 @@ import com.xinelu.manage.service.yzaiobs.IYZAIOBSService; import com.xinelu.manage.vo.labelfieldcontent.LabelFieldInfoContentVo; import com.xinelu.manage.vo.questionsubject.QuestionSubjectVO; import com.xinelu.manage.vo.yzaiobs.CallRecord; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.math.BigDecimal; +import java.net.HttpURLConnection; +import java.net.URL; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Value; @@ -76,6 +89,7 @@ import org.springframework.web.client.RestTemplate; * @create: 2025-12-17 17:18 **/ @Service +@Slf4j public class YZAIOBSServiceImpl implements IYZAIOBSService { @Value("${yzaiobs.url}") private String url; @@ -121,8 +135,10 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { private PatientQuestionOptionResultMapper patientQuestionOptionResultMapper; @Resource private LabelFieldContentMapper labelFieldContentMapper; + @Resource + private SystemBusinessConfig systemBusinessConfig; - @Override public JSONObject createDuty(CreateDutyDto createDutyDto) { + @Override public String createDuty(CreateDutyDto createDutyDto) { createDutyDto.setUserId(userId); createDutyDto.setRoleId(roleId); createDutyDto.setRouteNum(routeNum); @@ -131,68 +147,33 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); + log.info("创建外呼任务-传输对象:{}", com.alibaba.fastjson.JSONObject.toJSONString(createDutyDto, SerializerFeature.WriteMapNullValue)); String requestBody = JSON.toJSONString(createDutyDto); HttpEntity requestEntity = new HttpEntity<>(requestBody, headers); ResponseEntity responseEntity = restTemplate.postForEntity(url + "/duty/createDuty", requestEntity, String.class); 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, - "message": "任务名已存在!!!", - "ret": 0, - "success": false // 任务创建结果,true表示创建成功,false表示创建失败 - }*/ - - /*{ - "flag": true, - "message": "入库成功", - "ret": 0, // 0表示成功,非0表示失败 - "success": true, // 任务创建结果,true表示创建成功,false表示创建失败 - "value": { - "166": [ // 已创建的任务id - { - "id": 1045, // 任务资源id - "phoneNumber": "18156017972", // 用户手机号 - "downLoadState": false // 音频是否下载完成 - } - ] - } - }*/ if (object == null || object.getBoolean("success") == null || !object.getBoolean("success")) { - throw new ServiceException("创建任务失败," + object.getString("message")); + log.info("创建外呼任务失败-原因:{}", object.getString("message")); + return null; } + log.info("创建外呼任务成功-返回值:{}", com.alibaba.fastjson.JSONObject.toJSONString(object, SerializerFeature.WriteMapNullValue)); JSONObject data = object.getJSONObject("value"); - //Set taskIds = data.keySet(); - //Iterator iterator = taskIds.iterator(); - //String taskId = iterator.next(); - return data; + Set taskIds = data.keySet(); + Iterator iterator = taskIds.iterator(); + String taskId = iterator.next(); + log.info("创建外呼任务成功-任务id:{}", taskId); + return taskId; } @Override public JSONObject taskCallBack(DutyCallbackDto callbackDto) throws ClientException { // 从data中获取任务id + log.info("外呼回调接口开始执行-------"); JSONArray JSONArr = callbackDto.getData(); if (!CollectionUtils.isEmpty(JSONArr)) { for (int i = 0; i < JSONArr.size(); i++) { JSONObject jsonObject = JSONArr.getJSONObject(i); - System.out.println("数据回调-----------------------"); - System.out.println("数据" + i + ":"+jsonObject.toJSONString()); + log.info("数据{}:{}", i, com.alibaba.fastjson.JSONObject.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue)); DutyCallbackDataDto dutyCallbackDataDto = JSON.parseObject(jsonObject.toJSONString(), DutyCallbackDataDto.class); - System.out.println("数据转实体类" + i + ":" +dutyCallbackDataDto.toString()); // 是否发送短信标识 boolean needSendSms = false; // 是否重拨 @@ -246,7 +227,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { // signPatientManageRouteNode.setPhoneResultJson(com.alibaba.fastjson.JSON.toJSONString(data, SerializerFeature.WriteMapNullValue)); } - signPatientManageRouteNode.setPhoneResultJson(callbackDto.toString()); + signPatientManageRouteNode.setPhoneResultJson(com.alibaba.fastjson.JSON.toJSONString(dutyCallbackDataDto, SerializerFeature.WriteMapNullValue)); signPatientManageRouteNodeMapper.updateSignPatientManageRouteNode(signPatientManageRouteNode); @@ -268,7 +249,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { // 发送短信 if (needSendSms) { - //System.out.println("发送短信-------------------------------------------"); + log.info("发送短信......................"); iaiobService.sendSms(signPatientManageRoute.getPatientId(), signPatientManageRouteNode); } // 重拨 @@ -293,7 +274,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { PhoneDialRecord phoneDialRecord = new PhoneDialRecord(); phoneDialRecord.setPatientId(signPatientManageRoute.getPatientId()); phoneDialRecord.setManageRouteNodeId(signPatientManageRouteNode.getId()); - phoneDialRecord.setPatientPhone(callbackDto.getPhoneNum()); + phoneDialRecord.setPatientPhone(dutyCallbackDataDto.getPhoneNumber()); phoneDialRecord.setDialTime(LocalDateTime.now()); phoneDialRecord.setPhoneTemplateId(signPatientManageRouteNode.getScriptInfoId() + ""); phoneDialRecord.setPhoneDialMethod(signPatientManageRouteNode.getPhoneDialMethod()); @@ -303,7 +284,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { phoneDialRecord.setCtUuid(dutyCallbackDataDto.getCallid()); // 通话录音地址 - phoneDialRecord.setPhoneDialRecordVideo(iaiobService.videoPath(dutyCallbackDataDto.getMediaPath(), dutyCallbackDataDto.getCallid())); + phoneDialRecord.setPhoneDialRecordVideo(saveVideo(dutyCallbackDataDto.getMediaPath(), dutyCallbackDataDto.getCustId())); phoneDialRecordMapper.insertPhoneDialRecord(phoneDialRecord); @@ -330,7 +311,41 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { return retObj; } - @Override public JSONObject phoneCallBack() { + @Override + public String saveVideo(String downloadPath, String nodeId) { + if (StringUtils.isBlank(downloadPath)) { + throw new ServiceException("暂未获取到录音,请稍后再试!"); + } + String url = systemBusinessConfig.getProfile() + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + nodeId + ".wav"; + File outputPath = new File(url); + File dir = outputPath.getParentFile(); + if (!dir.exists()){ + dir.mkdirs(); + } + try { + outputPath.createNewFile(); // 创建文件 + URL fileUrl = new URL(downloadPath); + HttpURLConnection connection = (HttpURLConnection)fileUrl.openConnection(); + connection.setRequestMethod("GET"); + connection.connect(); + if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { + InputStream inputStream = new BufferedInputStream(connection.getInputStream()); + FileOutputStream outputStream = new FileOutputStream(outputPath); + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.close(); + inputStream.close(); + log.info("保存到本地的录音地址:{}", Constants.RESOURCE_PREFIX + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + nodeId + ".wav"); + return Constants.RESOURCE_PREFIX + systemBusinessConfig.getPhoneDialRecordVideo() + "/" + nodeId + ".wav"; + } else { + throw new ServiceException("下载录音失败,请稍后再试"); + } + } catch (IOException e) { + e.printStackTrace(); + } return null; } @@ -343,8 +358,11 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { * @Date 2025-12-25 15:45 */ private void parseQuestionInfo(String callResultTypes, String interactions, SignPatientManageRouteNode node, Long patientInfoId, Long taskExecuteRecordId) { + PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(patientInfoId); - if(StringUtils.isBlank(interactions)) { + if(StringUtils.isBlank(interactions) || StringUtils.isBlank(callResultTypes)) { + // 返回一个空的问卷 + genenrateQuestion(node, patientInfo, taskExecuteRecordId); return; } List callResultIntents = Arrays.asList(callResultTypes.split(",")); @@ -353,7 +371,7 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { if (CollectionUtils.isEmpty(recordList)) { return; } - PatientInfo patientInfo = patientInfoMapper.selectPatientInfoById(patientInfoId); + // 查询患者画像信息 List labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfoId); @@ -391,9 +409,9 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { boolean hasQuestion = false; String aiobQuestionName = ""; for (int i = 0; i < recordList.size(); i++) { - if (recordList.get(i).getContent().contains(questionNameAlias.replaceAll("\\p{P}", ""))) { + if (recordList.get(i).getContextText().contains(questionNameAlias.replaceAll("\\p{P}", ""))) { hasQuestion = true; - aiobQuestionName = recordList.get(i).getContent(); + aiobQuestionName = recordList.get(i).getContextText(); break; } } @@ -502,7 +520,11 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { //questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult); } - private List parseRecord(String interactions) { + @Override + public List parseRecord(String interactions) { + if (StringUtils.isBlank(interactions)) { + return null; + } // 先用|分隔完整的问题与答案,再用:分隔角色 List retList = new ArrayList<>(); List records = Arrays.asList(interactions.split("\\|")); @@ -513,7 +535,26 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { CallRecord callRecord = new CallRecord(); String[] str1 = record.split(":"); callRecord.setRole(str1[0]); - callRecord.setContent(str1[1]); + if (StringUtils.equals("机器人", str1[0])) { + callRecord.setRole("speech"); + if (str1.length > 1) { + if(StringUtils.isNotBlank(str1[1])) { + // 用^分隔 + String[] content = str1[1].split("\\^"); + for (int i = 0; i < content.length; i++) { + if (StringUtils.contains(content[i], "txt=")) { + callRecord.setContextText(content[i].replaceAll("txt=", "")); + } + } + } + } + } else if (StringUtils.equals("用户", str1[0])) { + callRecord.setRole("voice"); + if (str1.length > 1) { + callRecord.setContextText(str1[1]); + } + } + retList.add(callRecord); } return retList; @@ -529,12 +570,92 @@ public class YZAIOBSServiceImpl implements IYZAIOBSService { */ private String getReply(List 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(); + if (StringUtils.equals(callRecordList.get(i).getContextText(), question)) { + if (StringUtils.equals("voice",callRecordList.get(i+1).getRole())) { + return callRecordList.get(i+1).getContextText(); } } } return null; } + + private void genenrateQuestion(SignPatientManageRouteNode node, PatientInfo patientInfo, Long taskExecuteRecordId) { + QuestionInfo questionInfo = questionInfoMapper.selectQuestionInfoById(node.getQuestionInfoId()); + // 1、保存patient_question_submit_result + PatientQuestionSubmitResult patientQuestionSubmitResult = new PatientQuestionSubmitResult(); + patientQuestionSubmitResult.setTaskExecuteRecordId(taskExecuteRecordId); + patientQuestionSubmitResult.setPatientName(patientInfo.getPatientName()); + patientQuestionSubmitResult.setPatientId(patientInfo.getId()); + patientQuestionSubmitResult.setManageRouteId(node.getManageRouteId()); + patientQuestionSubmitResult.setManageRouteName(node.getManageRouteName()); + patientQuestionSubmitResult.setManageRouteNodeId(node.getId()); + patientQuestionSubmitResult.setManageRouteNodeName(node.getRouteNodeName()); + patientQuestionSubmitResult.setQuestionInfoId(questionInfo.getId()); + patientQuestionSubmitResult.setDepartmentId(questionInfo.getDepartmentId()); + patientQuestionSubmitResult.setDepartmentName(questionInfo.getDepartmentName()); + patientQuestionSubmitResult.setDiseaseTypeId(questionInfo.getDiseaseTypeId()); + patientQuestionSubmitResult.setDiseaseTypeName(questionInfo.getDiseaseTypeName()); + patientQuestionSubmitResult.setQuestionnaireName(questionInfo.getQuestionnaireName()); + patientQuestionSubmitResult.setQuestionnaireDescription(questionInfo.getQuestionnaireDescription()); + patientQuestionSubmitResult.setAnsweringMethod(questionInfo.getAnsweringMethod()); + patientQuestionSubmitResult.setQuestionnaireId(questionInfo.getQuestionnaireId()); + patientQuestionSubmitResult.setQuestionCount(questionInfo.getQuestionCount()); + patientQuestionSubmitResult.setQuestionnaireTotalScore(questionInfo.getQuestionnaireTotalScore()); + patientQuestionSubmitResult.setResidentId(patientInfo.getResidentId()); + patientQuestionSubmitResult.setCreateTime(LocalDateTime.now()); + questionSubmitResultMapper.insertPatientQuestionSubmitResult(patientQuestionSubmitResult); + // 2、保存patient_question_subject_result + List questionSubjectList = questionSubjectMapper.selectQuestionSubjectBy(node.getQuestionInfoId()); + questionSubjectList.forEach(questionSubjectVO -> { + PatientQuestionSubjectResult patientQuestionSubjectResult = new PatientQuestionSubjectResult(); + BeanUtils.copyProperties(questionSubjectVO, patientQuestionSubjectResult); + patientQuestionSubjectResult.setId(null); + patientQuestionSubjectResult.setQuestionSubmitResultId(patientQuestionSubmitResult.getId()); + patientQuestionSubjectResult.setCreateTime(LocalDateTime.now()); + //不管是否是 填空题,都 写入回答 文本 + patientQuestionSubjectResult.setFillBlanksAnswer(null); + + patientQuestionSubjectResult.setQuestionSubjectId(questionSubjectVO.getId()); + patientQuestionSubjectResultMapper.insertPatientQuestionSubjectResult(patientQuestionSubjectResult); + + // 3、保存patient_question_option_result + QuestionSubjectOption questionSubjectOptionQuery = new QuestionSubjectOption(); + questionSubjectOptionQuery.setQuestionnaireSubjectId(questionSubjectVO.getId()); + List questionSubjectOptions = questionSubjectOptionMapper.selectQuestionSubjectOptionList(questionSubjectOptionQuery); + List patientQuestionOptionResults = new ArrayList<>(); + + questionSubjectOptions.forEach(questionSubjectOption -> { + PatientQuestionOptionResult patientQuestionOptionResult = new PatientQuestionOptionResult(); + BeanUtils.copyProperties(questionSubjectOption, patientQuestionOptionResult); + patientQuestionOptionResult.setOptionChooseSign(0); + patientQuestionOptionResult.setOptionChooseSign(0); + patientQuestionOptionResult.setId(null); + patientQuestionOptionResult.setCreateTime(LocalDateTime.now()); + patientQuestionOptionResult.setQuestionSubjectResultId(patientQuestionSubjectResult.getId()); + + patientQuestionOptionResult.setQuestionSubjectOptionId(questionSubjectOption.getId()); + + patientQuestionOptionResults.add(patientQuestionOptionResult); + }); + + if (!CollectionUtils.isEmpty(patientQuestionOptionResults)) { + List remarkableFlag = patientQuestionOptionResults.stream() + .filter(Objects::nonNull) + .filter(item -> StringUtils.isNotBlank(item.getRemarkableFlag()) && Objects.nonNull(item.getOptionChooseSign()) && item.getOptionChooseSign().equals(0) && ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo().equals(item.getRemarkableFlag())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(remarkableFlag)) { + patientQuestionSubmitResult.setRemarkableFlag(ContentedAndRemarkableFlagEnum.REMARKABLE.getInfo()); + } + List 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()); + if (!CollectionUtils.isEmpty(contentedFlag)) { + patientQuestionSubmitResult.setContentedFlag(ContentedAndRemarkableFlagEnum.DISCONTENTED.getInfo()); + } + } + questionSubmitResultMapper.updatePatientQuestionSubmitResult(patientQuestionSubmitResult); + patientQuestionOptionResultMapper.saveQuestionOptionList(patientQuestionOptionResults); + }); + } } diff --git a/postdischarge-manage/src/main/java/com/xinelu/manage/vo/yzaiobs/CallRecord.java b/postdischarge-manage/src/main/java/com/xinelu/manage/vo/yzaiobs/CallRecord.java index 420d0c00..5f0ab5ca 100644 --- a/postdischarge-manage/src/main/java/com/xinelu/manage/vo/yzaiobs/CallRecord.java +++ b/postdischarge-manage/src/main/java/com/xinelu/manage/vo/yzaiobs/CallRecord.java @@ -17,6 +17,6 @@ public class CallRecord { /** * 说话内容 */ - private String content; + private String contextText; } diff --git a/postdischarge-quartz/src/main/java/com/xinelu/quartz/task/YZAIOBSTask.java b/postdischarge-quartz/src/main/java/com/xinelu/quartz/task/YZAIOBSTask.java index cc8c0fda..b4d7f519 100644 --- a/postdischarge-quartz/src/main/java/com/xinelu/quartz/task/YZAIOBSTask.java +++ b/postdischarge-quartz/src/main/java/com/xinelu/quartz/task/YZAIOBSTask.java @@ -163,6 +163,9 @@ public class YZAIOBSTask { createDutyDto.setStartDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); createDutyDto.setNoticeSwitch(1); createDutyDto.setDeduplicationSwitch(true); + JSONObject repStrategy = new JSONObject(); + repStrategy.fluentPut("hangState", "").fluentPut("state", "").fluentPut("intention", ""); + createDutyDto.setRepStrategy(repStrategy); //3、开始组装本任务下的客户变量 //遍历最内层任务节点 JSONArray dataArr = new JSONArray(); @@ -176,8 +179,7 @@ public class YZAIOBSTask { List labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId()); // 处理变量 JSONObject jsonObject = new JSONObject(); - //TODO 需要验证是任务id还是患者id - jsonObject.fluentPut("手机号", patientInfo.getPatientPhone()).fluentPut("custId", node.getId()); + jsonObject.fluentPut("手机号", patientInfo.getPatientPhone()).fluentPut("custId", node.getId() + ""); if (StringUtils.isNotBlank(scriptInfo.getVariables())) { List variables = Arrays.asList(scriptInfo.getVariables().split("\\|")); variables.forEach(variable -> { @@ -192,30 +194,30 @@ public class YZAIOBSTask { }); createDutyDto.setDataArr(dataArr); - JSONObject taskObj = iyzaiobsService.createDuty(createDutyDto); - String taskId = taskObj.keySet().iterator().next(); + String taskId = iyzaiobsService.createDuty(createDutyDto); + if (StringUtils.isNotBlank(taskId)) { + 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); - 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); - }); + //设置拨打状态 + 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); + }); + } } }); }); @@ -292,19 +294,21 @@ public class YZAIOBSTask { createDutyDto.setDutyName(dutyName); createDutyDto.setDutyType(scriptInfo.getRobotPublishId()); createDutyDto.setDutySceneId(Integer.parseInt(scriptInfo.getRobotPublishId())); - createDutyDto.setOutboundPeriods("[\"09:00~11:35\",\"15:55~23:30\"]"); + createDutyDto.setOutboundPeriods("[\"09:00~11:30\",\"14:00~17:30\"]"); createDutyDto.setStartDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + createDutyDto.setEndDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + JSONObject repStrategy = new JSONObject(); if (StringUtils.isNotBlank(node.getPhoneRedialTimes())) { createDutyDto.setDuplication(PhoneRedialTimesEnum.getValueByInfo(node.getPhoneRedialTimes()).getValue()); + createDutyDto.setPeriod(node.getPhoneTimeInterval()); + repStrategy.fluentPut("hangState", "").fluentPut("state", "1,2,4,5,6,7,8").fluentPut("intention", ""); } else { - createDutyDto.setDuplication(0); + repStrategy.fluentPut("hangState", "").fluentPut("state", "").fluentPut("intention", ""); } - 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); + createDutyDto.setDeduplicationSwitch(true); + createDutyDto.setNoticeSwitch(1); + //遍历最内层任务节点 JSONArray dataArr = new JSONArray(); @@ -317,8 +321,7 @@ public class YZAIOBSTask { List labelFieldContentList = labelFieldContentMapper.selectByPatientId(patientInfo.getId()); // 处理变量 JSONObject jsonObject = new JSONObject(); - //TODO 需要验证是任务id还是患者id - jsonObject.fluentPut("custId", node.getId()).fluentPut("手机号", patientInfo.getPatientPhone()); + jsonObject.fluentPut("custId", node.getId() + "").fluentPut("手机号", patientInfo.getPatientPhone()); if (StringUtils.isNotBlank(scriptInfo.getVariables())) { List variables = Arrays.asList(scriptInfo.getVariables().split("\\|")); variables.forEach(variable -> { @@ -332,12 +335,15 @@ public class YZAIOBSTask { } createDutyDto.setDataArr(dataArr); - JSONObject taskObj = iyzaiobsService.createDuty(createDutyDto); + String taskId = iyzaiobsService.createDuty(createDutyDto); //设置拨打状态 - SignPatientManageRouteNode signPatientManageRouteNode_DialStatus = new SignPatientManageRouteNode(); - signPatientManageRouteNode_DialStatus.setId(node.getId()); - signPatientManageRouteNode_DialStatus.setDialStatus(DialStatusEnum.DIALED.getInfo()); - signPatientManageRouteNodeMapper.updateDialStatusByNodeId(signPatientManageRouteNode_DialStatus); + if (StringUtils.isNotBlank(taskId)) { + SignPatientManageRouteNode signPatientManageRouteNode_DialStatus = new SignPatientManageRouteNode(); + signPatientManageRouteNode_DialStatus.setId(node.getId()); + signPatientManageRouteNode_DialStatus.setDialStatus(DialStatusEnum.DIALED.getInfo()); + signPatientManageRouteNode_DialStatus.setTaskIdExt(taskId); + signPatientManageRouteNodeMapper.updateDialStatusByNodeId(signPatientManageRouteNode_DialStatus); + } }); } log.info("曜智智能外呼创建实时任务定时任务执行完成......");