| | |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.google.gson.Gson; |
| | | import com.google.gson.GsonBuilder; |
| | | import com.ruoyi.common.core.redis.RedisCache; |
| | | import com.ruoyi.common.dx.MessageSend; |
| | | import com.ruoyi.common.enums.MsgLSEnum; |
| | | import com.ruoyi.common.enums.ServiceFromEnum; |
| | | import com.ruoyi.common.enums.WxGZHEnum; |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.HttpUtil; |
| | | import com.ruoyi.common.utils.OkHttpExample; |
| | | import com.ruoyi.common.utils.RSAPublicKeyExample; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | import com.ruoyi.common.utils.sign.Md5Utils; |
| | | import com.ruoyi.common.utils.sms.smsUtils; |
| | | import com.ruoyi.common.utils.*; |
| | | import com.ruoyi.message.MessageChannel; |
| | | 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.LSHospTokenUtil; |
| | | import com.smartor.common.MtSubmitSmUtil; |
| | | import com.smartor.domain.*; |
| | | import com.smartor.domain.entity.ServiceSubtaskEntity; |
| | | import com.smartor.mapper.*; |
| | | import com.smartor.service.IBaseSmsaccountService; |
| | | import com.smartor.service.IServiceOutPathService; |
| | | import com.smartor.service.IServiceSubtaskRecordService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.commons.collections4.CollectionUtils; |
| | |
| | | import org.springframework.data.redis.listener.RedisMessageListenerContainer; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.io.IOException; |
| | | import java.security.MessageDigest; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.net.URLEncoder; |
| | | import java.util.*; |
| | | import java.util.concurrent.ExecutorService; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | import static cn.hutool.core.convert.Convert.toHex; |
| | | |
| | | import com.ruoyi.template.domain.HeLibrary; |
| | | import com.ruoyi.template.api.TemplateFacade; |
| | | import com.ruoyi.common.core.domain.entity.PatArchive; |
| | | import com.ruoyi.task.domain.entity.ServiceSubtaskEntity; |
| | | import com.ruoyi.task.domain.ServiceSubtask; |
| | | import com.ruoyi.task.domain.ServiceSubtaskRecord; |
| | | import com.ruoyi.task.domain.ServiceTask; |
| | | import com.ruoyi.task.mapper.ServiceSubtaskMapper; |
| | | import com.ruoyi.task.mapper.ServiceTaskMapper; |
| | | import com.ruoyi.task.domain.ServiceOutPath; |
| | | import com.ruoyi.task.service.IServiceOutPathService; |
| | | import com.ruoyi.task.domain.ServiceSubtaskPreachform; |
| | | import com.ruoyi.task.domain.SendMagParam; |
| | | @Slf4j |
| | | @Component//监听此队列 |
| | | public class RedisMqReceiver extends KeyExpirationEventMessageListener { |
| | |
| | | @Autowired |
| | | private IServiceOutPathService iServiceOutPathService; |
| | | |
| | | /** |
| | | * 模板数据一律经 ruoyi-template 的门面取用(跨模块数据访问原则)。 |
| | | */ |
| | | @Autowired |
| | | private TemplateFacade templateFacade; |
| | | |
| | | /** |
| | | * 宣教模块的<b>常驻门面</b>,用于判 {@code sys_config: publicity.enabled}。 |
| | | * <p> |
| | | * ⚠️ 2025 修复:本类原本<b>完全没读宣教开关</b> —— |
| | | * {@code tsakHandle} 的公众号 {@code type == 3} 分支(L518「//宣教」) |
| | | * 照常拼宣教链接并发送,所以关掉 {@code publicity.enabled} 也拦不住这条路。 |
| | | */ |
| | | @Autowired |
| | | private com.ruoyi.publicity.api.PublicityFacade publicityFacade; |
| | | |
| | | @Autowired |
| | | private ServiceSubtaskMapper ivrTaskcallMapper; |
| | | |
| | | |
| | | @Autowired |
| | | private HeLibraryMapper heLibraryMapper; |
| | | |
| | | @Autowired |
| | | private ServiceTaskMapper ivrTaskMapper; |
| | |
| | | @Autowired |
| | | IBaseSmsaccountService baseSmsaccountService; |
| | | |
| | | @Value("${xhsmsPath}") |
| | | private String xhsmsPath; |
| | | |
| | | @Value("${xhsmsAccount}") |
| | | private String xhsmsAccount; |
| | | |
| | | @Value("${xhsmsPwd}") |
| | | private String xhsmsPwd; |
| | | |
| | | @Value("${server.port}") |
| | | private String port; |
| | | |
| | | @Value("${spring.profiles.active}") |
| | | private String active; |
| | | /** |
| | | * 消息发送方工厂(短信/微信公众号)。 |
| | | * <p> |
| | | * 原来短信与公众号的发送逻辑在本类里用 {@code if (active.equals("xx"))} 硬分支了约 300 行, |
| | | * 现已收口到 {@code ruoyi-message} 模块,这里只负责按 {@code active} 路由。 |
| | | */ |
| | | @Autowired |
| | | private SmsSenderFactory smsSenderFactory; |
| | | |
| | | @Autowired |
| | | private MtSubmitSmUtil mtSubmitSmUtil; |
| | | private WechatSenderFactory wechatSenderFactory; |
| | | |
| | | @Value("${spring.profiles.active}") |
| | | private String active; |
| | | |
| | | @Autowired |
| | | private ISysConfigService configService; |
| | |
| | | continue; |
| | | } |
| | | String descByCode = ServiceFromEnum.getDescByCode(Integer.valueOf(sendPreachform)); |
| | | |
| | | // ⚠️ 2025 修复(宣教开关失效):type == 3 是**宣教/通知**(纯发送、无作答, |
| | | // 见 setFailPreachForm 里「宣教或通知…直接改成 9」的判定),整条派发的所有通道 |
| | | // (电话/短信/公众号/人工)发的都是宣教内容。所以关掉 publicity.enabled 时 |
| | | // 应当**一个通道都不发**,而不是只拦其中一段。 |
| | | // |
| | | // ⚠️ 刻意**不推进 subtask 状态、也不记失败**:关闭是"暂时不发", |
| | | // 不是"这个患者不需要宣教"。若标成失败/不需要,开关恢复后这条宣教就永远丢了。 |
| | | // 保持 sendstate=2 不动,开关打开后下一次派发会照常发出。 |
| | | // (本方法的调用方 onMessage 处理完即删 Redis 消息、不重投,所以不会造成重投风暴。) |
| | | if (type != null && type == 3 && !publicityFacade.isEnabled()) { |
| | | log.warn("【宣教】模块未启用(参数配置 publicity.enabled=false),跳过宣教发送。subtaskId={}, patid={}", |
| | | serviceSubtask.getId(), serviceSubtask.getPatid()); |
| | | continue; |
| | | } |
| | | |
| | | if (descByCode.equals("电话")) { |
| | | try { |
| | | ServiceTask ivrTask = ivrTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); |
| | |
| | | serviceOutPath.setParam6(subId); |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | serviceOutPath.setDeptCode(serviceSubtask.getDeptcode()); |
| | | serviceOutPath.setWardCode(serviceSubtask.getLeavehospitaldistrictcode()); |
| | | serviceOutPath.setDeptName(serviceSubtask.getDeptname()); |
| | | serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | // sendMagParam.setUrl(ip + ":" + req_path + "/followvisit/particty?param1=" + taskId + "¶m2=" + patid + "¶m5=false"); |
| | | //转成16进制 |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | serviceOutPath.setUrl(ip + ":" + req_path + "/sf?p=" + format); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | sendMagParam.setPhone(serviceSubtask.getPhone()); |
| | | sendMagParam.setUrl(ip + ":" + req_path + "/sf?p=" + format); |
| | | SysConfig sysConfig = new SysConfig(); |
| | | if (StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && serviceSubtask.getServiceType().equals("6")) { |
| | | sysConfig = sysConfigMapper.checkConfigKeyUnique("zymyd.sms.template"); |
| | | }else if (StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && serviceSubtask.getServiceType().equals("14")) { |
| | | } else if (StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && serviceSubtask.getServiceType().equals("14")) { |
| | | sysConfig = sysConfigMapper.checkConfigKeyUnique("mzmyd.sms.template"); |
| | | }else { |
| | | } else { |
| | | sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template"); |
| | | } |
| | | if (!Objects.isNull(sysConfig)) { |
| | |
| | | serviceOutPath.setParam3(ivrTask1.getTaskName()); |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | serviceOutPath.setDeptCode(serviceSubtask.getDeptcode()); |
| | | serviceOutPath.setWardCode(serviceSubtask.getLeavehospitaldistrictcode()); |
| | | serviceOutPath.setDeptName(serviceSubtask.getDeptname()); |
| | | serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | serviceOutPath.setUrl(StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/wt?p=" + format : ip + "/wt?p=" + format); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | // sendMagParam.setUrl(ip + ":" + req_path + "/outsideChainwt?param1=" + taskId + "¶m2=" + patid + "¶m3=" + URLEncoder.encode(ivrTask1.getTaskName(), StandardCharsets.UTF_8.toString()) + "¶m5=false"); |
| | | sendMagParam.setPhone(serviceSubtask.getPhone()); |
| | |
| | | SysConfig sysConfig = new SysConfig(); |
| | | if (StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && serviceSubtask.getServiceType().equals("6")) { |
| | | sysConfig = sysConfigMapper.checkConfigKeyUnique("zymyd.sms.template"); |
| | | }else if (StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && serviceSubtask.getServiceType().equals("14")) { |
| | | } else if (StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && serviceSubtask.getServiceType().equals("14")) { |
| | | sysConfig = sysConfigMapper.checkConfigKeyUnique("mzmyd.sms.template"); |
| | | }else { |
| | | } else { |
| | | sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template"); |
| | | } |
| | | if (!Objects.isNull(sysConfig)) { |
| | |
| | | serviceOutPath.setParam3(ivrTask1.getTaskName()); |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | serviceOutPath.setDeptCode(serviceSubtask.getDeptcode()); |
| | | serviceOutPath.setWardCode(serviceSubtask.getLeavehospitaldistrictcode()); |
| | | serviceOutPath.setDeptName(serviceSubtask.getDeptname()); |
| | | serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String url = ""; |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | //需要通过模板ID去判断要发的内容是宣教还是通知 |
| | | HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid()); |
| | | // ⚠️ 与 RyTask 同口径:**刻意不**为 TemplateModuleDisabledException 降级 —— |
| | | // 模板模块关闭时宣教内容取不到、短信确实发不出去,外层 try-catch 如实记失败 |
| | | // 并走既有的通道升级机制。硬记成功等于用假记录掩盖"没发出去"。 |
| | | HeLibrary heLibrary = templateFacade.findHeLibraryById(serviceSubtask.getLibtemplateid()); |
| | | if (heLibrary.getHetype().equals("1")) { |
| | | sendMagParam.setPhone(serviceSubtask.getPhone()); |
| | | sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/xj?p=" + format : ip + "/xj?p=" + format); |
| | | url = StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/xj?p=" + format : ip + "/xj?p=" + format; |
| | | sendMagParam.setUrl(url); |
| | | |
| | | |
| | | SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("xj.sms.template"); |
| | |
| | | sendMagParam.setPhone(serviceSubtask.getPhone()); |
| | | sendMagParam.setContent(sc); |
| | | } |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | serviceOutPath.setUrl(url); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | } |
| | | |
| | | //短信还需要模板 |
| | | String s = null; |
| | | if (active.equals("xh")) { |
| | | //新华的短信发送方式 |
| | | Map<String, String> req = new HashMap<>(); |
| | | req.put("phone", sendMagParam.getPhone()); |
| | | req.put("content", sendMagParam.getContent()); |
| | | log.info("content返回值的内容是:{}", sendMagParam.getContent()); |
| | | s = HttpUtil.postJsonRequest(xhsmsPath, new Gson().toJson(req)); |
| | | } else if (active.equals("ls")) { |
| | | // String url = configService.selectConfigByKey("token.360", serviceSubtask.getOrgid()); |
| | | // log.info("-------00token.360的URL为:{}", url); |
| | | |
| | | //丽水的短信发送方式 |
| | | SysConfig config = new SysConfig(); |
| | | config.setConfigKey("ls.msg.info"); |
| | | config.setOrgid(serviceSubtask.getOrgid()); |
| | | List<SysConfig> sysConfigs = configService.selectConfigList(config); |
| | | Map<String, String> msgInfo = new HashMap<>(); |
| | | if (CollectionUtils.isNotEmpty(sysConfigs)) { |
| | | String configValue = sysConfigs.get(0).getConfigValue(); |
| | | ObjectMapper objectMapper = new ObjectMapper(); |
| | | if (StringUtils.isNotEmpty(configValue)) { |
| | | msgInfo = objectMapper.readValue(configValue, Map.class); |
| | | } |
| | | } |
| | | log.info("-----------map的值为:{}", msgInfo); |
| | | |
| | | if (ObjectUtils.isNotEmpty(msgInfo) && StringUtils.isEmpty(msgInfo.get("address"))) { |
| | | serviceSubtask.setCurrentPreachform(sendPreachform); |
| | | serviceSubtask.setVisitTime(getNextVisitTime(serviceSubtask.getId(), serviceSubtask.getTaskid(), serviceSubtask.getVisitTime(), serviceSubtask.getCurrentPreachform())); |
| | | setFailPreachForm(serviceSubtask, descByCode, "短信发送失败,该机构没有配置短信地址", "5"); |
| | | serviceSubtaskMapper.updateServiceSubtask(serviceSubtask); |
| | | continue; |
| | | } |
| | | |
| | | String token = LSHospTokenUtil.getToken(serviceSubtask.getOrgid(), msgInfo.get("tokenUrl")); |
| | | String dxCode = getDXCode(msgInfo.get("address"), sendMagParam.getPhone(), sendMagParam.getContent(), msgInfo.get("sendPersonId"), msgInfo.get("sendPersonName"), MsgLSEnum.getHeaderByCode(msgInfo), token); |
| | | ObjectMapper objectMapper = new ObjectMapper(); |
| | | Map<String, Object> textParam = objectMapper.readValue(dxCode, Map.class); |
| | | String code = textParam.get("Code").toString(); |
| | | if (code.equals("0")) { |
| | | s = "true"; |
| | | } else { |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送失败", "5"); |
| | | throw new BaseException("短信发送失败"); |
| | | } |
| | | } else if (active.equals("sltd") || active.equals("nhfy")) { |
| | | //省立同德的短信发送方式 |
| | | String data = null; |
| | | Map<String, Object> smsResult = null; |
| | | if (active.equals("sltd")) { |
| | | data = MessageSend.sendMsg(sendMagParam.getContent(), "6", sendMagParam.getPhone(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); |
| | | if (StringUtils.isNotEmpty(data)) { |
| | | ObjectMapper mapper = new ObjectMapper(); |
| | | JsonNode root = mapper.readTree(data); |
| | | String status = root.get("result").get(0).get("status").asText(); |
| | | if (status.equals("00000")) { |
| | | s = "true"; |
| | | } else { |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送失败: " + data, "5"); |
| | | throw new BaseException("短信发送失败"); |
| | | } |
| | | |
| | | } else { |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送失败: " + data, "5"); |
| | | throw new BaseException("短信发送失败"); |
| | | } |
| | | } else if (active.equals("nhfy")) { |
| | | smsResult = mtSubmitSmUtil.submitSm(sendMagParam.getPhone(), sendMagParam.getContent()); |
| | | if (smsResult != null && smsResult.get("result") != null && smsResult.get("result").toString().equals("0")) { |
| | | s = "true"; |
| | | } else { |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送失败", "5"); |
| | | throw new BaseException("短信发送失败"); |
| | | } |
| | | } |
| | | |
| | | } else if (active.equals("hzszlyy")) { |
| | | //市一 |
| | | long timestamp = new Date().getTime(); |
| | | String sign = Md5Utils.hash(xhsmsAccount + timestamp + Md5Utils.hash(xhsmsPwd)); |
| | | String content = sendMagParam.getContent(); |
| | | String jsonMsg = "{" + "\"userName\": \"" + xhsmsAccount + "\"," + "\"content\": \"" + content + "\"," + "\"phoneList\": [" + sendMagParam.getPhone() + "]," + "\"timestamp\": " + timestamp + "," + "\"sign\": \"" + sign + "\"" + "}"; |
| | | s = HttpUtil.postJsonRequest(xhsmsPath, jsonMsg); |
| | | log.info("------市一短信发送的值为:{}", s); |
| | | if (StringUtils.isNotEmpty(s)) { |
| | | JSONObject jsonObject = JSONObject.parseObject(s); |
| | | Object code = jsonObject.get("code"); |
| | | if (code.equals(0)) { |
| | | s = "true"; |
| | | } else { |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送失败", "5"); |
| | | throw new BaseException("短信发送失败"); |
| | | } |
| | | } |
| | | } |
| | | if (s.equals("true")) { |
| | | //短信发送:各站点对接方式差异较大(报文/签名/token/返回判定都不同), |
| | | //已收口到 ruoyi-message 模块,这里只负责组装入参并路由 |
| | | log.info("----active的值为:{}", active); |
| | | SendResult smsSendResult = sendSmsByActive(serviceSubtask, sendMagParam); |
| | | if (smsSendResult.isOk()) { |
| | | //在子任务表里记录一下 |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送成功", "2"); |
| | | //任务发送记录 |
| | |
| | | serviceSubtaskRecord.setResult("success"); |
| | | serviceSubtaskRecord.setRemark("短信发送成功"); |
| | | serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord); |
| | | log.error("serviceSubtaskRecord保存成功了吗?:{}", serviceSubtaskRecord); |
| | | } else { |
| | | //在子任务表里记录一下 |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "短信发送失败", "5"); |
| | | continue; |
| | | } |
| | | } catch (Exception e) { |
| | | ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord(); |
| | |
| | | serviceOutPath.setParam6(subId); |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | serviceOutPath.setDeptCode(serviceSubtask.getDeptcode()); |
| | | serviceOutPath.setWardCode(serviceSubtask.getLeavehospitaldistrictcode()); |
| | | serviceOutPath.setDeptName(serviceSubtask.getDeptname()); |
| | | serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | url = ip + ":" + req_path + "/sf?p=" + format; |
| | | serviceOutPath.setUrl(url); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | } else if (type == 2) { |
| | | //问券 |
| | | ServiceOutPath serviceOutPath = new ServiceOutPath(); |
| | |
| | | serviceOutPath.setParam6(subId); |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | serviceOutPath.setDeptCode(serviceSubtask.getDeptcode()); |
| | | serviceOutPath.setWardCode(serviceSubtask.getLeavehospitaldistrictcode()); |
| | | serviceOutPath.setDeptName(serviceSubtask.getDeptname()); |
| | | serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | |
| | | url = StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/wt?p=" + format : ip + "/wt?p=" + format; |
| | | //如果type是语音随访的话(说明补偿发送方式中有电话随访的方式,这里的外链就地址只能用/sf) |
| | | if (serviceSubtask.getType().equals("1")) |
| | | sendMagParam.setUrl(ip + ":" + req_path + "/sf?p=" + format); |
| | | |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUrl(url); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | } else if (type == 3) { |
| | | //宣教 |
| | | ServiceOutPath serviceOutPath = new ServiceOutPath(); |
| | |
| | | serviceOutPath.setParam3(ivrTask1.getTaskName()); |
| | | serviceOutPath.setParam6(subId); |
| | | serviceOutPath.setCreateTime(new Date()); |
| | | serviceOutPath.setDeptCode(serviceSubtask.getDeptcode()); |
| | | serviceOutPath.setWardCode(serviceSubtask.getLeavehospitaldistrictcode()); |
| | | serviceOutPath.setDeptName(serviceSubtask.getDeptname()); |
| | | serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname()); |
| | | serviceOutPath.setOrgid(serviceSubtask.getOrgid()); |
| | | iServiceOutPathService.insertServiceOutPath(serviceOutPath); |
| | | String format = String.format("%03X", serviceOutPath.getId()); |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | |
| | | //需要通过模板ID去判断要发的内容是宣教还是通知 |
| | | // HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid()); |
| | | // HeLibrary heLibrary = templateFacade.findHeLibraryById(serviceSubtask.getLibtemplateid()); |
| | | // if (heLibrary.getHetype().equals("1")) { |
| | | // sendMagParam.setPhone(serviceSubtask.getPhone()); |
| | | // sendMagParam.setUrl(ip + ":" + req_path + "/xj?p=" + format); |
| | |
| | | // } |
| | | |
| | | url = ip + ":" + req_path + "/xj?p=" + format; |
| | | serviceOutPath.setRadix(format); |
| | | serviceOutPath.setUpdateTime(new Date()); |
| | | serviceOutPath.setUrl(url); |
| | | iServiceOutPathService.updateServiceOutPath(serviceOutPath); |
| | | } |
| | | if (StringUtils.isEmpty(patArchive.getPatidHis())) { |
| | | serviceSubtask.setCurrentPreachform(sendPreachform); |
| | | serviceSubtask.setVisitTime(getNextVisitTime(serviceSubtask.getId(), serviceSubtask.getTaskid(), serviceSubtask.getVisitTime(), serviceSubtask.getCurrentPreachform())); |
| | | serviceSubtaskMapper.updateServiceSubtask(serviceSubtask); |
| | | //失败记录 |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "公众号发送失败,his系统的患者id为空", "5"); |
| | | continue; |
| | | } |
| | | |
| | | //获取微信公众号请求信息根据机构ID |
| | | //机构配置校验(WxGZHEnum)与 his 患者id 校验已收口到 |
| | | //ruoyi-message 的 WechatMpConfigProvider / XinHuaMpSender,调用点不再重复校验 |
| | | log.error("获取微信公众号请求信息根据机构ID:{}", patArchive.getOrgid()); |
| | | List<String> wxqqxx = WxGZHEnum.getDescByCode(patArchive.getOrgid()); |
| | | //市一医院 不校验 |
| | | if (CollectionUtils.isEmpty(wxqqxx) || wxqqxx.size() < 4) { |
| | | serviceSubtask.setCurrentPreachform(sendPreachform); |
| | | serviceSubtask.setVisitTime(getNextVisitTime(serviceSubtask.getId(), serviceSubtask.getTaskid(), serviceSubtask.getVisitTime(), serviceSubtask.getCurrentPreachform())); |
| | | serviceSubtaskMapper.updateServiceSubtask(serviceSubtask); |
| | | |
| | | //失败记录 |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "该机构的公众号配置信息不全,无法通过公众号发送", "5"); |
| | | continue; |
| | | } |
| | | String wxCode = ""; |
| | | if (active.equals("hzszlyy")) { |
| | | wxCode = smsUtils.sendChat(url, patArchive.getTelcode(), serviceSubtask.getSfzh()); |
| | | log.info("wxCode的值为:{}", wxCode); |
| | | if (!"xh".equals(active)) { |
| | | //市一:走自有公众号网关(不做机构配置校验、his患者id校验,与原实现一致) |
| | | sendWechatByActive(serviceSubtask, patArchive, url); |
| | | } else { |
| | | wxCode = getWXCode(serviceSubtask.getSfzh(), url, serviceSubtask.getTaskName(), serviceSubtask.getTaskName(), patArchive.getTelcode(), patArchive.getName(), patArchive.getPatidHis(), wxqqxx); |
| | | log.error("wxCode的值为:{}", wxCode); |
| | | Map<String, Object> map = JSONObject.parseObject(wxCode, Map.class); |
| | | log.error("map的值为:{}", map); |
| | | if (!map.isEmpty()) { |
| | | serviceSubtask.setResult("success"); |
| | | serviceSubtask.setSendstate(3L); |
| | | log.error("aBoolean的值为:{}", aBoolean); |
| | | if (map.get("succ").toString().equals("true")) { |
| | | aBoolean = true; |
| | | } |
| | | if (aBoolean == false) { |
| | | ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord(); |
| | | serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString()); |
| | | serviceSubtaskRecord.setSubtaskId(serviceSubtask.getId()); |
| | | serviceSubtaskRecord.setUuid(UUID.randomUUID().toString()); |
| | | serviceSubtaskRecord.setTasktype(serviceSubtask.getType()); |
| | | serviceSubtaskRecord.setPreachform("5"); |
| | | serviceSubtaskRecord.setStartTime(System.currentTimeMillis()); |
| | | serviceSubtaskRecord.setRemark(ObjectUtils.isNotEmpty(map.get("msg")) ? map.get("msg").toString() : null); |
| | | serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord); |
| | | //在子任务表里记录一下 |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "公众号发送失败", "5"); |
| | | continue; |
| | | } |
| | | //新华:his患者id校验失败即记录并进入下一种发送方式 |
| | | SendResult wechatSendResult = sendWechatByActive(serviceSubtask, patArchive, url); |
| | | if (!wechatSendResult.isOk()) { |
| | | ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord(); |
| | | serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString()); |
| | | serviceSubtaskRecord.setSubtaskId(serviceSubtask.getId()); |
| | | serviceSubtaskRecord.setUuid(UUID.randomUUID().toString()); |
| | | serviceSubtaskRecord.setTasktype(serviceSubtask.getType()); |
| | | serviceSubtaskRecord.setPreachform("5"); |
| | | serviceSubtaskRecord.setStartTime(System.currentTimeMillis()); |
| | | serviceSubtaskRecord.setRemark(wechatSendResult.getMessage()); |
| | | serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord); |
| | | //在子任务表里记录一下 |
| | | setFailPreachForm(serviceSubtask, sendPreachform, "公众号发送失败", "5"); |
| | | continue; |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 按 {@code active}(站点)路由到对应的短信发送方。 |
| | | * <p> |
| | | * 入参沿用原分支里已经组装好的 {@code SendMagParam},保证内容与线上完全一致。 |
| | | * 各站点差异见 {@code ruoyi-message} 模块各实现类。 |
| | | * <p> |
| | | * ⚠️ 新华({@code xh})在本入口原本走「URL 编码表单」, |
| | | * 与 {@code RyTask}(发空报文)/ {@code smsSubTask}(JSON)并不一致; |
| | | * 这里按原样走 {@code XinHuaSmsSender#sendForm}(表单模式)。 |
| | | */ |
| | | private SendResult sendSmsByActive(ServiceSubtask serviceSubtask, SendMagParam sendMagParam) { |
| | | SmsSendRequest request = SmsSendRequest.of( |
| | | sendMagParam.getPhone(), sendMagParam.getContent(), serviceSubtask.getOrgid()); |
| | | return smsSenderFactory.send(active, request); |
| | | } |
| | | |
| | | /** |
| | | * 按 {@code active}(站点)路由到对应的微信公众号发送方。 |
| | | * <p> |
| | | * ⚠️ 站点差异(与原实现一一对应): |
| | | * <ul> |
| | | * <li>市一({@code hzszlyy}):不做 his 患者id 校验,标题/内容都取任务名称;</li> |
| | | * <li>新华({@code xh}):要求 his 患者id 非空,患者姓名取 {@code patArchive.getName()};</li> |
| | | * <li>新华的 JSON 报文体需要 {@code disableHtmlEscaping},与 {@code RyTask} 不同。</li> |
| | | * </ul> |
| | | */ |
| | | private SendResult sendWechatByActive(ServiceSubtask serviceSubtask, PatArchive patArchive, String url) { |
| | | if (StringUtils.isEmpty(patArchive.getPatidHis())) { |
| | | return SendResult.fail(active, MessageChannel.WECHAT, |
| | | "公众号发送失败,his系统的患者id为空", null); |
| | | } |
| | | WechatSendRequest request = new WechatSendRequest(); |
| | | request.setOrgid(patArchive.getOrgid()); |
| | | request.setIdCard(serviceSubtask.getSfzh()); |
| | | request.setUrl(url); |
| | | request.setTitle(serviceSubtask.getTaskName()); |
| | | //原实现标题与内容都传 serviceSubtask.getTaskName() |
| | | request.setContent(serviceSubtask.getTaskName()); |
| | | request.setPhone(patArchive.getTelcode()); |
| | | request.setPatientName(patArchive.getName()); |
| | | request.setPatidHis(patArchive.getPatidHis()); |
| | | //原 RedisMqReceiver.getWXCode 使用 disableHtmlEscaping,与 RyTask 不同,此处保持 |
| | | request.setDisableHtmlEscaping(true); |
| | | return wechatSenderFactory.send(active, request); |
| | | } |
| | | |
| | | private String getSC(ServiceSubtask serviceSubtask, String scriptContent) { |
| | |
| | | serviceSubtaskPreachform1.setRemark(remark); |
| | | serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(serviceSubtaskPreachform1); |
| | | //如果当前的preachform已经是最后一个了,并且本次还是发送失败,那直接将serviceSubtask的sendstate状态改成5就行了(全失败了) |
| | | if (CollectionUtils.isNotEmpty(spSize) && serviceSubtaskPreachform1.getSort() == spSize.size()) { |
| | | if (CollectionUtils.isNotEmpty(spSize) && serviceSubtaskPreachform1.getSort() == spSize.size() |
| | | && isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) { |
| | | if (serviceSubtaskPreachform1.getSort() == spSize.size()) { |
| | | if (failSendstate.equals("4") || failSendstate.equals("5")) { |
| | | serviceSubtask.setCurrentPreachform(preachform); |
| | |
| | | return targetKey; |
| | | } |
| | | |
| | | // private String getKey() { |
| | | // Map<String, List> map = new HashMap<>(); |
| | | // for (int i = 0; i < 6; i++) { |
| | | // Boolean aBoolean = redisCache.hasKey("cache-" + i); |
| | | // if (!aBoolean) { |
| | | // redisCache.setCacheList("cache-" + i, new ArrayList<String>()); |
| | | // map.put("cache-" + i, new ArrayList<String>()); |
| | | // } else { |
| | | // map.put("cache-" + i, redisCache.getCacheObject("cache-" + i)); |
| | | // } |
| | | // } |
| | | // |
| | | // String key = null; |
| | | // List<String> value = new ArrayList<String>(); |
| | | // for (Map.Entry<String, List> entry : map.entrySet()) { |
| | | // if (CollectionUtils.isEmpty(value)) { |
| | | // value = entry.getValue(); |
| | | // key = entry.getKey(); |
| | | // } else { |
| | | // value = entry.getValue(); |
| | | // key = entry.getKey(); |
| | | // } |
| | | // } |
| | | // return key; |
| | | // } |
| | | // --------------------------------------------------------------------- |
| | | // 说明:原 getWXCode / getDXCode / encode 三个私有方法已随发送方一起收口到 |
| | | // ruoyi-message 模块(XinHuaMpApi / LishuiSmsSender),此处已删除,避免重复实现。 |
| | | // 注意:本类的 getWXCode 原使用 new GsonBuilder().disableHtmlEscaping(), |
| | | // 与 RyTask.getWXCode 的 new Gson() 不同,该差异已在 XinHuaMpApi 中按站点保留。 |
| | | // --------------------------------------------------------------------- |
| | | |
| | | private String getWXCode(String idcard, String url, String taskName, String taskDesc, String phone, String patientname, String setPatientid, List<String> wxqqxx) { |
| | | XinHuaWXReq xinHuaWXReq = new XinHuaWXReq(); |
| | | xinHuaWXReq.setIdcard(idcard); |
| | | xinHuaWXReq.setUrl(url); |
| | | xinHuaWXReq.setPatientid(setPatientid); |
| | | xinHuaWXReq.setPatientname(patientname); |
| | | xinHuaWXReq.setMobile(phone); |
| | | xinHuaWXReq.setMedcardno(null); |
| | | xinHuaWXReq.setTitlename(taskName); |
| | | xinHuaWXReq.setContent(taskDesc); |
| | | xinHuaWXReq.setAppid(wxqqxx.get(1)); |
| | | log.error("-----微信公众号的出参为----:{}", xinHuaWXReq); |
| | | // new Gson().toJson(xinHuaWXReq); |
| | | GsonBuilder gb = new GsonBuilder(); |
| | | gb.disableHtmlEscaping(); |
| | | String body = gb.create().toJson(xinHuaWXReq); |
| | | |
| | | log.error("encode的入参为wxqqxx :{}, body:{}", wxqqxx.get(2), body); |
| | | String encode = encode(wxqqxx.get(2).concat(body)); |
| | | log.error("--------encode的值为:{}-----", encode); |
| | | Map<String, String> headerMap = new HashMap<>(); |
| | | headerMap.put("sign", encode); |
| | | String result = HttpUtils.sendPostByHeader(wxqqxx.get(3), body, headerMap); |
| | | log.error("--------result的值为:{}-----", result); |
| | | |
| | | JSONObject jsonObject = JSONObject.parseObject(result); |
| | | String code = (String) jsonObject.toString(); |
| | | return code; |
| | | } |
| | | |
| | | |
| | | private String getDXCode(String address, String ShouJiHM, String FaSongNR, String FaSongRID, String FaSongRXM, Map<String, Object> headerMap, String token) { |
| | | Map<String, Object> map = new LinkedHashMap<>(); |
| | | |
| | | Map<String, Object> YeWuXX = new LinkedHashMap<>(); |
| | | Map<String, Object> DuanXinXX = new LinkedHashMap<>(); |
| | | DuanXinXX.put("ShouJiHM", ShouJiHM); |
| | | DuanXinXX.put("FaSongNR", FaSongNR); |
| | | DuanXinXX.put("FaSongRID", FaSongRID); |
| | | DuanXinXX.put("FaSongRXM", FaSongRXM); |
| | | YeWuXX.put("DuanXinXX", DuanXinXX); |
| | | |
| | | map.put("XiaoXiTou", headerMap); |
| | | map.put("YeWuXX", YeWuXX); |
| | | |
| | | String body = new Gson().toJson(map); |
| | | |
| | | String result = null; |
| | | try { |
| | | result = OkHttpExample.sendPostRequest(address, body, token); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | /** |
| | | * 随访任务是否超时 |
| | | * @param serviceSubtask |
| | | * @param serviceSubtaskPreachforms |
| | | * @return |
| | | */ |
| | | public boolean isSubtaskDeadline(ServiceSubtask serviceSubtask, List<ServiceSubtaskPreachform> serviceSubtaskPreachforms){ |
| | | if (ObjectUtils.isNotEmpty(serviceSubtask)) { |
| | | //只有出院随访和专病随访有超时 |
| | | if(StringUtils.isNotEmpty(serviceSubtask.getServiceType()) && |
| | | !serviceSubtask.getServiceType().equals("2") && !serviceSubtask.getServiceType().equals("13")){ |
| | | return true; |
| | | } |
| | | } |
| | | log.info("--------result的值为:{}-----", result); |
| | | |
| | | JSONObject jsonObject = JSONObject.parseObject(result); |
| | | String code = (String) jsonObject.toString(); |
| | | return code; |
| | | } |
| | | |
| | | |
| | | public String encode(String arg) { |
| | | if (arg == null) { |
| | | arg = ""; |
| | | if (Objects.isNull(serviceSubtask) || CollectionUtils.isEmpty(serviceSubtaskPreachforms)) { |
| | | return false; |
| | | } |
| | | MessageDigest md5 = null; |
| | | try { |
| | | md5 = MessageDigest.getInstance("MD5"); |
| | | md5.update(arg.getBytes("UTF-8")); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return toHex(md5.digest()); |
| | | // 基准时刻:出院时间 + 发送日(sendDay 缺省按 1),并兜底避免 NPE/脏数据 |
| | | ServiceTask serviceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); |
| | | int sendDay = serviceTask != null && serviceTask.getSendDay() != null ? serviceTask.getSendDay().intValue() : 1; |
| | | Date deadline = DateUtils.addDays(serviceSubtask.getEndtime(), sendDay); |
| | | int sumCompensateTime = CollectionUtils.isEmpty(serviceSubtaskPreachforms) ? 0 : serviceSubtaskPreachforms.stream() |
| | | .mapToInt(x -> x.getCompensateTime() == null ? 0 : Integer.parseInt(x.getCompensateTime())) |
| | | .sum(); |
| | | sumCompensateTime = sumCompensateTime + 1; |
| | | // 只补偿最后一步自身的补偿时间(天),脏值一律按 0 兜底 |
| | | deadline = DateUtils.addDays(deadline, sumCompensateTime); |
| | | // 出院(发送)时间 + 本步补偿时间 小于当前时间 -> 超时 |
| | | return deadline.getTime() < new Date().getTime(); |
| | | } |
| | | } |