package com.ruoyi.inhospvisit.service; import com.ruoyi.common.core.service.VisitTaskCreateApi; import com.ruoyi.common.core.service.dto.VisitLongTaskDto; import com.ruoyi.common.core.service.dto.VisitPendingSubtaskDto; import com.ruoyi.common.core.service.dto.VisitSubtaskDraft; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.core.service.dto.VisitArchiveRow; import com.ruoyi.inhospvisit.domain.row.VisitInhospRow; import com.ruoyi.inhospvisit.support.InhospFlagWriter; import com.ruoyi.inhospvisit.support.VisitSubtaskFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import java.util.Date; import java.util.List; /** * 随访子任务「写入口」—— 逐行搬自 {@code PatMedInhospServiceImpl#writeInSubTask}(L682-913,232 行)。 * *
| 原调用 | 现在 |
|---|---|
| {@code serviceTaskMapper.selectServiceTaskList(st)}(L689) | *{@link VisitTaskCreateApi#findPublishedLongTask(Long)} |
| {@code serviceSubtaskMapper.insertServiceSubtask(...)}(L823/838/854/862/873) | *{@link VisitTaskCreateApi#insertSubtask(VisitSubtaskDraft)} |
| {@code serviceSubtaskMapper.updateServiceSubtask(...)}(L782/791/812/836) | *{@link VisitTaskCreateApi#updatePendingSubtask(VisitPendingSubtaskDto)} |
| {@code serviceSubtaskMapper.selectServiceSubtaskList(subtask)}(L764) | *{@link VisitTaskCreateApi#findPendingSubtasks(Long, Long)} |
* 该方法(原 L1061-1103,43 行)在第 8 步才搬进本模块,
* 但 {@code writeInSubTask} 现在就用到它(L840/855/874)。
* 所以这里先用一个 {@code ObjectProvider} 惰性拿;取不到就跳过并打 WARN。
*/
@Autowired
private ObjectProvider
* ⚠️ 注意 type=0 在"成功/失败"分支里【没有】对应 if(原实现也没写),
* 所以 type=0 生成成功后不会把 {@code medcheck_flag} 置 1 —— 原样保留。
*
* remark 只有"失败"分支会写(原 L897)。
*/
private void writeFlagByType(Long inhospid, Integer type, String flagValue, String remark) {
if (type == null) {
return;
}
String column = flagColumnOfSuccessOrFail(type);
if (column == null) {
// type=0(药品宣教)在成功/失败分支里没有对应 flag,原实现同样什么都不做
return;
}
if (remark == null) {
flagWriter.setFlag(inhospid, column, flagValue);
} else {
flagWriter.setFlagWithRemark(inhospid, column, flagValue, remark);
}
}
/**
* type → 标志位列(成功/失败分支)。照抄原 L881-885 / L892-896:
*
* 组装器只读 task 的少量字段,这里逐字段映射;不留任何"看起来没用"的字段不映射
* —— 少映射一个就会静默丢值(见 VisitSubtaskFactory 的类注释)。
*
* ⚠️ {@code type / sendDay / updateBy / createBy / serviceType / preachform} 等
* 都在 {@link VisitLongTaskDto} 里有对应字段,直接搬。
*/
private com.ruoyi.inhospvisit.domain.row.VisitTaskRow toTaskSource(VisitLongTaskDto dto,
VisitInhospRow inhosp) {
com.ruoyi.inhospvisit.domain.row.VisitTaskRow t = new com.ruoyi.inhospvisit.domain.row.VisitTaskRow();
t.setTaskid(dto.getTaskid());
t.setTaskName(dto.getTaskName());
t.setType(dto.getType());
t.setServiceType(dto.getServiceType());
t.setTemplateid(dto.getTemplateid());
t.setTemplatename(dto.getTemplatename());
t.setLibtemplateid(dto.getLibtemplateid());
t.setSendDay(dto.getSendDay());
t.setPreachform(dto.getPreachform());
t.setPreachformDesc(dto.getPreachformDesc());
t.setOrgid(dto.getOrgid());
t.setCampusid(dto.getCampusid());
t.setUpdateBy(dto.getUpdateBy());
t.setCreateBy(dto.getCreateBy());
return t;
}
/**
* insert 草稿并把生成的自增主键回填(原实现 insert 后可继续用同一个对象)。
*/
private boolean insert(VisitTaskCreateApi api, VisitSubtaskDraft d) {
return api.insertSubtask(d);
}
/**
* 原 L782:对尚未 insert 的草稿调 {@code updateServiceSubtask}。
*
* 该草稿此时 {@code id} 为 null,所以 {@code where id = null} 影响 0 行。
* 为保持这一"无效写入"的原语义,这里用一个 id 为 null 的 pending 对象走同一条路径。
*/
private boolean writeBackDraft(VisitTaskCreateApi api, VisitSubtaskDraft d) {
VisitPendingSubtaskDto p = new VisitPendingSubtaskDto();
p.setId(d.getId());
p.setTaskid(d.getTaskid());
p.setSendstate(d.getSendstate());
p.setResult(d.getResult());
p.setRemark(d.getRemark());
p.setUpdateBy(d.getUpdateBy());
p.setUpdateTime(d.getUpdateTime());
return api.updatePendingSubtask(p);
}
/**
* 原 L840/855/874 的 {@code addServiceSubtaskPreachform}。该方法的实现第 8 步才搬进来,
* 所以这里惰性获取;取不到就跳过(不抛异常)。
*/
private void addServiceSubtaskPreachform(VisitSubtaskDraft subtask, String sendstate) {
if (preachformWriterProvider == null) {
return;
}
try {
SubtaskPreachformWriter writer = preachformWriterProvider.stream().findFirst().orElse(null);
if (writer == null) {
log.warn("【出入院随访】SubtaskPreachformWriter 未装配,跳过执行方式明细写入。subtaskId={}",
subtask.getId());
return;
}
writer.addServiceSubtaskPreachform(subtask, sendstate);
} catch (Exception e) {
// 这一步失败不应影响主流程(原实现在同一个 try 里,失败会走 catch 回滚标志位;
// 但那是因为它与 insert 同属一次事务。这里拆开后按"尽力而为"处理并记录)
log.warn("【出入院随访】写执行方式明细失败,已忽略。subtaskId={},原因={}",
subtask.getId(), e.toString());
}
}
private VisitTaskCreateApi taskCreateApi() {
if (taskCreateApiProvider == null) {
return null;
}
try {
return taskCreateApiProvider.stream().findFirst().orElse(null);
} catch (Exception e) {
log.warn("【出入院随访】获取 VisitTaskCreateApi 失败,按不可用处理:{}", e.toString());
return null;
}
}
/**
* 写执行方式明细的能力(原 {@code addServiceSubtaskPreachform},L1061-1103,43 行)。
*
* 该方法的实现第 8 步才搬进本模块,所以先定义接口、用 {@code ObjectProvider} 惰性获取。
* 这样第 7 步就能编译并跑断言,不必等第 8 步。
*/
public interface SubtaskPreachformWriter {
/**
* @param subtask 子任务草稿({@code id} 为落库后的主键)
* @param sendstate 指定的执行方式状态;{@code null} 表示按原逻辑处理
*/
void addServiceSubtaskPreachform(VisitSubtaskDraft subtask, String sendstate);
}
}
* 1 -> deptcheck_flag 2 -> wardcheck_flag 3 -> diagcheck_flag
* 4 -> in_deptcheck_flag 5 -> in_wardcheck_flag (0 无对应)
*
*/
private String flagColumnOfSuccessOrFail(Integer type) {
switch (type) {
case 1:
return "deptcheck_flag";
case 2:
return "wardcheck_flag";
case 3:
return "diagcheck_flag";
case 4:
return "in_deptcheck_flag";
case 5:
return "in_wardcheck_flag";
default:
return null;
}
}
/**
* 异常回滚时的标志位回写。照抄原 L905-908 ——
* ⚠️ 这里的分支与原"成功/失败"分支不同:
*
*
* 两处不一致是原代码本身的不一致,原样保留。
*/
private void writeFlagByTypeForRollback(Long inhospid, Integer type, String flagValue, String remark) {
if (type == null) {
return;
}
String column;
switch (type) {
case 1:
column = "deptcheck_flag";
break;
case 2:
column = "wardcheck_flag";
break;
case 3:
column = "diagcheck_flag";
break;
case 0:
column = "medcheck_flag";
break;
default:
// type=4/5 落这里:原实现不回写任何标志位
return;
}
flagWriter.setFlagWithRemark(inhospid, column, flagValue, remark);
}
// ==========================================================================
// 辅助
// ==========================================================================
/**
* 原 L845-851 / L864-870:手机号为空时追加备注、置 sendstate=4、result=error。
*/
private void markPhoneEmptyIfNeeded(VisitSubtaskDraft d) {
if (StringUtils.isEmpty(d.getPhone())) {
if (StringUtils.isNotEmpty(d.getRemark())) {
d.setRemark(d.getRemark() + ",手机号为空");
} else {
d.setRemark("手机号为空");
}
d.setSendstate(SENDSTATE_STOPPED);
d.setResult("error");
}
}
/**
* 原 {@code boxedServiceSubtask} 出院时间为空时的副作用(L1174-1176):
*
* patMedInhosp1.setDeptcheckFlag("2");
* patMedInhosp1.setRemark(patMedInhosp1.getRemark() + "& 该患者疾病出院时间为空,出院记录ID为:" + patMedInhosp1.getInhospid());
* patMedInhospMapper.updatePatMedInhosp(patMedInhosp1);
*
* ⚠️ 原实现这次调用【同时】写了 flag 与 remark,所以这里两步都要做。
*/
private void onMissingOutHospTime(VisitInhospRow row) {
flagWriter.setFlag(row.getInhospid(), "deptcheck_flag", "2");
flagWriter.setFlagWithRemark(row.getInhospid(), "deptcheck_flag", "2",
(row.getRemark() == null ? "" : row.getRemark())
+ "& 该患者疾病出院时间为空,出院记录ID为:" + row.getInhospid());
}
/**
* 把 {@link VisitLongTaskDto} 适配成 {@link com.ruoyi.inhospvisit.domain.row.VisitTaskRow},
* 供组装器使用。
*