liusheng
2026-10-12 26d1f59f0266672398975ba0337bb3d8267c2d95
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -8,24 +8,27 @@
import com.google.gson.Gson;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.dx.MessageSend;
import com.ruoyi.common.core.service.IConfigService;
import com.ruoyi.satisfaction.api.SatisfactionFacade;
import com.ruoyi.message.sms.provider.sltd.ws.MessageSend;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.core.service.IConfigService;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.message.SendResult;
import com.ruoyi.message.sms.SmsSendRequest;
import com.ruoyi.message.sms.SmsSenderFactory;
import com.ruoyi.message.wechat.WechatSendRequest;
import com.ruoyi.message.wechat.WechatSenderFactory;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService;
import com.smartor.common.FtpService;
import com.smartor.common.MtSubmitSmUtil;
import com.smartor.common.ScheduleSubtaskBuilder;
import com.smartor.config.PhoneUtils;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.DTO.*;
import com.smartor.domain.*;
import com.smartor.domain.VO.HeLibraryCountVO;
import com.smartor.domain.VO.ServiceSubtaskCotinueCountVO;
import com.smartor.domain.VO.TransferDeptVO;
import com.smartor.domain.VO.*;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import com.smartor.mapper.*;
import com.smartor.service.*;
@@ -41,12 +44,13 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.*;
@@ -58,6 +62,8 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static cn.hutool.core.convert.Convert.toHex;
/**
 * 单一任务(随访)Service业务层处理
 *
@@ -67,6 +73,16 @@
@Slf4j
@Service
public class ServiceSubtaskServiceImpl implements IServiceSubtaskService {
    /**
     * 满意度模块对外门面(常驻 Bean)。
     * <p>
     * 随访统计里的「满意度指数」({@code getSfStatisticsJoy})只能通过它取数;
     * 满意度模块关闭时门面返回全零 Map,不影响随访统计的其它字段与启动。
     */
    @Autowired
    private SatisfactionFacade satisfactionFacade;
    @Autowired
    private ServiceSubtaskMapper serviceSubtaskMapper;
@@ -163,10 +179,16 @@
    private ISysConfigService configService;
    @Autowired
    private MtSubmitSmUtil mtSubmitSmUtil;
    private SysConfigMapper sysConfigMapper;
    /**
     * 消息发送方工厂(短信/微信公众号),替代原来直接调用各站点发送代码的写法
     */
    @Autowired
    private SmsSenderFactory smsSenderFactory;
    @Autowired
    private SysConfigMapper sysConfigMapper;
    private WechatSenderFactory wechatSenderFactory;
    @Autowired
    private RedisTemplate redisTemplate;
@@ -189,9 +211,6 @@
    @Value("${req_path}")
    private String req_path;
    @Value("${xhsmsPath}")
    private String xhsmsPath;
    @Value("${phoneUpEveryHour}")
    private Integer phoneUpEveryHour;
    @Value("${phoneEndHour}")
@@ -204,6 +223,13 @@
    @Value("${spring.profiles.active}")
    private String active;
    @Autowired
    private ServiceOutPathMapper serviceOutPathMapper;
    private static final String KEY_SEP = "\u0001";
    @Autowired
    private PatMedOperationItemMapper patMedOperationItemMapper;
    /**
     * 查询单一任务(随访)
@@ -406,26 +432,7 @@
    @Override
    public List<ServiceSubtaskRes> patItem(ServiceSubtaskEntity serviceSubtaskEntity) {
        if (serviceSubtaskEntity.getSendstateView() != null) {
            //            1:待随访(1 被领取、2 待发送、3 已发送、5 发送失败、7、超时);2:已完成( 6 已完成)、3:无需随访(4 不执行)
            if (serviceSubtaskEntity.getSendstateView() == 1)
                serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 7L)));
            if (serviceSubtaskEntity.getSendstateView() == 2)
                serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(6L)));
            if (serviceSubtaskEntity.getSendstateView() == 3)
                serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(4L)));
        }
        //患者获取随访任务-需要查询同个患者(身份证)所有的任务 景宁
        if (StringUtils.isNotEmpty(serviceSubtaskEntity.getOrgid()) && serviceSubtaskEntity.getOrgid().equals("47255004333112711A1001")) {
            if (ObjectUtils.isNotEmpty(serviceSubtaskEntity.getPatid())) {
                PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtaskEntity.getPatid());
                if (ObjectUtils.isNotEmpty(patArchive) && StringUtils.isNotEmpty(patArchive.getIdcardno())) {
                    serviceSubtaskEntity.setPatid(null);
                    serviceSubtaskEntity.setSfzh(patArchive.getIdcardno());
                }
            }
        }
        List<ServiceSubtask> selectServiceSubtaskList = this.selectServiceSubtaskList(serviceSubtaskEntity);
        List<ServiceSubtask> selectServiceSubtaskList = getServiceSubtasks(serviceSubtaskEntity);
        List<ServiceSubtaskRes> serviceSubtaskResList = new ArrayList<>();
        for (ServiceSubtask serviceSubtask : selectServiceSubtaskList) {
@@ -461,6 +468,30 @@
            serviceSubtaskResList.add(serviceSubtaskRes);
        }
        return serviceSubtaskResList;
    }
    public List<ServiceSubtask> getServiceSubtasks(ServiceSubtaskEntity serviceSubtaskEntity) {
        if (serviceSubtaskEntity.getSendstateView() != null) {
            //            1:待随访(1 被领取、2 待发送、3 已发送、5 发送失败、7、超时);2:已完成( 6 已完成)、3:无需随访(4 不执行)
            if (serviceSubtaskEntity.getSendstateView() == 1)
                serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 7L)));
            if (serviceSubtaskEntity.getSendstateView() == 2)
                serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(6L)));
            if (serviceSubtaskEntity.getSendstateView() == 3)
                serviceSubtaskEntity.setSendstates(new ArrayList<>(Arrays.asList(4L)));
        }
        //患者获取随访任务-需要查询同个患者(身份证)所有的任务 景宁
        if (StringUtils.isNotEmpty(serviceSubtaskEntity.getOrgid()) && serviceSubtaskEntity.getOrgid().equals("47255004333112711A1001")) {
            if (ObjectUtils.isNotEmpty(serviceSubtaskEntity.getPatid())) {
                PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtaskEntity.getPatid());
                if (ObjectUtils.isNotEmpty(patArchive) && StringUtils.isNotEmpty(patArchive.getIdcardno())) {
                    serviceSubtaskEntity.setPatid(null);
                    serviceSubtaskEntity.setSfzh(patArchive.getIdcardno());
                }
            }
        }
        List<ServiceSubtask> selectServiceSubtaskList = this.selectServiceSubtaskList(serviceSubtaskEntity);
        return selectServiceSubtaskList;
    }
    @Override
@@ -584,7 +615,6 @@
//        return map;
//    }
    /**
     * 统计任务各种状态的数量(已优化)
     * 优化说明:
@@ -621,6 +651,43 @@
    }
    /**
     * 统计任务各种状态的数量(已优化)
     * 优化说明:
     * 1. 使用数据库层聚合计算,替代应用层遍历
     * 2. 性能提升 10-100 倍(取决于数据量)
     * 3. 降低内存占用和网络传输
     *
     * @param serviceSubtaskEntity 查询条件
     * @return 各状态统计结果
     */
    @Override
    public Map<String, Object> countByCondition(ServiceSubtaskEntity serviceSubtaskEntity) {
        // 直接调用数据库统计方法,在数据库层完成聚合计算
        Map<String, Object> result = serviceSubtaskMapper.countByCondition(serviceSubtaskEntity);
        // 处理空异常
        if (MapUtils.isEmpty(result)) {
            result = new HashMap<>();
            // 确保所有 key 都有值,避免空指针异常
            // MyBatis 的 SUM 在没有匹配行时会返回 null
            result.putIfAbsent("wzx", 0);
            result.putIfAbsent("ysf", 0);
            result.putIfAbsent("fssb", 0);
            result.putIfAbsent("yfs", 0);
            result.putIfAbsent("blq", 0);
            result.putIfAbsent("total", 0);
            result.putIfAbsent("wxsf", 0);
            result.putIfAbsent("xsf", 0);
            result.putIfAbsent("dsf", 0);
            result.putIfAbsent("dfs", 0);
            result.putIfAbsent("yfs", 0);
            result.putIfAbsent("ywc", 0);
            result.putIfAbsent("yc", 0);
            result.putIfAbsent("jg", 0);
        }
        return result;
    }
    /**
     * 新增单一任务(随访)
     *
     * @param serviceSubtask 单一任务(随访)
@@ -628,9 +695,64 @@
     */
    @Override
    public Map<String, Object> insertServiceSubtask(ServiceSubtask serviceSubtask) {
        serviceSubtask.setCreateTime(DateUtils.getNowDate());
        serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
        List<ServiceSubtask> serviceSubtasks = null;
        //先查询一下该患者是否已经创建根据serviceType,sendstate,inhospid,patid,orgid
        //这样判断主要是为了想让新华医院的外部导入患者创建任务,也能用这个接口
        if (StringUtils.isEmpty(serviceSubtask.getPatfrom()) || !serviceSubtask.getPatfrom().equals("2")) {
            ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
            serviceSubtaskVO.setServiceType(serviceSubtask.getServiceType());
            serviceSubtaskVO.setInhospid(serviceSubtask.getInhospid());
            serviceSubtaskVO.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 7L)));
            serviceSubtaskVO.setPatid(serviceSubtask.getPatid());
            serviceSubtaskVO.setOrgid(serviceSubtask.getOrgid());
            serviceSubtaskVO.setCampusid(serviceSubtask.getCampusid());
            serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
        }
        RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
        String format = null;
        if (CollectionUtils.isNotEmpty(serviceSubtasks)) {
            ServiceSubtask serviceSubtask1 = serviceSubtasks.get(0);
            ServiceOutPath serviceOutPath = new ServiceOutPath();
            serviceOutPath.setSubId(serviceSubtask1.getId());
            List<ServiceOutPath> serviceOutPaths = serviceOutPathMapper.selectServiceOutPathList(serviceOutPath);
            if (CollectionUtils.isNotEmpty(serviceOutPaths))
                format = String.format("%03X", serviceOutPaths.get(0).getId());
            else format = getOutPath(serviceSubtask1, rsaPublicKeyExample);
            serviceSubtask = serviceSubtask1;
        } else {
            //如果不存在,则新增
            ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
            if (ObjectUtils.isNotEmpty(serviceTask)) {
                serviceSubtask.setTaskDesc(serviceTask.getTaskDesc());
                serviceSubtask.setTaskName(serviceTask.getTaskName());
                serviceSubtask.setTemplatename(serviceTask.getTemplatename());
            }
            serviceSubtask.setCreateTime(DateUtils.getNowDate());
            serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
            //修改住院满意度状态(避免重复查询)
            if (serviceSubtask.getServiceType() != null && "6".equals(serviceSubtask.getServiceType())) {
                Long inhospid = serviceSubtask.getInhospid();
                if (inhospid != null) {
                    PatMedInhosp patMedInhosp = new PatMedInhosp();
                    patMedInhosp.setInhospMydFlag("1");
                    patMedInhosp.setInhospid(inhospid);
                    patMedInhospMapper.updatePatMedInhosp(patMedInhosp);
                }
            }
            format = getOutPath(serviceSubtask, rsaPublicKeyExample);
        }
        Map<String, Object> result = new HashMap<>();
        if (StringUtils.isNotEmpty(format))
            result.put("url", StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format);
        else result.put("url", null);
        result.put("subId", serviceSubtask.getId());
        return result;
    }
    private String getOutPath(ServiceSubtask serviceSubtask, RSAPublicKeyExample rsaPublicKeyExample) {
        String format;
        String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key);
        String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key);
        String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key);
