package com.smartor.common;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.ruoyi.common.exception.base.BaseException;
|
import com.ruoyi.common.utils.DateUtils;
|
import com.smartor.domain.*;
|
import com.smartor.mapper.ServiceSubtaskMapper;
|
import com.smartor.mapper.ServiceSubtaskPreachformMapper;
|
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.stereotype.Component;
|
|
import java.util.Calendar;
|
import java.util.Date;
|
import java.util.List;
|
import java.util.Map;
|
|
/**
|
* 任务组(appltype=5)subtask 生成器
|
* <p>
|
* 单一职责:根据 schedule + detailList 为每个患者派生 subtask。
|
* 同时服务两条路径:
|
* (a) 前端手动勾选患者(insertOrUpdateTask) —— 旧 6 参入口;
|
* (b) HIS 自动纳入新出院患者(PatMedInhospServiceImpl.writeInSubTask) —— 新 5 参入口。
|
* 两条路径统一从 baseSubtask 上取基准日字段,避免生成器与 PatTaskRelevance/ServiceTaskVO 耦合。
|
*
|
* @author smartor
|
* @date 2026-06-30
|
*/
|
@Slf4j
|
@Component
|
public class ScheduleSubtaskBuilder {
|
|
@Autowired
|
private ServiceSubtaskMapper serviceSubtaskMapper;
|
|
@Autowired
|
private ServiceSubtaskPreachformMapper serviceSubtaskPreachformMapper;
|
|
/**
|
* 为单个患者派生 subtask(appltype=5)—— 解耦入口(自动纳入 & 手动勾选统一走这里)。
|
* <p>
|
* 非循环:按 detailList 一次性铺平 N 条;
|
* 循环 :按 schedule.currentLoopCount 生成当前轮 N 条,后续轮次由调度器滚动建。
|
*
|
* @param serviceTask 主任务(已落库)
|
* @param schedule 已落库的主计划
|
* @param detailList 明细列表(按 seq 升序)
|
* @param baseSubtask 模板 subtask(已填充患者基础信息 + 基准日字段),方法内会深拷贝
|
* @param preachformList 发送方式(调用方已解析好,可为空)
|
*/
|
public void buildSubtasksForPatient(ServiceTask serviceTask,
|
ServiceTaskSchedule schedule,
|
List<ServiceTaskScheduleDetail> detailList,
|
ServiceSubtask baseSubtask,
|
List<Map<String, Object>> preachformList) {
|
if (CollectionUtils.isEmpty(detailList)) {
|
throw new BaseException("任务组明细为空,无法生成 subtask, taskid=" + serviceTask.getTaskid());
|
}
|
|
Date benchmark = resolveBenchmark(schedule, baseSubtask);
|
long currentLoop = schedule.getCurrentLoopCount() == null ? 0L : schedule.getCurrentLoopCount();
|
|
for (ServiceTaskScheduleDetail detail : detailList) {
|
ServiceSubtask subtask = copyFromBase(baseSubtask);
|
|
// 回溯字段
|
subtask.setScheduleId(schedule.getId());
|
subtask.setScheduleDetailId(detail.getId());
|
subtask.setScheduleSeq(detail.getSeq());
|
subtask.setLoopCount(currentLoop);
|
|
// 模板:detail 优先于 task
|
if (detail.getTemplateid() != null) {
|
subtask.setTemplateid(detail.getTemplateid());
|
subtask.setTemplatename(detail.getTemplatename());
|
}
|
if (detail.getLibtemplateid() != null) {
|
subtask.setLibtemplateid(detail.getLibtemplateid());
|
}
|
|
// 时间:基准日 + dayOffset
|
Date visitTime = addDays(benchmark, detail.getDayOffset());
|
subtask.setVisitTime(visitTime);
|
subtask.setSenddate(visitTime);
|
subtask.setLongSendTime(visitTime);
|
|
// 状态:与原流程一致,新建后置为待发送
|
subtask.setSendstate(2L);
|
subtask.setCreateTime(DateUtils.getNowDate());
|
subtask.setUpdateTime(DateUtils.getNowDate());
|
|
serviceSubtaskMapper.insertServiceSubtask(subtask);
|
|
insertPreachform(serviceTask, preachformList, subtask);
|
|
log.info("[任务组] taskid={} patid={} 生成 subtask id={} seq={} dayOffset={} visitTime={}",
|
serviceTask.getTaskid(), baseSubtask.getPatid(),
|
subtask.getId(), detail.getSeq(), detail.getDayOffset(), visitTime);
|
}
|
}
|
|
/**
|
* 兼容入口:前端手动勾选患者(insertOrUpdateTask)。
|
* 把 patTaskRelevance 的基准日字段回填到 baseSubtask 后,委托给解耦入口。
|
*/
|
public void buildSubtasksForPatient(ServiceTask serviceTask,
|
ServiceTaskVO serviceTaskVO,
|
ServiceTaskSchedule schedule,
|
List<ServiceTaskScheduleDetail> detailList,
|
PatTaskRelevance patTaskRelevance,
|
ServiceSubtask baseSubtask) {
|
// 回填基准日字段(手动路径的 baseSubtask 由 VO 拼装,基准日字段可能未填全)
|
if (baseSubtask.getStarttime() == null) {
|
baseSubtask.setStarttime(patTaskRelevance.getInhosptime() != null
|
? patTaskRelevance.getInhosptime() : patTaskRelevance.getStarttime());
|
}
|
if (baseSubtask.getEndtime() == null) {
|
baseSubtask.setEndtime(patTaskRelevance.getEndtime());
|
}
|
if (baseSubtask.getAdmindate() == null) {
|
baseSubtask.setAdmindate(patTaskRelevance.getVisittime());
|
}
|
buildSubtasksForPatient(serviceTask, schedule, detailList, baseSubtask,
|
serviceTaskVO.getPreachformList());
|
}
|
|
/**
|
* 根据 scheduleBenchmark 解析基准时间:
|
* 0-自定义时间 1-入院时间 2-出院时间 3-就诊时间 4-入组时间
|
* 全部从 baseSubtask 取,取不到兜底当前时间。
|
*/
|
private Date resolveBenchmark(ServiceTaskSchedule schedule, ServiceSubtask base) {
|
Integer benchmark = schedule.getScheduleBenchmark() == null ? 0 : schedule.getScheduleBenchmark();
|
Date now = DateUtils.getNowDate();
|
switch (benchmark) {
|
case 1:
|
return base.getStarttime() != null ? base.getStarttime() : now;
|
case 2:
|
return base.getEndtime() != null ? base.getEndtime() : now;
|
case 3:
|
return base.getAdmindate() != null ? base.getAdmindate() : now;
|
case 4:
|
return base.getCreateTime() != null ? base.getCreateTime() : now;
|
case 0:
|
default:
|
return schedule.getScheduleBenchmarkCustomTime() != null
|
? schedule.getScheduleBenchmarkCustomTime() : now;
|
}
|
}
|
|
private Date addDays(Date base, int dayOffset) {
|
Calendar c = Calendar.getInstance();
|
c.setTime(base);
|
c.add(Calendar.DAY_OF_MONTH, dayOffset);
|
return c.getTime();
|
}
|
|
/**
|
* 写 service_subtask_preachform,发送方式由调用方备好。
|
*/
|
private void insertPreachform(ServiceTask serviceTask, List<Map<String, Object>> pfList, ServiceSubtask subtask) {
|
if (CollectionUtils.isEmpty(pfList)) {
|
return;
|
}
|
for (Map<String, Object> map : pfList) {
|
ServiceSubtaskPreachform pf = new ServiceSubtaskPreachform();
|
pf.setSort(ObjectUtils.isEmpty(map.get("sort")) ? 0 : Long.valueOf(map.get("sort").toString()));
|
pf.setPreachform(ObjectUtils.isEmpty(map.get("preachform")) ? "" : map.get("preachform").toString());
|
pf.setCompensateTime(ObjectUtils.isEmpty(map.get("compensateTime")) ? "" : map.get("compensateTime").toString());
|
pf.setTaskid(serviceTask.getTaskid());
|
pf.setSubid(subtask.getId());
|
pf.setSendstate("1");
|
pf.setOrgid(serviceTask.getOrgid());
|
pf.setCreateTime(new Date());
|
serviceSubtaskPreachformMapper.insertServiceSubtaskPreachform(pf);
|
}
|
}
|
|
/**
|
* 深拷贝 baseSubtask 到一个新对象(每次 insert 后 id 会回写,必须独立实例)。
|
* 用 fastjson 做深拷贝,省一堆 set。
|
*/
|
private ServiceSubtask copyFromBase(ServiceSubtask base) {
|
String json = JSON.toJSONString(base);
|
ServiceSubtask copy = JSON.parseObject(json, ServiceSubtask.class);
|
// 主键、id 必须清掉,否则 useGeneratedKeys 仍会用上轮的 id 触发主键冲突
|
copy.setId(null);
|
return copy;
|
}
|
}
|