package com.ruoyi.quartz.task;
|
|
import com.alibaba.fastjson2.JSONObject;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
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.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.entity.SysDept;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.core.service.IDingTalkService;
|
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.utils.*;
|
import com.ruoyi.common.utils.http.HttpUtils;
|
import com.ruoyi.common.utils.sms.smsUtils;
|
import com.ruoyi.quartz.constant.MzGatherConstant;
|
import com.ruoyi.quartz.enums.MzGatherParamEnum;
|
import com.ruoyi.quartz.enums.MzGatherSlotEnum;
|
import com.ruoyi.quartz.enums.MzGatherStatusEnum;
|
import com.ruoyi.quartz.service.ICollectHISService;
|
import com.ruoyi.quartz.util.CreateDataTable;
|
import com.ruoyi.system.domain.SysConfig;
|
import com.ruoyi.system.mapper.SysConfigMapper;
|
import com.ruoyi.system.service.ISysConfigService;
|
import com.ruoyi.system.service.ISysDeptService;
|
import com.ruoyi.system.service.ISysUserService;
|
import com.smartor.common.LSHospTokenUtil;
|
import com.smartor.common.MtSubmitSmUtil;
|
import com.smartor.common.QwenLLMUtil;
|
import com.smartor.domain.*;
|
import com.smartor.domain.VO.ServiceSubtaskDetailTraceVO;
|
import com.smartor.domain.entity.ServiceSubtaskEntity;
|
import com.smartor.mapper.*;
|
import com.smartor.service.*;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
|
import java.io.IOException;
|
import java.net.URLEncoder;
|
import java.nio.charset.StandardCharsets;
|
import java.nio.file.Files;
|
import java.nio.file.Paths;
|
import java.security.MessageDigest;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.LocalTime;
|
import java.time.ZoneId;
|
import java.time.format.DateTimeFormatter;
|
import java.util.*;
|
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.TimeUnit;
|
import java.util.stream.Collectors;
|
|
import static cn.hutool.core.convert.Convert.toHex;
|
|
/**
|
* 定时任务调度测试
|
*
|
* @author ruoyi
|
*/
|
@Slf4j
|
@Component("ryTask")
|
public class RyTask {
|
@Autowired
|
private IServiceThirdDataService iServiceThirdDataService;
|
|
@Autowired
|
private IServiceOutPathService iServiceOutPathService;
|
|
@Autowired
|
private IServiceSubtaskAnswerService serviceSubtaskAnswerService;
|
|
@Autowired
|
private IPatMedInhospService iPatMedInhospService;
|
|
@Autowired
|
private IPatMedOuthospService iPatMedOuthospService;
|
|
@Autowired
|
private IPatMedOperationService iPatMedOperationService;
|
|
@Autowired
|
private IServiceSubtaskService iServiceSubtaskService;
|
|
@Autowired
|
private IServicePatientTempService iServicePatientTempService;
|
|
@Autowired
|
private IHNGatherPatArchiveService ihnGatherPatArchiveService;
|
|
@Autowired
|
private IServiceSLTDHealthcareRecordService serviceSLTDHealthcareRecordService;
|
|
@Autowired
|
private SysUserImportMapper sysUserImportMapper;
|
|
@Autowired
|
private HeLibraryMapper heLibraryMapper;
|
|
@Autowired
|
private ICollectHISService ichService;
|
|
@Autowired
|
private ISysConfigService configService;
|
|
@Autowired
|
private IDingTalkService dingTalkService;
|
|
@Autowired
|
private ISysUserService userService;
|
|
|
@Value("${localIP}")
|
private String localIP;
|
|
@Value("${xhsmsPath}")
|
private String xhsmsPath;
|
|
@Value("${xhsmsAccount}")
|
private String xhsmsAccount;
|
|
@Value("${xhsmsPwd}")
|
private String xhsmsPwd;
|
// 虚拟接入码
|
@Value("${xhsmsjrm}")
|
private String xhsmsjrm;
|
|
@Value("${pub_key}")
|
private String pub_key;
|
|
@Value("${req_path}")
|
private String req_path;
|
|
@Autowired
|
private ServiceTaskMapper serviceTaskMapper;
|
|
@Autowired
|
private ServiceSubtaskMapper serviceSubtaskMapper;
|
|
@Autowired
|
private RedisCache redisCache;
|
|
@Autowired
|
private IServiceSubtaskRecordService serviceSubtaskRecordService;
|
|
@Autowired
|
IIcd10Service iIcd10Service;
|
|
@Autowired
|
IPatArchiveService patArchiveService;
|
|
@Autowired
|
ISysDeptService sysDeptService;
|
|
@Autowired
|
IServiceSubtaskDetailTraceService serviceSubtaskDetailTraceService;
|
|
@Autowired
|
IPatMedOuthospService patMedOuthospService;
|
|
@Autowired
|
ISvyTaskTemplateService svyTaskTemplateService;
|
|
@Autowired
|
IIvrTaskTemplateService iIvrTaskTemplateService;
|
|
@Autowired
|
IXHGatherPatArchiveService ixhGatherPatArchiveService;
|
|
@Autowired
|
ServiceSubtaskPreachformMapper serviceSubtaskPreachformMapper;
|
|
@Autowired
|
ICollectHISService icollectHis;
|
|
@Autowired
|
CreateDataTable createDataTable;
|
|
|
@Value("${appid}")
|
private String appid;
|
|
@Value("${server.port}")
|
private String port;
|
|
@Autowired
|
private MtSubmitSmUtil mtSubmitSmUtil;
|
|
@Value("${spring.profiles.active}")
|
private String active;
|
@Autowired
|
private SysConfigMapper sysConfigMapper;
|
|
@Autowired
|
private IServiceTaskScheduleService serviceTaskScheduleService;
|
|
public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) {
|
System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
|
}
|
|
public void ryParams(String params) {
|
System.out.println("执行有参方法:" + params);
|
}
|
|
public void ryNoParams() {
|
System.out.println("执行无参方法");
|
}
|
|
public void importData() {
|
String filePath = "C:\\Users\\86176\\Desktop\\新建文本文档 4.txt"; // 替换为你的文件路径
|
|
try {
|
// 读取文件内容
|
String jsonContent = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
|
|
// 创建ObjectMapper对象
|
ObjectMapper objectMapper = new ObjectMapper();
|
// 解析JSON为JsonNode
|
JsonNode rootNode = objectMapper.readTree(jsonContent);
|
// 获取resultList
|
JsonNode resultListNode = rootNode.path("results").path("resultList");
|
// 遍历resultList中的每个对象
|
for (JsonNode item : resultListNode) {
|
|
SysUserImport person = objectMapper.treeToValue(item, SysUserImport.class);
|
person.setStaffPhoto("");
|
sysUserImportMapper.insertSysUserImport(person);
|
|
}
|
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
|
}
|
|
public void analysisData() {
|
//数据解析
|
ServiceThirdData serviceThirdData = new ServiceThirdData();
|
serviceThirdData.setDataType("ADT^A03");
|
serviceThirdData.setIsDeal(0);
|
serviceThirdData.setCreateTime(new Date());
|
iServiceThirdDataService.queryList(serviceThirdData);
|
}
|
|
/**
|
* 定时发送SLTD满意度异常信息
|
*/
|
public void sendSLTDMYDExceptInfo() {
|
//1.获取发送人工号
|
ServiceSubtaskDetailTraceVO subtaskDetailTraceVO = new ServiceSubtaskDetailTraceVO();
|
subtaskDetailTraceVO.setHandleFlag("0");
|
List<ServiceSubtaskDetailTrace> serviceSubtaskDetailTraces = serviceSubtaskDetailTraceService.selectServiceSubtaskDetailTtraceList(subtaskDetailTraceVO);
|
// 把 dutyDeptPersonCode 整理到 list 中(如果多个人用逗号分割,则展开并去重)
|
List<String> dutyDeptPersonCodeList = serviceSubtaskDetailTraces.stream().map(ServiceSubtaskDetailTrace::getDutyDeptPersonCode).filter(StringUtils::isNotBlank).flatMap(code -> Arrays.stream(code.split(","))).map(String::trim).filter(StringUtils::isNotBlank).distinct() // 去重
|
.collect(Collectors.toList());
|
// 获取“省立同德满意度异常内容提醒"
|
SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("sltd.myd.send.except.contont");
|
String exceptContent = sysConfig.getConfigValue();
|
|
// 获取“省立同德满意度异常内容提醒测试人工号”
|
String testPerson = sysConfigMapper.checkConfigKeyUnique("sltd.myd.send.test.person").getConfigValue();
|
if (StringUtils.isNotBlank(testPerson)) {
|
String[] split = testPerson.split(",");
|
if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) dutyDeptPersonCodeList = Arrays.asList(split);
|
else dutyDeptPersonCodeList.addAll(Arrays.asList(split));
|
}
|
|
if (CollectionUtils.isNotEmpty(dutyDeptPersonCodeList)) {
|
for (String dutyDeptPersonCode : dutyDeptPersonCodeList) {
|
log.info("【sendSLTDMYDExceptInfo】发送人工号:{}", dutyDeptPersonCode);
|
String data = MessageSend.sendMsg(exceptContent, "7", dutyDeptPersonCode, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
|
}
|
}
|
}
|
|
/**
|
* 定时发送异常信息-景宁
|
*/
|
public void sendExceptInfo() throws Exception {
|
//1.获取发送人工号
|
ServiceSubtaskDetailTraceVO subtaskDetailTraceVO = new ServiceSubtaskDetailTraceVO();
|
subtaskDetailTraceVO.setHandleFlag("0");
|
List<ServiceSubtaskDetailTrace> serviceSubtaskDetailTraces =
|
serviceSubtaskDetailTraceService.selectServiceSubtaskDetailTtraceList(subtaskDetailTraceVO);
|
// 获取“异常内容提醒"
|
SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("send.except.content");
|
String exceptContent = sysConfig.getConfigValue();
|
|
// 获取“内容提醒测试人工号”
|
SysConfig testPersonConfig = sysConfigMapper.checkConfigKeyUnique("send.test.person");
|
String testPerson = ObjectUtils.isNotEmpty(testPersonConfig) ? testPersonConfig.getConfigValue() : "";
|
if(CollectionUtils.isNotEmpty(serviceSubtaskDetailTraces)){
|
for (ServiceSubtaskDetailTrace serviceSubtaskDetailTrace : serviceSubtaskDetailTraces) {
|
List<String> dutyDeptPersonCodeList = new ArrayList<>();
|
// 把 dutyDeptPersonCode 整理到 list 中(如果多个人用逗号分割,则展开并去重)
|
String dutyDeptPersonCodeStr = serviceSubtaskDetailTrace.getDutyDeptPersonCode();
|
if(StringUtils.isNotEmpty(dutyDeptPersonCodeStr)){
|
String[] dutyDeptPersonCodeSplit = dutyDeptPersonCodeStr.split(",");
|
if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) {
|
dutyDeptPersonCodeList = new ArrayList<>(Arrays.asList(dutyDeptPersonCodeSplit));
|
} else {
|
dutyDeptPersonCodeList.addAll(Arrays.asList(dutyDeptPersonCodeSplit));
|
}
|
|
}
|
|
if (StringUtils.isNotBlank(testPerson)) {
|
String[] split = testPerson.split(",");
|
if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) {
|
dutyDeptPersonCodeList = new ArrayList<>(Arrays.asList(split));
|
} else {
|
dutyDeptPersonCodeList.addAll(Arrays.asList(split));
|
}
|
}
|
|
if (CollectionUtils.isNotEmpty(dutyDeptPersonCodeList)) {
|
for (String dutyDeptPersonCode : dutyDeptPersonCodeList) {
|
log.info("【sendExceptInfo】发送人工号:{}", dutyDeptPersonCode);
|
SysUser sysUser = new SysUser();
|
SysUser sysUserVo = new SysUser();
|
sysUserVo.setUserName(dutyDeptPersonCode);
|
sysUserVo.setOrgid(serviceSubtaskDetailTrace.getOrgid());
|
List<SysUser> users = userService.getUserList(sysUserVo);
|
String phoneNumber = "";
|
if(ObjectUtils.isNotEmpty(users)){
|
sysUser = users.get(0);
|
phoneNumber = sysUser.getPhonenumber();
|
}else {
|
continue;
|
}
|
|
if(StringUtils.isEmpty(phoneNumber)){
|
continue;
|
}
|
String dutyDeptPerson = dingTalkService.getDingTalkUserByMobile(phoneNumber);
|
if(StringUtils.isNotBlank(dutyDeptPerson)){
|
String context = TemplateUtils.render(exceptContent, serviceSubtaskDetailTrace);
|
dingTalkService.sendDingTalkText(context, dutyDeptPerson);
|
//更新状态
|
serviceSubtaskDetailTrace.setHandleFlag("1");
|
serviceSubtaskDetailTrace.setUpdateTime(new Date());
|
serviceSubtaskDetailTraceService.updateServiceSubtaskDetailTtrace(serviceSubtaskDetailTrace);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/**
|
* 定时处理外链的数据
|
*/
|
public void runServiceSubTaskAnswer() {
|
serviceSubtaskAnswerService.saveQuestionAnswer(null, 0L);
|
}
|
|
/**
|
* 获取预约停诊记录信息
|
*
|
*/
|
public void getAppointRecordInfo() {
|
LocalDateTime tomorrowStart = LocalDate.now().plusDays(1).atStartOfDay(); // 明天 00:00:00
|
LocalDateTime tomorrowEnd = tomorrowStart.plusDays(1).minusSeconds(1); // 明天 23:59:59
|
ixhGatherPatArchiveService.getAppointRecordInfo("2", tomorrowStart, tomorrowEnd);
|
}
|
|
/**
|
* 每月15号和月底,查询并处理 HIS 数据(同德,南华)
|
*/
|
public void dealHisDataHalfMonth() {
|
LocalDateTime now = LocalDateTime.now();
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
String formattedNow = now.format(formatter);
|
dealHisData(formattedNow);
|
}
|
|
|
/**
|
* HIS数据采集
|
* 定时任务:采集患者信息、出院、门诊数据
|
* todayZeroStr 当前的时间 例如:2026-05-06 00:00:00
|
*/
|
public void dealHisData(String todayZeroStr) {
|
log.info("【dealHisData】开始执行HIS数据采集任务");
|
// 获取昨天0点到今天0点的时间范围
|
LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
|
if (StringUtils.isNotBlank(todayZeroStr)) {
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
todayZero = LocalDateTime.parse(todayZeroStr, formatter);
|
}
|
LocalDateTime yesterdayZero = todayZero.minusDays(1);
|
log.info("【dealHisData】采集时间范围:{} ~ {}", yesterdayZero, todayZero);
|
|
if (active.trim().equals("xh")) {
|
try {
|
// 采集入院数据
|
log.info("【dealHisData】新华开始采集入院数据");
|
ixhGatherPatArchiveService.getInHospDataGather("0", yesterdayZero, todayZero);
|
log.info("【dealHisData】新华入院数据采集完成");
|
|
// 采集出院数据
|
log.info("【dealHisData】新华开始采集出院数据");
|
ixhGatherPatArchiveService.getInHospDataGather("1", yesterdayZero, todayZero);
|
log.info("【dealHisData】新华出院数据采集完成");
|
|
} catch (Exception e) {
|
log.error("【dealHisData】新华数据采集异常", e);
|
}
|
} else if (active.trim().equals("hn")) {
|
try {
|
// 河南数据采集
|
HnDataGatherVO hnDataGatherVO = new HnDataGatherVO();
|
log.info("【dealHisData】河南开始采集数据");
|
Date startTime = Date.from(yesterdayZero.atZone(ZoneId.systemDefault()).toInstant());
|
Date endTime = Date.from(todayZero.atZone(ZoneId.systemDefault()).toInstant());
|
|
hnDataGatherVO.setStartTime(startTime);
|
hnDataGatherVO.setEndTime(endTime);
|
ihnGatherPatArchiveService.hnDataGather(hnDataGatherVO);
|
log.info("【dealHisData】河南结束采集数据");
|
} catch (Exception e) {
|
log.error("【dealHisData】河南数据采集异常", e);
|
}
|
} else if (active.trim().equals("sltd") || active.trim().equals("nhfy")) {
|
//省立同德与华南附一用同一套采集方法(都是来未来提供)
|
|
try {
|
//获取是否需要采集用户、部门信息
|
SysConfig config = new SysConfig();
|
config.setConfigKey("sltd.gather.sysuser");
|
config.setOrgid("20001001");
|
List<SysConfig> sysConfigs = configService.selectConfigList(config);
|
|
//获取省立同德要采集的院区
|
SysConfig cf = new SysConfig();
|
cf.setConfigKey("sltd.gather.campusid");
|
cf.setOrgid("20001001");
|
List<SysConfig> sysConfigcampusids = configService.selectConfigList(cf);
|
|
List<Long> campusidList = new ArrayList<>();
|
if (CollectionUtils.isNotEmpty(sysConfigcampusids)) {
|
String[] split = sysConfigcampusids.get(0).getConfigValue().split(",");
|
campusidList = Arrays.stream(split).map(Long::valueOf).collect(Collectors.toList());
|
} else {
|
log.error("SysConfig中的院区ID为空!");
|
return;
|
}
|
|
//configValue = 1 不需要采集 configValue = 2需要采集
|
if (CollectionUtils.isNotEmpty(sysConfigs) && sysConfigs.get(0).getConfigValue().equals("2")) {
|
log.info("【dealHisData】省立同德“部门信息”开始采集数据");
|
ServiceSLTDDeptReqVO serviceSLTDDeptReqVO = new ServiceSLTDDeptReqVO();
|
serviceSLTDDeptReqVO.setOrgId("20001001");
|
serviceSLTDDeptReqVO.setCampusIds(campusidList);
|
Boolean aBoolean1 = serviceSLTDHealthcareRecordService.queryDeptWardAreaInfoList(serviceSLTDDeptReqVO);
|
log.info("【dealHisData】省立同德“部门信息”结束采集数据:{}", aBoolean1);
|
|
Boolean aBoolean = false;
|
for (Long cid : campusidList) {
|
log.info("【dealHisData】省立同德“用户信息”开始采集数据,院区:{}", cid);
|
ServiceSLTDInhospReqVO reqVO = new ServiceSLTDInhospReqVO();
|
reqVO.setOrgId("20001001");
|
reqVO.setCampusId(cid);
|
ArrayList<String> statusList = new ArrayList<>();
|
statusList.add("1");
|
reqVO.setStatusList(statusList);
|
aBoolean = serviceSLTDHealthcareRecordService.queryHospUserInfoList(reqVO);
|
}
|
log.info("【dealHisData】省立同德“用户信息”结束采集数据:{}", aBoolean);
|
//疾病字典采集
|
iIcd10Service.queryAddIcd10();
|
}
|
|
// nhfy/sltd回溯30天分段采集判断(每段最多4天)
|
boolean isBackfill = (active.trim().equals("nhfy") || active.trim().equals("sltd")) && StringUtils.isNotBlank(todayZeroStr);
|
if (isBackfill) {
|
DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
LocalDate segStart = todayZero.toLocalDate().minusDays(30);
|
LocalDate segEndDate = todayZero.toLocalDate();
|
int segCount = 0;
|
while (!segStart.isAfter(segEndDate)) {
|
LocalDate segEnd = segStart.plusDays(3);
|
if (segEnd.isAfter(segEndDate)) {
|
segEnd = segEndDate;
|
}
|
segCount++;
|
log.info("【dealHisData】{}回溯第{}段采集,日期范围:{} ~ {}", active.trim(), segCount, segStart.format(dateFmt), segEnd.format(dateFmt));
|
for (Long cid : campusidList) {
|
collectSegmentData(cid, segStart.format(dateFmt), segEnd.format(dateFmt));
|
}
|
segStart = segEnd.plusDays(1);
|
}
|
log.info("【dealHisData】{}回溯采集完成,共{}段", active.trim(), segCount);
|
}
|
|
// 省立同德数据采集(非回溯模式才执行)
|
if (!isBackfill) {
|
for (Long cid : campusidList) {
|
log.info("【dealHisData】省立同德预入院开始采集数据,院区:{}", cid);
|
String nowTime = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
ServiceSLTDInhospReqVO serviceSLTDInhospReqVO = new ServiceSLTDInhospReqVO();
|
serviceSLTDInhospReqVO.setOrgId("20001001");
|
serviceSLTDInhospReqVO.setCampusId(cid);
|
serviceSLTDInhospReqVO.setEncounterTimeStart(nowTime);
|
serviceSLTDInhospReqVO.setEncounterTimeEnd(nowTime);
|
if (active.trim().equals("nhfy")) {
|
serviceSLTDInhospReqVO.setEncounterTimeStart(yesterdayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
serviceSLTDInhospReqVO.setEncounterTimeEnd(todayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
}
|
List<String> list = new ArrayList<>();
|
list.add("FH0109.22");
|
list.add("FH0109.23");
|
list.add("FH0109.53");
|
serviceSLTDInhospReqVO.setStatusList(list);
|
// log.info("【dealHisData】省立同德“预入院”采集数据入参:{}", serviceSLTDInhospReqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
|
log.info("【dealHisData】省立同德“预入院”結束采集数据,院区:{}", cid);
|
|
log.info("【dealHisData】省立同德“入院”开始采集数据,院区:{}", cid);
|
serviceSLTDInhospReqVO.setOrgId("20001001");
|
serviceSLTDInhospReqVO.setCampusId(cid);
|
serviceSLTDInhospReqVO.setEncounterTimeStart(null);
|
serviceSLTDInhospReqVO.setEncounterTimeEnd(null);
|
serviceSLTDInhospReqVO.setStartHeadTime(nowTime);
|
serviceSLTDInhospReqVO.setStartTailTime(nowTime);
|
if (active.trim().equals("nhfy")) {
|
serviceSLTDInhospReqVO.setStartHeadTime(yesterdayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
serviceSLTDInhospReqVO.setStartTailTime(todayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
}
|
List<String> listStr = new ArrayList<>();
|
listStr.add("FH0109.24");
|
serviceSLTDInhospReqVO.setStatusList(listStr);
|
// log.info("【dealHisData】省立同德“入院”采集数据入参:{}", serviceSLTDInhospReqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
|
log.info("【dealHisData】省立同德“入院”結束采集数据,院区:{}", cid);
|
|
log.info("【dealHisData】省立同德“出院”开始采集数据,院区:{}", cid);
|
serviceSLTDInhospReqVO.setStartHeadTime(null);
|
serviceSLTDInhospReqVO.setStartTailTime(null);
|
serviceSLTDInhospReqVO.setEncounterTimeStart(null);
|
serviceSLTDInhospReqVO.setEncounterTimeEnd(null);
|
serviceSLTDInhospReqVO.setPreOutHospitalHeadDate(nowTime);
|
serviceSLTDInhospReqVO.setPreOutHospitalTailDate(nowTime);
|
if (active.trim().equals("nhfy")) {
|
serviceSLTDInhospReqVO.setPreOutHospitalHeadDate(yesterdayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
serviceSLTDInhospReqVO.setPreOutHospitalTailDate(todayZero.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
}
|
serviceSLTDInhospReqVO.setHealthcareRecordTypeList(null);
|
List<String> list2 = new ArrayList<>();
|
// list2.add("FH0108.02");
|
//出院
|
list2.add("FH0109.27");
|
//预出院
|
list2.add("FH0109.25");
|
serviceSLTDInhospReqVO.setStatusList(list2);
|
// log.info("【dealHisData】省立同德“出院”采集数据入参:{}", serviceSLTDInhospReqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
|
log.info("【dealHisData】省立同德“出院”束采集数据,院区:{}", cid);
|
}
|
}
|
|
} catch (Exception e) {
|
log.error("【dealHisData】省立同德数据采集异常", e);
|
}
|
}
|
}
|
|
/**
|
* 分段采集数据(预入院、入院、出院)
|
* 用于nhfy/sltd回溯采集,每次最多查询7天数据
|
*
|
* @param cid 院区ID
|
* @param startDateStr 日期开始 yyyy-MM-dd
|
* @param endDateStr 日期结束 yyyy-MM-dd
|
*/
|
private void collectSegmentData(Long cid, String startDateStr, String endDateStr) {
|
// // 预入院
|
log.info("【dealHisData】预入院开始采集数据,院区:{},时间段:{} ~ {}", cid, startDateStr, endDateStr);
|
ServiceSLTDInhospReqVO reqVO = new ServiceSLTDInhospReqVO();
|
reqVO.setOrgId("20001001");
|
reqVO.setCampusId(cid);
|
reqVO.setEncounterTimeStart(startDateStr);
|
reqVO.setEncounterTimeEnd(endDateStr);
|
List<String> preAdmitStatus = new ArrayList<>();
|
preAdmitStatus.add("FH0109.22");
|
preAdmitStatus.add("FH0109.23");
|
preAdmitStatus.add("FH0109.53");
|
reqVO.setStatusList(preAdmitStatus);
|
log.info("【dealHisData】预入院采集数据入参:{}", reqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
|
log.info("【dealHisData】预入院終了采集数据,院区:{}", cid);
|
|
// 入院
|
log.info("【dealHisData】入院开始采集数据,院区:{},时间段:{} ~ {}", cid, startDateStr, endDateStr);
|
reqVO = new ServiceSLTDInhospReqVO();
|
reqVO.setOrgId("20001001");
|
reqVO.setCampusId(cid);
|
reqVO.setStartHeadTime(startDateStr);
|
reqVO.setStartTailTime(endDateStr);
|
List<String> admitStatus = new ArrayList<>();
|
admitStatus.add("FH0109.24");
|
reqVO.setStatusList(admitStatus);
|
log.info("【dealHisData】入院采集数据入参:{}", reqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
|
log.info("【dealHisData】入院終了采集数据,院区:{}", cid);
|
|
// 出院
|
log.info("【dealHisData】出院开始采集数据,院区:{},时间段:{} ~ {}", cid, startDateStr, endDateStr);
|
reqVO = new ServiceSLTDInhospReqVO();
|
reqVO.setOrgId("20001001");
|
reqVO.setCampusId(cid);
|
reqVO.setPreOutHospitalHeadDate(startDateStr);
|
reqVO.setPreOutHospitalTailDate(endDateStr);
|
List<String> dischargeStatus = new ArrayList<>();
|
//出院
|
dischargeStatus.add("FH0109.27");
|
//预出院
|
dischargeStatus.add("FH0109.25");
|
reqVO.setStatusList(dischargeStatus);
|
log.info("【dealHisData】出院采集数据入参:{}", reqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
|
log.info("【dealHisData】出院结束采集数据,院区:{}", cid);
|
}
|
|
/**
|
* HIS省立同德门急诊数据采集(每半小时一轮,按天全量刷新 + 分页断点续采)
|
* <p>
|
* HIS 侧门急诊数据只能按天查,每轮拉到的都是当天全量(到晚上一万多条),这个取数成本改不了;
|
* 能改的是处理成本:当天数据里绝大多数上一轮已经入库,靠"整页批量查重 + 已入库直接跳过",
|
* 每轮真正需要做档案处理和入库的只有新出现的那几百条,一万多条也能在很短时间内跑完。
|
* <p>
|
* 每一轮做三件事:
|
* <ol>
|
* <li>今天的整轮刷新:第 1 页翻到最后一页,只处理新记录;</li>
|
* <li>昨天的收尾采集:每天只做一次,兜住 23:xx 之后才写入 HIS 的记录和跨零点的数据;</li>
|
* <li>手工回溯:任务入参给了日期时,把那天补采一次(同一天只补一次,不会每轮重复补)。</li>
|
* </ol>
|
* 每轮最多跑 {@link MzGatherParamEnum#BUDGET_MINUTES}(默认 20 分钟),到点保存页码断点正常退出,下一轮从该页继续;
|
* 每采完一页都会落一次断点,进程被杀也不会从头重扫。
|
* <p>
|
* 失败一律不阻断采集进度:
|
* <ul>
|
* <li>数据层失败(转换/档案/入库)落 pat_med_outhosp_error 表交人工处理;</li>
|
* <li>接口层失败(网络超时、来未来返回非 200)没有数据可落表,只写 error 日志(含院区、日期、页码、接口入参),
|
* 跳过该页继续往后采,本轮结束时把断点留在第一个失败页;因为每轮都是整天从头全量刷新,
|
* 被跳过的页下一轮必然重新采到,不会漏;</li>
|
* <li>连续 {@link MzGatherConstant#MAX_CONSECUTIVE_PAGE_FAIL} 页接口失败判定为接口整体不可用,本轮提前结束(避免空转几十页),
|
* 断点留在第一个失败页,下一轮再试。</li>
|
* </ul>
|
*
|
* @param todayZeroStr 可选,手工指定要一次性回溯的日期,支持 yyyy-MM-dd HH:mm:ss 或 yyyy-MM-dd;为空时只刷新今天+收尾昨天
|
*/
|
public void dealHisDataMZ(String todayZeroStr) {
|
log.info("【dealHisDataMZ】门急诊数据采集开始,入参:{}", todayZeroStr);
|
// 南华附一的先不采门急诊数据
|
if (!"sltd".equals(active.trim())) {
|
log.info("【dealHisDataMZ】当前环境 {} 不采集门急诊数据,跳过", active.trim());
|
return;
|
}
|
|
long budgetMinutes = getMzConfigLong(MzGatherParamEnum.BUDGET_MINUTES);
|
long pageSize = getMzConfigLong(MzGatherParamEnum.PAGE_SIZE);
|
long maxPage = getMzConfigLong(MzGatherParamEnum.MAX_PAGE);
|
|
LocalDateTime now = LocalDateTime.now().withNano(0);
|
LocalDateTime deadline = now.plusMinutes(budgetMinutes);
|
|
// 获取省立同德要采集的院区
|
SysConfig cf = new SysConfig();
|
cf.setConfigKey("sltd.gather.campusid");
|
cf.setOrgid(MzGatherConstant.ORG_ID);
|
List<SysConfig> sysConfigcampusids = configService.selectConfigList(cf);
|
if (CollectionUtils.isEmpty(sysConfigcampusids) || StringUtils.isBlank(sysConfigcampusids.get(0).getConfigValue())) {
|
log.error("【dealHisDataMZ】SysConfig中的院区ID为空!");
|
return;
|
}
|
List<Long> campusidList = Arrays.stream(sysConfigcampusids.get(0).getConfigValue().split(","))
|
.map(String::trim).filter(StringUtils::isNotBlank).map(Long::valueOf).collect(Collectors.toList());
|
log.info("【dealHisDataMZ】院区:{},单轮预算:{}分钟,每页:{}条", campusidList, budgetMinutes, pageSize);
|
|
for (Long cid : campusidList) {
|
if (LocalDateTime.now().isAfter(deadline)) {
|
log.warn("【dealHisDataMZ】本轮时间预算已用尽,剩余院区留到下一轮继续,院区:{}", cid);
|
break;
|
}
|
// 防止上一轮还没跑完就被下一轮叠着跑(预算配置过大、或手工触发时兜底)
|
String lockKey = "mzRunning:" + cid;
|
if (Boolean.TRUE.equals(redisCache.hasKey(lockKey))) {
|
log.warn("【dealHisDataMZ】该院区上一轮采集尚未结束,本轮跳过,院区:{}(断点已保留,下一轮继续)", cid);
|
continue;
|
}
|
redisCache.setCacheObject(lockKey, MzGatherConstant.MINUTE_FMT.format(now), budgetMinutes * 2, TimeUnit.MINUTES);
|
try {
|
collectOutpatientDaily(cid, todayZeroStr, pageSize, maxPage, deadline);
|
} catch (Exception e) {
|
log.error("【dealHisDataMZ】门急诊采集异常,院区:{},断点已保留,下一轮从断点继续", cid, e);
|
} finally {
|
redisCache.deleteObject(lockKey);
|
}
|
}
|
log.info("【dealHisDataMZ】门急诊采集本轮结束,耗时:{}秒",
|
java.time.Duration.between(now, LocalDateTime.now()).getSeconds());
|
}
|
|
/**
|
* 采集某个院区:先补一次性回溯日期,再做昨天的收尾采集,最后整轮刷新今天
|
*/
|
private void collectOutpatientDaily(Long cid, String backfillParam, long pageSize, long maxPage,
|
LocalDateTime deadline) {
|
String cursorKey = "mzDayCursor:" + cid;
|
MzDayCursor cursor = loadMzDayCursor(cursorKey);
|
LocalDate today = LocalDate.now();
|
LocalDate yesterday = today.minusDays(1);
|
|
// 手工入参指定的一次性回溯:同一个日期只补一次,避免定时任务每轮重复补
|
LocalDateTime backfillTime = parseMzStartTime(backfillParam);
|
if (backfillTime != null) {
|
LocalDate backfillDay = backfillTime.toLocalDate();
|
if (backfillDay.toString().equals(cursor.backfillDone)) {
|
log.info("【dealHisDataMZ】入参日期 {} 已完成回溯,跳过,院区:{}", backfillDay, cid);
|
} else if (backfillDay.equals(today)) {
|
// 入参就是今天,交给下面的整轮刷新处理即可
|
cursor.backfillDone = backfillDay.toString();
|
saveMzDayCursor(cursorKey, cursor);
|
} else {
|
cursor.backfillDay = backfillDay.toString();
|
cursor.backfillPage = 1L;
|
saveMzDayCursor(cursorKey, cursor);
|
log.info("【dealHisDataMZ】待回溯日期:{},院区:{}", backfillDay, cid);
|
}
|
}
|
|
// 1) 一次性回溯
|
if (cursor.backfillDay != null) {
|
LocalDate day = LocalDate.parse(cursor.backfillDay);
|
MzGatherStatusEnum status = runDayPass(cid, cursorKey, cursor, MzGatherSlotEnum.BACKFILL, day,
|
cursor.backfillPage, pageSize, maxPage, deadline);
|
if (status != MzGatherStatusEnum.DONE) {
|
log.warn("【dealHisDataMZ】回溯日期 {} 本轮未完成({}),断点已保留,院区:{}", day, status.getDesc(), cid);
|
return;
|
}
|
cursor.backfillDone = cursor.backfillDay;
|
cursor.backfillDay = null;
|
cursor.backfillPage = 1L;
|
saveMzDayCursor(cursorKey, cursor);
|
}
|
|
// 2) 昨天收尾采集:每天一次,兜住 23:xx 之后才写进 HIS 的记录和跨零点的数据
|
if (!yesterday.toString().equals(cursor.finalDay)) {
|
MzGatherStatusEnum status = runDayPass(cid, cursorKey, cursor, MzGatherSlotEnum.FINAL, yesterday,
|
cursor.finalPage, pageSize, maxPage, deadline);
|
if (status != MzGatherStatusEnum.DONE) {
|
log.warn("【dealHisDataMZ】昨日收尾采集 {} 本轮未完成({}),断点已保留,院区:{}", yesterday, status.getDesc(), cid);
|
return;
|
}
|
cursor.finalDay = yesterday.toString();
|
cursor.finalPage = 1L;
|
saveMzDayCursor(cursorKey, cursor);
|
}
|
|
// 3) 今天的整轮刷新
|
if (!today.toString().equals(cursor.day)) {
|
cursor.day = today.toString();
|
cursor.page = 1L;
|
saveMzDayCursor(cursorKey, cursor);
|
}
|
MzGatherStatusEnum status = runDayPass(cid, cursorKey, cursor, MzGatherSlotEnum.TODAY, today,
|
cursor.page, pageSize, maxPage, deadline);
|
if (status == MzGatherStatusEnum.DONE) {
|
// 整轮刷新完成,页码归位,下一轮重新从第一页整轮刷新
|
cursor.page = 1L;
|
saveMzDayCursor(cursorKey, cursor);
|
log.info("【dealHisDataMZ】{} 门急诊整轮刷新完成,院区:{}", today, cid);
|
}
|
}
|
|
/**
|
* 全量采集某一天(分页直到采完),每采完一页立即落一次断点
|
*
|
* @param slot 断点槽位(今天整轮刷新 / 昨日收尾 / 手工回溯),决定中断页码记到哪个字段
|
* @return {@link MzGatherStatusEnum} 采集完成 / 预算用尽 / 接口连续失败提前结束
|
*/
|
private MzGatherStatusEnum runDayPass(Long cid, String cursorKey, MzDayCursor cursor, MzGatherSlotEnum slot,
|
LocalDate day, long startPage, long pageSize, long maxPage,
|
LocalDateTime deadline) {
|
String startStr = day.format(MzGatherConstant.DAY_FMT);
|
String endStr = day.plusDays(1).format(MzGatherConstant.DAY_FMT);
|
|
ServiceSLTDInhospReqVO reqVO = new ServiceSLTDInhospReqVO();
|
reqVO.setOrgId(MzGatherConstant.ORG_ID);
|
reqVO.setCampusId(cid);
|
reqVO.setStartHeadTime(null);
|
reqVO.setStartTailTime(null);
|
reqVO.setStatusList(null);
|
// 接口只支持按天查,起止都传日期
|
reqVO.setEncounterTimeStart(startStr);
|
reqVO.setEncounterTimeEnd(endStr);
|
List<String> typeList = new ArrayList<>();
|
typeList.add("FH0108.01"); // 门诊
|
typeList.add("FH0108.03"); // 急诊
|
reqVO.setHealthcareRecordTypeList(typeList);
|
reqVO.setSize(pageSize);
|
|
long page = startPage < 1L ? 1L : startPage;
|
long total = 0L;
|
long pageCount = 0L;
|
// 接口层失败跳过的页数、第一个失败页、连续失败页数
|
long skippedPages = 0L;
|
long firstFailPage = -1L;
|
int consecutiveFail = 0;
|
while (true) {
|
if (LocalDateTime.now().isAfter(deadline)) {
|
// 本轮有跳过的页时,断点回到第一个失败页,保证下一轮先把这些页补回来
|
long resumePage = (skippedPages > 0 && firstFailPage > 0) ? firstFailPage : page;
|
saveMzDayPage(cursorKey, cursor, slot, resumePage);
|
log.warn("【dealHisDataMZ】本轮时间预算用尽,{} 本轮已采{}页{}条{},下次从第{}页继续,院区:{}",
|
day, pageCount, total, skippedLog(skippedPages), resumePage, cid);
|
return MzGatherStatusEnum.BUDGET_UP;
|
}
|
reqVO.setCurrent(page);
|
log.info("【dealHisDataMZ】采集门急诊数据,院区:{},日期:{},第{}页", cid, day, page);
|
|
List<ServiceSLTDInhospResDTO> pageData = null;
|
Exception lastError = null;
|
for (int attempt = 1; attempt <= MzGatherConstant.PAGE_RETRY_TIMES; attempt++) {
|
try {
|
pageData = serviceSLTDHealthcareRecordService.queryHealthcareRecordList(reqVO);
|
lastError = null;
|
break;
|
} catch (Exception e) {
|
lastError = e;
|
log.error("【dealHisDataMZ】门急诊第{}页第{}次采集失败,院区:{},日期:{}", page, attempt, cid, day, e);
|
if (attempt < MzGatherConstant.PAGE_RETRY_TIMES) {
|
try {
|
Thread.sleep(MzGatherConstant.PAGE_RETRY_SLEEP_MS);
|
} catch (InterruptedException ie) {
|
Thread.currentThread().interrupt();
|
break;
|
}
|
}
|
}
|
}
|
if (lastError != null) {
|
// 接口层失败(网络超时 / 来未来返回非200)没有数据可以落表,只写 error 日志,然后跳过该页继续往后采,不阻断进度。
|
// 每轮都是整天从头全量刷新,被跳过的页下一轮必然重新采到,所以不会漏数据。
|
skippedPages++;
|
if (firstFailPage < 0) {
|
firstFailPage = page;
|
}
|
consecutiveFail++;
|
log.error("【dealHisDataMZ】接口层采集失败,已记 error 日志并跳过该页,本轮继续往后采;"
|
+ "院区:{},日期:{},第{}页,接口入参:{},异常:{}",
|
cid, day, page, new Gson().toJson(reqVO), lastError.getMessage(), lastError);
|
if (consecutiveFail >= MzGatherConstant.MAX_CONSECUTIVE_PAGE_FAIL) {
|
// 连续多页接口失败,判定来未来接口整体不可用,本轮提前结束(不再空转后面几十页),断点留在第一个失败页
|
log.error("【dealHisDataMZ】连续{}页接口失败,判定来未来接口不可用,本轮提前结束;院区:{},日期:{},断点保留在第{}页",
|
consecutiveFail, cid, day, firstFailPage);
|
saveMzDayPage(cursorKey, cursor, slot, firstFailPage);
|
return MzGatherStatusEnum.FAILED;
|
}
|
page++;
|
continue;
|
}
|
consecutiveFail = 0;
|
|
if (CollectionUtils.isEmpty(pageData)) {
|
log.info("【dealHisDataMZ】{} 第{}页无数据,采集结束,院区:{},本轮{}页共{}条{}",
|
day, page, cid, pageCount, total, skippedLog(skippedPages));
|
return MzGatherStatusEnum.DONE;
|
}
|
pageCount++;
|
total += pageData.size();
|
log.info("【dealHisDataMZ】{} 第{}页采集{}条,院区:{}", day, page, pageData.size(), cid);
|
if (pageData.size() < pageSize) {
|
log.info("【dealHisDataMZ】{} 采集结束,院区:{},本轮{}页共{}条{}", day, cid, pageCount, total, skippedLog(skippedPages));
|
return MzGatherStatusEnum.DONE;
|
}
|
page++;
|
if (page > maxPage) {
|
log.error("【dealHisDataMZ】{} 已翻到第{}页,超过单日上限{}页,按采完处理,院区:{}", day, page, maxPage, cid);
|
return MzGatherStatusEnum.DONE;
|
}
|
// 每采完一页立即落断点:进程被重启/强杀也能从这一页继续,不从头重扫,也不会漏
|
saveMzDayPage(cursorKey, cursor, slot, page);
|
}
|
}
|
|
/** 按槽位保存中断页码 */
|
private void saveMzDayPage(String cursorKey, MzDayCursor cursor, MzGatherSlotEnum slot, long page) {
|
if (slot == MzGatherSlotEnum.FINAL) {
|
cursor.finalPage = page;
|
} else if (slot == MzGatherSlotEnum.BACKFILL) {
|
cursor.backfillPage = page;
|
} else {
|
cursor.page = page;
|
}
|
saveMzDayCursor(cursorKey, cursor);
|
}
|
|
/** 日志里提示接口层失败跳过了几页(下一轮整轮刷新会重新采到) */
|
private String skippedLog(long skippedPages) {
|
return skippedPages > 0L ? ",接口失败跳过" + skippedPages + "页(下一轮整轮刷新会重新采到)" : "";
|
}
|
|
/** 读取 sys_config 里的门急诊采集参数(机构 orgid=20001001),取不到或超范围时用枚举里的默认值 */
|
private long getMzConfigLong(MzGatherParamEnum param) {
|
try {
|
SysConfig config = new SysConfig();
|
config.setConfigKey(param.getKey());
|
config.setOrgid(MzGatherConstant.ORG_ID);
|
List<SysConfig> configs = configService.selectConfigList(config);
|
if (CollectionUtils.isNotEmpty(configs) && StringUtils.isNotBlank(configs.get(0).getConfigValue())) {
|
long value = Long.parseLong(configs.get(0).getConfigValue().trim());
|
if (value >= param.getMin() && value <= param.getMax()) {
|
return value;
|
}
|
log.warn("【dealHisDataMZ】配置{}的值{}超出范围[{},{}],使用默认值{}",
|
param.getKey(), value, param.getMin(), param.getMax(), param.getDefaultValue());
|
}
|
} catch (Exception e) {
|
log.warn("【dealHisDataMZ】读取配置{}失败,使用默认值{}", param.getKey(), param.getDefaultValue(), e);
|
}
|
return param.getDefaultValue();
|
}
|
|
/** 解析任务入参(要一次性回溯的日期),支持 yyyy-MM-dd HH:mm:ss 与 yyyy-MM-dd */
|
private LocalDateTime parseMzStartTime(String text) {
|
LocalDateTime time = parseMzTimeQuiet(text);
|
if (time == null && StringUtils.isNotBlank(text)) {
|
log.warn("【dealHisDataMZ】入参 {} 无法解析为日期,按未指定处理", text);
|
}
|
return time;
|
}
|
|
/** 静默解析日期,支持 yyyy-MM-dd HH:mm:ss 与 yyyy-MM-dd,格式不符返回 null(不刷日志) */
|
private LocalDateTime parseMzTimeQuiet(String text) {
|
if (StringUtils.isBlank(text)) {
|
return null;
|
}
|
String value = text.trim();
|
try {
|
return LocalDateTime.parse(value, MzGatherConstant.MINUTE_FMT);
|
} catch (Exception ignore) {
|
// 兼容只传日期的情况,落到下面按日期解析
|
}
|
try {
|
return LocalDate.parse(value).atStartOfDay();
|
} catch (Exception ignore) {
|
return null;
|
}
|
}
|
|
/** 保存门急诊采集断点(各轮次中断的页码) */
|
private void saveMzDayCursor(String cursorKey, MzDayCursor cursor) {
|
JSONObject json = new JSONObject();
|
json.put("day", cursor.day);
|
json.put("page", cursor.page);
|
json.put("finalDay", cursor.finalDay);
|
json.put("finalPage", cursor.finalPage);
|
json.put("backfillDay", cursor.backfillDay);
|
json.put("backfillPage", cursor.backfillPage);
|
json.put("backfillDone", cursor.backfillDone);
|
json.put("updateTime", MzGatherConstant.MINUTE_FMT.format(LocalDateTime.now().withNano(0)));
|
redisCache.setCacheObject(cursorKey, json.toJSONString(), MzGatherConstant.CACHE_TTL_HOURS, TimeUnit.HOURS);
|
}
|
|
/** 读取门急诊采集断点,读不到或解析失败时返回空断点(等价于从第一页开始整轮刷新) */
|
private MzDayCursor loadMzDayCursor(String cursorKey) {
|
MzDayCursor cursor = new MzDayCursor();
|
try {
|
String json = redisCache.getCacheObject(cursorKey);
|
if (StringUtils.isBlank(json)) {
|
return cursor;
|
}
|
JSONObject obj = JSONObject.parseObject(json);
|
cursor.day = obj.getString("day");
|
cursor.page = obj.getLongValue("page");
|
cursor.finalDay = obj.getString("finalDay");
|
cursor.finalPage = obj.getLongValue("finalPage");
|
cursor.backfillDay = obj.getString("backfillDay");
|
cursor.backfillPage = obj.getLongValue("backfillPage");
|
cursor.backfillDone = obj.getString("backfillDone");
|
if (cursor.page < 1L) {
|
cursor.page = 1L;
|
}
|
if (cursor.finalPage < 1L) {
|
cursor.finalPage = 1L;
|
}
|
if (cursor.backfillPage < 1L) {
|
cursor.backfillPage = 1L;
|
}
|
return cursor;
|
} catch (Exception e) {
|
log.warn("【dealHisDataMZ】读取断点{}失败,按空断点处理", cursorKey, e);
|
return new MzDayCursor();
|
}
|
}
|
|
/**
|
* 门急诊采集断点:每天一轮全量刷新,这里分别记录三个轮次中断在第几页
|
* (页码为 1 表示该轮次下一轮从第一页整轮开始)
|
*/
|
private static class MzDayCursor {
|
/** 今天的整轮刷新 */
|
private String day;
|
private long page = 1L;
|
/** 昨天的收尾采集 */
|
private String finalDay;
|
private long finalPage = 1L;
|
/** 待做的一次性回溯 */
|
private String backfillDay;
|
private long backfillPage = 1L;
|
/** 已经补过的回溯日期,避免定时任务每轮重复补同一天 */
|
private String backfillDone;
|
}
|
|
/**
|
* 同德药品数据采集
|
*/
|
|
public void dealHisDataMedication() {
|
final long OUTP_PAGE_SIZE = 500L;
|
ServiceSLTDInhospReqVO serviceSLTDInhospReqVO = new ServiceSLTDInhospReqVO();
|
serviceSLTDInhospReqVO.setOrgId("20001001");
|
Long outpPage = 1L;
|
int totalCount = 0; // 统计总共采集的药品数量
|
|
while (true) {
|
serviceSLTDInhospReqVO.setCurrent(outpPage);
|
serviceSLTDInhospReqVO.setSize(OUTP_PAGE_SIZE);
|
log.info("【dealHisData】省立同德\"药品数据\"采集第{}页数据", outpPage);
|
|
try {
|
Integer fetchedCount = serviceSLTDHealthcareRecordService.queryMedicationItemList(serviceSLTDInhospReqVO);
|
log.info("【dealHisData】省立同德\"药品数据\"第{}页采集到{}条记录", outpPage, fetchedCount);
|
|
totalCount += fetchedCount != null ? fetchedCount : 0;
|
|
// 如果返回的数据量小于 pageSize,说明已经是最后一页了,退出循环
|
if (fetchedCount == null || fetchedCount < OUTP_PAGE_SIZE) {
|
log.info("【dealHisData】省立同德\"药品数据\"采集完成,总页数:{}, 总计{}条记录", outpPage, totalCount);
|
break;
|
}
|
|
outpPage++;
|
} catch (Exception e) {
|
log.error("【dealHisData】省立同德\"药品数据\"第{}页采集失败", outpPage, e);
|
// 出错时也可以选择退出或继续,这里选择退出避免无限重试
|
break;
|
}
|
}
|
}
|
|
|
public void dealHisDataSLTD() {
|
log.info("【dealHisData】开始执行HIS数据采集任务");
|
|
try {
|
LocalDate startDate = LocalDate.of(2025, 11, 1);
|
LocalDate endDate = LocalDate.of(2026, 2, 27);
|
|
// 省立同德数据采集
|
// String nowTime = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
|
String nowTime = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
ServiceSLTDInhospReqVO serviceSLTDInhospReqVO = new ServiceSLTDInhospReqVO();
|
serviceSLTDInhospReqVO.setOrgId("20001001");
|
serviceSLTDInhospReqVO.setCampusId(30001002L);
|
log.info("【dealHisData】省立同德“门急诊”开始采集数据,院区:{}", "30001002");
|
serviceSLTDInhospReqVO.setStartHeadTime(null);
|
serviceSLTDInhospReqVO.setStartTailTime(null);
|
serviceSLTDInhospReqVO.setEncounterTimeStart(nowTime);
|
serviceSLTDInhospReqVO.setEncounterTimeEnd(nowTime);
|
serviceSLTDInhospReqVO.setStatusList(null);
|
List<String> list1 = new ArrayList<>();
|
list1.add("FH0108.01");
|
list1.add("FH0108.03");
|
serviceSLTDInhospReqVO.setHealthcareRecordTypeList(list1);
|
log.info("【dealHisData】省立同德“门急诊”采集数据入参:{}", serviceSLTDInhospReqVO);
|
serviceSLTDHealthcareRecordService.queryHealthcareRecordList(serviceSLTDInhospReqVO);
|
log.info("【dealHisData】省立同德“门急诊”束采集数据,院区:{}", "30001002");
|
}
|
} catch (Exception e) {
|
log.error("【dealHisData】省立同德数据采集异常", e);
|
}
|
|
}
|
|
/**
|
* 这个只是新华临时使用,平时用不到
|
*/
|
public void dealHisData2() {
|
//将患者信息、出入院数据全部采集
|
// 指定的开始日期
|
LocalDate endDate = LocalDate.of(2026, 7, 6);
|
// 当前日期
|
LocalDate currentDate = LocalDate.now();
|
// 定义日期格式
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd ");
|
|
// 从开始日期到当前日期逐天打印
|
for (LocalDate date = endDate; !date.isAfter(currentDate); date = date.plusDays(1)) {
|
System.out.println(date.format(formatter));
|
ixhGatherPatArchiveService.getInHospDataGather("0", date.minusDays(1).atStartOfDay(), date.atStartOfDay());
|
ixhGatherPatArchiveService.getInHospDataGather("1", date.minusDays(1).atStartOfDay(), date.atStartOfDay());
|
}
|
|
}
|
|
/**
|
* 处理患者信息,进入子任务表
|
*/
|
public void dealOutHospInfo() {
|
String config = configService.selectConfigByKey("visit.early.day");
|
if (port.equals("8095")) {
|
//出院表
|
iPatMedInhospService.dealOutHospInfo(config);
|
//门诊表(新华的暂时不做门诊随访)
|
if (!active.equals("xh")) {
|
iPatMedOuthospService.dealOutpatientInfo();
|
}
|
}
|
}
|
|
/**
|
* 处理患者信息,进入子任务表(任务组)
|
*/
|
public void dealOutHospInfoBySchedule() {
|
String config = configService.selectConfigByKey("visit.early.day");
|
if (port.equals("8095")) {
|
//出院表
|
iPatMedInhospService.dealOutHospInfoBySchedule(config);
|
//门诊表(新华的暂时不做门诊随访)
|
// if (!active.equals("xh")) {
|
// //iPatMedOuthospService.dealOutpatientInfo();
|
// }
|
}
|
}
|
|
|
/**
|
* 处理手术信息,进入子任务表
|
*/
|
public void dealOperationInfo() {
|
if (port.equals("8095")) iPatMedOperationService.dealOperationInfo();
|
|
}
|
|
/**
|
* 门诊分表定时任务:从 sys_config 读取分表模式,按模式建表并刷新视图 v_pat_med_outhosp
|
* 配置 key: outhosp.split.mode
|
* quarter -> 按季度,表名示例:pat_med_outhosp_20260103
|
* year -> 按年,表名示例:pat_med_outhosp_2026
|
* month -> 按月,表名示例:pat_med_outhosp_202601
|
* 查询不到配置则不分表
|
*/
|
public void createOuthospQuarterTable() {
|
log.info("【createOuthospQuarterTable】开始执行门诊分表任务");
|
createDataTable.createOuthospQuarterTable();
|
}
|
|
/**
|
* 处理患者信息,进入子任务表(微信小程序)
|
*/
|
public void dealOutHospInfoXHC() {
|
if (port.equals("8095")) {
|
PatMedInhosp patMedInhosp = new PatMedInhosp();
|
//获取未处理的数据
|
List<ServicePatientTemp> servicePatientTemps = iServicePatientTempService.selectServicePatientTempList(new ServicePatientTemp());
|
}
|
}
|
|
|
/**
|
* 长期任务发送
|
*/
|
public void longTaskSend() {
|
//获取任务信息
|
ServiceTask st = new ServiceTask();
|
st.setDelFlag("0");
|
st.setLongTask(1);
|
List<ServiceTask> serviceTasks = serviceTaskMapper.selectServiceTaskList(st);
|
log.info("【longTaskSend】获取到{}个长期任务", serviceTasks.size());
|
for (ServiceTask serviceTask : serviceTasks) {
|
CommonTaskcallMQ commonTaskcallMQ = new CommonTaskcallMQ();
|
commonTaskcallMQ.setTaskid(serviceTask.getTaskid());
|
commonTaskcallMQ.setPreachform(serviceTask.getPreachform());
|
commonTaskcallMQ.setSendType("2");
|
|
//通过任务ID拿到患者信息,并且随访时间得是今天之前的
|
ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
|
serviceSubtaskVO.setTaskid(commonTaskcallMQ.getTaskid());
|
serviceSubtaskVO.setSendstate(2L);
|
serviceSubtaskVO.setIsVisitAgain(1);
|
serviceSubtaskVO.setVisitTime(new Date());
|
List<ServiceSubtask> selectServiceSubtaskList = serviceSubtaskMapper.queryServiceSubtaskList(serviceSubtaskVO);
|
for (ServiceSubtask serviceSubtask : selectServiceSubtaskList) {
|
sfHandlle(serviceSubtask);
|
}
|
}
|
}
|
|
/**
|
* 处理补偿任务
|
*/
|
public void compensateTask() {
|
//获取到sendstate=3、1 并且 visit_time为小于等于今天的subtask
|
List<Long> list = Arrays.asList(3L, 1L);
|
ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
|
List<ServiceSubtask> serviceSubtaskList = new ArrayList<>();
|
for (Long sendstate : list) {
|
serviceSubtaskVO.setSendstate(sendstate);
|
serviceSubtaskVO.setVisitTime(new Date());
|
List<ServiceSubtask> compensateServiceSubtaskList = serviceSubtaskMapper.getCompensateServiceSubtaskList(serviceSubtaskVO);
|
serviceSubtaskList.addAll(compensateServiceSubtaskList);
|
}
|
for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
|
//根据当前的执行方式,获取下一种执行方式
|
ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
|
serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
|
serviceSubtaskPreachform.setSubid(serviceSubtask.getId());
|
serviceSubtaskPreachform.setOrgid(serviceSubtask.getOrgid());
|
List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
|
//获取当前执行方式的序号
|
Optional<Long> currentSort = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getSort).findFirst();
|
Optional<Long> id = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getId).findFirst();
|
if (currentSort.isPresent()) {
|
//1先检查一下,是不是有执行状态是完成的(怕之前已经有完的了,没有将servuce_subtask的状态改成功,这里再检查一下)
|
boolean finishState = serviceSubtaskPreachforms.stream().allMatch(item -> item.getSendstate().equals("9"));
|
if (finishState) {
|
serviceSubtask.setSendstate(6L);
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
continue;
|
}
|
|
//2判断一下,当前的sort是不是等于需要执行的总个数,如果等于的话,说明是最后一个,直接将servuce_subtask的状态改成5,执行失败就行了
|
Long cs = currentSort.get();
|
|
if (cs.equals(serviceSubtaskPreachforms.size())
|
&& isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) {
|
serviceSubtask.setSendstate(7L);
|
serviceSubtask.setRemark("处理补偿任务,当前处理最后补偿,全部执行失败(超时)");
|
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
//修改发送方式的状态为失败
|
serviceSubtaskPreachform.setSendstate("5");
|
serviceSubtaskPreachform.setId(id.get());
|
|
serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(serviceSubtaskPreachform);
|
continue;
|
}
|
|
//3.不是最后一个,获取到下一个执行方式(因为都是在今天执行,那就直接发出去就完了)
|
sfHandlle(serviceSubtask);
|
}
|
}
|
}
|
|
/**
|
* 设置失败任务默认值,并将失败任务重新置为成功
|
* <p>
|
* *@param failDay (失败天数:距离当前日期失败天数)
|
*
|
* @return
|
*/
|
public void setFailSubTaskDefalutVal() {
|
String failDay = configService.selectConfigByKey("hosp.default.fail.day");
|
if (StringUtils.isNotEmpty(failDay)) iServiceSubtaskService.setFailSubTaskDefalutVal(Long.valueOf(failDay));
|
}
|
|
|
/**
|
* 判断日期是否是今天
|
*
|
* @param date
|
* @return
|
*/
|
private boolean isDateToday(Date date) {
|
if (date == null) {
|
return false;
|
}
|
// 将 Date 转为 LocalDate
|
LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
// 获取今天的 LocalDate
|
LocalDate today = LocalDate.now();
|
// 如果日期早于或等于今天,返回 true
|
return !localDate.isAfter(today);
|
}
|
|
/**
|
* 随访-补偿处理
|
*
|
* @param serviceSubtask
|
*/
|
private void sfHandlle(ServiceSubtask serviceSubtask) {
|
//这里需要根据身份证去重(给微信小程序的固定任务用的)
|
List<ServiceSubtask> serviceSubtaskListFilter = new ArrayList<>();
|
ServiceTask ivrTask1 = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
|
ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
|
serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
|
serviceSubtaskPreachform.setSubid(serviceSubtask.getId());
|
//获取发送方式
|
String sendPreachform = getSendPreachform(serviceSubtaskPreachform, serviceSubtask);
|
if (sendPreachform.equals("-1") || serviceSubtask.getSendstate() == 6 || serviceSubtask.getSendstate() == 5 || serviceSubtask.getSendstate() == 4) {
|
//说明已经全部遍历完了,当前的执行方式序号是最后一个了 或者 该患者已经随访结束(成功或失败了或不执行)
|
log.error("说明已经全部遍历完了,当前的执行方式序号是最后一个了 或者 该患者已经随访结束(成功或失败了或不执行)");
|
return;
|
}
|
//先判断患者是不是还要发送
|
PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid());
|
if (!Objects.isNull(patArchive) && patArchive.getNotrequiredFlag() == "1") {
|
//不需要发送
|
serviceSubtask.setResult("患者不需要随访");
|
serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + "患者不需要随访," + patArchive.getNotrequiredreason() : "患者不需要随访," + patArchive.getNotrequiredreason());
|
|
serviceSubtask.setSendstate(4L);
|
iServiceSubtaskService.insertServiceSubtask(serviceSubtask);
|
setSuccessPreachForm(serviceSubtask, "-1", "不需要执行", "6");
|
return;
|
}
|
|
String descByCode = ServiceFromEnum.getDescByCode(Integer.valueOf(sendPreachform));
|
if (descByCode.equals("电话")) {
|
List<String> list = new ArrayList<>();
|
ServiceTask ivrTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
|
if (ivrTask.getSendState() != null && ivrTask.getSendState() == 3 || ivrTask.getSendState() != null && ivrTask.getSendState() == 4) {
|
//如何任务被"暂停"或"终止"
|
return;
|
}
|
|
if (org.apache.commons.lang3.StringUtils.isEmpty(serviceSubtask.getPhone())) {
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "手机号为空", "4");
|
return;
|
}
|
boolean dateToday = isDateToday(serviceSubtask.getVisitTime());
|
//说明是立即发送(先把消息放到cache-0中, displayNo不知道怎么配置)
|
if (dateToday) {
|
list.add(serviceSubtask.getId().toString());
|
//在子任务表里记录一下
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "长期任务,电话进入队列成功", "2");
|
//任务发送记录
|
ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord();
|
serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString());
|
serviceSubtaskRecord.setSubtaskId(serviceSubtask.getId());
|
serviceSubtaskRecord.setUuid(UUID.randomUUID().toString());
|
serviceSubtaskRecord.setTasktype(serviceSubtask.getType());
|
serviceSubtaskRecord.setPreachform("3");
|
serviceSubtaskRecord.setStartTime(System.currentTimeMillis());
|
serviceSubtaskRecord.setRemark("长期任务,电话进入队列成功");
|
serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord);
|
}
|
//将要执行的放到缓存中
|
if (list.size() > 0) {
|
redisCache.setCacheListLeftAndDistinct("cache-0", list);
|
log.info("【sfHandlle】电话任务已加入队列,数量:{}", list.size());
|
}
|
} else if (descByCode.equals("微信小程序")) {
|
//微信小程序
|
if (ObjectUtils.isNotEmpty(ivrTask1) && ivrTask1.getPatCycle() == 1) {
|
//说明该任务的患者是循环执行的
|
//判断患者过滤集合中,是否存在当前执行患者的身份证
|
boolean continutFlag = false;
|
for (ServiceSubtask ss : serviceSubtaskListFilter) {
|
if (ss.getSfzh().equals(serviceSubtask.getSfzh())) {
|
continutFlag = true;
|
}
|
}
|
//如果存在当前执行患者的身份证,则不执行该患者了
|
if (continutFlag) {
|
return;
|
}
|
|
//将子任务ID删除 、sendstate改成3(循环任务就是这样)
|
serviceSubtask.setSendstate(3L);
|
serviceSubtask.setId(null);
|
serviceSubtask.setFinishtime(null);
|
serviceSubtask.setCreateTime(new Date());
|
serviceSubtask.setUpdateTime(new Date());
|
serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
|
|
//将当前要执行的患者放到过滤患者集合中
|
serviceSubtaskListFilter.add(serviceSubtask);
|
}
|
} else if (descByCode.equals("短信")) {
|
RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
|
String taskId = rsaPublicKeyExample.encryptedData(ivrTask1.getTaskid().toString(), pub_key);
|
log.info("【sfHandlle】处理短信长期任务,患者ID:{}", serviceSubtask.getPatid());
|
boolean dateToday = isDateToday(serviceSubtask.getVisitTime());
|
//记录当前时间 如果失败记录当前时间
|
LocalDateTime now = LocalDateTime.now();
|
if (dateToday) {
|
try {
|
String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key);
|
String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key);
|
SendMagParam sendMagParam = new SendMagParam();
|
sendMagParam.setType("4");
|
ServiceOutPath serviceOutPath = new ServiceOutPath();
|
serviceOutPath.setParam1(taskId);
|
serviceOutPath.setParam2(patid);
|
serviceOutPath.setParam3(ivrTask1.getTaskName());
|
serviceOutPath.setParam6(subId);
|
serviceOutPath.setCreateTime(new Date());
|
serviceOutPath.setOrgid(serviceSubtask.getOrgid());
|
iServiceOutPathService.insertServiceOutPath(serviceOutPath);
|
String url = "";
|
String format = String.format("%03X", serviceOutPath.getId());
|
//先判断一下发的是不是宣教
|
if (!"3".equals(serviceSubtask.getType())) {
|
sendMagParam.setPhone(serviceSubtask.getPhone());
|
url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format;
|
sendMagParam.setUrl(url);
|
//如果type是语音随访的话(说明补偿发送方式中有电话随访的方式,这里的外链就地址只能用/sf)
|
if (serviceSubtask.getType().equals("1"))
|
url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/sf?p=" + format : localIP + "/sf?p=" + format;
|
sendMagParam.setUrl(url);
|
|
// SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template");
|
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")) {
|
sysConfig = sysConfigMapper.checkConfigKeyUnique("mzmyd.sms.template");
|
} else {
|
sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template");
|
}
|
if (!Objects.isNull(sysConfig)) {
|
String smsContemt = sysConfig.getConfigValue();
|
// sendMagParam.setContent("您好,邀请您填写出院调查表,请点击" + sendMagParam.getUrl() + "填写。感谢您配合!");
|
sendMagParam.setContent(smsContemt.replace("${wjurl}", sendMagParam.getUrl()));
|
}
|
} else {
|
HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid());
|
if (heLibrary.getHetype().equals("1")) {
|
sendMagParam.setPhone(serviceSubtask.getPhone());
|
url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/xj?p=" + format : localIP + "/xj?p=" + format;
|
|
sendMagParam.setUrl(url);
|
|
SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("xj.sms.template");
|
if (!Objects.isNull(sysConfig)) {
|
String smsContemt = sysConfig.getConfigValue();
|
// sendMagParam.setContent("您好,邀请您填写出院宣教调查表,请点击" + sendMagParam.getUrl() + "查看。感谢您配合!");
|
sendMagParam.setContent(smsContemt.replace("${xjurl}", sendMagParam.getUrl()));
|
|
}
|
} else if (heLibrary.getHetype().equals("2")) {
|
//通知
|
sendMagParam.setPhone(serviceSubtask.getPhone());
|
// 替换文本内容中的变量
|
String content = getObject(serviceSubtask, heLibrary.getPreachcontent());
|
sendMagParam.setContent(content);
|
}
|
|
}
|
|
serviceOutPath.setRadix(format);
|
serviceOutPath.setUpdateTime(new Date());
|
serviceOutPath.setUrl(url);
|
iServiceOutPathService.updateServiceOutPath(serviceOutPath);
|
String isSuccess = null;
|
log.info("active的值为:{}", active);
|
if (active.equals("xh")) {
|
Map<String, String> req = new HashMap<>();
|
// req.put("phone", sendMagParam.getPhone());
|
// req.put("content", sendMagParam.getContent());
|
Map<String, String> map2 = new HashMap<String, String>();
|
map2.put("action", "send");
|
map2.put("account", xhsmsAccount);
|
map2.put("password", xhsmsPwd);
|
map2.put("mobile", sendMagParam.getPhone());
|
map2.put("content", sendMagParam.getContent());
|
map2.put("extno", xhsmsjrm);
|
map2.put("rt", "json");
|
StringBuilder encodedParams = new StringBuilder();
|
|
for (Map.Entry<String, String> entry : map2.entrySet()) {
|
if (encodedParams.length() > 0) {
|
encodedParams.append("&");
|
}
|
// 对键和值进行URL编码
|
String encodedKey = URLEncoder.encode(entry.getKey(), "UTF-8");
|
String encodedValue = URLEncoder.encode(entry.getValue(), "UTF-8");
|
encodedParams.append(encodedKey).append("=").append(encodedValue);
|
}
|
Boolean result = HttpUtils.sendPost(xhsmsPath, new Gson().toJson(req));
|
if (result) isSuccess = "true";
|
} else if (active.equals("ls")) {
|
// String url = configService.selectConfigByKey("token.360", serviceSubtask.getOrgid());
|
// //丽水的短信发送方式
|
// Map<String, String> map = MsgLSEnum.getAddressByCode(serviceSubtask.getOrgid());
|
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);
|
String token = LSHospTokenUtil.getToken(serviceSubtask.getOrgid(), msgInfo.get("tokenUrl"));
|
if (ObjectUtils.isNotEmpty(msgInfo) && StringUtils.isEmpty(msgInfo.get("address"))) {
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "短信发送失败,该机构没有配置短信地址, 时间:" + now, "5");
|
return;
|
}
|
log.info("【sfHandlle】丽水短信发送,地址:{},参数:{},机构ID:{}", msgInfo.get("address"), sendMagParam, serviceSubtask.getOrgid());
|
String dxCode = getDXCode(msgInfo.get("address"), sendMagParam.getPhone(), sendMagParam.getContent(), msgInfo.get("sendPersonId"), msgInfo.get("sendPersonName"), MsgLSEnum.getHeaderByCode(msgInfo), token);
|
log.info("【sfHandlle】丽水短信发送结果:{}", dxCode);
|
ObjectMapper objectMapper = new ObjectMapper();
|
Map<String, Object> textParam = objectMapper.readValue(dxCode, Map.class);
|
String code = textParam.get("Code").toString();
|
if (code.equals("0")) {
|
isSuccess = "true";
|
}
|
} else if (active.equals("sltd") || active.equals("nhfy")) {
|
log.info("sltd进来了吗?{} ,---sendMagParam.getContent()的参数为:{}", active, sendMagParam.getContent());
|
if (active.equals("sltd")) {
|
//省立同德的短信发送方式
|
String data = MessageSend.sendMsg(sendMagParam.getContent(), "6", sendMagParam.getPhone(), LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
|
if (StringUtils.isNotEmpty(data)) {
|
// 解析 result=0&description=成功&faillist= 格式(result=0成功,1失败)
|
log.info("【sfHandlle】省立同德短信发送返回:{}", data);
|
String[] pairs = data.split("&");
|
String resultVal = null;
|
for (String pair : pairs) {
|
String[] kv = pair.split("=", 2);
|
if ("result".equals(kv[0])) {
|
resultVal = kv.length > 1 ? kv[1] : null;
|
break;
|
}
|
}
|
if ("0".equals(resultVal)) {
|
isSuccess = "true";
|
}
|
}
|
} else 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")) {
|
isSuccess = "true";
|
}
|
}
|
} else if (active.equals("hzszlyy")) {//市一医院
|
String content = sendMagParam.getContent().replace("【新华医院】", "");
|
|
SysDept sysDeptVo = new SysDept();
|
List<SysDept> sysDepts = new ArrayList<>();
|
if (ObjectUtils.isNotEmpty(serviceSubtask.getDeptcode())) {
|
sysDeptVo.setDeptType("1");
|
sysDeptVo.setOrgid(serviceSubtask.getOrgid());
|
sysDeptVo.setDeptCode(serviceSubtask.getDeptcode());
|
sysDeptService.selectDeptList(sysDeptVo);
|
} else if (ObjectUtils.isNotEmpty(serviceSubtask.getLeavehospitaldistrictcode())) {
|
sysDeptVo.setDeptType("2");
|
sysDeptVo.setOrgid(serviceSubtask.getOrgid());
|
sysDeptVo.setDeptCode(serviceSubtask.getLeavehospitaldistrictcode());
|
sysDeptService.selectDeptList(sysDeptVo);
|
}
|
SysDept sysDept = CollectionUtils.isNotEmpty(sysDepts) ? sysDepts.get(0) : new SysDept();
|
String campusid = ObjectUtils.isNotEmpty(sysDept) ? sysDept.getCampusid() : "2";
|
//湖滨单独发送方式
|
if ("1".equals(campusid)) {
|
String result = smsUtils.sendSms1(xhsmsPath, xhsmsAccount, xhsmsPwd, sendMagParam.getPhone(), content);
|
//这里需要根据result返回的值去判断,是否成功,然后将值赋值给isSuccess
|
if (StringUtils.isNotEmpty(result) && result.contains("处理成功")) {
|
isSuccess = "true";
|
}
|
} else {
|
String result = smsUtils.sendSms(xhsmsPath, xhsmsAccount, xhsmsPwd, sendMagParam.getPhone(), content);
|
//这里需要根据result返回的值去判断,是否成功,然后将值赋值给isSuccess
|
if (StringUtils.isNotEmpty(result) && result.contains("处理成功")) {
|
isSuccess = "true";
|
}
|
}
|
}
|
//任务发送记录
|
ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord();
|
serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString());
|
serviceSubtaskRecord.setSubtaskId(serviceSubtask.getId());
|
serviceSubtaskRecord.setUuid(UUID.randomUUID().toString());
|
serviceSubtaskRecord.setTasktype(serviceSubtask.getType());
|
serviceSubtaskRecord.setPreachform("4");
|
serviceSubtaskRecord.setStartTime(System.currentTimeMillis());
|
serviceSubtaskRecord.setResult("success");
|
if (StringUtils.isNotEmpty(isSuccess) && !isSuccess.equals("true"))
|
serviceSubtaskRecord.setResult("error");
|
serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord);
|
|
//发送完成后,修改状态
|
serviceSubtask.setSendstate(3L);
|
if (StringUtils.isNotEmpty(isSuccess) && isSuccess.equals("true")) {
|
serviceSubtask.setResult("success");
|
serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ",短信发送成功" : "短信发送成功");
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "短信发送成功", "2");
|
} else {
|
serviceSubtask.setResult("error");
|
serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + ",短信发送失败" + now : "短信发送失败" + now);
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "短信发送失败" + now, "5");
|
}
|
} catch (Exception e) {
|
String guid = UUID.randomUUID().toString();
|
log.error("【sfHandlle】长期任务短信发送失败,原因:{},GUID:{}, 时间: {}", e.getMessage(), guid, now);
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "长期任务短信发送失败:系统错误, 时间: " + now, "5");
|
}
|
}
|
|
} else if (descByCode.equals("公众号")) {
|
log.info("【sfHandlle】处理公众号任务,任务信息:{}", ivrTask1);
|
//公众号
|
RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
|
String taskId = rsaPublicKeyExample.encryptedData(ivrTask1.getTaskid().toString(), pub_key);
|
boolean dateToday = isDateToday(serviceSubtask.getVisitTime());
|
if (dateToday) {
|
try {
|
String patid = rsaPublicKeyExample.encryptedData(serviceSubtask.getPatid().toString(), pub_key);
|
String subId = rsaPublicKeyExample.encryptedData(serviceSubtask.getId().toString(), pub_key);
|
String url = null;
|
url = localIP + ":" + req_path + "/outsideChainwt?param1=" + taskId + "¶m2=" + patid + "¶m3=" + URLEncoder.encode(ivrTask1.getTaskName(), StandardCharsets.UTF_8.toString()) + "¶m5=false" + "$param6=" + subId;
|
|
ServiceOutPath serviceOutPath = new ServiceOutPath();
|
serviceOutPath.setParam1(taskId);
|
serviceOutPath.setParam2(patid);
|
serviceOutPath.setParam3(ivrTask1.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);
|
|
//获取微信公众号请求信息根据机构ID
|
List<String> wxqqxx = WxGZHEnum.getDescByCode(patArchive.getOrgid());
|
//市一医院 不校验
|
|
if (CollectionUtils.isEmpty(wxqqxx) || wxqqxx.size() < 4) {
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "【公众号】该机构的公众号配置信息不全,无法通过公众号发送", "4");
|
return;
|
}
|
|
if (StringUtils.isEmpty(patArchive.getPatidHis())) {
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "【公众号】公众号发送失败,his系统的患者id为空", "5");
|
return;
|
}
|
String wxCode = "";
|
//市一医院
|
if (active.equals("hzszlyy")) {
|
//处理中文乱码问题
|
wxCode = smsUtils.sendChat(url, patArchive.getTelcode(), serviceSubtask.getSfzh());
|
} else {
|
wxCode = getWXCode(serviceSubtask.getSfzh(), url, serviceSubtask.getTaskName(), serviceSubtask.getTaskDesc(), patArchive.getTelcode(), serviceSubtask.getSendname(), patArchive.getPatidHis(), wxqqxx);
|
}
|
|
Map map = JSONObject.parseObject(wxCode, Map.class);
|
//任务发送记录
|
ServiceSubtaskRecord serviceSubtaskRecord = new ServiceSubtaskRecord();
|
serviceSubtaskRecord.setTaskid(serviceSubtask.getTaskid().toString());
|
serviceSubtaskRecord.setUuid(UUID.randomUUID().toString());
|
serviceSubtaskRecord.setTasktype(serviceSubtask.getType());
|
serviceSubtaskRecord.setPreachform("4");
|
serviceSubtaskRecord.setStartTime(System.currentTimeMillis());
|
serviceSubtaskRecord.setResult("success");
|
Boolean wxCodeSuccess = false;
|
if (active.equals("hzszlyy")) {
|
if (!map.isEmpty() && map.get("success") != null) {
|
Integer wxCodeSuccessShiyi = (Integer) map.get("success");
|
if (ObjectUtils.isNotEmpty(wxCodeSuccessShiyi) && wxCodeSuccessShiyi == 1) {
|
wxCodeSuccess = true;
|
} else {
|
wxCodeSuccess = false;
|
}
|
}
|
} else {
|
if (!map.isEmpty() && map.get("succ") != null) {
|
wxCodeSuccess = (boolean) map.get("succ");
|
}
|
}
|
if (!map.isEmpty() && !wxCodeSuccess) serviceSubtaskRecord.setResult("error");
|
serviceSubtaskRecordService.insertServiceSubtaskRecord(serviceSubtaskRecord);
|
|
//发送完成后,修改状态
|
serviceSubtask.setSendstate(3L);
|
if (wxCodeSuccess) {
|
serviceSubtask.setResult("success");
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "【公众号】公众号发送成功", "2");
|
} else {
|
log.error("【sfHandlle】公众号发送失败,患者信息:{},错误信息:{}", serviceSubtask, map.get("msg"));
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "【公众号】公众号发送失败", "5");
|
}
|
} catch (Exception e) {
|
String guid = UUID.randomUUID().toString();
|
log.error("【sfHandlle】长期任务公众号发送失败,原因:{},GUID:{}", e.getMessage(), guid);
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "【公众号】长期任务公众号发送失败,原因:" + e.getMessage(), "5");
|
}
|
}
|
} else if (descByCode.equals("人工")) {
|
setSuccessPreachForm(serviceSubtask, sendPreachform, "人工发送成功", "2");
|
}
|
|
}
|
|
|
private Date getNextVisitTime(Long subid, Long taskid, Date visitTime) {
|
ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
|
serviceSubtaskPreachform.setSubid(subid);
|
serviceSubtaskPreachform.setTaskid(taskid);
|
List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
|
if (CollectionUtils.isNotEmpty(serviceSubtaskPreachforms)) {
|
String compensateTime = serviceSubtaskPreachforms.get(0).getCompensateTime();
|
int hoursToAdd = Integer.valueOf(compensateTime) * 24;
|
Calendar calendar = Calendar.getInstance();
|
calendar.setTime(visitTime);
|
calendar.add(Calendar.HOUR_OF_DAY, hoursToAdd);
|
Date newDate = calendar.getTime();
|
return newDate;
|
}
|
return visitTime;
|
}
|
|
private String getSendPreachform(ServiceSubtaskPreachform serviceSubtaskPreachform, ServiceSubtask serviceSubtask) {
|
List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
|
|
if (CollectionUtils.isEmpty(serviceSubtaskPreachforms)) {
|
//如果serviceSubtaskPreachforms为空的话,则需要进行新增一下
|
List<ServiceSubtaskPreachform> serviceSubtaskPreachformList = addServiceSubtaskPreachform(serviceSubtask, "1");
|
if (CollectionUtils.isEmpty(serviceSubtaskPreachformList)) {
|
log.error("ryTask--发送方式失败了serviceSubtask的入参为:{}", serviceSubtask);
|
return null;
|
}
|
serviceSubtaskPreachforms = serviceSubtaskPreachformList;
|
}
|
|
// 情况1:currentPreachform为空,取sort为1的preachform
|
if (StringUtils.isEmpty(serviceSubtask.getCurrentPreachform())) {
|
String firstPreachform = serviceSubtaskPreachforms.stream().filter(item -> item.getSort() == 1L).map(ServiceSubtaskPreachform::getPreachform).findFirst().orElse(null);
|
|
//更新一下当前发送时间
|
if (StringUtils.isNotEmpty(firstPreachform)) {
|
serviceSubtaskPreachform.setPreachform(firstPreachform);
|
serviceSubtaskPreachform.setCurrentSendTime(new Date());
|
serviceSubtaskPreachformMapper.updateSSPByCondition(serviceSubtaskPreachform);
|
}
|
return firstPreachform;
|
}
|
|
// 情况2:currentPreachform不为空,找下一个sort
|
Optional<Long> currentSort = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getSort).findFirst();
|
|
if (currentSort.isPresent()) {
|
// 检查是否所有sendstate不等于9
|
boolean allSendStateNot1AndNot9 = serviceSubtaskPreachforms.stream().allMatch(item -> !item.getSendstate().equals("9"));
|
if (!allSendStateNot1AndNot9) {
|
//说明,在某种方式发送失败后,又成功了(例如短信或公众号,在规定时间外患者做完了,这个时候,状态改成了9)
|
serviceSubtask.setSendstate(6L);
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
return "-1";
|
}
|
// 当sort等于列表size时,并且所有sendstate都不等于9,则返回-1
|
if (currentSort.get().equals((long) serviceSubtaskPreachforms.size())
|
&& isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) {
|
if (allSendStateNot1AndNot9) {
|
//说明全发送失败了
|
serviceSubtask.setSendstate(7L);
|
serviceSubtask.setFinishtime(null);
|
log.error("getSendPreachform方法 检查是否所有sendstate不等于9, 全失败了");
|
serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + "所有执行方式均未获取结果,任务失败(超时)" : "所有执行方式均未获取结果,任务失败(超时)");
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
//修改发送状态
|
setFail(serviceSubtaskPreachforms, serviceSubtask);
|
}
|
return "-1";
|
}
|
|
// 当sort等于列表size时,下一个sort为-1
|
Long nextSort = currentSort.get() + 1;
|
//如果当前的发送方式不为空,并且开始准备要用下一种方式发送了,那当前的肯定没有发送成功,需要设置失败
|
if (StringUtils.isNotEmpty(serviceSubtask.getCurrentPreachform())) {
|
setFail(serviceSubtaskPreachforms, serviceSubtask);
|
}
|
|
// 找到下一个sort对应的preachform
|
String nextPreachform = serviceSubtaskPreachforms.stream().filter(item -> nextSort.equals(item.getSort())).map(ServiceSubtaskPreachform::getPreachform).findFirst().orElse("-1");
|
|
//更新一下当前发送时间
|
if (StringUtils.isNotEmpty(nextPreachform)) {
|
serviceSubtaskPreachform.setCurrentSendTime(new Date());
|
serviceSubtaskPreachform.setPreachform(nextPreachform);
|
serviceSubtaskPreachformMapper.updateSSPByCondition(serviceSubtaskPreachform);
|
}
|
return nextPreachform;
|
}
|
return null;
|
}
|
|
private List<ServiceSubtaskPreachform> addServiceSubtaskPreachform(ServiceSubtask serviceSubtask, String sendstate) {
|
//将preachformDesc的json对象,放到list集合中
|
ServiceTask serviceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
|
String preachformDesc = serviceTask.getPreachformDesc();
|
|
List<ServiceSubtaskPreachform> sspl = null;
|
ObjectMapper objectMapper = new ObjectMapper();
|
if (org.apache.commons.lang3.StringUtils.isNotEmpty(preachformDesc)) {
|
try {
|
sspl = objectMapper.readValue(preachformDesc, new TypeReference<List<ServiceSubtaskPreachform>>() {
|
});
|
} catch (JsonProcessingException e) {
|
log.error("ryTask--preachform转List<ServiceSubtaskPreachform>报错了:{}", e.getMessage());
|
}
|
for (ServiceSubtaskPreachform serviceSubtaskPreachform : sspl) {
|
serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
|
serviceSubtaskPreachform.setSubid(serviceSubtask.getId());
|
//这个sendstate需要在数据库设置一个默认值为“1”
|
serviceSubtaskPreachform.setSendstate("1");
|
if (StringUtils.isNotEmpty(sendstate)) serviceSubtaskPreachform.setSendstate(sendstate);
|
serviceSubtaskPreachform.setOrgid(serviceSubtask.getOrgid());
|
serviceSubtaskPreachformMapper.insertServiceSubtaskPreachform(serviceSubtaskPreachform);
|
}
|
|
}
|
|
return sspl;
|
}
|
|
private Integer setFail(List<ServiceSubtaskPreachform> serviceSubtaskPreachforms, ServiceSubtask serviceSubtask) {
|
Optional<Long> id = serviceSubtaskPreachforms.stream().filter(item -> serviceSubtask.getCurrentPreachform().equals(item.getPreachform())).map(ServiceSubtaskPreachform::getId).findFirst();
|
if (id.isPresent()) {
|
ServiceSubtaskPreachform subtaskPreachform = new ServiceSubtaskPreachform();
|
subtaskPreachform.setSendstate("5");
|
subtaskPreachform.setId(id.get());
|
subtaskPreachform.setRemark("当前发送方式在规定时间内未成功获取结果");
|
return serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(subtaskPreachform);
|
}
|
return 0;
|
}
|
|
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 = HttpUtils.sendPost(address, body);
|
String result = null;
|
try {
|
result = OkHttpExample.sendPostRequest(address, body, token);
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
log.info("【getDXCode】短信发送结果:{}", result);
|
|
JSONObject jsonObject = JSONObject.parseObject(result);
|
String code = (String) jsonObject.toString();
|
return code;
|
}
|
|
|
private String getWXCode(String idcard, String url, String taskName, String taskDesc, String phone, String setPatientname, String setPatientid, List<String> wxqqxx) {
|
XinHuaWXReq xinHuaWXReq = new XinHuaWXReq();
|
xinHuaWXReq.setIdcard(idcard);
|
xinHuaWXReq.setUrl(url);
|
xinHuaWXReq.setPatientid(setPatientid);
|
xinHuaWXReq.setPatientname(setPatientname);
|
xinHuaWXReq.setMobile(phone);
|
xinHuaWXReq.setMedcardno(null);
|
xinHuaWXReq.setTitlename(taskName);
|
xinHuaWXReq.setContent(taskDesc);
|
xinHuaWXReq.setAppid(wxqqxx.get(1));
|
log.info("【getWXCode】微信公众号请求参数:{}", xinHuaWXReq);
|
String body = new Gson().toJson(xinHuaWXReq);
|
String encode = encode(wxqqxx.get(2).concat(body));
|
Map<String, String> headerMap = new HashMap<>();
|
headerMap.put("sign", encode);
|
String result = HttpUtils.sendPostByHeader(wxqqxx.get(3), body, headerMap);
|
log.info("【getWXCode】微信公众号返回参数:{}", result);
|
JSONObject jsonObject = JSONObject.parseObject(result);
|
String code = (String) jsonObject.toString();
|
return code;
|
}
|
|
|
public String encode(String arg) {
|
if (arg == null) {
|
arg = "";
|
}
|
MessageDigest md5 = null;
|
try {
|
md5 = MessageDigest.getInstance("MD5");
|
md5.update(arg.getBytes("UTF-8"));
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return toHex(md5.digest());
|
}
|
|
public void collectHIS() {
|
try {
|
// HIS数据采集
|
log.info("【dealHisData】HIS开始采集数据");
|
ichService.sync();
|
log.info("【dealHisData】HIS结束采集数据");
|
} catch (Exception e) {
|
log.error("【dealHisData】HIS数据采集异常", e);
|
}
|
}
|
|
public void collectHISYesterday() {
|
try {
|
// 获取昨天0点到今天0点的时间范围
|
LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
|
LocalDateTime yesterdayZero = todayZero.minusDays(1);
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
String startTime = yesterdayZero.format(formatter);
|
String endTime = todayZero.format(formatter);
|
// HIS数据采集
|
log.info("【collectHISYesterday】HIS开始采集数据");
|
// 立即返回,后台异步执行
|
CompletableFuture.runAsync(() -> {
|
ichService.syncMedInhosp(startTime, endTime);
|
});
|
log.info("【collectHISYesterday】HIS结束采集数据");
|
} catch (Exception e) {
|
log.error("【collectHISYesterday】HIS数据采集异常", e);
|
}
|
}
|
|
public void collectHISDaysBefore(Long daysBefore) {
|
try {
|
// 获取daysBefore 0点到daysBefore-1 0点的时间范围
|
LocalDateTime todayZero = LocalDateTime.now().with(LocalTime.MIN);
|
LocalDateTime daysBeforeZeroStart = todayZero.minusDays(daysBefore);
|
LocalDateTime daysBeforeZeroEnd = todayZero.minusDays(daysBefore-1L);
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
String startTime = daysBeforeZeroStart.format(formatter);
|
String endTime = daysBeforeZeroEnd.format(formatter);
|
// HIS数据采集
|
log.info("【collectHISDaysBefore】HIS开始采集数据: startTime:{}, endtime:{}",startTime, endTime);
|
// 立即返回,后台异步执行
|
CompletableFuture.runAsync(() -> {
|
ichService.syncMedInhosp(startTime, endTime);
|
});
|
log.info("【collectHISDaysBefore】HIS结束采集数据: startTime:{}, endtime:{}",startTime, endTime);
|
} catch (Exception e) {
|
log.error("【collectHISDaysBefore】HIS数据采集异常", e);
|
}
|
}
|
|
public Boolean setSuccessPreachForm(ServiceSubtask serviceSubtask, String preachform, String remark, String failSendstate) {
|
if (preachform.equals("-1")) {
|
//说明都不需要执行了
|
ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
|
serviceSubtaskPreachform.setSubid(serviceSubtask.getId());
|
serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
|
serviceSubtaskPreachform.setOrgid(serviceSubtask.getOrgid());
|
serviceSubtaskPreachform.setSendstate(failSendstate);
|
serviceSubtaskPreachform.setCurrentSendTime(new Date());
|
serviceSubtaskPreachformMapper.updateSSPByCondition(serviceSubtaskPreachform);
|
return true;
|
}
|
|
ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
|
serviceSubtaskPreachform.setSubid(serviceSubtask.getId());
|
serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
|
serviceSubtaskPreachform.setOrgid(serviceSubtask.getOrgid());
|
List<ServiceSubtaskPreachform> sspCount = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
|
|
serviceSubtaskPreachform.setPreachform(preachform);
|
//1:未发送状态
|
serviceSubtaskPreachform.setSendstate("1");
|
//电话的未发送状态,需要查2,因为,数据可能卡在队列里了; (没进队列,电话状态还是1)
|
if (preachform.equals("3") && StringUtils.isNotEmpty(failSendstate) && Long.valueOf(failSendstate) > 2)
|
serviceSubtaskPreachform.setSendstate("2");
|
// //人工的未发送状态,需要查2
|
// if (preachform.equals("1") && StringUtils.isNotEmpty(failSendstate) && Long.valueOf(failSendstate) > 2)
|
// serviceSubtaskPreachform.setSendstate("2");
|
log.error("-----serviceSubtaskPreachform的入参是?{}", serviceSubtaskPreachform);
|
List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
|
if (CollectionUtils.isNotEmpty(serviceSubtaskPreachforms)) {
|
ServiceSubtaskPreachform serviceSubtaskPreachform1 = serviceSubtaskPreachforms.get(0);
|
serviceSubtaskPreachform1.setSendstate(failSendstate);
|
if (serviceSubtask.getType().equals("3") || serviceSubtask.getType().equals("4")) {
|
//如果是宣教或通知,并且发送成功,直接将发送状态改成9
|
if (failSendstate.equals("2")) serviceSubtaskPreachform1.setSendstate("9");
|
}
|
serviceSubtaskPreachform1.setRemark(remark);
|
serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(serviceSubtaskPreachform1);
|
|
//如果当前的preachform已经是最后一个了,那直接将serviceSubtask的sendstate状态改成7就行了(全超时了)
|
if (serviceSubtaskPreachform1.getSort() == sspCount.size()
|
&& isSubtaskDeadline(serviceSubtask, serviceSubtaskPreachforms)) {
|
if (failSendstate.equals("4") || failSendstate.equals("5")) {
|
serviceSubtask.setCurrentPreachform(preachform);
|
serviceSubtask.setSendstate(7L);
|
log.error("setSuccessPreachForm方法,当前的preachform已经是最后一个了,全部执行失败");
|
serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + "所有发送方式均未获取结果,任务失败(超时)" : "所有发送方式均未获取结果,任务失败(超时)");
|
//serviceSubtask.setRemark("setSuccessPreachForm方法,当前的preachform已经是最后一个了,全部执行失败");
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
return true;
|
}
|
}
|
} else {
|
log.error("【定时任务中该患者没有查询到属于他的发送方式,subid:{},prechform:{},orgid:{}】", serviceSubtask.getId(), preachform, serviceSubtask.getOrgid());
|
return false;
|
}
|
|
//将下一次的随访时间与当前执行方式记录一下
|
serviceSubtask.setVisitTime(getNextVisitTime(serviceSubtask.getId(), serviceSubtask.getTaskid(), serviceSubtask.getVisitTime()));
|
serviceSubtask.setCurrentPreachform(preachform);
|
serviceSubtask.setSendstate(3L);
|
|
if (serviceSubtask.getType().equals("3") || serviceSubtask.getType().equals("4")) {
|
//如果是宣教或通知,并且发送成功,则直接将serviceSubtask状态改成6L(这个患者是没有题做的,不会再触发接口进行状态修改)
|
if (failSendstate.equals("2")) {
|
serviceSubtask.setSendstate(6L);
|
}
|
}
|
serviceSubtask.setRemark(StringUtils.isNotEmpty(serviceSubtask.getRemark()) ? serviceSubtask.getRemark() + "," + remark : remark);
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
return true;
|
}
|
|
/**
|
* 通配符变量替换
|
*
|
* @param serviceSubtask
|
* @param scriptContent
|
* @return
|
*/
|
private String getObject(ServiceSubtask serviceSubtask, String scriptContent) {
|
Map<String, Map<String, String>> param = getParam(serviceSubtask.getTaskid());
|
for (Map<String, String> map : param.values()) {
|
for (String key : map.keySet()) {
|
scriptContent = scriptContent.replace(key, StringUtils.isNotEmpty(map.get(key)) ? map.get(key) : "");
|
}
|
}
|
if (StringUtils.isEmpty(scriptContent)) {
|
return scriptContent;
|
}
|
scriptContent = scriptContent.replace("${name}", StringUtils.isNotEmpty(serviceSubtask.getSendname()) ? serviceSubtask.getSendname() : "");
|
scriptContent = scriptContent.replace("${dzz}", StringUtils.isNotEmpty(serviceSubtask.getAddr()) ? serviceSubtask.getAddr() : "");
|
scriptContent = scriptContent.replace("${phone}", StringUtils.isNotEmpty(serviceSubtask.getTelcode()) ? serviceSubtask.getTelcode() : "");
|
|
return scriptContent;
|
}
|
|
/**
|
* 获取任务里的通配符
|
*
|
* @param taskId
|
* @return
|
*/
|
private Map<String, Map<String, String>> getParam(Long taskId) {
|
ServiceTask serviceTask = serviceTaskMapper.selectServiceTaskByTaskid(taskId);
|
ObjectMapper objectMapper = new ObjectMapper();
|
Map<String, Map<String, String>> serviceTaskMap = null;
|
try {
|
serviceTaskMap = objectMapper.readValue(serviceTask.getTextParam(), Map.class);
|
} catch (JsonProcessingException e) {
|
e.printStackTrace();
|
}
|
return serviceTaskMap;
|
}
|
|
public int qwenLLMTest(String questionText, String voiceText, String value, String regexText) {
|
int result = QwenLLMUtil.matchRegex(questionText, voiceText, value, regexText);
|
return result;
|
}
|
|
/**
|
* 任务组(appltype=5)首轮纳入:扫描新出院患者,按 schedule 绑定的维度匹配任务组,
|
* 为命中的患者按计划明细一次性生成第 0 轮 N 条 subtask,并置 schedulecheck_flag=1。
|
* 后续轮次由 {@link #rollTaskGroupCycle()} 负责。
|
* <p>
|
* 与主扫描 dealOutHospInfo 分离,互不干扰。建议每 30 分钟执行一次。
|
*/
|
public void dealTaskGroupOutHosp() {
|
log.info("【dealTaskGroupOutHosp】开始扫描任务组新出院患者");
|
if (!port.equals("8095")) {
|
return;
|
}
|
try {
|
String config = configService.selectConfigByKey("visit.early.day");
|
iPatMedInhospService.dealOutHospInfoBySchedule(config);
|
log.info("【dealTaskGroupOutHosp】任务组首轮纳入扫描完成");
|
} catch (Exception e) {
|
log.error("【dealTaskGroupOutHosp】任务组扫描异常", e);
|
}
|
}
|
|
/**
|
* 任务组(appltype=5)循环任务滚动调度。
|
* <p>
|
* 扫描所有 schedule_style=1 的计划,若本轮 subtask 全部 finalize(sendstate ∉ 1/2/3),
|
* 则克隆本轮患者到下一轮,推进 current_loop_count 与 visit_time。
|
* <p>
|
* 建议每小时或每半小时执行一次,避免轮次积压。
|
*/
|
public void rollTaskGroupCycle() {
|
log.info("【rollTaskGroupCycle】开始扫描循环任务组");
|
try {
|
int rolled = serviceTaskScheduleService.rollCycleTasks();
|
log.info("【rollTaskGroupCycle】本次推进 {} 个计划", rolled);
|
} catch (Exception e) {
|
log.error("【rollTaskGroupCycle】滚动调度异常", e);
|
}
|
}
|
|
/**
|
* 随访任务是否超时
|
* @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;
|
}
|
}
|
if (Objects.isNull(serviceSubtask) || CollectionUtils.isEmpty(serviceSubtaskPreachforms)) {
|
return false;
|
}
|
// 基准时刻:出院时间 + 发送日(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();
|
}
|
|
/**
|
* 处理超时随访任务
|
* @return
|
*/
|
public void dealSubtaskDeadline(String orgid, Integer deadlineDay){
|
//获取任务信息
|
ServiceTask st = new ServiceTask();
|
st.setDelFlag("0");
|
st.setLongTask(1);
|
st.setNexttaskflag("1");
|
st.setOrgid(orgid);
|
List<ServiceTask> serviceTasks = serviceTaskMapper.selectServiceTaskList(st);
|
for (ServiceTask serviceTask : serviceTasks) {
|
deadlineDay = -deadlineDay;
|
Date deadline = DateUtils.addDays(new Date(), deadlineDay);
|
//通过任务ID拿到患者信息,并且随访时间得是今天之前的
|
ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
|
serviceSubtaskVO.setOrgid(orgid);
|
serviceSubtaskVO.setSendstate(7L);
|
//只扫描首次随访的
|
serviceSubtaskVO.setVisitCount(1);
|
serviceSubtaskVO.setTaskid(serviceTask.getTaskid());
|
serviceSubtaskVO.setEndOutHospTime(deadline);
|
List<ServiceSubtask> serviceSubtaskList
|
= serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
|
log.info("【dealSubtaskDeadline】获取到{}个超时任务, taskid={}", serviceSubtaskList.size(), serviceTask.getTaskid());
|
for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
|
PatMedInhosp patMedInhospVo = new PatMedInhosp();
|
patMedInhospVo.setOrgid(serviceSubtask.getOrgid());
|
patMedInhospVo.setInhospid(serviceSubtask.getInhospid());
|
List<PatMedInhosp> patMedInhospList = iPatMedInhospService.selectPatMedInhospList(patMedInhospVo);
|
PatMedInhosp patMedInhosp = new PatMedInhosp();
|
if (!patMedInhospList.isEmpty()) {
|
patMedInhosp = patMedInhospList.get(0);
|
}else {
|
continue;
|
}
|
if(ObjectUtils.isEmpty(serviceTask.getNexttaskid())){
|
continue;
|
}
|
ServiceTask nextServiceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceTask.getNexttaskid());
|
PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid());
|
String config = configService.selectConfigByKey("visit.early.day");
|
Integer type = 1;
|
|
//新增再次随访任务
|
ServiceSubtask serviceSubtaskAgain = iPatMedInhospService.boxedServiceSubtask(nextServiceTask,
|
patMedInhosp, patArchive, config, type);
|
serviceSubtaskAgain.setId(null);
|
serviceSubtaskAgain.setUpid(serviceSubtask.getId().intValue());
|
serviceSubtaskAgain.setVisitCount(serviceSubtask.getVisitCount() + 1);
|
serviceSubtaskAgain.setSendstate(2L);
|
serviceSubtaskAgain.setCreateTime(new Date());
|
serviceSubtaskAgain.setUpdateTime(new Date());
|
serviceSubtaskAgain.setVisitType(serviceSubtask.getVisitType());
|
serviceSubtaskAgain.setVisitDeptCode(serviceSubtask.getVisitDeptCode());
|
serviceSubtaskAgain.setVisitDeptName(serviceSubtask.getVisitDeptName());
|
int i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain);
|
if (i == 1) {
|
//再次随访任务创建成功后,原任务改为失败状态
|
serviceSubtask.setSendstate(5L);
|
serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
|
}
|
}
|
}
|
}
|
|
}
|