@@ -640,17 +762,15 @@
        serviceOutPath.setCreateTime(new Date());
        serviceOutPath.setParam6(subId);
        serviceOutPath.setOrgid(serviceSubtask.getOrgid());
        serviceOutPath.setTaskId(serviceSubtask.getTaskid());
        serviceOutPath.setSubId(serviceSubtask.getId());
        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
        //转成16进制
        String format = String.format("%03X", serviceOutPath.getId());
        format = String.format("%03X", serviceOutPath.getId());
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        Map<String, Object> result = new HashMap<>();
        result.put("url", StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format);
        result.put("subId", serviceSubtask.getId());
        return result;
        return format;
    }
    /**
@@ -667,8 +787,12 @@
        patMedInhosp.setInhospstate("0");
        List<PatMedInhosp> patMedInhospList = patMedInhospMapper.selectPatMedInhospList(patMedInhosp);
        PatArchive patArchive = patArchiveMapper.selectPatArchiveByPatid(serviceSubtask1.getPatid());
        if (patMedInhospList.size() > 0) {
        //景宁 新增再次随访不能触发患者再入院
        boolean inhospAgain = true;
        if (serviceSubtask1.getOrgid().equals("47255004333112711A1001")) {
            inhospAgain = false;
        }
        if (patMedInhospList.size() > 0 && inhospAgain) {
            serviceSubtask1.setIsVisitAgain(2);
            serviceSubtask1.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";患者再入院了" : "患者再入院了");
            serviceSubtask1.setSendstate(4L);
@@ -719,6 +843,7 @@
        serviceSubtask.setUpdateTime(DateUtils.getNowDate());
        if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 6)
            serviceSubtask.setFinishtime(new Date());
        return serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
    }
@@ -736,7 +861,6 @@
            svyTaskTemplateService.deleteSvyTaskTemplateBySvyid(serviceSubtask.getTemplateid());
        } else if (serviceSubtask.getType().equals("1"))
            ivrTaskTemplateService.deleteIvrTaskTemplateByID(serviceSubtask.getTemplateid());
        String tempName = svyTaskTemplateService.selectSvyTaskTemplateBySvyid(Long.valueOf(taskTempid)).getSvyname();
        serviceSubtask.setTemplateid(taskTempid.longValue());
@@ -987,8 +1111,8 @@
            //将任务信息放到服务表中
            ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class);
            serviceSubtask.setTaskid(serviceTask.getTaskid().longValue());
            serviceSubtask.setTemplatename(tempName);
            serviceSubtask.setTemplateid(tempid);
            serviceSubtask.setTemplatename(ObjectUtils.isNotEmpty(tempid) ? tempName : serviceTask.getTemplatename());
            serviceSubtask.setTemplateid(ObjectUtils.isNotEmpty(tempid) ? tempid : serviceTask.getTemplateid());
            serviceSubtask.setLibtemplateid(ObjectUtils.isEmpty(serviceTask.getLibtemplateid()) ? null : Long.valueOf(serviceTask.getLibtemplateid()));
            serviceSubtask.setLibtemplatename(serviceTask.getLibtemplatename());
            //新增
@@ -1071,8 +1195,7 @@
                }
            }
        }
        else if (serviceTaskVO.getIsoperation() != null && serviceTaskVO.getIsoperation() == 2) {
        } else if (serviceTaskVO.getIsoperation() != null && serviceTaskVO.getIsoperation() == 2) {
            //任务修改
            if (ObjectUtils.isNotEmpty(serviceTaskVO.getSendTimeslot()))
                serviceTask.setSendTimeSlot(JSON.toJSONString(serviceTaskVO.getSendTimeslot()));
@@ -1100,7 +1223,7 @@
                    redisCache.removeElementFromList("cache-3", serviceSubtask.getId().toString());
                    redisCache.removeElementFromList("cache-4", serviceSubtask.getId().toString());
                    //将出入院表的数据,还原成还未处理的状态
                    if (serviceSubtask.getServiceType().equals("2")) {
                    if (serviceSubtask.getServiceType().equals("2") || serviceSubtask.getServiceType().equals("13")) {
                        ServiceTask st = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                        //如果任务是长期任务,需要将该患者的出入院数据还原成还未处理的状态
                        if (st != null && st.getLongTask() == 1) {
@@ -1121,6 +1244,16 @@
                                patMedOuthosp.setServerState("0");
                                patMedOuthospService.updatePatMedOuthosp(patMedOuthosp);
                            }
                        }
                    } else if (serviceSubtask.getServiceType().equals("19")) {
                        ServiceTask st = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                        //如果任务是长期任务,需要将该患者的出院详情状态还原成还未处理的状态
                        if (st != null && st.getLongTask() == 1
                                && ObjectUtils.isNotEmpty(serviceSubtask.getOperationItemId())) {
                            PatMedOperationItem patMedOperationItem = new PatMedOperationItem();
                            patMedOperationItem.setOpercheckFlag("0");
                            patMedOperationItem.setId(serviceSubtask.getOperationItemId());
                            patMedOperationItemMapper.updatePatMedOperationItem(patMedOperationItem);
                        }
                    }
                }
@@ -1354,6 +1487,8 @@
                    ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTaskVO, ServiceSubtask.class);
                    serviceSubtask.setLibtemplateid(ObjectUtils.isEmpty(serviceTaskVO.getLibtemplateid()) ? null : Long.valueOf(serviceTaskVO.getLibtemplateid()));
                    serviceSubtask.setLibtemplatename(serviceTaskVO.getLibtemplatename());
                    serviceSubtask.setTemplateid(serviceTask.getTemplateid());
                    serviceSubtask.setTemplatename(serviceTask.getTemplatename());
                    serviceSubtask.setSendname(patTaskRelevance.getName());
                    serviceSubtask.setAge(patTaskRelevance.getAge());
                    serviceSubtask.setSfzh(patTaskRelevance.getSfzh());
@@ -2345,7 +2480,6 @@
        return phoneCallBackYQVO;
    }
    private String getObject(ServiceSubtask serviceSubtask, String scriptContent) {
        Map<String, Map<String, String>> param = getParam(serviceSubtask.getTaskid());
        for (Map<String, String> map : param.values()) {
@@ -2362,7 +2496,6 @@
        return scriptContent;
    }
    /**
     * 获取任务里的通配符
@@ -2412,7 +2545,6 @@
        }
        return map;
    }
    /**
     * 雨绮任务拉取
@@ -2482,7 +2614,6 @@
        log.info("-----------实际拉取的电话数据量:{}", CollectionUtils.isNotEmpty(pullTaskVOList) ? pullTaskVOList.size() : null);
        return pullTaskVOList;
    }
    private List<PullTaskVO> getPullTaskList(List<String> subIds, String cacheName) {
        log.error("任务拉取subIds的值是多少:{}", subIds);
@@ -2555,7 +2686,6 @@
        return pullTaskVOList;
    }
    @Override
    public Integer saveQuestionAnswerPhone(ServiceSubTaskDetailReq serviceSubTaskDetailReq) {
@@ -2815,7 +2945,7 @@
     * @return
     */
    @Override
    @Cacheable(value = "sfStatistics", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()")
//    @Cacheable(value = "sfStatistics", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()")
    public List<ServiceSubtaskStatistic> getSfStatistics(ServiceSubtaskCountReq serviceSubtaskCountReq) {
        log.info("getSfStatistics的入参为:{}", serviceSubtaskCountReq);
        String drcode = "drcode";
@@ -2849,6 +2979,10 @@
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrcode()).orElse("Unknown")));
                break;
            case "management_doctor_code":
                rawData = rawData.stream().peek(item -> {
                    item.setDrname(item.getManagementDoctor());
                    item.setDrcode(item.getManagementDoctorCode());
                }).collect(Collectors.toList());
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getManagementDoctorCode()).orElse("Unknown")));
                break;
            case "deptcode":
