package com.ruoyi.outpatientvisit.service; import com.ruoyi.common.core.service.ArchiveReadApi; import com.ruoyi.common.core.service.ServiceTaskMatchApi; import com.ruoyi.common.core.service.VisitTaskCreateApi; import com.ruoyi.common.core.service.dto.OuthospSubtaskDraft; import com.ruoyi.common.core.service.dto.ServiceTaskMatchDto; import com.ruoyi.common.core.service.dto.VisitArchiveRow; import com.ruoyi.common.core.service.dto.VisitLongTaskDto; import com.ruoyi.common.core.service.dto.VisitPendingSubtaskDto; import com.ruoyi.outpatientvisit.domain.PatMedOuthosp; import com.ruoyi.outpatientvisit.domain.PatMedOuthospQueryReq; import com.ruoyi.outpatientvisit.mapper.PatMedOuthospMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Objects; /** * 门急诊随访编排:扫描未处理门诊记录 → 按科室/诊断维度匹配长期任务 → 写子任务。 * *
| 本类方法 | 原实现 |
|---|---|
| {@link #dealOutpatientInfo()} | *{@code PatMedOuthospServiceImpl#dealOutpatientInfo} L385-427(43 行) |
| {@link #writeInSubTask} | *同文件 L436-521(86 行) |
| {@link #boxedServiceSubtask} | *同文件 L525-581(35 个 setter) |
* 逐行对应原 {@code dealOutpatientInfo}(L385-427): *
* PatMedOuthosp q = new PatMedOuthosp();
* q.setDiagcheckFlag("0");
* q.setFuflag("1");
* for (每条未处理门诊记录) {
* 查档案;
* 科室维度:longtask=1 + deptCode + service_type="3" -> writeInSubTask(taskId, true, ..., 1)
* 诊断维度:longtask=1 + icd10code -> writeInSubTask(taskId, true, ..., 2)
* }
* return 1; // 固定值
*
*
* @return 固定 {@code 1}(与原实现一致,不是处理条数)
*/
public Integer dealOutpatientInfo() {
ServiceTaskMatchApi matchApi = matchApi();
VisitTaskCreateApi taskApi = taskApi();
ArchiveReadApi archiveApi = archiveApi();
if (matchApi == null || taskApi == null) {
log.warn("【门急诊随访】跨模块契约不可用(ServiceTaskMatchApi={}, VisitTaskCreateApi={}),跳过本次门诊随访。",
matchApi != null, taskApi != null);
return 1;
}
PatMedOuthosp query = new PatMedOuthosp();
query.setDiagcheckFlag("0");
query.setFuflag("1");
List
* 逐行对应原 {@code PatMedOuthospServiceImpl#writeInSubTask}(L436-521)。
*
* @param type 1 = 科室维度;2 = 诊断维度
* ⚠️ 原实现的 flag 映射是交叉的(见类注释第 2 条),原样保留。
*/
private void writeInSubTask(VisitTaskCreateApi taskApi, Long taskid, Boolean check,
PatMedOuthosp row, VisitArchiveRow archive, Integer type) {
// 原 L438-441:查「已发布的长期任务」(taskid + sendState=2)
VisitLongTaskDto serviceTask = taskApi.findPublishedLongTask(taskid);
if (serviceTask == null) {
log.info("该患者疾病随访长期任务不存在,任务ID为:{}", taskid);
// ⚠️ 原实现的交叉映射,原样保留
if (type == 1) row.setDiagcheckFlag("2");
if (type == 2) row.setDeptcheckFlag("2");
row.setRemark("该患者门诊随访长期任务不存在,任务ID为:" + taskid);
updateFlag(row);
return;
}
// 原 L452:封装 serviceSubtask
OuthospSubtaskDraft draft = boxedServiceSubtask(serviceTask, row, archive);
boolean ok = false;
// 原 L455:先判断一下,是否需要校验
if (Boolean.TRUE.equals(check)) {
// 原 L457-464:按 patid + sendstate=2 + taskid 查待执行子任务
List
* 原 L484-490 / L492-499 两处逻辑相同:
*
* 逐字段对应原 {@code boxedServiceSubtask}(L525-581)。
* 35 个赋值里绝大多数落在 {@code VisitSubtaskDraft} 已有字段上;
* 只有 {@code admitdate} / {@code fudate} / {@code finishtime} / {@code hospType}
* 落在 {@link OuthospSubtaskDraft}(见该类注释的对照表)。
*
*
* 逐行对应原 {@code PatMedOuthospServiceImpl#addDays}(L561-568)。
* ⚠️ 与出入院侧的 {@code minusDay} 不是同一个方法(那个硬编码减 2 天并忽略入参)。
*/
private Date addDays(Date date, Integer days) {
if (days == null) {
days = 1;
}
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_MONTH, days);
return calendar.getTime();
}
/**
* 按"传什么更新什么"更新门诊记录的标志位。
*
* 原实现调 {@code updatePatMedOuthosp},其 SQL 走 {@code updateInTable}
* (动态表名 + 全列可选更新),这里保持同样的入口与表名。
*/
private void updateFlag(PatMedOuthosp row) {
try {
patMedOuthospMapper.updateInTable("pat_med_outhosp", row);
} catch (Exception e) {
log.warn("【门急诊随访】更新门诊记录标志位失败,row.id={}:{}", row.getId(), e.toString());
}
}
/**
* 门诊实体 → 存储过程入参。
*
* 本路径只用到 {@code diagcheckFlag} 与 {@code fuflag} 两个筛选条件,
* 故按最小必要字段设置;不用 DtoConversionUtils——
* 它会把全部同名字段带过去,而多带的字段可能改变存储过程的 WHERE 分支。
*/
private PatMedOuthospQueryReq toQueryReq(PatMedOuthosp q) {
PatMedOuthospQueryReq req = new PatMedOuthospQueryReq();
req.setDiagcheckFlag(q.getDiagcheckFlag());
req.setFuflag(q.getFuflag());
return req;
}
private ServiceTaskMatchApi matchApi() {
return providerGet(matchApiProvider, "ServiceTaskMatchApi");
}
private ArchiveReadApi archiveApi() {
return providerGet(archiveApiProvider, "ArchiveReadApi");
}
private VisitTaskCreateApi taskApi() {
return providerGet(taskApiProvider, "VisitTaskCreateApi");
}
private
* if (StringUtils.isEmpty(serviceSubtask.getPhone())) {
* serviceSubtask.setRemark("手机号为空");
* serviceSubtask.setSendstate(4L);
* serviceSubtask.setResult("error");
* }
* serviceSubtask.setCreateBy(serviceTask.getCreateBy());
* serviceSubtask.setCreateTime(new Date());
* i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
*
*/
private boolean insertSubtask(VisitTaskCreateApi taskApi, OuthospSubtaskDraft draft,
VisitLongTaskDto serviceTask) {
if (StringUtils.isEmpty(draft.getPhone())) {
draft.setRemark("手机号为空");
draft.setSendstate(SENDSTATE_SKIP);
draft.setResult("error");
}
draft.setCreateBy(serviceTask.getCreateBy());
draft.setCreateTime(new Date());
return taskApi.insertSubtask(draft);
}
/**
* 门诊版子任务组装。
* ⚠️ 刻意保留的原行为
*
*
*/
private OuthospSubtaskDraft boxedServiceSubtask(VisitLongTaskDto serviceTask,
PatMedOuthosp row,
VisitArchiveRow archive) {
OuthospSubtaskDraft d = new OuthospSubtaskDraft();
// ---- 来自 serviceTask ----
d.setTaskid(serviceTask.getTaskid());
d.setOrgid(serviceTask.getOrgid());
d.setCampusid(serviceTask.getCampusid());
// 原 L533-534:libtemplateid 在 ServiceTask 里是 String,落库列/草稿里是 Long,
// 原实现显式 Long.valueOf 转换,且【仅在非空时】设值(为空则保持 null -> 列不写)。原样保留。
if (StringUtils.isNotEmpty(serviceTask.getLibtemplateid())) {
d.setLibtemplateid(Long.valueOf(serviceTask.getLibtemplateid()));
}
d.setTemplateid(serviceTask.getTemplateid());
d.setTemplatename(serviceTask.getTemplatename());
d.setServiceType(serviceTask.getServiceType());
d.setPreachform(serviceTask.getPreachform());
d.setUpdateBy(serviceTask.getUpdateBy());
// ---- 来自门诊记录 ----
d.setDrcode(row.getDrcode());
d.setDrname(row.getDrname());
d.setDeptcode(row.getDeptcode());
d.setInhospid(row.getId());
d.setHospno(row.getOuthospno());
d.setDeptname(row.getDeptname());
d.setLeavediagname(row.getDiagname());
d.setLeaveicd10code(row.getIcd10code());
d.setVisitDeptCode(row.getDeptcode());
d.setVisitDeptName(row.getDeptname());
// 门诊侧独有(父类没有的字段)
d.setAdmitdate(row.getAdmitdate());
d.setFudate(row.getFudate());
// ---- 来自患者档案 ----
if (archive != null) {
d.setPatid(archive.getId());
d.setSendname(archive.getName());
d.setSfzh(archive.getIdcardno());
// 原实现:phone 取 telcode;为空则取 relativetelcode
d.setPhone(StringUtils.isBlank(archive.getTelcode())
? archive.getRelativetelcode() : archive.getTelcode());
d.setSex(archive.getSex());
d.setAge(archive.getAge());
}
// ---- 固定值 / 状态 ----
d.setSendstate(SENDSTATE_PENDING);
d.setSfzh(archive == null ? null : archive.getIdcardno());
// ⚠️ 硬编码 "1"(原实现不读 serviceTask.getHospType()),原样保留
d.setHospType(HOSP_TYPE_OUTHOSP);
d.setCreateTime(new Date());
d.setUpdateBy(serviceTask.getUpdateBy());
d.setUpdateTime(new Date());
d.setUpdateTime(new Date());
// ---- 发送时间(原 L562-570)----
if (serviceTask.getSendDay() == null) {
serviceTask.setSendDay(1L);
}
Date newDate = addDays(row.getAdmitdate(), serviceTask.getSendDay().intValue());
if (row.getFudate() != null) {
// 如果门诊表有指定随访时间,那就用指定的
newDate = row.getFudate();
}
d.setLongSendTime(newDate);
d.setVisitTime(newDate);
// ---- 患者不需要随访(原 L571-579)----
if (archive != null && StringUtils.isNotEmpty(archive.getNotrequiredFlag())
&& NOT_REQUIRED_YES.equals(archive.getNotrequiredFlag())) {
d.setRemark(archive.getNotrequiredreason());
d.setResult("error");
d.setSendstate(SENDSTATE_SKIP);
}
return d;
}
/**
* 在 {@code date} 上加 {@code days} 天;{@code days} 为 null 时按 1 天。
*