@@ -2933,6 +3067,8 @@
        ssRate.setOrgid(serviceSubtaskCountReq.getOrgid());
        ssRate.setStarttime(serviceSubtaskCountReq.getStartTime());
        ssRate.setEndtime(serviceSubtaskCountReq.getEndTime());
        ssRate.setStartOutHospTime(serviceSubtaskCountReq.getHospitalStartTime());
        ssRate.setEndOutHospTime(serviceSubtaskCountReq.getHospitalEndTime());
        ssRate.setVisitCount(serviceSubtaskCountReq.getVisitCount());
        ssRate.setServiceTypeList(serviceSubtaskCountReq.getServiceType());
        if (serviceSubtaskCountReq.getEndTime() != null && new Date().before(serviceSubtaskCountReq.getEndTime())) {
@@ -2947,7 +3083,6 @@
        }
        return jsRates;
    }
    public List<ServiceSubtaskStatistic> getSfStatisticsExport(ServiceSubtaskCountReq serviceSubtaskCountReq) {
        List<ServiceSubtaskStatistic> sfStatistics = getSfStatistics(serviceSubtaskCountReq);
@@ -3024,6 +3159,8 @@
            if (serviceSubtaskCountReq.getEndTime() != null && new Date().before(serviceSubtaskCountReq.getEndTime())) {
                ss.setEndtime(new Date());
            }
            ss.setStartOutHospTime(serviceSubtaskCountReq.getHospitalStartTime());
            ss.setEndOutHospTime(serviceSubtaskCountReq.getHospitalEndTime());
            Double jsRate = serviceSubtaskMapper.selectTimelyRate(ss);
            statistic.setRate(jsRate);
            if (ObjectUtils.isNotEmpty(statistic)) {
@@ -3033,13 +3170,15 @@
        if (CollectionUtils.isNotEmpty(serviceSubtaskStatistics)) {
            for (ServiceSubtaskStatistic serviceSubtaskStatistic : serviceSubtaskStatistics) {
                //所有满意度数量
                //满意度模块化后:满意度指数据此改为调用满意度模块门面;
                //模块关闭时门面返回全零 Map(与被迁移实现的实际输出一致),不影响随访统计其它字段。
                if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getDeptcodes())) {
                    Map<String, Object> satisfactionIndex = getSatisfactionIndex("1", serviceSubtaskStatistic.getDeptcode(), orgid, serviceSubtaskCountReq.getIvrCategoryid(), serviceSubtaskCountReq.getSvyCategoryid());
                    Map<String, Object> satisfactionIndex = satisfactionFacade.getSatisfactionIndex("1", serviceSubtaskStatistic.getDeptcode(), orgid, serviceSubtaskCountReq.getIvrCategoryid(), serviceSubtaskCountReq.getSvyCategoryid());
                    serviceSubtaskStatistic.setJoyAllCount(satisfactionIndex.get("mydtmzl") != null ? (Integer) satisfactionIndex.get("mydtmzl") : 0);
                    serviceSubtaskStatistic.setJoyCount(satisfactionIndex.get("mydtbl") != null ? (Integer) satisfactionIndex.get("mydtbl") : 0);
                    serviceSubtaskStatistic.setJoyTotal((Double) satisfactionIndex.get("wcbl"));
                } else if (CollectionUtils.isNotEmpty(serviceSubtaskCountReq.getLeavehospitaldistrictcodes())) {
                    Map<String, Object> satisfactionIndex = getSatisfactionIndex("2", serviceSubtaskStatistic.getLeavehospitaldistrictcode(), orgid, serviceSubtaskCountReq.getIvrCategoryid(), serviceSubtaskCountReq.getSvyCategoryid());
                    Map<String, Object> satisfactionIndex = satisfactionFacade.getSatisfactionIndex("2", serviceSubtaskStatistic.getLeavehospitaldistrictcode(), orgid, serviceSubtaskCountReq.getIvrCategoryid(), serviceSubtaskCountReq.getSvyCategoryid());
                    serviceSubtaskStatistic.setJoyAllCount(satisfactionIndex.get("mydtmzl") != null ? (Integer) satisfactionIndex.get("mydtmzl") : 0);
                    serviceSubtaskStatistic.setJoyCount(satisfactionIndex.get("mydtbl") != null ? (Integer) satisfactionIndex.get("mydtbl") : 0);
                    serviceSubtaskStatistic.setJoyTotal((Double) satisfactionIndex.get("wcbl"));
@@ -3049,103 +3188,6 @@
        return serviceSubtaskStatistics;
    }
    /**
     * 获取满意度题目总量
     * type : 1-科室   2病区
     * code: 科室或病区code
     *
     * @return
     */
    private Map<String, Object> getSatisfactionIndex(String type, String code, String orgid, Long ivrCategoryid, Long svyCategoryid) {
        Map<String, Object> map = new HashMap<>();
        List<ServiceTask> serviceTasks = null;
        if (type.equals("1")) {
            ServiceTask serviceTask = new ServiceTask();
            serviceTask.setDeptcode(code);
            serviceTask.setOrgid(orgid);
            serviceTasks = serviceTaskService.selectServiceTaskList(serviceTask);
        } else if (type.equals("2")) {
            ServiceTask serviceTask = new ServiceTask();
            serviceTask.setLeavehospitaldistrictcode(code);
            serviceTask.setOrgid(orgid);
            serviceTasks = serviceTaskService.selectServiceTaskList(serviceTask);
        }
        //获取满意度题目总量
        BigDecimal mydtmzlsum = new BigDecimal(0);
        //获取满意度题目填报量
        BigDecimal mydtblsum = new BigDecimal(0);
        if (CollectionUtils.isNotEmpty(serviceTasks)) {
            //获取满意度题目总量
            for (ServiceTask serviceTask : serviceTasks) {
                if (serviceTask.getType().equals("1")) {
                    //语音
                    Long templateid = serviceTask.getTemplateid();
                    IvrTaskTemplateScript ivrTaskTemplateScript = new IvrTaskTemplateScript();
                    ivrTaskTemplateScript.setTemplateID(templateid);
                    ivrTaskTemplateScript.setOrgid(serviceTask.getOrgid());
                    //先默认为1吧,assortid=1  代表是满意度
                    ivrTaskTemplateScript.setScriptAssortid(ivrCategoryid);
                    List<IvrTaskTemplateScript> ivrTaskTemplateScripts = iIvrTaskTemplateScriptService.selectIvrTaskTemplateScriptList(ivrTaskTemplateScript);
                    if (CollectionUtils.isNotEmpty(ivrTaskTemplateScripts)) {
                        //需要先计算出发送量,再乘以单个问券满意度题目数量,得到满意度题目总量(包含了未做的)
                        ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
                        serviceSubtaskVO.setTaskid(serviceTask.getTaskid());
                        List<Long> sendstates = new ArrayList<>(Arrays.asList(3L, 5L, 6L));
                        serviceSubtaskVO.setSendstates(sendstates);
                        List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskBySendstate(serviceSubtaskVO);
                        if (CollectionUtils.isNotEmpty(serviceSubtaskList)) {
                            int mydtmzlCount = ivrTaskTemplateScripts.size() * serviceSubtaskList.size();
                            mydtmzlsum.add(new BigDecimal(mydtmzlCount));
                        }
                    }
                } else if (serviceTask.getType().equals("2")) {
                    //问卷
                    SvyTaskTemplateScript svyTaskTemplateScript = new SvyTaskTemplateScript();
                    svyTaskTemplateScript.setTemplateID(serviceTask.getTemplateid());
                    svyTaskTemplateScript.setOrgid(serviceTask.getOrgid());
                    svyTaskTemplateScript.setCategoryid(svyCategoryid);
                    List<SvyTaskTemplateScript> svyTaskTemplateScriptList = svyTaskTemplateScriptService.selectSvyTaskTemplateScriptList(svyTaskTemplateScript);
                    if (CollectionUtils.isNotEmpty(svyTaskTemplateScriptList)) {
                        ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
                        serviceSubtaskEntity.setTaskid(serviceTask.getTaskid());
                        List<Long> sendstates = new ArrayList<>(Arrays.asList(3L, 5L, 6L));
                        serviceSubtaskEntity.setSendstates(sendstates);
                        List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskBySendstate(serviceSubtaskEntity);
                        if (CollectionUtils.isNotEmpty(serviceSubtaskList)) {
                            int mydtmzlCount = svyTaskTemplateScriptList.size() * serviceSubtaskList.size();
                            mydtmzlsum.add(new BigDecimal(mydtmzlCount));
                        }
                    }
                }
                //获取满意度题目填报量
                ServiceSubtaskDetail serviceSubtaskDetail = new ServiceSubtaskDetail();
                serviceSubtaskDetail.setTaskid(serviceTask.getTaskid());
                if (serviceTask.getType().equals("1")) serviceSubtaskDetail.setCategoryid(ivrCategoryid);
                if (serviceTask.getType().equals("2")) serviceSubtaskDetail.setCategoryid(svyCategoryid);
                serviceSubtaskDetail.setOrgid(serviceTask.getOrgid());
                List<ServiceSubtaskDetail> serviceSubtaskDetails = serviceSubtaskDetailMapper.selectServiceSubtaskDetailList(serviceSubtaskDetail);
                if (CollectionUtils.isNotEmpty(serviceSubtaskDetails))
                    mydtblsum.add(new BigDecimal(serviceSubtaskDetails.size()));
            }
        }
        //满意度题目总量
        map.put("mydtmzl", mydtmzlsum.intValue());
        map.put("mydtbl", mydtblsum.intValue());
        map.put("wcbl", 0.0);
        if (mydtmzlsum.intValue() != 0) {
            map.put("wcbl", mydtblsum.divide(mydtmzlsum, 2, RoundingMode.HALF_UP).doubleValue());
        }
        return map;
    }
    private ServiceSubtaskStatistic getStatistic(List<ServiceSubtask> serviceSubtaskList, String followUpCountStyle, Integer visitCount) {
        ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic();
@@ -3271,6 +3313,24 @@
                            serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L);
                        }
                    }
                    //首次随访人工成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) {
                        serviceSubtaskStatistic.setManualSuccess(serviceSubtaskStatistic.getManualSuccess() + 1L);
                    }
                    //首次随访语音成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) {
                        serviceSubtaskStatistic.setVoiceSuccess(serviceSubtaskStatistic.getVoiceSuccess() + 1L);
                    }
                    //首次随访短信成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) {
                        serviceSubtaskStatistic.setSmsSuccess(serviceSubtaskStatistic.getSmsSuccess() + 1L);
                    }
                    //首次随访微信成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) {
                        serviceSubtaskStatistic.setWeChatSuccess(serviceSubtaskStatistic.getWeChatSuccess() + 1L);
                    }
                    if (serviceSubtaskStatistic.getNeedFollowUp() > 0) {
                        double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccess() + serviceSubtaskStatistic.getFollowUpFail()) / serviceSubtaskStatistic.getNeedFollowUp();
                        serviceSubtaskStatistic.setFollowUpRate(percentFormat.format(rate));
@@ -3366,6 +3426,24 @@
                            serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L);
                        }
                    }
                    //再次随访人工成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) {
                        serviceSubtaskStatistic.setManualAgainSuccess(serviceSubtaskStatistic.getManualAgainSuccess() + 1L);
                    }
                    //再次随访语音成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) {
                        serviceSubtaskStatistic.setVoiceAgainSuccess(serviceSubtaskStatistic.getVoiceAgainSuccess() + 1L);
                    }
                    //再次随访短信成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) {
                        serviceSubtaskStatistic.setSmsAgainSuccess(serviceSubtaskStatistic.getSmsAgainSuccess() + 1L);
                    }
                    //再次随访微信成功
                    if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) {
                        serviceSubtaskStatistic.setWeChatAgainSuccess(serviceSubtaskStatistic.getWeChatAgainSuccess() + 1L);
                    }
                    if (serviceSubtaskStatistic.getNeedFollowUp() > 0) {
                        double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccessAgain() + serviceSubtaskStatistic.getFollowUpFailAgain()) / serviceSubtaskStatistic.getNeedFollowUpAgain();
                        serviceSubtaskStatistic.setFollowUpRateAgain(percentFormat.format(rate));
@@ -3520,6 +3598,24 @@
                        serviceSubtaskStatistic.setWeChat(serviceSubtaskStatistic.getWeChat() + 1L);
                    }
                }
                //首次随访人工成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) {
                    serviceSubtaskStatistic.setManualSuccess(serviceSubtaskStatistic.getManualSuccess() + 1L);
                }
                //首次随访语音成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) {
                    serviceSubtaskStatistic.setVoiceSuccess(serviceSubtaskStatistic.getVoiceSuccess() + 1L);
                }
                //首次随访短信成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) {
                    serviceSubtaskStatistic.setSmsSuccess(serviceSubtaskStatistic.getSmsSuccess() + 1L);
                }
                //首次随访微信成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) {
                    serviceSubtaskStatistic.setWeChatSuccess(serviceSubtaskStatistic.getWeChatSuccess() + 1L);
                }
                if (serviceSubtaskStatistic.getNeedFollowUp() > 0) {
                    double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccess() + serviceSubtaskStatistic.getFollowUpFail()) / serviceSubtaskStatistic.getNeedFollowUp();
                    serviceSubtaskStatistic.setFollowUpRate(percentFormat.format(rate));
@@ -3671,6 +3767,24 @@
                        serviceSubtaskStatistic.setWeChatAgain(serviceSubtaskStatistic.getWeChatAgain() + 1L);
                    }
                }
                //再次随访人工成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("1")) {
                    serviceSubtaskStatistic.setManualAgainSuccess(serviceSubtaskStatistic.getManualAgainSuccess() + 1L);
                }
                //再次随访语音成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("3")) {
                    serviceSubtaskStatistic.setVoiceAgainSuccess(serviceSubtaskStatistic.getVoiceAgainSuccess() + 1L);
                }
                //再次随访短信成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("4")) {
                    serviceSubtaskStatistic.setSmsAgainSuccess(serviceSubtaskStatistic.getSmsAgainSuccess() + 1L);
                }
                //再次随访微信成功
                if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) && ObjectUtils.isNotEmpty(serviceSubtask.getCurrentPreachform()) && serviceSubtask.getCurrentPreachform().equals("5")) {
                    serviceSubtaskStatistic.setWeChatAgainSuccess(serviceSubtaskStatistic.getWeChatAgainSuccess() + 1L);
                }
                if (serviceSubtaskStatistic.getNeedFollowUp() > 0) {
                    double rate = (double) (serviceSubtaskStatistic.getFollowUpSuccessAgain() + serviceSubtaskStatistic.getFollowUpFailAgain()) / serviceSubtaskStatistic.getNeedFollowUpAgain();
                    serviceSubtaskStatistic.setFollowUpRateAgain(percentFormat.format(rate));
@@ -3704,7 +3818,6 @@
        }
        return serviceSubtaskStatistic;
    }
    private ServiceSubtaskStatistic getStatisticJoy(List<ServiceSubtask> serviceSubtaskList, List<ServiceSubtaskCount> joySubCount) {
        ServiceSubtaskStatistic serviceSubtaskStatistic = new ServiceSubtaskStatistic();
@@ -3828,7 +3941,6 @@
        if (subCounts == null) {
            subCounts = new ArrayList<>();
        }
        for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
            List<ServiceSubtaskCount> subCountTemp = subCounts.stream().filter(r -> r.getSubTaskId().equals(serviceSubtask.getId())).collect(Collectors.toList());
@@ -4008,16 +4120,17 @@
        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
        //转成16进制
        String format = String.format("%03X", serviceOutPath.getId());
        String url = "";
        SendMagParam sendMagParam = new SendMagParam();
        url = localIP + ":" + req_path + "/sf?p=" + format;
        sendMagParam.setUrl(url);
        sendMagParam.setContent("【新华医院】您好,邀请您填写出院随访调查表,请点击" + sendMagParam.getUrl() + "填写。感谢您配合!");
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        serviceOutPath.setUrl(url);
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        SendMagParam sendMagParam = new SendMagParam();
        sendMagParam.setUrl(localIP + ":" + req_path + "/sf?p=" + format);
        sendMagParam.setContent("【新华医院】您好,邀请您填写出院随访调查表,请点击" + sendMagParam.getUrl() + "填写。感谢您配合!");
        Map<String, String> map = new HashMap<>();
        map.put("phone", serviceSubtask.getPhone());
        map.put("content", sendMagParam.getContent());
        HttpUtil.postJsonRequest(xhsmsPath, new Gson().toJson(map));
        //短信发送已收口到 ruoyi-message 模块;与原实现一致:不判断发送结果
        smsSenderFactory.send(active, SmsSendRequest.of(serviceSubtask.getPhone(), sendMagParam.getContent(), serviceSubtask.getOrgid()));
        redisCache.setCacheObject(subTaskId + "recordAccept-hungup", "1", 10, TimeUnit.MINUTES);
        if (StringUtils.isNotEmpty(serviceSubtask.getRemark()))
            serviceSubtask.setRemark("电话发送拒接,短信补偿发送成功");
@@ -4098,6 +4211,10 @@
     * voiceInfo - visitCount = 1 && currentPreachForm = "3"
     * smsInfo - visitCount = 1 && currentPreachForm = "4"
     * wechatInfo - visitCount = 1 && currentPreachForm = "5"
     * manualSuccessInfo - visitCount = 1 && currentPreachForm = "1" && sendstate = 6
     * voiceSuccessInfo - visitCount = 1 && currentPreachForm = "3" && sendstate = 6
     * smsSuccessInfo - visitCount = 1 && currentPreachForm = "4" && sendstate = 6
     * wechatSuccessInfo - visitCount = 1 && currentPreachForm = "5" && sendstate = 6
     * abnormalInfo - visitCount = 1 && excep = "1"
     * needFollowUpAgainInfo - visitCount > 1 && sendstate != 4
     * pendingFollowUpAgainInfo -  visitCount > 1 && sendstate = 2
@@ -4107,6 +4224,10 @@
     * voiceAgainInfo - visitCount > 1 && currentPreachForm = "3"
     * smsAgainInfo - visitCount > 1 && currentPreachForm = "4"
     * wechatAgainInfo -  visitCount > 1 && currentPreachForm = "5"
     * manualAgainSuccessInfo - visitCount > 1 && currentPreachForm = "1" && sendstate = 6
     * voiceAgainSuccessInfo - visitCount > 1 && currentPreachForm = "3" && sendstate = 6
     * smsAgainSuccessInfo - visitCount > 1 && currentPreachForm = "4" && sendstate = 6
     * wechatAgainSuccessInfo - visitCount > 1&& currentPreachForm = "5" && sendstate = 6
     * abnormalAgainInfo- visitCount = 1 && excep = "1"
     * taskSituation1Info - taskSituation = 1
     * taskSituation2Info - taskSituation = 2
@@ -4190,6 +4311,26 @@
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setCurrentPreachform("5");
                break;
            case "manualSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("1");
                break;
            case "voiceSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("3");
                break;
            case "smsSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("4");
                break;
            case "wechatSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("5");
                break;
            case "abnormalInfo":
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setExcep("1");
@@ -4226,6 +4367,26 @@
                serviceSubtaskCountReq.setVisitCount(2);
                serviceSubtaskCountReq.setCurrentPreachform("5");
                break;
            case "manualAgainSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(1);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("1");
                break;
            case "voiceAgainSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(2);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("3");
                break;
            case "smsAgainSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(2);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("4");
                break;
            case "wechatAgainSuccessInfo":
                serviceSubtaskCountReq.setVisitCount(2);
                serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L)));
                serviceSubtaskCountReq.setCurrentPreachform("5");
                break;
            case "abnormalAgainInfo":
                serviceSubtaskCountReq.setVisitCount(2);
                serviceSubtaskCountReq.setExcep("1");
@@ -4256,7 +4417,6 @@
                break;
        }
    }
    /**
     * 获取随访统计比例
@@ -4479,7 +4639,6 @@
        return result;
    }
    /**
     * @param serviceSubtask
     * @param preachform
@@ -4510,7 +4669,6 @@
            serviceSubtaskPreachform1.setSendstate(failSendstate);
            serviceSubtaskPreachform1.setRemark(remark);
            serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(serviceSubtaskPreachform1);
            //如果当前的preachform已经是最后一个了,那直接将serviceSubtask的sendstate状态改成5就行了(全失败了)
            if (serviceSubtaskPreachform1.getSort() == spSize.size() && failSendstate.equals("4")) {
@@ -4557,7 +4715,6 @@
        }
        return visitTime;
    }
    /**
     * 计算总计行
@@ -4889,6 +5046,12 @@
        String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key);
        String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key);
        //丽水中医院发送的是微信公众号
        if (StringUtils.isNotEmpty(serviceSubtask.getOrgid()) && serviceSubtask.getOrgid().equals("47231022633110211A2101")) {
            resultMap = wechatSubTask(subid);
            return resultMap;
        }
        //发送数据的封装
        ServiceOutPath serviceOutPath = new ServiceOutPath();
        serviceOutPath.setParam1(taskId);
@@ -4899,15 +5062,17 @@
        serviceOutPath.setOrgid(serviceSubtask.getOrgid());
        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
        String format = String.format("%03X", serviceOutPath.getId());
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        String url = "";
        SendMagParam sendMagParam = new SendMagParam();
        sendMagParam.setType("4");
        sendMagParam.setPhone(serviceSubtask.getPhone());
        sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format);
        url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format;
        sendMagParam.setUrl(url);
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        serviceOutPath.setUrl(url);
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        SysConfig sysConfig = new SysConfig();
        sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template");
@@ -4917,9 +5082,11 @@
            sendMagParam.setContent(smsContemt.replace("${wjurl}", sendMagParam.getUrl()));
        }
        //短信发送:各站点对接方式差异较大,已收口到 ruoyi-message 模块
        if (active.equals("nhfy")) {
            Map<String, Object> smsResult = mtSubmitSmUtil.submitSm(sendMagParam.getPhone(), sendMagParam.getContent());
            if (smsResult != null && smsResult.get("result") != null && smsResult.get("result").toString().equals("0")) {
            SendResult smsResult = smsSenderFactory.send(active,
                    SmsSendRequest.of(sendMagParam.getPhone(), sendMagParam.getContent(), serviceSubtask.getOrgid()));
            if (smsResult.isOk()) {
                resultMap.put("code", "200");
                resultMap.put("msg", "发送成功");
                serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ";短信发送成功(手动提交)" : "短信发送成功(手动提交)");
@@ -4931,14 +5098,78 @@
        return resultMap;
    }
    @Override
    public List<ServiceSubtaskDetailRatioExport> statQuestionOption(List<Long> taskIds, Date startOutHospTime, Date endOutHospTime) {
        //先清理一下重复数据
        List<Long> repeatIds = serviceSubtaskDetailMapper.selectRepeatDetailIds();
        if (!CollectionUtils.isEmpty(repeatIds)) {
            serviceSubtaskDetailMapper.deleteRepeatDetailByIds(repeatIds);
    public Map<String,Object> wechatSubTask(Long subid){
        log.info("wechatSubTask的入参为:{}", subid);
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", "500");
        resultMap.put("msg", "发送失败");
        try{
            //获取随访的基本信息
            ServiceSubtask serviceSubtask = selectServiceSubtaskById(subid);
            //获取患者信息
            PatArchive patArchive = patArchiveMapper.selectPatArchiveByPatid(serviceSubtask.getPatid());
            RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
            String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key);
            String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key);
            String taskId = rsaPublicKeyExample.encryptedData(serviceSubtask.getTaskid().toString(), pub_key);
            String url = localIP + ":" + req_path + "/outsideChainwt?param1=" + taskId + "&param2=" + patid + "&param3="
                    + URLEncoder.encode(serviceSubtask.getTaskName(), StandardCharsets.UTF_8.toString()) + "&param5=false"
                    + "$param6=" + subId;
            ServiceOutPath serviceOutPath = new ServiceOutPath();
            serviceOutPath.setParam1(taskId);
            serviceOutPath.setParam2(patid);
            serviceOutPath.setParam3(serviceSubtask.getTaskName());
            serviceOutPath.setParam6(subId);
            serviceOutPath.setCreateTime(new Date());
            serviceOutPath.setOrgid(serviceSubtask.getOrgid());
            iServiceOutPathService.insertServiceOutPath(serviceOutPath);
            String format = String.format("%03X", serviceOutPath.getId());
            serviceOutPath.setRadix(format);
            serviceOutPath.setUpdateTime(new Date());
            serviceOutPath.setUrl(url);
            iServiceOutPathService.updateServiceOutPath(serviceOutPath);
            //his患者id校验(与原实现一致:先校验这一项)
            if (StringUtils.isEmpty(serviceSubtask.getPatidHis())) {
                resultMap.put("code", -1);
                resultMap.put("message", "发送异常:" + "【公众号】公众号发送失败,his系统的患者id为空");
                return resultMap;
            }
            //机构配置校验、报文签名与返回判定均已收口到 ruoyi-message 的发送方实现
            WechatSendRequest wechatRequest = new WechatSendRequest();
            wechatRequest.setOrgid(serviceSubtask.getOrgid());
            wechatRequest.setIdCard(serviceSubtask.getSfzh());
            wechatRequest.setUrl(url);
            wechatRequest.setTitle(serviceSubtask.getTaskName());
            wechatRequest.setContent(serviceSubtask.getTaskDesc());
            wechatRequest.setPhone(patArchive.getTelcode());
            wechatRequest.setPatientName(serviceSubtask.getSendname());
            wechatRequest.setPatidHis(patArchive.getPatidHis());
            SendResult wechatResult = wechatSenderFactory.send(active, wechatRequest);
            //发送完成后,修改状态
            serviceSubtask.setSendstate(3L);
            if (wechatResult.isOk()) {
                serviceSubtask.setResult("success");
                resultMap.put("code", "200");
                resultMap.put("msg", "发送成功");
            } else {
                log.error("【sfHandlle】公众号发送失败,患者信息:{},错误信息:{}", serviceSubtask, wechatResult.getMessage());
                resultMap.put("code", -1);
                resultMap.put("message", "【公众号】公众号发送失败");
                return resultMap;
            }
        } catch (Exception e) {
            String guid = UUID.randomUUID().toString();
            log.error("【sfHandlle】长期任务公众号发送失败,原因:{},GUID:{}", e.getMessage(), guid);
            resultMap.put("code", -1);
            resultMap.put("message", "【公众号】长期任务公众号发送失败,原因:" + e.getMessage());
            return resultMap;
        }
        return serviceSubtaskMapper.statQuestionOption(taskIds, startOutHospTime, endOutHospTime);
        return resultMap;
    }
    private Boolean saveServiceSubtaskDetail(ServiceSubtask serviceSubtask) {
@@ -5186,7 +5417,39 @@
        Date newDate = new Date();
        serviceSubtask.setLongSendTime(newDate);
        serviceSubtask.setVisitTime(newDate);
        // 院区:/scanGenerateSubtask 是匿名接口(SecurityConfig permitAll),取不到登录用户;
        // 而 service_task.campusid 在本库是占位值 '1',直接沿用会让统计接口(@AddOrgId 按院区过滤)查不到数据。
        // 这里用任务配置的病区(其次科室)反查 sys_dept.campusid 落库,保证问卷统计能按院区取到。
        String campusIdByDept = queryCampusIdByDeptCode(serviceSubtask.getLeavehospitaldistrictcode(), serviceTask.getOrgid());
        if (StringUtils.isEmpty(campusIdByDept)) {
            campusIdByDept = queryCampusIdByDeptCode(serviceSubtask.getDeptcode(), serviceTask.getOrgid());
        }
        if (StringUtils.isNotEmpty(campusIdByDept)) {
            serviceSubtask.setCampusid(campusIdByDept);
        }
        // 只配了科室(没有病区)的满意度任务:这道答卷在按病区筛选的报表里统计不到,留日志便于运维发现
        if (StringUtils.isEmpty(serviceSubtask.getLeavehospitaldistrictcode())
                && ("6".equals(serviceSubtask.getServiceType()) || "14".equals(serviceSubtask.getServiceType()))) {
            log.warn("【扫码生成任务】满意度子任务没有病区,按病区筛选的报表将统计不到该答卷:taskid={}, deptcode={}, campusid={}",
                    serviceSubtask.getTaskid(), serviceSubtask.getDeptcode(), serviceSubtask.getCampusid());
        }
        return serviceSubtask;
    }
    /**
     * 按科室/病区编码反查所属院区(查不到返回 null)
     */
    private String queryCampusIdByDeptCode(String deptCode, String orgid) {
        if (StringUtils.isEmpty(deptCode)) {
            return null;
        }
        try {
            SysDept sysDept = sysDept2Mapper.selectDeptByCode(deptCode, orgid);
            return sysDept == null ? null : sysDept.getCampusid();
        } catch (Exception e) {
            log.warn("按编码反查院区失败:deptCode={}, orgid={}, err={}", deptCode, orgid, e.getMessage());
            return null;
        }
    }
    /**
@@ -5197,6 +5460,7 @@
     * @param options
     * @return
     */
    @Override
    public Integer matchOptionIndex(String url, String questionText, String voiceText, List<IvrTaskTemplateTargetoption> options, String uuid) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userQuestion", questionText);
@@ -5224,12 +5488,167 @@
        }
    }
    public PhoneCallBackSHVO getFirstQues(PhoneCallReqYQVO phoneCallReqYQVO) {
        //用于返回
        PhoneCallBackSHVO phoneCallBackSHVO = new PhoneCallBackSHVO();
        //根据手机号获取用户的的子任务信息
        ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
        serviceSubtaskVO.setPhone(phoneCallReqYQVO.getPhone());
        serviceSubtaskVO.setType("1");
        serviceSubtaskVO.setSendstate(2L);
        List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
        if (CollectionUtils.isNotEmpty(serviceSubtasks)) {
            ServiceSubtask serviceSubtask = serviceSubtasks.get(0);
            IvrTaskTemplate ivrTaskTemplate = ivrTaskTemplateService.selectIvrTaskTemplateByID(serviceSubtask.getTemplateid());
            //通过任务模板中的"第一次问题编号"获取第一个问题;
            IvrTaskTemplateScript ivrTaskTemplateScript = null;
            IvrTaskTemplateScript ivrTaskTemplateScript1 = new IvrTaskTemplateScript();
            ivrTaskTemplateScript1.setTemplateID(ivrTaskTemplate.getId());
            List<IvrTaskTemplateScript> ivrTaskTemplateScripts = iIvrTaskTemplateScriptService.selectIvrTaskTemplateScriptList(ivrTaskTemplateScript1);
            for (IvrTaskTemplateScript ivrTaskTemplateScript2 : ivrTaskTemplateScripts) {
                if (ivrTaskTemplate.getFirstQuestionNum() == Long.valueOf(ivrTaskTemplateScript2.getSort())) {
                    ivrTaskTemplateScript = ivrTaskTemplateScript2;
                    break;
                }
            }
            //获取开场白
            ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
            phoneCallBackSHVO.setSubId(serviceSubtask.getId());
            phoneCallBackSHVO.setScriptId(ivrTaskTemplateScript.getId());
            phoneCallBackSHVO.setSort(ivrTaskTemplateScript.getSort());
            phoneCallBackSHVO.setTaskTemplateid(ivrTaskTemplateScript.getTemplateID());
            phoneCallBackSHVO.setScriptContent(serviceTask.getKcb() + "," + ivrTaskTemplateScript.getScriptContent());
        }
        return phoneCallBackSHVO;
    }
    /**
     * 三汇ASR结果处理
     *
     * @param phoneCallResultYQVO
     * @return
     */
    public PhoneCallBackSHVO processResust(PhoneCallResultYQVO phoneCallResultYQVO) {
        PhoneCallBackSHVO phoneCallBackSHVO = new PhoneCallBackSHVO();
        //通过scriptid,获取所有的结果
        String url = configService.selectConfigByKey("sys.voice.match.ai.url", phoneCallResultYQVO.getOrgid());
        ServiceSubtask serviceSubtask = serviceSubtaskMapper.selectServiceSubtaskById(phoneCallResultYQVO.getSubId());
        IvrTaskTemplate ivrTaskTemplate = ivrTaskTemplateService.selectIvrTaskTemplateByID(serviceSubtask.getTemplateid());
        IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO = iIvrTaskTemplateScriptService.getTaskTempScriptInfoByid(Long.valueOf(phoneCallResultYQVO.getScriptId()));
        Integer i = matchOptionIndex(url, phoneCallResultYQVO.getScriptContent(), phoneCallResultYQVO.getAsrResult(), ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList(), phoneCallResultYQVO.getUuid());
        if (i >= 0) {
            String optiondesc = ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList().get(i).getOptiondesc();
            //将患者的回答写进service_subtask_detail中
            ServiceSubTaskDetailReq serviceSubTaskDetailReq = new ServiceSubTaskDetailReq();
            List<ServiceSubtaskDetail> serviceSubtaskDetailList = new ArrayList<>();
            ivrTaskTemplateScriptVO.setQuestionResult(optiondesc);
            PhoneCallReqYQVO phoneCallReqYQVO = new PhoneCallReqYQVO();
            phoneCallReqYQVO.setTaskid("" + serviceSubtask.getId());
            phoneCallReqYQVO.setPhone(phoneCallResultYQVO.getPhone());
            phoneCallReqYQVO.setAsrtext(phoneCallResultYQVO.getAsrResult());
            ServiceSubtaskDetail serviceSubtaskDetail = getServiceSubtaskDetail(phoneCallReqYQVO, ivrTaskTemplateScriptVO, serviceSubtask, ivrTaskTemplate);
            //修改一下语音路径(改成前端可以访问的,存到数据库中)
            if (StringUtils.isNotEmpty(serviceSubtaskDetail.getQuestionvoice())) {
                String questionvoice = serviceSubtaskDetail.getQuestionvoice();
                String[] split = questionvoice.split("\\\\");
                if (split.length > 0) {
                    String lastPart = split[split.length - 1];
                    serviceSubtaskDetail.setQuestionvoice(voicePathPrefix + lastPart);
                }
            }
            serviceSubtaskDetailList.add(serviceSubtaskDetail);
            serviceSubTaskDetailReq.setServiceSubtaskDetailList(serviceSubtaskDetailList);
            serviceSubTaskDetailReq.setGuid(phoneCallResultYQVO.getGuid());
            serviceSubTaskDetailReq.setOrgid(phoneCallResultYQVO.getOrgid());
            saveQuestionAnswerPhone(serviceSubTaskDetailReq);
            IvrTaskTemplateScript ivrTaskTemplateScript = new IvrTaskTemplateScript();
            ivrTaskTemplateScript.setTemplateID(ivrTaskTemplateScriptVO.getTemplateID());
            List<IvrTaskTemplateScript> ivrTaskTemplateScripts = iIvrTaskTemplateScriptService.selectIvrTaskTemplateScriptList(ivrTaskTemplateScript);
            //获取下一题
            for (IvrTaskTemplateScript script : ivrTaskTemplateScripts) {
                if (ivrTaskTemplateScriptVO.getNextScriptno() == null || ivrTaskTemplateScriptVO.getNextScriptno() == 0) {
                    ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                    phoneCallBackSHVO.setScriptContent(serviceTask.getJsy());
                    phoneCallBackSHVO.setTaskTemplateid(script.getTemplateID());
                    phoneCallBackSHVO.setSort(script.getSort());
                    phoneCallBackSHVO.setScriptId(script.getId());
                    phoneCallBackSHVO.setSubId(serviceSubtask.getId());
                    phoneCallBackSHVO.setStatus("0");
                } else if (script.getSort() == ivrTaskTemplateScriptVO.getNextScriptno().intValue()) {
                    phoneCallBackSHVO.setScriptContent(script.getScriptContent());
                    phoneCallBackSHVO.setTaskTemplateid(script.getTemplateID());
                    phoneCallBackSHVO.setSort(script.getSort());
                    phoneCallBackSHVO.setScriptId(script.getId());
                    phoneCallBackSHVO.setSubId(serviceSubtask.getId());
                    break;
                }
            }
            //把缓存清除
            redisCache.deleteObject(phoneCallResultYQVO.getSubId() + "-" + phoneCallResultYQVO.getScriptId());
        } else {
            //再将重复询问
            //记录一下这个问题被问题的次数
            Object cacheObject = redisCache.getCacheObject(phoneCallResultYQVO.getSubId() + "-" + phoneCallResultYQVO.getScriptId());
            if (cacheObject == null || (Integer) cacheObject < ivrTaskTemplate.getMateNum()) {
                // 获取选项集合中的 optiondesc 用于引导患者
                List<IvrTaskTemplateTargetoption> optionList = ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList();
                String optionDescStr = "";
                if (optionList != null && !optionList.isEmpty()) {
                    optionDescStr = optionList.stream().map(IvrTaskTemplateTargetoption::getTargetvalue).filter(StringUtils::isNotEmpty).collect(Collectors.joining("或"));
                }
                String scriptContent = "请问" + phoneCallResultYQVO.getScriptContent();
                if (StringUtils.isNotEmpty(optionDescStr)) {
                    scriptContent += ",你可以回答:" + optionDescStr;
                }
                phoneCallBackSHVO.setScriptContent(scriptContent);
                phoneCallBackSHVO.setTaskTemplateid(phoneCallResultYQVO.getTaskTemplateid());
                phoneCallBackSHVO.setSort(phoneCallResultYQVO.getSort());
                phoneCallBackSHVO.setScriptId(phoneCallResultYQVO.getScriptId());
                phoneCallBackSHVO.setSubId(phoneCallResultYQVO.getSubId());
                if (cacheObject == null)
                    redisCache.setCacheObject(phoneCallResultYQVO.getSubId() + "-" + phoneCallResultYQVO.getScriptId(), 1, 120, TimeUnit.MINUTES);
                else
                    redisCache.setCacheObject(phoneCallResultYQVO.getSubId() + "-" + phoneCallResultYQVO.getScriptId(), (Integer) cacheObject + 1, 120, TimeUnit.MINUTES);
            } else if ((Integer) cacheObject >= ivrTaskTemplate.getMateNum()) {
                //如果已经问了规定次数,就不问了,继续问下一题(这个要商量一下,是继续问下一题,还是停了,是不是要做个开关)
                IvrTaskTemplateScript ivrTaskTemplateScript = new IvrTaskTemplateScript();
                ivrTaskTemplateScript.setTemplateID(ivrTaskTemplateScriptVO.getTemplateID());
                List<IvrTaskTemplateScript> ivrTaskTemplateScripts = iIvrTaskTemplateScriptService.selectIvrTaskTemplateScriptList(ivrTaskTemplateScript);
                //获取下一题
                for (IvrTaskTemplateScript script : ivrTaskTemplateScripts) {
                    if (script.getSort() == ivrTaskTemplateScriptVO.getNextScriptno().intValue()) {
                        phoneCallBackSHVO.setScriptContent(script.getScriptContent());
                        phoneCallBackSHVO.setTaskTemplateid(script.getTemplateID());
                        phoneCallBackSHVO.setSort(script.getSort());
                        phoneCallBackSHVO.setScriptId(script.getId());
                        phoneCallBackSHVO.setSubId(serviceSubtask.getId());
                        break;
                    }
                }
                //把缓存清除
                redisCache.deleteObject(phoneCallResultYQVO.getSubId() + "-" + phoneCallResultYQVO.getScriptId());
            }
        }
        return phoneCallBackSHVO;
    }
    public PhoneCallBackYQVO AiMatch(String url, PhoneCallReqYQVO phoneCallReqYQVO, PhoneCallBackYQVO phoneCallBackYQVO, IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO, ServiceSubtask serviceSubtask, IvrTaskTemplate ivrTaskTemplate, List<IvrTaskTemplateScript> ivrTaskTemplateScripts, String scriptId, Integer flag, String uuid) {
        PhoneCallBackYQVO back = null;
        List<IvrTaskTemplateTargetoption> options = ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList();
        String voiceText = phoneCallReqYQVO.getAsrtext();
        String questionText = StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getIvrtext()) ? ivrTaskTemplateScriptVO.getIvrtext() : ivrTaskTemplateScriptVO.getScriptContent();
        Integer matched = -1;
        log.info("AI匹配:url = {},questionText = {},voiceText = {},options = {},uuid ={}",
                url,questionText,voiceText,options,uuid);
        matched = matchOptionIndex(url, questionText, voiceText, options, uuid);
        //说明匹配正确了
        if (matched != null && matched >= 0) {
@@ -5323,7 +5742,8 @@
                phoneCallBackYQVO.setValue(phoneCallBackYQVO.getCommonValue() + serviceTask.getJsy());
                //记录状态
                setFailPreachForm(serviceSubtask, "3", "电话拨打已完成", "9");
                return phoneCallBackYQVO;
                back = phoneCallBackYQVO;
                return back;
            }
            flag = 1;
@@ -5331,9 +5751,10 @@
            redisCache.deleteObject(phoneCallReqYQVO.getUuid() + "PlayEventCallbackPlaystop");
//                        //获取下一题
            log.error("获取下一题的信息:{}", ivrTaskTemplateScriptVO);
            if (ivrTaskTemplateScriptVO.getBranchFlag().equals("1") || ivrTaskTemplateScriptVO.getBranchFlag().equals("0") && ivrTaskTemplateScriptVO.getNextScriptno() != null && ivrTaskTemplateScriptVO.getNextScriptno() != 0) {
            //branchFlag为null时按分支0处理,避免NPE
            if ("1".equals(ivrTaskTemplateScriptVO.getBranchFlag()) || "0".equals(ivrTaskTemplateScriptVO.getBranchFlag()) && ivrTaskTemplateScriptVO.getNextScriptno() != null && ivrTaskTemplateScriptVO.getNextScriptno() != 0) {
                Long nextQuestion = null;
                if (ivrTaskTemplateScriptVO.getBranchFlag().equals("1")) {
                if ("1".equals(ivrTaskTemplateScriptVO.getBranchFlag())) {
                    nextQuestion = chosenOption.getNextQuestion();
                    //更新分数
                    double score = redisCache.getCacheObject(phoneCallReqYQVO.getUuid() + "SCORE");
@@ -5366,15 +5787,9 @@
                    redisCache.setCacheObject(phoneCallReqYQVO.getUuid() + "- jsy", serviceTask.getJsy(), 120, TimeUnit.MINUTES);
                    phoneCallBackYQVO.setType("text");
                    phoneCallBackYQVO.setValue(phoneCallBackYQVO.getCommonValue() + serviceTask.getJsy());
                    //将结果写进detail表
                    ServiceSubTaskDetailReq ssdReq = new ServiceSubTaskDetailReq();
                    List<ServiceSubtaskDetail> serviceSubtaskDetailList2 = new ArrayList<>();
                    serviceSubtaskDetailList.add(getServiceSubtaskDetail(phoneCallReqYQVO, ivrTaskTemplateScriptVO, serviceSubtask, ivrTaskTemplate));
                    serviceSubTaskDetailReq.setServiceSubtaskDetailList(serviceSubtaskDetailList2);
                    ssdReq.setGuid(phoneCallReqYQVO.getGuid());
                    ssdReq.setOrgid(phoneCallReqYQVO.getOrgid());
                    saveQuestionAnswerPhone(ssdReq);
                    return phoneCallBackYQVO;
                    //明细在本题匹配成功时已落库(见上方 saveQuestionAnswerPhone),这里不再重复保存
                    back = phoneCallBackYQVO;
                    return back;
                }
                for (IvrTaskTemplateScript script : ivrTaskTemplateScripts) {
@@ -5391,6 +5806,15 @@
                        redisCache.deleteObject(phoneCallReqYQVO.getTaskid().trim() + "&&" + "mate" + "&&" + phoneCallReqYQVO.getUuid());
                    }
                }
                //下一题脚本没找到时,兜底重问当前题,避免调用方误判为未处理而退回正则识别
                if (StringUtils.isEmpty(phoneCallBackYQVO.getValue())) {
                    log.error("下一题脚本未找到,重问当前题,nextQuestion:{}", nextQuestion);
                    phoneCallBackYQVO.setType("text");
                    phoneCallBackYQVO.setSilent_interval(ivrTaskTemplate.getSilencetime().intValue());
                    phoneCallBackYQVO.setValue(phoneCallBackYQVO.getCommonValue() + getObject(serviceSubtask, questionText));
                }
                back = phoneCallBackYQVO;
                return back;
            } else if (ivrTaskTemplateScriptVO.getNextScriptno() == null || ivrTaskTemplateScriptVO.getNextScriptno() == 0) {
                ServiceTask serviceTask1 = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                phoneCallBackYQVO.setType("text");
@@ -5419,46 +5843,113 @@
                //在redis中保存一下结束语,在调用挂电话的方法时删除
                ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                redisCache.setCacheObject(phoneCallReqYQVO.getUuid() + "- jsy", serviceTask.getJsy(), 120, TimeUnit.MINUTES);
//                                return phoneCallBackYQVO;
                //结束语已拼进返回值,挂机由平台按返回值执行
                back = phoneCallBackYQVO;
                return back;
            }
        } else {
            log.info("没有匹配上----------------------------");
            //flag=0,说明没 匹配上,也要把患者说的话记录下来
            if (matched == ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList().size() - 1 && flag == 0) {
                ServiceSubTaskDetailReq serviceSubTaskDetailReq = new ServiceSubTaskDetailReq();
                List<ServiceSubtaskDetail> serviceSubtaskDetailList = new ArrayList<>();
                ServiceSubtaskDetail serviceSubtaskDetail = getServiceSubtaskDetail(phoneCallReqYQVO, ivrTaskTemplateScriptVO, serviceSubtask, ivrTaskTemplate);
                //修改一下语音路径(改成前端可以访问的,存到数据库中)
                if (StringUtils.isNotEmpty(serviceSubtaskDetail.getQuestionvoice())) {
                    String questionvoice = serviceSubtaskDetail.getQuestionvoice();
                    String[] split = questionvoice.split("\\\\");
                    if (split.length > 0) {
                        String lastPart = split[split.length - 1];
                        serviceSubtaskDetail.setQuestionvoice(voicePathPrefix + lastPart);
            //AI没有匹配上:由AI分支自己按"没问清就重问"的次数处理,不再退回正则识别
            log.info("ai没有匹配上----------------------------");
            //没匹配上也要把患者说的话记录下来(matchedtext置空,与正则路径口径一致)
            ServiceSubTaskDetailReq serviceSubTaskDetailReq = new ServiceSubTaskDetailReq();
            List<ServiceSubtaskDetail> serviceSubtaskDetailList = new ArrayList<>();
            ServiceSubtaskDetail serviceSubtaskDetail = getServiceSubtaskDetail(phoneCallReqYQVO, ivrTaskTemplateScriptVO, serviceSubtask, ivrTaskTemplate);
            //修改一下语音路径(改成前端可以访问的,存到数据库中)
            if (StringUtils.isNotEmpty(serviceSubtaskDetail.getQuestionvoice())) {
                String questionvoice = serviceSubtaskDetail.getQuestionvoice();
                String[] split = questionvoice.split("\\\\");
                if (split.length > 0) {
                    String lastPart = split[split.length - 1];
                    serviceSubtaskDetail.setQuestionvoice(voicePathPrefix + lastPart);
                }
            }
            serviceSubtaskDetailList.add(serviceSubtaskDetail);
            //如果没有 匹配上,这个必须为null
            serviceSubtaskDetailList.get(0).setMatchedtext("");
            serviceSubTaskDetailReq.setServiceSubtaskDetailList(serviceSubtaskDetailList);
            serviceSubTaskDetailReq.setGuid(phoneCallReqYQVO.getGuid());
            serviceSubTaskDetailReq.setOrgid(phoneCallReqYQVO.getOrgid());
            saveQuestionAnswerPhone(serviceSubTaskDetailReq);
            String mateKey = phoneCallReqYQVO.getTaskid().trim() + "&&" + "mate" + "&&" + phoneCallReqYQVO.getUuid();
            Integer count = null;
            Object countObj = redisCache.getCacheObject(mateKey);
            if (ObjectUtils.isNotEmpty(countObj)) count = (Integer) countObj;
            if (count != null && count >= ivrTaskTemplate.getMateNum()) {
                //没匹配次数已经用满,不能再重问了
                boolean noNextQuestion = ("0".equals(ivrTaskTemplateScriptVO.getBranchFlag()) || "1".equals(ivrTaskTemplateScriptVO.getBranchFlag()))
                        && (ivrTaskTemplateScriptVO.getNextScriptno() == null || ivrTaskTemplateScriptVO.getNextScriptno() == 0);
                if (noNextQuestion) {
                    //已经是最后一题,直接挂机
                    ServiceTask serviceTask1 = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                    phoneCallBackYQVO.setType("text");
                    phoneCallBackYQVO.setSilent_interval(ivrTaskTemplate.getSilencetime().intValue());
                    phoneCallBackYQVO.setValue(phoneCallBackYQVO.getCommonValue() + serviceTask1.getJsy());
                    //更新一下分数
                    Double score = null;
                    Object scoreObj = redisCache.getCacheObject(phoneCallReqYQVO.getUuid() + "SCORE");
                    if (ObjectUtils.isNotEmpty(scoreObj)) score = (Double) scoreObj;
                    serviceSubtask.setScore(String.valueOf(score));
                    serviceSubtask.setFinishtime(new Date());
                    serviceSubtask.setSendstate(6L);
                    serviceSubtask.setRemark("电话拨打已完成");
                    serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
                    //记录状态
                    setFailPreachForm(serviceSubtask, "3", "电话拨打已完成", "9");
                    //在redis中保存一下结束语,在调用挂电话的方法时删除
                    ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
                    redisCache.setCacheObject(phoneCallReqYQVO.getUuid() + "- jsy", serviceTask.getJsy(), 120, TimeUnit.MINUTES);
                    //去redis中,把该子任务ID删除
                    Long id = serviceSubtask.getId();
                    Map<String, String> map = delRedisValue(null, id.toString());
                    if (ObjectUtils.isNotEmpty(map)) {
                        redisCache.setCacheObject(map.get("cacheName"), map.get("val"));
                        redisCache.deleteObject(serviceSubtask.getId() + "-" + serviceSubtask.getPhone());
                        redisCache.deleteObject(phoneCallReqYQVO.getUuid() + "SCORE");
                    }
                } else {
                    //还有下一题,按nextScriptno继续提问
                    for (IvrTaskTemplateScript script : ivrTaskTemplateScripts) {
                        if (script.getSort() == ivrTaskTemplateScriptVO.getNextScriptno().intValue()) {
                            phoneCallBackYQVO.setType("text");
                            phoneCallBackYQVO.setSilent_interval(ivrTaskTemplate.getSilencetime().intValue());
                            String scriptContent = StringUtils.isNotEmpty(script.getIvrtext()) ? script.getIvrtext() : script.getScriptContent();
                            phoneCallBackYQVO.setValue(phoneCallBackYQVO.getCommonValue() + getObject(serviceSubtask, scriptContent));
                            //将该患者的Redis中的题目ID,进行修改
                            redisCache.setCacheObject(phoneCallReqYQVO.getTaskid().trim() + "-" + phoneCallReqYQVO.getPhone().trim(), script.getId().toString(), 120, TimeUnit.MINUTES);
                            //更新一下分数
                            Double score = null;
                            Object scoreObj = redisCache.getCacheObject(phoneCallReqYQVO.getUuid() + "SCORE");
                            if (ObjectUtils.isNotEmpty(scoreObj)) score = (Double) scoreObj;
                            score = BigDecimal.valueOf(score).add(new BigDecimal(script.getScore())).doubleValue();
                            redisCache.setCacheObject(phoneCallReqYQVO.getUuid() + "SCORE", score, 120, TimeUnit.MINUTES);
                            //换题成功,没匹配次数清零
                            redisCache.deleteObject(mateKey);
                        }
                    }
                }
                serviceSubtaskDetailList.add(serviceSubtaskDetail);
                //如果没有 匹配上,这个必须为null
                serviceSubtaskDetailList.get(0).setMatchedtext("");
                serviceSubTaskDetailReq.setServiceSubtaskDetailList(serviceSubtaskDetailList);
                serviceSubTaskDetailReq.setGuid(phoneCallReqYQVO.getGuid());
                serviceSubTaskDetailReq.setOrgid(phoneCallReqYQVO.getOrgid());
                saveQuestionAnswerPhone(serviceSubTaskDetailReq);
            } else {
                //还没问满次数,用noMatchText引导患者重答
                redisCache.setCacheObject(mateKey, count == null ? 1 : count + 1, 120, TimeUnit.MINUTES);
                phoneCallBackYQVO.setType("text");
                phoneCallBackYQVO.setSilent_interval(ivrTaskTemplate.getSilencetime().intValue());
                phoneCallBackYQVO.setValue(ivrTaskTemplateScriptVO.getNoMatchText() + getObject(serviceSubtask, StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getIvrtext()) ? ivrTaskTemplateScriptVO.getIvrtext() : ivrTaskTemplateScriptVO.getScriptContent()));
            }
            back = phoneCallBackYQVO;
            return back;
        }
        return back;
    }
    //获取任务组信息
    private void findServiceTaskScheduleVO(ServiceTaskVO serviceTaskVO){
        if(StringUtils.isNotEmpty(serviceTaskVO.getAppltype()) && serviceTaskVO.getAppltype().equals("5")){
    private void findServiceTaskScheduleVO(ServiceTaskVO serviceTaskVO) {
        if (StringUtils.isNotEmpty(serviceTaskVO.getAppltype()) && serviceTaskVO.getAppltype().equals("5")) {
            //任务组信息
            ServiceTaskSchedule schedule = serviceTaskScheduleService.selectByTaskid(serviceTaskVO.getTaskid());
            if (ObjectUtils.isNotEmpty(schedule)) {
                ServiceTaskScheduleVO serviceTaskScheduleVO = DtoConversionUtils.sourceToTarget(schedule, ServiceTaskScheduleVO.class);
                List<ServiceTaskScheduleDetail> scheduleDetailList =
                        serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId());
                List<ServiceTaskScheduleDetail> scheduleDetailList = serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId());
                serviceTaskScheduleVO.setDetailList(scheduleDetailList);
                serviceTaskVO.setServiceTaskScheduleVO(serviceTaskScheduleVO);
            }
@@ -5490,4 +5981,9 @@
        }
        log.info("ai匹配成功,匹配结果是:" + matchedText);
    }
    // ---------------------------------------------------------------------
    // 说明:原私有 getWXCode / encode 已随发送方一起收口到 ruoyi-message 模块
    // (XinHuaMpApi),此处已删除,避免三份拷贝各写一套签名逻辑。
    // ---------------------------------------------------------------------
}