673757e7a669769041a54ef6471b4d8d250e3416..1f66eb9a6353d638f5b9cb33b934bd4705e4efed
2026-07-29 陈昶聿
Merge branch 'master-任务组'
1f66eb 对比 | 目录
2026-07-29 liusheng
枚举新增
a55e53 对比 | 目录
2026-07-29 liusheng
1,患者过滤状态修改(之前只支持发送之前的过滤,现在支持发送之后的过滤,如果任务发送后,外链不能再打开) 2.在出入院表新增入院申请单字段 3.采集入...
25a0ba 对比 | 目录
2026-07-29 陈昶聿
【丽水】宣教超链接跳转调整
bebb8f 对比 | 目录
2026-07-29 陈昶聿
【丽水】宣教超链接跳转调整
717abb 对比 | 目录
2026-07-29 陈昶聿
【丽水】JZ_MZ_WanChengJZ 就诊信息同步生成随访任务
dfdedd 对比 | 目录
2026-07-28 陈昶聿
Merge branch 'master' into master-任务组
db2a00 对比 | 目录
2026-07-21 陈昶聿
Merge branch 'master' into master-任务组
fcb98e 对比 | 目录
2026-07-16 陈昶聿
Merge branch 'master' into master-任务组
83c499 对比 | 目录
2026-07-14 陈昶聿
Merge branch 'master' into master-任务组
12213c 对比 | 目录
2026-07-14 陈昶聿
Merge branch 'master' into master-任务组
521959 对比 | 目录
2026-07-13 陈昶聿
Merge branch 'master' into master-任务组
37e23a 对比 | 目录
2026-07-13 陈昶聿
Merge branch 'master' into master-任务组
c93b5b 对比 | 目录
2026-07-10 陈昶聿
Merge branch 'master' into master-任务组
6e3d0a 对比 | 目录
2026-07-03 陈昶聿
Merge branch 'master' into master-任务组
609bff 对比 | 目录
2026-07-02 陈昶聿
【市一】任务组调试
d67891 对比 | 目录
2026-07-02 陈昶聿
【市一】任务组调试
608bdb 对比 | 目录
2026-07-02 陈昶聿
Merge branch 'master' into master-任务组
6d2ca8 对比 | 目录
2026-07-02 陈昶聿
【市一】新增手术随访 配置科室病区
655d01 对比 | 目录
2026-07-02 陈昶聿
Merge branch 'master' into master-任务组
dbdd6d 对比 | 目录
2026-07-01 陈昶聿
【景宁】任务组开发
af6c73 对比 | 目录
2026-07-01 陈昶聿
【景宁】任务组开发
724594 对比 | 目录
2026-07-01 陈昶聿
【景宁】任务组开发
f7307b 对比 | 目录
2026-07-01 陈昶聿
【景宁】任务组开发
af3ec5 对比 | 目录
已修改20个文件
已添加14个文件
3103 ■■■■■ 文件已修改
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SmsController.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/common/ScheduleSubtaskBuilder.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/common/enums/EmergencyLevelEnum.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/common/enums/ImportFlagEnum.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/AppendPatientsReq.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/DTO/PatMedInhospDTO.java 543 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/PatMedInhosp.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/PatMedInhospVO.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/PatMedOperationItem.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceSLTDInhospResDTO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceSubtask.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceTaskSchedule.java 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceTaskScheduleDetail.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceTaskScheduleVO.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceTaskVO.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/mapper/ServiceTaskScheduleDetailMapper.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/mapper/ServiceTaskScheduleMapper.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/IPatMedInhospService.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/IServiceTaskScheduleService.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/PatArchiveServiceImpl.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java 288 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java 129 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceTaskScheduleServiceImpl.java 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/PatMedInhospMapper.xml 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/PatMedOperationItemMapper.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/ServiceTaskScheduleDetailMapper.xml 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/ServiceTaskScheduleMapper.xml 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SmsController.java
@@ -12,12 +12,10 @@
import com.ruoyi.common.utils.sms.smsUtils;
import com.smartor.common.MtSubmitSmUtil;
import com.smartor.common.ShiyiSmsUtil;
import com.smartor.domain.ServiceOutPath;
import com.smartor.domain.ShiyiSmsRequest;
import com.smartor.domain.ShiyiSmsResponse;
import com.smartor.domain.smsVO;
import com.smartor.domain.*;
import com.smartor.mapper.UtilsMapper;
import com.smartor.service.IServiceOutPathService;
import com.smartor.service.IServiceSubtaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@@ -71,6 +69,8 @@
    @Autowired
    private IServiceOutPathService iServiceOutPathService;
    @Autowired
    private IServiceSubtaskService iServiceSubtaskService;
    @Value("${spring.profiles.active}")
    private String active;
@@ -106,6 +106,12 @@
    @PostMapping("/send")
    public AjaxResult sendAsk(@RequestBody smsVO vo) throws UnsupportedEncodingException {
        String content = "";
        if (StringUtils.isNotEmpty(vo.getSubId())) {
            ServiceSubtask serviceSubtask = iServiceSubtaskService.selectServiceSubtaskById(Long.valueOf(vo.getSubId()));
            if (serviceSubtask.getSendstate() == 4L) content = "该任务不执行";
            return AjaxResult.error(content);
        }
        if (StringUtils.isNotEmpty(vo.getTaskId()) && StringUtils.isNotEmpty(vo.getPatId()) && StringUtils.isNotEmpty(vo.getSubId())) {
            RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
            String taskId = rsaPublicKeyExample.encryptedData(vo.getTaskId().toString(), pub_key);
@@ -193,8 +199,13 @@
     */
    @ApiOperation("微信发送")
    @PostMapping("/sendChat")
    public AjaxResult sendChat(@RequestBody smsVO vo) throws UnsupportedEncodingException {
    public AjaxResult sendChat(@RequestBody smsVO vo) {
        String sendMsg = "";
        if (StringUtils.isNotEmpty(vo.getSubId())) {
            ServiceSubtask serviceSubtask = iServiceSubtaskService.selectServiceSubtaskById(Long.valueOf(vo.getSubId()));
            if (serviceSubtask.getSendstate() == 4L) sendMsg = "该任务不执行";
            return AjaxResult.error(sendMsg);
        }
        if (StringUtils.isNotEmpty(vo.getTaskId()) && StringUtils.isNotEmpty(vo.getPatId()) && StringUtils.isNotEmpty(vo.getSubId())) {
            RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
            String taskId = rsaPublicKeyExample.encryptedData(vo.getTaskId().toString(), pub_key);
@@ -246,6 +257,11 @@
            serviceOutPath.setUrl(url);
            iServiceOutPathService.insertServiceOutPath(serviceOutPath);
        }
        if (StringUtils.isNotEmpty(vo.getSubId())) {
            ServiceSubtask serviceSubtask = iServiceSubtaskService.selectServiceSubtaskById(Long.valueOf(vo.getSubId()));
            if (serviceSubtask.getSendstate() == 4L) content = "该任务不执行";
        }
        return AjaxResult.success(content);
    }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/PatMedInhospController.java
@@ -12,6 +12,7 @@
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.service.ISysConfigService;
import com.smartor.domain.DTO.PatMedInhospDTO;
import com.smartor.domain.PatMedInhosp;
import com.smartor.domain.PatMedInhospVO;
import com.smartor.domain.PatMedReq;
@@ -79,6 +80,27 @@
    }
    /**
     * æŸ¥è¯¢æ‚£è€…住院记录通过入院申请单信息
     */
    @ApiOperation("查询患者住院记录通过入院申请单信息")
    //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:list')")
    @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
    @PostMapping("/selectPatMedInhospByApplication")
    public TableDataInfo selectPatMedInhospByApplication(@RequestBody PatMedInhosp patMedInhosp) {
        PageUtils.startPageByPost(patMedInhosp.getPageNum(), patMedInhosp.getPageSize());
        SysUser user = getLoginUser().getUser();
        patMedInhosp.setOrgid(user.getOrgid());
        List<PatMedInhospDTO> list = patMedInhospService.selectPatMedInhospByApplication(patMedInhosp);
        long count = PageUtils.count(new ISelect() {
            @Override
            public void doSelect() {
                patMedInhospService.selectPatMedInhospByApplication(patMedInhosp);
            }
        });
        return getDataTable2(count, list);
    }
    /**
     * å‡ºé™¢ã€é—¨è¯Šäººæ•°å’Œéšè®¿é‡ç»Ÿè®¡ï¼ˆå‘¨ï¼Œæœˆï¼Œå¹´ï¼‰
     */
    @ApiOperation("出院、门诊人数和随访量统计(周,月,年)")
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
@@ -952,12 +952,6 @@
        return AjaxResult.success(serviceSubtaskService.scanGenerateSubtask(serviceTask));
    }
    @PostMapping("/test")
    public void test() {
        ryTask.dealOutHospInfo();
    }
    @PostMapping("/syncMedInhospForShiyi")
    public void syncMedInhospForShiyi(@RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime) {
        collectHISService.syncMedInhosp(startTime, endTime);
@@ -967,12 +961,5 @@
    public void syncMedOperForShiyi(@RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime) {
        collectHISService.syncOper(startTime, endTime);
    }
    @PostMapping("/qwenLLMTest")
    public int qwenLLMTest(@RequestParam("voiceText") String questionText, @RequestParam("voiceText") String voiceText, @RequestParam("value") String value, @RequestParam("regexText") String regexText) {
        int result = ryTask.qwenLLMTest(questionText, voiceText, value, regexText);
        return result;
    }
}
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -150,6 +150,9 @@
    IServiceSubtaskDetailTraceService serviceSubtaskDetailTraceService;
    @Autowired
    IPatMedOuthospService patMedOuthospService;
    @Autowired
    ISvyTaskTemplateService svyTaskTemplateService;
    @Autowired
@@ -181,6 +184,21 @@
    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"; // æ›¿æ¢ä¸ºä½ çš„æ–‡ä»¶è·¯å¾„
@@ -699,17 +717,17 @@
    }
    /**
     * å¤„理患者信息,进入子任务表
     * å¤„理患者信息,进入子任务表(任务组)
     */
    public void dealOutHospInfoByDimension() {
    public void dealOutHospInfoBySchedule() {
        String config = configService.selectConfigByKey("visit.early.day");
        if (port.equals("8095")) {
            //出院表
            iPatMedInhospService.dealOutHospInfoByDimension(config);
            iPatMedInhospService.dealOutHospInfoBySchedule(config);
            //门诊表(新华的暂时不做门诊随访)
            if (!active.equals("xh")) {
                //iPatMedOuthospService.dealOutpatientInfo();
            }
//            if (!active.equals("xh")) {
//                //iPatMedOuthospService.dealOutpatientInfo();
//            }
        }
    }
@@ -1603,4 +1621,43 @@
        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);
        }
    }
}
smartor/src/main/java/com/smartor/common/ScheduleSubtaskBuilder.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,192 @@
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,
                                        List<Map<String, Object>> preachformList,
                                        ServiceTaskSchedule schedule,
                                        List<ServiceTaskScheduleDetail> scheduleDetailList,
                                        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, scheduleDetailList, baseSubtask, preachformList);
    }
    /**
     * æ ¹æ® 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;
    }
}
smartor/src/main/java/com/smartor/common/enums/EmergencyLevelEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package com.smartor.common.enums;
/**
 * å…¥é™¢ç”³è¯·ç´§æ€¥ç¨‹åº¦æžšä¸¾
 *
 * @author ruoyi
 */
public enum EmergencyLevelEnum {
    /**
     * ç›®æ ‡
     */
    TARGET("FH0164.01", "目标"),
    /**
     * æ€¥å±é‡
     */
    CRITICAL("FH0164.02", "急危重"),
    /**
     * æ‹©æœŸ
     */
    ELECTIVE("FH0164.03", "择期"),
    /**
     * åŸºç¡€
     */
    BASIC("FH0164.04", "基础");
    private String code;
    private String desc;
    EmergencyLevelEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    public static String getDescByCode(String code) {
        if (code == null || code.isEmpty()) {
            return null;
        }
        for (EmergencyLevelEnum item : values()) {
            if (item.getCode().equals(code)) {
                return item.getDesc();
            }
        }
        return null;
    }
    public static String getCodeByDesc(String desc) {
        if (desc == null || desc.isEmpty()) {
            return null;
        }
        for (EmergencyLevelEnum item : values()) {
            if (item.getDesc().equals(desc)) {
                return item.getCode();
            }
        }
        return null;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}
smartor/src/main/java/com/smartor/common/enums/ImportFlagEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
package com.smartor.common.enums;
/**
 * å…¥é™¢ç”³è¯·é‡è¦æ€§æ ‡è®°æžšä¸¾
 *
 * @author ruoyi
 */
public enum ImportFlagEnum {
    /**
     * ç‰¹çº¦äººå‘˜
     */
    SPECIAL_PERSONNEL("FH0165.98", "特约人员"),
    /**
     * ç¦»ä¼‘人员
     */
    RETIRED_CADRE("FH0165.99", "离休人员"),
    /**
     * æ— 
     */
    NONE("FH0165.03", "无"),
    /**
     * æ—¥é—´è¯Šç–—
     */
    DAY_TREATMENT("FH0165.02", "日间诊疗"),
    /**
     * æ—¥é—´æ‰‹æœ¯
     */
    DAY_SURGERY("FH0165.01", "日间手术");
    private String code;
    private String desc;
    ImportFlagEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    public static String getDescByCode(String code) {
        if (code == null || code.isEmpty()) {
            return null;
        }
        for (ImportFlagEnum item : values()) {
            if (item.getCode().equals(code)) {
                return item.getDesc();
            }
        }
        return null;
    }
    public static String getCodeByDesc(String desc) {
        if (desc == null || desc.isEmpty()) {
            return null;
        }
        for (ImportFlagEnum item : values()) {
            if (item.getDesc().equals(desc)) {
                return item.getCode();
            }
        }
        return null;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }
}
smartor/src/main/java/com/smartor/domain/AppendPatientsReq.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.smartor.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * å‘已有任务追加患者的请求体(用于拆包解决413问题)
 */
@Data
@ApiModel(value = "AppendPatientsReq", description = "向已有任务追加患者")
public class AppendPatientsReq {
    @ApiModelProperty(value = "任务ID(insertOrUpdateTask ç¬¬ä¸€æ¬¡è°ƒç”¨åŽè¿”回的 taskId)", required = true)
    private Long taskId;
    @ApiModelProperty(value = "本批次患者列表")
    private List<PatTaskRelevance> patTaskRelevances;
}
smartor/src/main/java/com/smartor/domain/DTO/PatMedInhospDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,543 @@
package com.smartor.domain.DTO;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
 * æ‚£è€…住院记录对象返参 pat_med_inhosp
 *
 * @author smartor
 * @date 2023-03-04
 */
@ApiModel(value = "PatMedInhospDTO", description = "患者住院记录对象返参")
@Data
public class PatMedInhospDTO extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * è‡ªå¢žID
     */
    @ApiModelProperty(value = "自增ID")
    private Long inhospid;
    /**
     * æ€§åˆ«
     */
    @ApiModelProperty(value = "性别 1男  2女")
    private Long sex;
    /**
     * ä½é™¢å·
     */
    @ApiModelProperty(value = "住院号")
    private String inhospno;
    /**
     * æµæ°´å·
     */
    @ApiModelProperty(value = "流水号")
    private String serialnum;
    /**
     * æŠ¤å£«ID
     */
    @ApiModelProperty(value = "护士ID")
    private String nurseId;
    /**
     * æŠ¤å£«å§“名
     */
    @ApiModelProperty(value = "护士姓名")
    private String nurseName;
    /**
     * åŒ»é™¢åç§°
     */
    @ApiModelProperty(value = "医院名称")
    @Excel(name = " åŒ»é™¢åç§° ")
    private String hospitalname;
    /**
     * åŒ»é™¢ç¼–号
     */
    @ApiModelProperty(value = "医院编号")
    private String hospitalcode;
    /**
     * é™¢åŒºç¼–号
     */
    @ApiModelProperty(value = "院区编号")
    private String hospitaldistrictcode;
    /**
     * é™¢åŒºç¼–号集合
     */
    @ApiModelProperty(value = "院区编号集合")
    private List<String> hospitaldistrictcodeList;
    /**
     * é™¢åŒºåç§°
     */
    @ApiModelProperty(value = "院区名称")
    @Excel(name = " é™¢åŒºåç§° ")
    private String hospitaldistrictname;
    /**
     * å…¥é™¢è¯Šæ–­ICD值
     */
    @ApiModelProperty(value = "入院诊断ICD值")
    private String icd10code;
    /**
     * å…¥é™¢è¯Šæ–­åç§°
     */
    @ApiModelProperty(value = "入院诊断名称")
    private String diagname;
    /**
     * å…¥é™¢æ—¶é—´
     */
    @ApiModelProperty(value = "入院时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = " å…¥é™¢æ—¶é—´ ", width = 30, dateFormat = "yyyy-MM-dd")
    private Date starttime;
    /**
     * å‡ºé™¢æ—¶é—´
     */
    @ApiModelProperty(value = "出院时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = " å‡ºé™¢æ—¶é—´ ", width = 30, dateFormat = "yyyy-MM-dd")
    private Date endtime;
    /**
     * å…¥é™¢ç§‘室代码
     */
    @ApiModelProperty(value = "入院科室代码")
    private String deptcode;
    /**
     * å…¥é™¢ç§‘室代码
     */
    @ApiModelProperty(value = "入院科室代码集合")
    private List<String> deptcodeList;
    /**
     * å…¥é™¢ç§‘室名称
     */
    @ApiModelProperty(value = "入院科室名称")
    private String deptname;
    /**
     * æˆ¿é—´å·
     */
    @ApiModelProperty(value = "房间号")
    private String roomno;
    /**
     * åºŠä½å·
     */
    @ApiModelProperty(value = "床位号")
    @Excel(name = " åºŠä½å· ")
    private String bedNo;
    /**
     * æœºæž„ID
     */
    @ApiModelProperty(value = "机构ID")
    @Excel(name = " æœºæž„ID ")
    private String orgid;
    /**
     * åˆ é™¤æ ‡è®°
     */
    @ApiModelProperty(value = "删除标记")
    private String delFlag;
    /**
     * ä¸Šä¼ æ ‡è®°
     */
    @ApiModelProperty(value = "上传标记")
    private Long isupload;
    /**
     * ä¸Šä¼ æ—¶é—´
     */
    @ApiModelProperty(value = "上传时间")
    private Date uploadTime;
    /**
     * æ¡£æ¡ˆID
     */
    @ApiModelProperty(value = "档案ID")
    private Long patid;
    /**
     * å‡ºé™¢è¯Šæ–­
     */
    @ApiModelProperty(value = "出院诊断")
    @Excel(name = " å‡ºé™¢è¯Šæ–­ ")
    private String leavediagname;
    /**
     * å‡ºé™¢è¯Šæ–­ICD值
     */
    @ApiModelProperty(value = "出院诊断ICD值")
    private String leaveicd10code;
    /**
     * åŒ»ç”Ÿå·¥å·
     */
    @ApiModelProperty(value = "医生工号")
    private String drcode;
    /**
     * åŒ»ç”Ÿåç§°
     */
    @ApiModelProperty(value = "医生名称")
    @Excel(name = " åŒ»ç”Ÿåç§° ")
    private String drname;
    /**
     * æ˜¯å¦ç”Ÿæˆæ–¹æ¡ˆçŠ¶æ€;0预入院 1生成入院 2生成出院 9无匹配方案   3生成入院撤销   4生成出院撤销
     */
    @ApiModelProperty(value = "是否生成方案状态;0预入院 1生成入院 2生成出院 9无匹配方案   3生成入院撤销   4生成出院撤销")
    private Long schemestatus;
    /**
     * æ˜¯å¦ç”Ÿæˆé€šç”¨æ–¹æ¡ˆçŠ¶æ€;0未生成 1生成 9无匹配方案
     */
    @ApiModelProperty(value = "是否生成通用方案状态;0未生成 1生成 9无匹配方案")
    private Long generalschemestatus;
    /**
     * å‡ºé™¢ç§‘室代码
     */
    @ApiModelProperty(value = "出院科室代码")
    private String leaveldeptcode;
    /**
     * å‡ºé™¢ç§‘室名称
     */
    @ApiModelProperty(value = "出院科室名称")
    @Excel(name = " å‡ºé™¢ç§‘室名称 ")
    private String leaveldeptname;
    /**
     * ç—…区ID
     */
    @ApiModelProperty(value = "病区ID")
    private String hospitaldistrictid;
    /**
     * å‡ºé™¢ç—…区编号
     */
    @ApiModelProperty(value = "出院病区编号")
    private String leavehospitaldistrictcode;
    /**
     * å‡ºé™¢ç—…区名称
     */
    @ApiModelProperty(value = "出院病区名称")
    @Excel(name = " å‡ºé™¢ç—…区名称 ")
    private String leavehospitaldistrictname;
    /**
     * å‡ºé™¢ç—…区ID
     */
    @ApiModelProperty(value = "出院病区ID")
    private String leavehospitaldistrictid;
    /**
     * å…¥é™¢ç§‘室ID
     */
    @ApiModelProperty(value = "入院科室ID")
    private String deptid;
    /**
     * å‡ºé™¢ç§‘室ID
     */
    @ApiModelProperty(value = "出院科室ID")
    private String leaveldeptid;
    /**
     * æ–¹æ¡ˆçŠ¶æ€æ“ä½œæ—¶é—´
     */
    @ApiModelProperty(value = "方案状态操作时间")
    private Date schemetime;
    /**
     * æ‚£è€…姓名
     */
    @ApiModelProperty(value = "患者姓名")
    private String patname;
    /**
     * æ‚£è€…编号
     */
    @ApiModelProperty(value = "患者编号")
    private String patno;
    /**
     * ä½é™¢æ ‡è¯†ï¼š 0:在院  1:出院    2:转科
     */
    @ApiModelProperty(value = "住院标识: 0:在院  1:出院    2:转科  3待入院")
    private String inhospstate;
    /**
     * ç§‘室长期任务,是否处理:0未处理   1处理
     */
    @ApiModelProperty(value = "长期任务,是否处理:0未处理   1处理成功    2处理失败 ")
    private String deptcheckFlag;
    /**
     * ç—…区长期任务,是否处理:0未处理   1处理
     */
    @ApiModelProperty(value = "病区长期任务,是否处理:0未处理   1处理成功    2处理失败 ")
    private String wardcheckFlag;
    /**
     * ç–¾ç—…长期任务,是否处理:0未处理   1处理
     */
    @ApiModelProperty(value = "疾病长期任务,是否处理:0未处理   1处理成功    2处理失败 ")
    private String diagcheckFlag;
    /**
     * å…¥é™¢ç§‘室长期任务,是否处理:0未处理   1处理
     */
    @ApiModelProperty(value = "入院科室长期任务,是否处理:0未处理   1处理成功    2处理失败 ")
    private String inDeptcheckFlag;
    /**
     * å…¥é™¢ç—…区长期任务,是否处理:0未处理   1处理
     */
    @ApiModelProperty(value = "入院病区长期任务,是否处理:0未处理   1处理成功    2处理失败 ")
    private String inWardcheckFlag;
    /**
     * å¹´é¾„
     */
    @ApiModelProperty(value = "年龄")
    private String age;
    /**
     * æ‰‹æœºå·
     */
    @ApiModelProperty(value = "手机号")
    private String telcode;
    /**
     * é•¿æœŸä»»åŠ¡åŽŸå› 
     */
    @ApiModelProperty(value = "长期任务原因")
    private String longTaskReason;
    /**
     * pageNum
     */
    @ApiModelProperty("pageNum")
    private Integer pageNum;
    /**
     * pageSize
     */
    @ApiModelProperty("pageSize")
    private Integer pageSize;
    /**
     * pageNum
     */
    @ApiModelProperty("pn")
    private Integer pn;
    /**
     * pageSize
     */
    @ApiModelProperty("ps")
    private Integer ps;
    /**
     * å‡ºé™¢æ–¹å¼åºå·
     */
    @ApiModelProperty("出院方式序号")
    @Excel(name = "出院方式序号")
    private String outWayId;
    /**
     * å‡ºé™¢æ–¹å¼åç§°
     */
    @ApiModelProperty("出院方式名称")
    @Excel(name = "出院方式名称")
    private String outWayName;
    /**
     * å‡ºå…¥é™¢æ ‡è¯†
     */
    @ApiModelProperty("出入院标识:0入院  1出院 2 è½¬ç§‘  3 é¢„入院")
    private Integer cry;
    /**
     * å‡ºé™¢ç—…区编号
     */
    @ApiModelProperty(value = "出院病区编号集合")
    private List<String> leavehospitaldistrictcodes;
    /**
     * å‡ºé™¢ç§‘室代码集合
     */
    @ApiModelProperty(value = "出院科室代码集合")
    private List<String> leaveldeptcodes;
    /**
     * å¼€å§‹å‡ºé™¢æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "  ", width = 30, dateFormat = "yyyy-MM-dd")
    @ApiModelProperty(value = "开始出院日期")
    private Date startOutHospTime;
    /**
     * ç»“束出院日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "  ", width = 30, dateFormat = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束出院日期")
    private Date endOutHospTime;
    /**
     * å¼€å§‹å…¥é™¢æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "  ", width = 30, dateFormat = "yyyy-MM-dd")
    @ApiModelProperty(value = "开始入院日期")
    private Date startInHospTime;
    /**
     * ç»“束入院日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "  ", width = 30, dateFormat = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束入院日期")
    private Date endInHospTime;
    @ApiModelProperty(value = "是否外部导入:0不是    1是")
    private Integer outImport = 0;
    @ApiModelProperty(value = "查询类型:1全部   2出院   3入院   4门诊   5外部患者 ")
    private Integer queryType = 1;
    @ApiModelProperty(value = "机构ID")
    private String guid;
    @ApiModelProperty(value = "操作人")
    private String operator;
    @ApiModelProperty(value = "操作人ID")
    private String operatorId;
    @ApiModelProperty(value = "标签名")
    private String tagname;
    @ApiModelProperty(value = "随访标识:0不需要,1要")
    private String fuflag;
    @ApiModelProperty(value = "随访日期")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date fudate;
    @ApiModelProperty(value = "随访周期建议")
    private String fuperiod;
    @ApiModelProperty(value = "随访类型编码")
    private String futypecode;
    @ApiModelProperty(value = "随访类型名称")
    private String futypedesc;
    @ApiModelProperty(value = "随访复诊指导")
    private String fuadvice;
    @ApiModelProperty(value = "专病随访建议")
    private String fuspecialadvice;
    /**
     * è¯ä»¶å·ç 
     */
    @ApiModelProperty("证件号码")
    @Excel(name = " è¯ä»¶å·ç  ")
    private String idcardno;
    /**
     * ç»ç®¡åŒ»ç”Ÿ
     */
    @ApiModelProperty("经管医生")
    @Excel(name = " ç»ç®¡åŒ»ç”Ÿ ")
    private String managementDoctor;
    /**
     * ç»ç®¡åŒ»ç”Ÿ
     */
    @ApiModelProperty("经管医生")
    @Excel(name = " ç»ç®¡åŒ»ç”Ÿ ")
    private String managementDoctorCode;
    @ApiModelProperty(value = "最后开始时间")
    private String lastStartTime;
    @ApiModelProperty(value = "最后结束时间")
    private String lastEndTime;
    /**
     * æœºæž„ID
     */
    @ApiModelProperty("院区")
    @Excel(name = " é™¢åŒº ")
    private String campusid;
    /**
     * å°±è¯Šæ¥æºID
     */
    @ApiModelProperty("就诊来源ID")
    @Excel(name = " å°±è¯Šæ¥æºID ")
    private String encounterSourceId;
    /**
     * é‡è¦æ€§æ ‡è®°ç¼–码
     * æžšä¸¾ç±»åž‹ï¼šImportFlagEnum
     * FH0165.98 - ç‰¹çº¦äººå‘˜
     * FH0165.99 - ç¦»ä¼‘人员
     * FH0165.03 - æ— 
     * FH0165.02 - æ—¥é—´è¯Šç–—
     * FH0165.01 - æ—¥é—´æ‰‹æœ¯
     */
    @ApiModelProperty(value = "重要性标记编码", example = "FH0165.01")
    @Excel(name = " é‡è¦æ€§æ ‡è®°ç¼–码 ")
    private String importanceFlagCode;
    /**
     * ç´§æ€¥ç¨‹åº¦ç¼–码
     * æžšä¸¾ç±»åž‹ï¼šEmergencyLevelEnum
     * FH0164.01 - ç›®æ ‡
     * FH0164.02 - æ€¥å±é‡
     * FH0164.03 - æ‹©æœŸ
     * FH0164.04 - åŸºç¡€
     */
    @ApiModelProperty(value = "紧急程度编码", example = "FH0164.01")
    @Excel(name = " ç´§æ€¥ç¨‹åº¦ç¼–码 ")
    private String emergencyLevelCode;
    @ApiModelProperty(value = "是否宣教过")
    @Excel(name = " æ˜¯å¦å®£æ•™å®Œæˆ:0 æœªå®£æ•™ 1 å·²å®£æ•™ ")
    private String finishFlag = "0";
    /**
     * '满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2)
     */
    @ApiModelProperty("'满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2)")
    @Excel(name = " '满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2) ")
    private String inhospMydFlag;
}
smartor/src/main/java/com/smartor/domain/PatMedInhosp.java
@@ -98,6 +98,11 @@
    private String icd10code;
    /**
     * å…¥é™¢è¯Šæ–­ICD值编号集合
     */
    @ApiModelProperty(value = "入院诊断ICD值编号集合")
    private List<String> icd10codeList;
    /**
     * å…¥é™¢è¯Šæ–­åç§°
     */
    @ApiModelProperty(value = "入院诊断名称")
@@ -309,6 +314,13 @@
    private String diagcheckFlag;
    /**
     * ä»»åŠ¡ç»„ï¼ˆappltype=5)首轮纳入标记:0未处理  1已生成首轮  2无匹配/失败
     * ç‹¬ç«‹äºŽ dept/ward/diag check_flag,专供任务组独立扫描使用;后续轮次由 rollTaskGroupCycle è´Ÿè´£ã€‚
     */
    @ApiModelProperty(value = "任务组(appltype=5)首轮纳入标记:0未处理 1已生成首轮 2无匹配/失败")
    private String scheduleCheckFlag;
    /**
     * å…¥é™¢ç§‘室长期任务,是否处理:0未处理   1处理
     */
    @ApiModelProperty(value = "入院科室长期任务,是否处理:0未处理   1处理成功    2处理失败 ")
@@ -501,6 +513,38 @@
    private String campusid;
    /**
     * å°±è¯Šæ¥æºID
     */
    @ApiModelProperty("就诊来源ID")
    @Excel(name = " å°±è¯Šæ¥æºID ")
    private String encounterSourceId;
    /**
     * é‡è¦æ€§æ ‡è®°ç¼–码
     * æžšä¸¾ç±»åž‹ï¼šImportFlagEnum
     * FH0165.98 - ç‰¹çº¦äººå‘˜
     * FH0165.99 - ç¦»ä¼‘人员
     * FH0165.03 - æ— 
     * FH0165.02 - æ—¥é—´è¯Šç–—
     * FH0165.01 - æ—¥é—´æ‰‹æœ¯
     */
    @ApiModelProperty(value = "重要性标记编码", example = "FH0165.01")
    @Excel(name = " é‡è¦æ€§æ ‡è®°ç¼–码 ")
    private String importanceFlagCode;
    /**
     * ç´§æ€¥ç¨‹åº¦ç¼–码
     * æžšä¸¾ç±»åž‹ï¼šEmergencyLevelEnum
     * FH0164.01 - ç›®æ ‡
     * FH0164.02 - æ€¥å±é‡
     * FH0164.03 - æ‹©æœŸ
     * FH0164.04 - åŸºç¡€
     */
    @ApiModelProperty(value = "紧急程度编码", example = "FH0164.01")
    @Excel(name = " ç´§æ€¥ç¨‹åº¦ç¼–码 ")
    private String emergencyLevelCode;
    /**
     * '满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2)
     */
    @ApiModelProperty("'满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2)")
smartor/src/main/java/com/smartor/domain/PatMedInhospVO.java
@@ -396,5 +396,44 @@
    @ApiModelProperty("院区")
    @Excel(name = " é™¢åŒº ")
    private String campusid;
    /**
     * å°±è¯Šæ¥æºID
     */
    @ApiModelProperty("就诊来源ID")
    @Excel(name = " å°±è¯Šæ¥æºID ")
    private String encounterSourceId;
    /**
     * é‡è¦æ€§æ ‡è®°ç¼–码
     * æžšä¸¾ç±»åž‹ï¼šImportFlagEnum
     * FH0165.98 - ç‰¹çº¦äººå‘˜
     * FH0165.99 - ç¦»ä¼‘人员
     * FH0165.03 - æ— 
     * FH0165.02 - æ—¥é—´è¯Šç–—
     * FH0165.01 - æ—¥é—´æ‰‹æœ¯
     */
    @ApiModelProperty(value = "重要性标记编码", example = "FH0165.01")
    @Excel(name = " é‡è¦æ€§æ ‡è®°ç¼–码 ")
    private String importanceFlagCode;
    /**
     * ç´§æ€¥ç¨‹åº¦ç¼–码
     * æžšä¸¾ç±»åž‹ï¼šEmergencyLevelEnum
     * FH0164.01 - ç›®æ ‡
     * FH0164.02 - æ€¥å±é‡
     * FH0164.03 - æ‹©æœŸ
     * FH0164.04 - åŸºç¡€
     */
    @ApiModelProperty(value = "紧急程度编码", example = "FH0164.01")
    @Excel(name = " ç´§æ€¥ç¨‹åº¦ç¼–码 ")
    private String emergencyLevelCode;
    /**
     * '满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2)
     */
    @ApiModelProperty("'满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2)")
    @Excel(name = " '满意度标识:0未做满度   1住院满度度  2出院满意度  ï¼ˆå¦‚果既要做住院,又要做出院,则用“,”分割,例如1,2) ")
    private String inhospMydFlag;
}
smartor/src/main/java/com/smartor/domain/PatMedOperationItem.java
@@ -8,6 +8,7 @@
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
 * æ‚£è€…检查检验记录子对象 pat_med_operation_item
@@ -216,5 +217,14 @@
    @ApiModelProperty("护士姓名")
    @Excel(name = "护士姓名")
    private String nurseName;
    @ApiModelProperty(value = "病区编码集合")
    private List<String> wardCodes;
    @ApiModelProperty(value = "部门编码集合")
    private List<String> deptCodes;
    @ApiModelProperty(value = "手术等级集合")
    private List<String> opLevelCodes;
}
smartor/src/main/java/com/smartor/domain/ServiceSLTDInhospResDTO.java
@@ -211,6 +211,9 @@
    @ApiModelProperty(value = "病历文件状态")
    private Integer medicalRecordFileStatus;
    @ApiModelProperty(value = "就诊来源ID")
    private String encounterSourceId;
    @ApiModelProperty(value = "主要出院诊断")
    private ServiceSLTDDiagnosisResDTO mainDischargeDiagnosis;
smartor/src/main/java/com/smartor/domain/ServiceSubtask.java
@@ -722,4 +722,30 @@
    @JsonFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束发送日期")
    private Date endSendDateTime;
    // ===================== ä»»åŠ¡ç»„ï¼ˆappltype=5)回溯字段 =====================
    /**
     * å…³è” service_task_schedule.id(appltype=5 æ—¶ä½¿ç”¨ï¼‰
     */
    @ApiModelProperty(value = "关联 service_task_schedule.id(appltype=5)")
    private Long scheduleId;
    /**
     * å…³è” service_task_schedule_detail.id
     */
    @ApiModelProperty(value = "关联 service_task_schedule_detail.id")
    private Long scheduleDetailId;
    /**
     * æœ¬æ¡ subtask åœ¨è®¡åˆ’中的顺序号
     */
    @ApiModelProperty(value = "本条 subtask åœ¨è®¡åˆ’中的顺序号")
    private Integer scheduleSeq;
    /**
     * æ‰€åœ¨å¾ªçŽ¯è½®æ¬¡ï¼ˆéžå¾ªçŽ¯ä»»åŠ¡ä¸º0)
     */
    @ApiModelProperty(value = "所在循环轮次(非循环任务为0)")
    private Long loopCount;
}
smartor/src/main/java/com/smartor/domain/ServiceTaskSchedule.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,166 @@
package com.smartor.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’ä¸»è¡¨ service_task_schedule
 * <p>
 * ç”¨äºŽ appltype=5(按任务组):一个 service_task å¯¹åº”一条 schedule + å¤šæ¡ detail,
 * åŒä¸€å‡ºé™¢è®°å½•据此可生成多个 service_subtask。
 *
 * @author smartor
 * @date 2026-06-30
 */
@Data
@ApiModel(value = "ServiceTaskSchedule", description = "随访任务计划主表")
public class ServiceTaskSchedule extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®
     */
    @ApiModelProperty("主键id")
    private Long id;
    /**
     * å…³è” service_task.taskid
     */
    @ApiModelProperty("关联 service_task.taskid")
    @Excel(name = "任务id")
    private Long taskid;
    /**
     * æœ€å¤§å¾ªçŽ¯æ¬¡æ•°ï¼ˆå¾ªçŽ¯ä»»åŠ¡ç”¨ï¼ŒNULL或0表示无限)
     */
    @ApiModelProperty("最大循环次数(循环任务用,NULL或0表示无限)")
    private Long maxLoopCount;
    /**
     * å½“前已完成循环次数
     */
    @ApiModelProperty("当前已完成循环次数")
    private Long currentLoopCount;
    /**
     * å½“前执行顺序号
     */
    @ApiModelProperty("当前执行顺序号")
    private Integer currentSeq;
    /**
     * ä¸‹ä¸€æ‰§è¡Œé¡ºåºå·
     */
    @ApiModelProperty("下一执行顺序号")
    private Integer nextSeq;
    /**
     * æ‰§è¡Œå‘¨æœŸæ–¹å¼(1-循环 0-非循环)
     */
    @ApiModelProperty("执行周期方式(1-循环 0-非循环)")
    private Integer scheduleStyle;
    /**
     * å¾ªçŽ¯æ—¶é—´æ•°
     */
    @ApiModelProperty("循环时间数")
    private Integer scheduleTimeNum;
    /**
     * å¾ªçŽ¯æ—¶é—´å•ä½; 1-天 2-周 3-月 4-å¹´
     */
    @ApiModelProperty("循环时间单位; 1-天 2-周 3-月 4-å¹´")
    private Integer scheduleTimeUnit;
    /**
     * ä¸‹æ¬¡æ‰§è¡Œæ—¶é—´
     */
    @ApiModelProperty("下次执行时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date nextExecuteTime;
    /**
     * å‘¨æœŸåŸºå‡†ç±»åž‹; 0-自定义时间 1-入院时间 2-出院时间 3-就诊时间 4-入组时间
     */
    @ApiModelProperty("周期基准类型; 0-自定义时间 1-入院时间 2-出院时间 3-就诊时间 4-入组时间")
    private Integer scheduleBenchmark;
    /**
     * å‘¨æœŸåŸºå‡†è‡ªå®šä¹‰æ—¶é—´
     */
    @ApiModelProperty("周期基准自定义时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date scheduleBenchmarkCustomTime;
    /**
     * åˆ é™¤æ ‡è®°ï¼ˆ0存在 1删除)
     */
    @ApiModelProperty("删除标记(0存在 1删除)")
    private String delFlag;
    /**
     * æœºæž„ID
     */
    @ApiModelProperty("机构ID")
    private String orgid;
    /**
     * é™¢åŒºID
     */
    @ApiModelProperty("院区ID")
    private String campusid;
    /**
     * ç»‘定科室代码(逗号分隔),任务组自动纳入匹配用
     */
    @ApiModelProperty("绑定科室代码(逗号分隔),自动纳入用")
    private String deptCodes;
    /**
     * ç»‘定病区代码(逗号分隔),任务组自动纳入匹配用
     */
    @ApiModelProperty("绑定病区代码(逗号分隔),自动纳入用")
    private String wardCodes;
    /**
     * ç»‘定疾病ICD10代码(逗号分隔),任务组自动纳入匹配用
     */
    @ApiModelProperty("绑定疾病ICD10代码(逗号分隔),自动纳入用")
    private String icd10Codes;
    /**
     * ç»‘定手术类型代码(逗号分隔),任务组自动纳入匹配用(本期暂不用)
     */
    @ApiModelProperty("绑定手术类型代码(逗号分隔),自动纳入用(本期暂不用)")
    private String oplevelCodes;
    /**
     * ç»‘定科室代码
     */
    @ApiModelProperty("绑定科室代码")
    private String deptCode;
    /**
     * ç»‘定病区代码
     */
    @ApiModelProperty("绑定病区代码")
    private String wardCode;
    /**
     * ç»‘定疾病ICD10代码
     */
    @ApiModelProperty("绑定疾病ICD10代码")
    private String icd10Code;
    /**
     * ç»‘定手术类型代码
     */
    @ApiModelProperty("绑定手术类型代码")
    private String oplevelCode;
}
smartor/src/main/java/com/smartor/domain/ServiceTaskScheduleDetail.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
package com.smartor.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’æ˜Žç»†è¡¨ service_task_schedule_detail
 *
 * @author smartor
 * @date 2026-06-30
 */
@Data
@ApiModel(value = "ServiceTaskScheduleDetail", description = "随访任务计划明细表")
public class ServiceTaskScheduleDetail extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®
     */
    @ApiModelProperty("主键")
    private Long id;
    /**
     * å…³è” service_task.taskid
     */
    @ApiModelProperty("关联 service_task.taskid")
    @Excel(name = "任务id")
    private Long taskid;
    /**
     * å…³è” service_task_schedule.id
     */
    @ApiModelProperty("关联 service_task_schedule.id")
    private Long scheduleid;
    /**
     * é¡ºåºå·ï¼Œä»Ž1开始
     */
    @ApiModelProperty("顺序号,从1开始")
    private Integer seq;
    /**
     * é—´éš”天数(固定任务:相对基准日;循环任务:相对上一次完成日)
     */
    @ApiModelProperty("间隔天数(固定任务:相对基准日;循环任务:相对上一次完成日)")
    private Integer dayOffset;
    /**
     * è¯¥æ¬¡ä½¿ç”¨çš„æ¨¡æ¿ID
     */
    @ApiModelProperty("该次使用的模板ID")
    private Long templateid;
    /**
     * æ¨¡æ¿åº“ID
     */
    @ApiModelProperty("模板库ID")
    private Long libtemplateid;
    /**
     * æ¨¡æ¿åç§°
     */
    @ApiModelProperty("模板名称")
    private String templatename;
    /**
     * è¯¥æ¬¡è‡ªå®šä¹‰å†…容(JSON:kcb/jsy/text_param等)
     */
    @ApiModelProperty("该次自定义内容(JSON:kcb/jsy/text_param等)")
    private String content;
    /**
     * ä¸‹æ¬¡æ‰§è¡Œæ—¶é—´
     */
    @ApiModelProperty("下次执行时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date nextExecuteTime;
    /**
     * åˆ é™¤æ ‡è®°ï¼ˆ0存在 1删除)
     */
    @ApiModelProperty("删除标记(0存在 1删除)")
    private String delFlag;
    /**
     * æœºæž„ID
     */
    @ApiModelProperty("机构ID")
    private String orgid;
    /**
     * é™¢åŒºID
     */
    @ApiModelProperty("院区ID")
    private String campusid;
}
smartor/src/main/java/com/smartor/domain/ServiceTaskScheduleVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.smartor.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’ VO(主计划 + æ˜Žç»†åˆ—表)
 * ç”¨äºŽ appltype=5 ä»»åŠ¡ç»„åˆ›å»º/修改的入参。
 *
 * @author smartor
 * @date 2026-06-30
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ServiceTaskScheduleVO", description = "随访任务计划")
public class ServiceTaskScheduleVO extends ServiceTaskSchedule {
    private static final long serialVersionUID = 1L;
    /**
     * è®¡åˆ’明细列表(按 seq æŽ’序)
     */
    @ApiModelProperty("计划明细列表(按 seq æŽ’序)")
    private List<ServiceTaskScheduleDetail> detailList;
}
smartor/src/main/java/com/smartor/domain/ServiceTaskVO.java
@@ -434,10 +434,10 @@
    @Excel(name = "手术等级编码")
    private String oplevelcode;
    /**
     * é€‚用条件类型:1、按科室、2、按病区、3、按疾病诊断、4、按手术类型
     * é€‚用条件类型:1、按科室、2、按病区、3、按疾病诊断、4、按手术类型、5、按任务组
     */
    @ApiModelProperty("适用条件类型:1、按科室、2、按病区、3、按疾病诊断、4、按手术类型")
    @Excel(name = "适用条件类型:1、按科室、2、按病区、3、按疾病诊断、4、按手术类型")
    @ApiModelProperty("适用条件类型:1、按科室、2、按病区、3、按疾病诊断、4、按手术类型、5、按任务组")
    @Excel(name = "适用条件类型:1、按科室、2、按病区、3、按疾病诊断、4、按手术类型、5、按任务组")
    private String appltype;
    @ApiModelProperty(value = "随访部门编码")
@@ -452,4 +452,10 @@
    @ApiModelProperty(value = "疾病病种")
    @Excel(name = " ç–¾ç—…病种")
    private String diagType;
    /**
     * ä»»åŠ¡ç»„è®¡åˆ’ï¼ˆappltype=5 å¿…填,主计划 + æ˜Žç»†åˆ—表)
     */
    @ApiModelProperty(value = "任务组计划(appltype=5 å¿…填,主计划+明细)")
    private ServiceTaskScheduleVO serviceTaskScheduleVO;
}
smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java
@@ -69,6 +69,23 @@
    public int insertServiceSubtask(ServiceSubtask ServiceSubtask);
    /**
     * ä»»åŠ¡ç»„ï¼ˆappltype=5):统计某一轮次内仍在运行的 subtask æ•°é‡ã€‚
     * ä»åœ¨è¿è¡Œ = sendstate in (1,2,3) ä¸”未删除。
     * ç”¨äºŽåˆ¤æ–­æœ¬è½®æ˜¯å¦å·²å…¨éƒ¨ finalize(成功/失败/不执行/超时)。
     *
     * @param scheduleId è®¡åˆ’主键
     * @param loopCount  è½®æ¬¡ï¼ˆ0=首轮)
     */
    public int countActiveByScheduleIdAndLoop(@Param("scheduleId") Long scheduleId,
                                              @Param("loopCount") Long loopCount);
    /**
     * ä»»åŠ¡ç»„ï¼ˆappltype=5):拉取某一轮次的全部 subtask(用于克隆到下一轮)。
     */
    public List<ServiceSubtask> selectByScheduleIdAndLoop(@Param("scheduleId") Long scheduleId,
                                                          @Param("loopCount") Long loopCount);
    /**
     * éšè®¿åŠæ—¶çŽ‡ï¼šåº”éšè®¿æ—¶é—´<实际随访时间
     *
     * @param ServiceSubtask
smartor/src/main/java/com/smartor/mapper/ServiceTaskScheduleDetailMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package com.smartor.mapper;
import com.smartor.domain.ServiceTaskScheduleDetail;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’æ˜Žç»† Mapper æŽ¥å£
 *
 * @author smartor
 * @date 2026-06-30
 */
@Mapper
public interface ServiceTaskScheduleDetailMapper {
    /**
     * æŸ¥è¯¢æ˜Žç»†
     */
    ServiceTaskScheduleDetail selectServiceTaskScheduleDetailById(Long id);
    /**
     * æŸ¥è¯¢æ˜Žç»†åˆ—表
     */
    List<ServiceTaskScheduleDetail> selectServiceTaskScheduleDetailList(ServiceTaskScheduleDetail detail);
    /**
     * æŒ‰ scheduleid æŸ¥è¯¢æ˜Žç»†åˆ—表(按 seq å‡åºï¼‰
     */
    List<ServiceTaskScheduleDetail> selectByScheduleid(@Param("scheduleid") Long scheduleid);
    /**
     * æŒ‰ taskid æŸ¥è¯¢æ˜Žç»†åˆ—表(按 seq å‡åºï¼‰
     */
    List<ServiceTaskScheduleDetail> selectByTaskid(@Param("taskid") Long taskid);
    /**
     * æ–°å¢žæ˜Žç»†
     */
    int insertServiceTaskScheduleDetail(ServiceTaskScheduleDetail detail);
    /**
     * æ‰¹é‡æ–°å¢žæ˜Žç»†
     */
    int batchInsertServiceTaskScheduleDetail(@Param("list") List<ServiceTaskScheduleDetail> list);
    /**
     * ä¿®æ”¹æ˜Žç»†
     */
    int updateServiceTaskScheduleDetail(ServiceTaskScheduleDetail detail);
    /**
     * é€»è¾‘删除(按 id)
     */
    int deleteServiceTaskScheduleDetailById(Long id);
    /**
     * é€»è¾‘删除(按 scheduleid):修改任务时清空旧明细
     */
    int deleteByScheduleid(@Param("scheduleid") Long scheduleid);
    /**
     * é€»è¾‘删除(按 taskid)
     */
    int deleteByTaskid(@Param("taskid") Long taskid);
}
smartor/src/main/java/com/smartor/mapper/ServiceTaskScheduleMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
package com.smartor.mapper;
import com.smartor.domain.ServiceTaskSchedule;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’ä¸»è¡¨ Mapper æŽ¥å£
 *
 * @author smartor
 * @date 2026-06-30
 */
@Mapper
public interface ServiceTaskScheduleMapper {
    /**
     * æŸ¥è¯¢è®¡åˆ’详情
     */
    ServiceTaskSchedule selectServiceTaskScheduleById(Long id);
    /**
     * é€šè¿‡ taskid æŸ¥è¯¢ä»»åŠ¡å¯¹åº”çš„æœ‰æ•ˆè®¡åˆ’ï¼ˆappltype=5 ä¸€å¯¹ä¸€ï¼‰
     */
    ServiceTaskSchedule selectByTaskid(@Param("taskid") Long taskid);
    /**
     * æŸ¥è¯¢è®¡åˆ’列表
     */
    List<ServiceTaskSchedule> selectServiceTaskScheduleList(ServiceTaskSchedule serviceTaskSchedule);
    /**
     * æ–°å¢žè®¡åˆ’
     */
    int insertServiceTaskSchedule(ServiceTaskSchedule serviceTaskSchedule);
    /**
     * ä¿®æ”¹è®¡åˆ’
     */
    int updateServiceTaskSchedule(ServiceTaskSchedule serviceTaskSchedule);
    /**
     * é€»è¾‘删除(按 id)
     */
    int deleteServiceTaskScheduleById(Long id);
    /**
     * é€»è¾‘删除(按 taskid):修改任务时清空旧计划
     */
    int deleteByTaskid(@Param("taskid") Long taskid);
    /**
     * ä»»åŠ¡ç»„ï¼ˆappltype=5)滚动调度用:查询所有未达上限的循环计划。
     * æ¡ä»¶ï¼šschedule_style=1 ä¸” (max_loop_count is null or max_loop_count=0 or current_loop_count &lt; max_loop_count)
     * é™åˆ¶è¿”回条数避免长事务。
     */
    List<ServiceTaskSchedule> selectActiveCycleSchedules(@Param("limit") int limit);
}
smartor/src/main/java/com/smartor/service/IPatMedInhospService.java
@@ -3,6 +3,7 @@
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.smartor.domain.*;
import com.smartor.domain.DTO.PatMedInhospDTO;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@@ -32,6 +33,8 @@
     * @return æ‚£è€…住院记录集合
     */
    public List<PatMedInhosp> selectPatMedInhospList(PatMedInhosp patMedInhosp);
    public List<PatMedInhospDTO> selectPatMedInhospByApplication(PatMedInhosp patMedInhosp);
    /**
     * å‡ºé™¢ã€é—¨è¯Šäººæ•°å’Œéšè®¿é‡ç»Ÿè®¡ï¼ˆå‘¨ï¼Œæœˆï¼Œå¹´ï¼‰
@@ -93,12 +96,12 @@
    public int dealOutHospInfo(String config);
    /**
     * å¤„理从his取来的出院数据
     * å¤„理从his取来的出院数据 ä»»åŠ¡ç»„ç”Ÿæˆ
     *
     * @param
     * @return ç»“æžœ
     */
    public int dealOutHospInfoByDimension(String config);
    public int dealOutHospInfoBySchedule(String config);
    /**
     * èŽ·å–å‡ºé™¢ï¼Œä½é™¢ï¼Œé—¨è¯ŠæœåŠ¡äººæ¬¡
smartor/src/main/java/com/smartor/service/IServiceTaskScheduleService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package com.smartor.service;
import com.smartor.domain.ServiceTaskSchedule;
import com.smartor.domain.ServiceTaskScheduleDetail;
import com.smartor.domain.ServiceTaskScheduleVO;
import java.util.List;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’ Service æŽ¥å£
 *
 * @author smartor
 * @date 2026-06-30
 */
public interface IServiceTaskScheduleService {
    /**
     * ä¿å­˜è®¡åˆ’(含明细)。
     * è‹¥ taskid å·²æœ‰è®¡åˆ’:先软删旧的,再新建。
     *
     * @param vo ä¸»è®¡åˆ’ + æ˜Žç»†
     * @return ä¿å­˜åŽçš„主计划(含主键)
     */
    ServiceTaskSchedule saveScheduleWithDetail(ServiceTaskScheduleVO vo);
    /**
     * æŒ‰ taskid æŸ¥è¯¢è®¡åˆ’详情(含明细)
     */
    ServiceTaskScheduleVO getScheduleByTaskid(Long taskid);
    /**
     * é€šè¿‡ taskid æŸ¥è¯¢ä¸»è®¡åˆ’
     */
    ServiceTaskSchedule selectByTaskid(Long taskid);
    /**
     * é€šè¿‡ scheduleid æŸ¥è¯¢æ˜Žç»†
     */
    List<ServiceTaskScheduleDetail> selectDetailByScheduleid(Long scheduleid);
    /**
     * æŒ‰ taskid è½¯åˆ ä¸»è®¡åˆ’ + æ˜Žç»†
     */
    int removeByTaskid(Long taskid);
    /**
     * å¾ªçŽ¯ä»»åŠ¡æ»šåŠ¨è°ƒåº¦ï¼š
     * <p>
     * æ‰«ææ‰€æœ‰ schedule_style=1 çš„æœ‰æ•ˆè®¡åˆ’,若 current_loop_count å·²è¾¾ä¸Šé™åˆ™è·³è¿‡ï¼›
     * å¦åˆ™åˆ¤å®šæœ¬è½®ï¼ˆcurrent_loop_count)是否已全部 finalize(sendstate âˆ‰ 1/2/3)。
     * æ˜¯ -> ç”Ÿæˆä¸‹ä¸€è½® subtask(克隆本轮的患者,visit_time = æœ¬è½® visit_time + N天/周/月/年),
     *      current_loop_count + 1,next_execute_time æŽ¨è¿›ã€‚
     * å¦ -> è·³è¿‡ç­‰å¾…下次扫描。
     * <p>
     * ç”± RyTask å®šæ—¶è°ƒç”¨ï¼Œå•次扫描限制 200 æ¡é¿å…é•¿äº‹åŠ¡ã€‚
     *
     * @return å®žé™…推进了多少个计划
     */
    int rollCycleTasks();
}
smartor/src/main/java/com/smartor/service/impl/PatArchiveServiceImpl.java
@@ -164,23 +164,23 @@
            patArchiveVO.setIsoperation(2);
            patArchiveMapper.updatePatArchive(patArchive);
            if (StringUtils.isNotEmpty(patArchive.getNotrequiredFlag()) && patArchive.getNotrequiredFlag().equals("1")) {
                //不需要服务了,需要通过patid和sendstate=2或者sendstate=1去查询一下,service_subtask里是否有正在执行的任务,有的话,立即停了
                //不需要服务了,需要通过patid和sendstate=1,2,3,5,7去查询一下,service_subtask里是否有正在执行的任务,有的话,立即停了
                List<Long> list = Arrays.asList(1L, 2L, 3L, 5L, 7L);
                List<ServiceSubtask> serviceSubtaskList = new ArrayList<>();
                ServiceSubtaskEntity serviceSubtaskVO = new ServiceSubtaskEntity();
                serviceSubtaskVO.setPatid(patArchive.getId());
                serviceSubtaskVO.setSendstate(2L);
                List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
                serviceSubtaskVO.setSendstate(1L);
                List<ServiceSubtask> serviceSubtaskList1 = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
                if (CollectionUtils.isNotEmpty(serviceSubtaskList)) {
                    if (CollectionUtils.isNotEmpty(serviceSubtaskList1)) serviceSubtaskList.addAll(serviceSubtaskList1);
                } else {
                    if (CollectionUtils.isNotEmpty(serviceSubtaskList1)) serviceSubtaskList = serviceSubtaskList1;
                for (Long ss : list) {
                    serviceSubtaskVO.setSendstate(ss);
                    List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskVO);
                    serviceSubtaskList.addAll(serviceSubtasks);
                }
                //去redis中,查询是否有subid,有的话移除cache-exist
                if (CollectionUtils.isNotEmpty(serviceSubtaskList)) {
                    for (ServiceSubtask serviceSubtask : serviceSubtaskList) {
                        log.info("需要移除的subId为:{}", serviceSubtask.getId().toString());
                        serviceSubtaskMapper.deleteServiceSubtaskById(serviceSubtask.getId());
                        serviceSubtask.setSendstate(4L);
                        serviceSubtask.setRemark(patArchiveVO.getNotrequiredreason());
                        serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
                        redisCache.removeElementFromList("cache-exist", serviceSubtask.getId().toString());
                        redisCache.removeElementFromList("cache-0", serviceSubtask.getId().toString());
                        redisCache.removeElementFromList("cache-1", serviceSubtask.getId().toString());
smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java
@@ -9,7 +9,9 @@
import com.ruoyi.common.utils.DtoConversionUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.smartor.common.ScheduleSubtaskBuilder;
import com.smartor.domain.*;
import com.smartor.domain.DTO.PatMedInhospDTO;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import com.smartor.mapper.*;
import com.smartor.service.IPatMedInhospService;
@@ -64,6 +66,13 @@
    private String active;
    @Autowired
    private IConfigService iSysConfigService;
    @Autowired
    private ServiceTaskScheduleMapper serviceTaskScheduleMapper;
    @Autowired
    private ScheduleSubtaskBuilder scheduleSubtaskBuilder;
    @Autowired
    private ServiceTaskScheduleDetailMapper serviceTaskScheduleDetailMapper;
    /**
@@ -110,6 +119,24 @@
            patMedInhosp1.setTagname(tagname);
        }
        return patMedInhospList;
    }
    @Override
    public List<PatMedInhospDTO> selectPatMedInhospByApplication(PatMedInhosp patMedInhosp) {
        List<PatMedInhosp> patMedInhosps = selectPatMedInhospList(patMedInhosp);
        if (!org.springframework.util.CollectionUtils.isEmpty(patMedInhosps)) {
            return null;
        }
        List<PatMedInhospDTO> patMedInhospDTOList = DtoConversionUtils.sourceToTarget(patMedInhosps, PatMedInhospDTO.class);
        for (PatMedInhospDTO pmd : patMedInhospDTOList) {
            ServiceSubtaskEntity serviceSubtask = new ServiceSubtaskEntity();
            serviceSubtask.setServiceType("4");
            serviceSubtask.setInhospid(pmd.getInhospid());
            List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtask);
            if (CollectionUtils.isNotEmpty(serviceSubtasks)) pmd.setFinishFlag("1");
        }
        return patMedInhospDTOList;
    }
    @Override
@@ -333,139 +360,152 @@
    }
    /**
     * å¤šç»´åº¦éšè®¿
     * ä»»åŠ¡ç»„éšè®¿
     *
     * @param config
     * @return
     */
    public int dealOutHospInfoByDimension(String config) {
        // ä¸€æ¬¡æ€§æŸ¥å‡ºæ‰€æœ‰éœ€è¦å¤„理的出院患者(三个维度任意一个未完成)
        List<PatMedInhosp> patList = patMedInhospMapper.selectNeedProcessList();
        log.info("【统一扫描】待处理患者数:{}", patList.size());
    public int dealOutHospInfoBySchedule(String config) {
        for (PatMedInhosp patMedInhosp1 : patList) {
            PatArchive patArchive = patArchiveMapper.selectPatArchiveByPatid(patMedInhosp1.getPatid());
            if (Objects.isNull(patArchive)) {
                // ä¸‰ä¸ªç»´åº¦éƒ½æ ‡è®°ä¸ºå¤±è´¥
                markAllFlagsAsError(patMedInhosp1, "患者基本信息为空");
                continue;
            }
        ServiceTask serviceTaskVo = new ServiceTask();
        serviceTaskVo.setLongTask(1);
        serviceTaskVo.setAppltype("5");
        List<ServiceTask> serviceTasks = serviceTaskMapper.selectServiceTaskList(serviceTaskVo);
            // â”€â”€ ç»´åº¦1:科室 â”€â”€
            if ("0".equals(patMedInhosp1.getDeptcheckFlag())) {
                processTasksByDimension(patMedInhosp1, patArchive, config, 1);
            }
        if (CollectionUtils.isNotEmpty(serviceTasks)) {
            for (ServiceTask serviceTask : serviceTasks) {
                if(!ObjectUtils.isEmpty(serviceTask.getTaskid())){
                    ServiceTaskSchedule serviceTaskSchedule = new ServiceTaskSchedule();
                    ServiceTaskSchedule taskSchedule = new ServiceTaskSchedule();
                    taskSchedule.setTaskid(serviceTask.getTaskid());
                    List<ServiceTaskSchedule> serviceTaskSchedules = serviceTaskScheduleMapper.selectServiceTaskScheduleList(taskSchedule);
                    if(CollectionUtils.isNotEmpty(serviceTaskSchedules)){
                        serviceTaskSchedule = serviceTaskSchedules.get(0);
                        String deptCodes = serviceTaskSchedule.getDeptCodes();
                        String wardCodes = serviceTaskSchedule.getWardCodes();
                        String icd10Codes = serviceTaskSchedule.getIcd10Codes();
                        String opLevelCodes = serviceTaskSchedule.getOplevelCodes();
            // â”€â”€ ç»´åº¦2:病区 â”€â”€ï¼ˆæ–°åŽåŒ»é™¢è·³è¿‡ï¼‰
            if (!active.equals("xh") && "0".equals(patMedInhosp1.getWardcheckFlag())) {
                processTasksByDimension(patMedInhosp1, patArchive, config, 2);
            }
                        List<String> icd10CodeList = new ArrayList<>();
                        List<String> opLevelCodeList = new ArrayList<>();
                        List<String> deptCodeList = new ArrayList<>();
                        List<String> wardCodeList = new ArrayList<>();
            // â”€â”€ ç»´åº¦3:疾病 â”€â”€ï¼ˆæ–°åŽåŒ»é™¢è·³è¿‡ï¼‰
            if (!active.equals("xh") && "0".equals(patMedInhosp1.getDiagcheckFlag())) {
                processTasksByDimension(patMedInhosp1, patArchive, config, 3);
                        /**
                         * éšè®¿ç±»åž‹(1-科室,2-病区,3-疾病 4-入院科室 5-入院病区 6-手术)
                         */
                        Integer type = 1;
                        if (StringUtils.isNotEmpty(deptCodes)) {
                            type = 1;
                            deptCodeList = Arrays.asList(deptCodes.split(","));
                        }
                        if(StringUtils.isNotEmpty(wardCodes)) {
                            type = 2;
                            wardCodeList = Arrays.asList(wardCodes.split(","));
                        }
                        if(StringUtils.isNotEmpty(icd10Codes)) {
                            type = 3;
                            icd10CodeList = Arrays.asList(icd10Codes.split(","));
                        }
                        if (StringUtils.isNotEmpty(opLevelCodes)) {
                            type = 6;
                            opLevelCodeList = Arrays.asList(opLevelCodes.split(","));
                        }
                        //非手术处理方式
                        if(type != 6){
                            PatMedInhosp patMedInhospVo = new PatMedInhosp();
                            patMedInhospVo.setScheduleCheckFlag("0");
                            patMedInhospVo.setInhospstate("1");
                            patMedInhospVo.setFuflag("1");
//                            patMedInhospVo.setDeptcodeList(deptCodeList);
                            patMedInhospVo.setLeaveldeptcodes(deptCodeList);
                            patMedInhospVo.setLeavehospitaldistrictcodes(wardCodeList);
                            patMedInhospVo.setIcd10codeList(icd10CodeList);
                            List<PatMedInhosp> patList = patMedInhospMapper.selectPatMedInhospList(patMedInhospVo);
                            log.info("dealOutHospInfoBySchedule ä»»åŠ¡ç»„éšè®¿, taskid = {}, æ‰«ææ‚£è€…人数 {}", serviceTask.getTaskid(), patList.size());
                            for(PatMedInhosp patMedInhosp : patList){
                                ServiceTaskScheduleDetail scheduleDetailVo = new ServiceTaskScheduleDetail();
                                scheduleDetailVo.setTaskid(serviceTask.getTaskid());
                                scheduleDetailVo.setScheduleid(serviceTaskSchedule.getId());
                                List<ServiceTaskScheduleDetail> serviceTaskScheduleDetails = serviceTaskScheduleDetailMapper.selectServiceTaskScheduleDetailList(scheduleDetailVo);
                                PatArchive patArchive = patArchiveMapper.selectPatArchiveByPatid(patMedInhosp.getPatid());
                                if (Objects.isNull(patArchive)) {
                                    continue;
                                }
                                //封装serviceSubtask
                                ServiceSubtask serviceSubtask = boxedServiceSubtask(serviceTask, patMedInhosp, patArchive, config, type);
                                List<Map<String, Object>> preachformList = new ArrayList<>();
                                if(StringUtils.isNotEmpty(serviceTask.getPreachformDesc())){
                                    try {
                                        ObjectMapper objectMapper = new ObjectMapper();
                                        preachformList = objectMapper.readValue(serviceTask.getPreachformDesc(), List.class);
                                    }catch (Exception e){
                                        log.error("任务组preachformDesc解析失败,taskid={},inhospid={}", serviceTask.getTaskid(), patMedInhosp.getInhospid());
                                    }
                                }
                                scheduleSubtaskBuilder.buildSubtasksForPatient(serviceTask, serviceTaskSchedule, serviceTaskScheduleDetails, serviceSubtask, preachformList);
                                //置首轮纳入标记,避免下次扫描重复生成(后续轮次由 rollTaskGroupCycle è´Ÿè´£ï¼‰
                                PatMedInhosp flagUpd = new PatMedInhosp();
                                flagUpd.setInhospid(patMedInhosp.getInhospid());
                                flagUpd.setScheduleCheckFlag("1");
                                patMedInhospMapper.updatePatMedInhosp(flagUpd);
                            }
                        }else {
                            //任务组 - æ‰‹æœ¯éšè®¿
                            if(CollectionUtils.isNotEmpty(opLevelCodeList)){
                                PatMedOperationItem pmoi = new PatMedOperationItem();
                                //获取需要出院疾病随访,未处理的数据
                                pmoi.setOpercheckFlag("0");
                                pmoi.setMainFlag("1");
                                pmoi.setDeptCodes(deptCodeList);
                                pmoi.setWardCodes(wardCodeList);
                                pmoi.setOpLevelCodes(opLevelCodeList);
                                List<PatMedOperationItem> patMedOperationItems = patMedOperationItemMapper.selectOperationItemList(pmoi);
                                for(PatMedOperationItem patMedOperationItem : patMedOperationItems){
                                    PatArchive patArchive = patArchiveMapper.selectPatArchiveByPatid(patMedOperationItem.getPatid());
                                    if (Objects.isNull(patArchive)) {
                                        continue;
                                    }
                                    PatMedInhosp patMedInhospVo = new PatMedInhosp();
                                    patMedInhospVo.setPatid((patMedOperationItem.getPatid()));
                                    patMedInhospVo.setScheduleCheckFlag("0");
                                    patMedInhospVo.setInhospstate("1");
                                    patMedInhospVo.setFuflag("1");
                                    List<PatMedInhosp> patMedInhospList = patMedInhospMapper.selectPatMedInhospList(patMedInhospVo);
                                    if(CollectionUtils.isNotEmpty(patMedInhospList)){
                                        ServiceTaskScheduleDetail scheduleDetailVo = new ServiceTaskScheduleDetail();
                                        scheduleDetailVo.setTaskid(serviceTask.getTaskid());
                                        scheduleDetailVo.setScheduleid(serviceTaskSchedule.getId());
                                        List<ServiceTaskScheduleDetail> serviceTaskScheduleDetails = serviceTaskScheduleDetailMapper.selectServiceTaskScheduleDetailList(scheduleDetailVo);
                                        //封装serviceSubtask
                                        ServiceSubtask serviceSubtask = boxedServiceSubtaskForOp(serviceTask, patMedInhospList.get(0), patMedOperationItem, patArchive, config);
                                        List<Map<String, Object>> preachformList = new ArrayList<>();
                                        if(StringUtils.isNotEmpty(serviceTask.getPreachformDesc())){
                                            try {
                                                ObjectMapper objectMapper = new ObjectMapper();
                                                preachformList = objectMapper.readValue(serviceTask.getPreachformDesc(), List.class);
                                            }catch (Exception e){
                                                log.error("任务组(手术)preachformDesc解析失败,taskid={}", serviceTask.getTaskid());
                                            }
                                        }
                                        scheduleSubtaskBuilder.buildSubtasksForPatient(serviceTask, serviceTaskSchedule, serviceTaskScheduleDetails, serviceSubtask, preachformList);
                                        //置首轮纳入标记,避免重复生成
                                        PatMedInhosp flagUpd = new PatMedInhosp();
                                        flagUpd.setInhospid(patMedInhospList.get(0).getInhospid());
                                        flagUpd.setScheduleCheckFlag("1");
                                        patMedInhospMapper.updatePatMedInhosp(flagUpd);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return 1;
    }
    /**
     * æŒ‰ç»´åº¦æ‰¾åˆ°æ‰€æœ‰åŒ¹é…é•¿æœŸä»»åŠ¡ï¼Œæ‰¹é‡ç”Ÿæˆ subtask
     * type: 1=科室, 2=病区, 3=疾病
     */
    private void processTasksByDimension(PatMedInhosp patMedInhosp1, PatArchive patArchive, String config, int type) {
        List<Long> matchedTaskIds = findMatchingTaskIds(patMedInhosp1, type);
        if (CollectionUtils.isEmpty(matchedTaskIds)) {
            String reason = getDimensionReason(type);
            markFlagAsNoConfig(patMedInhosp1, type, reason);
            return;
        }
        // ä¸€æ¡ inhosp è®°å½• â†’ å¤šä¸ªåŒ¹é…ä»»åŠ¡ â†’ å¤šæ¡ subtask
        for (Long taskId : matchedTaskIds) {
            writeInSubTask(taskId, true, patMedInhosp1, patArchive, type, config);
        }
    }
    private String getDimensionReason(int type) {
        switch (type) {
            case 1: { // ç§‘室
                return "未找到科室匹配的长期任务";
            }
            case 2: { // ç—…区
                return "未找到病区匹配的长期任务";
            }
            case 3: { // ç–¾ç—…
                return "未找到疾病匹配的长期任务";
            }
        }
        return "多维长期任务-匹配类型为空";
    }
    private void markFlagAsNoConfig(PatMedInhosp patMedInhosp, int type, String reason) {
        switch (type) {
            case 1: { // ç§‘室
                patMedInhosp.setDeptcheckFlag("2");
                patMedInhosp.setRemark(reason);
                patMedInhospMapper.updatePatMedInhosp(patMedInhosp);
                break;
            }
            case 2: { // ç—…区
                patMedInhosp.setWardcheckFlag("2");
                patMedInhosp.setRemark(reason);
                patMedInhospMapper.updatePatMedInhosp(patMedInhosp);
                break;
            }
            case 3: { // ç–¾ç—…
                patMedInhosp.setDiagcheckFlag("2");
                patMedInhosp.setRemark(reason);
                patMedInhospMapper.updatePatMedInhosp(patMedInhosp);
                break;
            }
        }
    }
    private void markAllFlagsAsError(PatMedInhosp patMedInhosp, String reason) {
        patMedInhosp.setDeptcheckFlag("2");
        patMedInhosp.setWardcheckFlag("2");
        patMedInhosp.setDiagcheckFlag("2");
        patMedInhosp.setRemark(reason);
        patMedInhospMapper.updatePatMedInhosp(patMedInhosp);
    }
    /**
     * æ ¹æ®ç»´åº¦ç±»åž‹æŸ¥è¯¢åŒ¹é…çš„长期任务 ID åˆ—表
     */
    private List<Long> findMatchingTaskIds(PatMedInhosp patMedInhosp1, int type) {
        switch (type) {
            case 1: { // ç§‘室
                ServiceTaskdept query = new ServiceTaskdept();
                query.setLongtask(1L);
                query.setDeptCode(patMedInhosp1.getLeaveldeptcode());
                query.setDeptType("1");
                query.setOrgid(patMedInhosp1.getOrgid());
                return serviceTaskdeptMapper.selectServiceTaskdeptList(query).stream().map(ServiceTaskdept::getTaskId).collect(Collectors.toList());
            }
            case 2: { // ç—…区
                ServiceTaskdept query = new ServiceTaskdept();
                query.setLongtask(1L);
                query.setDeptCode(patMedInhosp1.getLeavehospitaldistrictcode());
                query.setDeptType("2");
                query.setOrgid(patMedInhosp1.getOrgid());
                return serviceTaskdeptMapper.selectServiceTaskdeptList(query).stream().map(ServiceTaskdept::getTaskId).collect(Collectors.toList());
            }
            case 3: { // ç–¾ç—…
                if (StringUtils.isEmpty(patMedInhosp1.getLeaveicd10code())) return Collections.emptyList();
                ServiceTaskdiag query = new ServiceTaskdiag();
                query.setLongtask(1L);
                query.setIcd10code(patMedInhosp1.getLeaveicd10code());
                query.setOrgid(patMedInhosp1.getOrgid());
                return serviceTaskdiagMapper.selectServiceTaskdiagList(query).stream().map(ServiceTaskdiag::getTaskId).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }
@@ -811,10 +851,10 @@
        if (ObjectUtils.isEmpty(serviceSubtask)) {
            return;
        }
        if(StringUtils.isNotEmpty(patMedOperationItem.getDeptcode())){
        if (StringUtils.isNotEmpty(patMedOperationItem.getDeptcode())) {
            serviceSubtask.setVisitDeptCode(patMedOperationItem.getDeptcode());
            serviceSubtask.setVisitDeptName(patMedOperationItem.getDeptname());
        }else {
        } else {
            serviceSubtask.setVisitDeptCode(patMedOperationItem.getHospitaldistrictcode());
            serviceSubtask.setVisitDeptName(patMedOperationItem.getHospitaldistrictname());
        }
smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
@@ -9,6 +9,8 @@
import com.ruoyi.common.core.domain.entity.SysUserDept;
import com.ruoyi.common.core.domain.entity.SysUserRole;
import com.ruoyi.common.utils.StringUtils;
import com.smartor.common.enums.EmergencyLevelEnum;
import com.smartor.common.enums.ImportFlagEnum;
import com.ruoyi.common.utils.http.HttpUtils;
import com.smartor.common.DistinctByProperty;
import com.smartor.domain.*;
@@ -795,7 +797,6 @@
        patMedInhosp.setInhospno(dto.getHealthcareRecordNo());
        patMedInhosp.setFuflag("1");
        if (StringUtils.isNotEmpty(patArchive.getNotrequiredFlag()) && patArchive.getNotrequiredFlag().equals("1"))
            patMedInhosp.setFuflag("0");
        if ("0".equals(cry)) {
@@ -840,6 +841,13 @@
            setDischargeInfo(patMedInhosp, dto);
        } else {
            setAdmissionInfo(patMedInhosp, dto);
            patMedInhosp.setEncounterSourceId(dto.getEncounterSourceId() == null ? "" : dto.getEncounterSourceId());
            if (StringUtils.isNotEmpty(dto.getEncounterSourceId())) {
                //根据 encounterSourceId èŽ·å– importanceFlagCode   emergencyLevelCode
                Map<String, String> applyInfo = hospitalizedApply(dto.getEncounterSourceId(), dto.getOrgId());
                patMedInhosp.setImportanceFlagCode(applyInfo.get("importanceFlagCode"));
                patMedInhosp.setEmergencyLevelCode(applyInfo.get("emergencyLevelCode"));
            }
        }
        patMedInhosp.setDrname(dto.getDoctorName());
@@ -884,6 +892,86 @@
        patMedInhosp.setHospitaldistrictid("" + dto.getAreaId());
        patMedInhosp.setHospitaldistrictcode("" + dto.getAreaId());
        patMedInhosp.setHospitaldistrictname(dto.getAreaName());
    }
    /**
     * æ ¹æ®å…¥é™¢ç”³è¯·å•ID查询入院申请单详情
     * åªæå– importanceFlagCode(importanceFlagCodeList逗号拼接)和 emergencyLevelCode ä¸¤ä¸ªå€¼
     */
    private Map<String, String> hospitalizedApply(String encounterSourceId, String orgid) {
        Map<String, String> applyInfo = new HashMap<>();
        Map<String, String> headers = buildRequestHeaders();
        log.info("院申请单ID查询入院申请单:{},appKey:{}", sltdPubPath + "/sf/hospitalizedApply/query", APP_KEY);
        //设置入参
        Map<String, Object> requestParams = new HashMap<>();
        requestParams.put("applyId", encounterSourceId);
        requestParams.put("orgId", orgid);
        String result = null;
        if (StringUtils.isNotEmpty(encounterSourceId) && StringUtils.isNotEmpty(orgid))
            result = HttpUtils.sendPostByHeader(sltdPubPath + "/sf/hospitalizedApply/query", new Gson().toJson(requestParams), headers);
        if (StringUtils.isEmpty(result)) {
            log.error("【hospitalizedApply】接口返回为空,applyId={}", encounterSourceId);
            return applyInfo;
        }
        try {
            Gson gson = new Gson();
            Type mapType = new TypeToken<Map<String, Object>>() {
            }.getType();
            Map<String, Object> responseMap = gson.fromJson(result, mapType);
            Object dataObj = responseMap == null ? null : responseMap.get("data");
            if (dataObj instanceof Map) {
                Map<String, Object> data = (Map<String, Object>) dataObj;
                //重要性标记编码,接口返回是数组,需要转换为字典名称
                Object importanceFlagCodeListObj = data.get("importanceFlagCodeList");
                if (importanceFlagCodeListObj instanceof List) {
                    List<?> importanceFlagCodeList = (List<?>) importanceFlagCodeListObj;
                    // è¿‡æ»¤æŽ‰ null å€¼
                    List<String> nonNullList = importanceFlagCodeList.stream()
                            .filter(Objects::nonNull)
                            .map(Object::toString)
                            .filter(StringUtils::isNotEmpty)
                            .collect(Collectors.toList());
                    if (!nonNullList.isEmpty()) {
                        String importanceFlagLabel;
                        if (nonNullList.size() == 1) {
                            // åªæœ‰ä¸€ä¸ªå€¼ï¼Œç›´æŽ¥é€šè¿‡æžšä¸¾èŽ·å–æè¿°
                            importanceFlagLabel = ImportFlagEnum.getDescByCode(nonNullList.get(0));
                        } else {
                            // å¤šä¸ªå€¼ï¼Œç”¨é€—号拼接枚举描述
                            StringBuilder labelBuilder = new StringBuilder();
                            for (String code : nonNullList) {
                                String label = ImportFlagEnum.getDescByCode(code);
                                if (StringUtils.isNotEmpty(label)) {
                                    labelBuilder.append(label).append(",");
                                }
                            }
                            importanceFlagLabel = StringUtils.stripEnd(labelBuilder.toString(), ",");
                        }
                        if (StringUtils.isNotEmpty(importanceFlagLabel)) {
                            applyInfo.put("importanceFlagCode", importanceFlagLabel);
                        }
                    }
                }
                //紧急程度编码,通过枚举转换描述
                Object emergencyLevelCodeObj = data.get("emergencyLevelCode");
                if (emergencyLevelCodeObj != null) {
                    String emergencyLevelLabel = EmergencyLevelEnum.getDescByCode(emergencyLevelCodeObj.toString());
                    if (StringUtils.isNotEmpty(emergencyLevelLabel)) {
                        applyInfo.put("emergencyLevelCode", emergencyLevelLabel);
                    }
                }
            } else {
                log.error("【hospitalizedApply】接口返回data不是对象,applyId={},result:{}", encounterSourceId, result);
            }
        } catch (Exception e) {
            log.error("【hospitalizedApply】解析入院申请单详情失败,applyId={}", encounterSourceId, e);
        }
        log.info("【hospitalizedApply】applyId={},importanceFlagCode={},emergencyLevelCode={}", encounterSourceId, applyInfo.get("importanceFlagCode"), applyInfo.get("emergencyLevelCode"));
        return applyInfo;
    }
    /**
@@ -1076,6 +1164,7 @@
        dto.setCostCategoryCode(getStringValue(dataItem, "costCategoryCode"));
        dto.setCostNatureName(getStringValue(dataItem, "costNatureName"));
        dto.setCostNatureCode(getStringValue(dataItem, "costNatureCode"));
        dto.setEncounterSourceId(getStringValue(dataItem, "encounterSourceId"));
        dto.setFurtherConsultationStatus(getIntegerValue(dataItem, "furtherConsultationStatus"));
        Object mainDiagObj = dataItem.get("mainDischargeDiagnosis");
        if (mainDiagObj instanceof Map) {
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
@@ -5,6 +5,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DtoConversionUtils;
import com.ruoyi.common.utils.RSAPublicKeyExample;
@@ -738,6 +739,13 @@
    public Map<String, Object> selectPatQuestionResult(ServiceSubTaskQueryReq serviceSubTaskQueryReq) {
        log.info("selectPatQuesTionResult的入参为:{}", serviceSubTaskQueryReq);
        Map<String, Object> map = new HashMap<>();
        if (serviceSubTaskQueryReq.getSubId() != null) {
            ServiceSubtask serviceSubtask = serviceSubtaskMapper.selectServiceSubtaskById(serviceSubTaskQueryReq.getSubId());
            if (serviceSubtask.getSendstate() == 4L) {
                log.info("患者子任务ID为:{},状态为:{}", serviceSubTaskQueryReq.getSubId(), serviceSubtask.getSendstate());
                throw new BaseException("该任务不执行");
            }
        }
        //获取本次的问答结果
        Map<String, Object> scriptInfoByCondition = serviceTaskService.getScriptInfoByCondition(serviceSubTaskQueryReq.getTaskid(), serviceSubTaskQueryReq.getPatid(), serviceSubTaskQueryReq.getIsFinish(), serviceSubTaskQueryReq.getPatfrom(), serviceSubTaskQueryReq.getSubId());
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -6,7 +6,6 @@
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.redis.RedisCache;
import com.ruoyi.common.dx.MessageSend;
@@ -18,9 +17,9 @@
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService;
import com.smartor.common.DeepSeekApi;
import com.smartor.common.FtpService;
import com.smartor.common.MtSubmitSmUtil;
import com.smartor.common.ScheduleSubtaskBuilder;
import com.smartor.config.PhoneUtils;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.*;
@@ -33,7 +32,6 @@
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.annotations.Param;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -121,6 +119,12 @@
    @Autowired
    private IServiceSubtaskDetailTraceService traceService;
    @Autowired
    private IServiceTaskScheduleService serviceTaskScheduleService;
    @Autowired
    private ScheduleSubtaskBuilder scheduleSubtaskBuilder;
    @Autowired
    private FtpService ftpService;
@@ -834,6 +838,29 @@
                            serviceTaskoperService.insertServiceTaskoper(serviceTaskoper);
                        }
                    }
                } else if (serviceTaskVO.getAppltype().equals("5")) {
                    // ä»»åŠ¡ç»„ï¼šå¿…é¡»ä¸ºé•¿æœŸä»»åŠ¡ï¼ˆå¦åˆ™ findMatchingTaskIds æ‰«ä¸åˆ°ï¼Œæ— æ³•自动纳入新出院患者)
                    if (serviceTaskVO.getLongTask() == null || serviceTaskVO.getLongTask() != 1) {
                        throw new BaseException("appltype=5 ä»»åŠ¡ç»„å¿…é¡»ä¸ºé•¿æœŸä»»åŠ¡ï¼ˆlongTask=1)");
                    }
                    // ä¿å­˜è®¡åˆ’ + æ˜Žç»†
                    ServiceTaskScheduleVO scheduleVO = serviceTaskVO.getServiceTaskScheduleVO();
                    if (scheduleVO == null) {
                        throw new BaseException("appltype=5 ä»»åŠ¡ç»„ï¼šserviceTaskScheduleVO ä¸èƒ½ä¸ºç©º");
                    }
                    scheduleVO.setTaskid(serviceTask.getTaskid());
                    scheduleVO.setOrgid(serviceTask.getOrgid());
                    scheduleVO.setCampusid(serviceTask.getCampusid());
                    scheduleVO.setCreateBy(serviceTask.getCreateBy());
                    scheduleVO.setDeptCodes(serviceTaskVO.getDeptcode());
                    scheduleVO.setWardCodes(serviceTaskVO.getLeavehospitaldistrictcode());
                    scheduleVO.setIcd10Codes(serviceTaskVO.getIcd10code());
                    scheduleVO.setOplevelCodes(serviceTaskVO.getOplevelcode());
                    log.info("----serviceTaskSchedule的值为:{}", scheduleVO);
                    serviceTaskScheduleService.saveScheduleWithDetail(scheduleVO);
                } else {
                    ServiceTaskdept serviceTaskdept = new ServiceTaskdept();
                    serviceTaskdept.setTaskId(serviceTask.getTaskid());
@@ -919,6 +946,20 @@
                        serviceSubtask.setLongSendTime(patTaskRelevance.getLongSendTime());
                        serviceSubtask.setVisitTime(patTaskRelevance.getVisittime());
                    }
                    // ===== appltype=5 ä»»åŠ¡ç»„ï¼šæŒ‰ schedule çš„ detailList æ´¾ç”Ÿå¤šæ¡ subtask =====
                    if ("5".equals(serviceTaskVO.getAppltype())) {
                        ServiceTaskSchedule schedule = serviceTaskScheduleService.selectByTaskid(serviceTask.getTaskid());
                        if (schedule == null) {
                            throw new BaseException("appltype=5 ä»»åŠ¡ç»„ï¼šæœªæ‰¾åˆ° taskid=" + serviceTask.getTaskid() + " çš„计划");
                        }
                        List<ServiceTaskScheduleDetail> detailList =
                                serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId());
                        scheduleSubtaskBuilder.buildSubtasksForPatient(
                                serviceTask, serviceTaskVO.getPreachformList(), schedule, detailList, patTaskRelevance, serviceSubtask);
                        continue;
                    }
                    serviceSubtaskMapper.insertServiceSubtask(serviceSubtask);
                    serviceSubtask.getId().intValue();
@@ -1133,6 +1174,24 @@
                            }
                        }
                    }
                } else if (serviceTaskVO.getAppltype().equals("5")) {
                    // ä»»åŠ¡ç»„ä¿®æ”¹ï¼šåˆ æ—§ schedule + æ˜Žç»†ï¼Œé‡å»ºã€‚subtask ä¸Šé¢å·²æ‰¹é‡æ¸…理。
                    if (serviceTaskVO.getLongTask() == null || serviceTaskVO.getLongTask() != 1) {
                        throw new BaseException("appltype=5 ä»»åŠ¡ç»„å¿…é¡»ä¸ºé•¿æœŸä»»åŠ¡ï¼ˆlongTask=1)");
                    }
                    ServiceTaskScheduleVO scheduleVO = serviceTaskVO.getServiceTaskScheduleVO();
                    if (scheduleVO == null) {
                        throw new BaseException("appltype=5 ä»»åŠ¡ç»„ï¼šserviceTaskScheduleVO ä¸èƒ½ä¸ºç©º");
                    }
                    scheduleVO.setTaskid(serviceTask.getTaskid());
                    scheduleVO.setOrgid(serviceTask.getOrgid());
                    scheduleVO.setCampusid(serviceTask.getCampusid());
                    scheduleVO.setDeptCodes(serviceTaskVO.getDeptcode());
                    scheduleVO.setWardCodes(serviceTaskVO.getLeavehospitaldistrictcode());
                    scheduleVO.setIcd10Codes(serviceTaskVO.getIcd10code());
                    scheduleVO.setOplevelCodes(serviceTaskVO.getOplevelcode());
                    scheduleVO.setCreateBy(serviceTask.getUpdateBy());
                    serviceTaskScheduleService.saveScheduleWithDetail(scheduleVO);
                }
            }
            if (ObjectUtils.isNotEmpty(serviceTaskVO.getIvrTaskTemplateVO())) {
@@ -1186,6 +1245,20 @@
                    serviceSubtask.setVisitTime(patTaskRelevance.getVisittime());
                    serviceSubtask.setTextParam(new Gson().toJson(serviceTaskVO.getTextParam()));
                    if (patTaskRelevance.getIsoperation() != null) {
                        // appltype=5 ä»»åŠ¡ç»„ï¼šè¿½åŠ æ‚£è€…ï¼ˆisoperation=1)走计划派生;修改(2)/删除(3)仍走原逻辑
                        if ("5".equals(serviceTaskVO.getAppltype()) && patTaskRelevance.getIsoperation() == 1) {
                            ServiceTaskSchedule schedule = serviceTaskScheduleService.selectByTaskid(serviceTask.getTaskid());
                            if (schedule == null) {
                                throw new BaseException("appltype=5 ä»»åŠ¡ç»„ï¼šæœªæ‰¾åˆ° taskid=" + serviceTask.getTaskid() + " çš„计划");
                            }
                            List<ServiceTaskScheduleDetail> detailList =
                                    serviceTaskScheduleService.selectDetailByScheduleid(schedule.getId());
                            serviceSubtask.setUpdateBy(serviceTask.getUpdateBy());
                            serviceSubtask.setCreateBy(serviceTask.getUpdateBy());
                            scheduleSubtaskBuilder.buildSubtasksForPatient(
                                    serviceTask, serviceTaskVO.getPreachformList(), schedule, detailList, patTaskRelevance, serviceSubtask);
                            continue;
                        }
                        if (patTaskRelevance.getIsoperation() == 2) {
                            serviceSubtask.setUpdateBy(serviceTask.getUpdateBy());
                            serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
@@ -1238,7 +1311,6 @@
        map.put("taskId", serviceTask.getTaskid().intValue());
        return map;
    }
    @Override
    public void phoneCallBack(PhoneCallBackVO phoneCallBackVO) {
@@ -1745,15 +1817,15 @@
                configVoiceMatchAi.setConfigKey("sys.voice.match.ai");
                SysConfig matchAi = sysConfigMapper.selectConfig(configVoiceMatchAi);
//            if (ObjectUtils.isNotEmpty(matchAi) && StringUtils.isNotEmpty(matchAi.getConfigValue())
//                    && matchAi.getConfigValue().equals("1")) {
//                PhoneCallBackYQVO aiMatchResult = AiMatch(phoneCallReqYQVO, phoneCallBackYQVO,
//                        ivrTaskTemplateScriptVO, serviceSubtask, ivrTaskTemplate,
//                        ivrTaskTemplateScripts, scriptId, flag);
//                if(aiMatchResult != null){
//                    return aiMatchResult;
//                }
//            } else {
            if (ObjectUtils.isNotEmpty(matchAi) && StringUtils.isNotEmpty(matchAi.getConfigValue())
                    && matchAi.getConfigValue().equals("1")) {
                PhoneCallBackYQVO aiMatchResult = AiMatch(phoneCallReqYQVO, phoneCallBackYQVO,
                        ivrTaskTemplateScriptVO, serviceSubtask, ivrTaskTemplate,
                        ivrTaskTemplateScripts, scriptId, flag, phoneCallReqYQVO.getUuid());
                if(aiMatchResult != null){
                    return aiMatchResult;
                }
            } else {
                //是选择题
                for (int j = 0; j < ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList().size(); j++) {
                    log.error("phoneCallReqYQVO.getAsrtext()的值为:{}", phoneCallReqYQVO.getAsrtext());
@@ -1995,7 +2067,7 @@
                        continue;
                    }
                }
//            }
            }
                //都没有匹配到
                if (StringUtils.isEmpty(phoneCallBackYQVO.getValue())) {
                    log.info("都没有匹配到-------------------------");
@@ -2617,16 +2689,21 @@
    @Cacheable(value = "sfStatistics", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()")
    public List<ServiceSubtaskStatistic> getSfStatistics(ServiceSubtaskCountReq serviceSubtaskCountReq) {
        log.info("getSfStatistics的入参为:{}", serviceSubtaskCountReq);
        String groupKey = "drcode";
        String drcode = "drcode";
        //缙云人民 æ ¹æ®ç»ç®¡åŒ»ç”Ÿåˆ†ç»„
        if(serviceSubtaskCountReq.getOrgid().equals("47246116333112211A1001")){
            drcode = "management_doctor_code";
        }
        String groupKey = drcode;
        if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 1) {
            if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) {
                groupKey = "drcode";
                groupKey = drcode;
            } else {
                groupKey = "leavehospitaldistrictcode";
            }
        } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 2) {
            if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) {
                groupKey = "drcode";
                groupKey = drcode;
            } else {
                groupKey = "deptcode";
            }
@@ -2639,11 +2716,14 @@
        serviceSubtaskCountReq.setGroupKeyList(groupKeyList);
        List<ServiceSubtask> rawData = serviceSubtaskMapper.getSfStatistics(serviceSubtaskCountReq);
        switch (groupKey) {
            case "deptcode":
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDeptcode()).orElse("Unknown")));
                break;
            case "drcode":
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrcode()).orElse("Unknown")));
                break;
            case "management_doctor_code":
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getManagementDoctorCode()).orElse("Unknown")));
                break;
            case "deptcode":
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDeptcode()).orElse("Unknown")));
                break;
            case "leavehospitaldistrictcode":
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getLeavehospitaldistrictcode()).orElse("Unknown")));
@@ -4981,11 +5061,12 @@
     * @param options
     * @return
     */
    public Integer matchOptionIndex(String questionText, String voiceText, List<IvrTaskTemplateTargetoption> options){
    public Integer matchOptionIndex(String questionText, String voiceText, List<IvrTaskTemplateTargetoption> options, String uuid){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userQuestion",questionText);
        jsonObject.put("userAnswer",voiceText);
        jsonObject.put("options", options);
        jsonObject.put("uuid", uuid);
        String jsonString = jsonObject.toJSONString();
        String result = null;
@@ -5010,13 +5091,13 @@
    public PhoneCallBackYQVO AiMatch(PhoneCallReqYQVO phoneCallReqYQVO, PhoneCallBackYQVO phoneCallBackYQVO,
                        IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO, ServiceSubtask serviceSubtask, IvrTaskTemplate ivrTaskTemplate,
                        List<IvrTaskTemplateScript> ivrTaskTemplateScripts, String scriptId, Integer flag){
                        List<IvrTaskTemplateScript> ivrTaskTemplateScripts, String scriptId, Integer flag, String uuid){
        PhoneCallBackYQVO back = null;
        List<IvrTaskTemplateTargetoption> options = ivrTaskTemplateScriptVO.getIvrTaskScriptTargetoptionList();
        String voiceText = phoneCallReqYQVO.getAsrtext();
        String questionText = StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getIvrtext()) ? ivrTaskTemplateScriptVO.getIvrtext() : ivrTaskTemplateScriptVO.getScriptContent();
        Integer matched = -1;
        matched = matchOptionIndex(questionText, voiceText, options);
        matched = matchOptionIndex(questionText, voiceText, options, uuid);
        //说明匹配正确了
        if(matched != null && matched >= 0){
            IvrTaskTemplateTargetoption chosenOption = options.get(matched);
@@ -5253,7 +5334,7 @@
        ivrTaskTemplateTargetoption3.setTargetvalue("其他");
        options.add(ivrTaskTemplateTargetoption3);
        Integer matched = matchOptionIndex(questionText,voiceText,options);
        Integer matched = matchOptionIndex(questionText,voiceText,options,"1");
        if(ObjectUtils.isNotEmpty(matched)){
            if(matched >= 0){
                matchedText = options.get(matched).getTargetvalue();
smartor/src/main/java/com/smartor/service/impl/ServiceTaskScheduleServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,356 @@
package com.smartor.service.impl;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.smartor.domain.ServiceSubtask;
import com.smartor.domain.ServiceSubtaskPreachform;
import com.smartor.domain.ServiceTaskSchedule;
import com.smartor.domain.ServiceTaskScheduleDetail;
import com.smartor.domain.ServiceTaskScheduleVO;
import com.smartor.mapper.ServiceSubtaskMapper;
import com.smartor.mapper.ServiceSubtaskPreachformMapper;
import com.smartor.mapper.ServiceTaskScheduleDetailMapper;
import com.smartor.mapper.ServiceTaskScheduleMapper;
import com.smartor.service.IServiceTaskScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
 * éšè®¿ä»»åŠ¡è®¡åˆ’ Service å®žçް
 *
 * @author smartor
 * @date 2026-06-30
 */
@Slf4j
@Service
public class ServiceTaskScheduleServiceImpl implements IServiceTaskScheduleService {
    @Autowired
    private ServiceTaskScheduleMapper serviceTaskScheduleMapper;
    @Autowired
    private ServiceTaskScheduleDetailMapper serviceTaskScheduleDetailMapper;
    @Autowired
    private ServiceSubtaskMapper serviceSubtaskMapper;
    @Autowired
    private ServiceSubtaskPreachformMapper serviceSubtaskPreachformMapper;
    /** å•次扫描的最大计划数,避免长事务。 */
    private static final int ROLL_BATCH_LIMIT = 200;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceTaskSchedule saveScheduleWithDetail(ServiceTaskScheduleVO vo) {
        if (vo == null || vo.getTaskid() == null) {
            throw new BaseException("任务计划入参非法:taskid ä¸èƒ½ä¸ºç©º");
        }
        if (CollectionUtils.isEmpty(vo.getDetailList())) {
            throw new BaseException("任务计划明细不能为空(至少一条 detail)");
        }
        // 1. æ—§è®¡åˆ’软删
        serviceTaskScheduleMapper.deleteByTaskid(vo.getTaskid());
        serviceTaskScheduleDetailMapper.deleteByTaskid(vo.getTaskid());
        // 2. ä¸»è®¡åˆ’落库
        Date now = DateUtils.getNowDate();
        ServiceTaskSchedule schedule = new ServiceTaskSchedule();
        // æ‹·è´çˆ¶ç±»ï¼ˆServiceTaskSchedule)字段
        schedule.setTaskid(vo.getTaskid());
        schedule.setMaxLoopCount(vo.getMaxLoopCount());
        schedule.setCurrentLoopCount(vo.getCurrentLoopCount() == null ? 0L : vo.getCurrentLoopCount());
        schedule.setCurrentSeq(vo.getCurrentSeq() == null ? 0 : vo.getCurrentSeq());
        schedule.setNextSeq(vo.getNextSeq() == null ? 1 : vo.getNextSeq());
        schedule.setScheduleStyle(vo.getScheduleStyle() == null ? 0 : vo.getScheduleStyle());
        schedule.setScheduleTimeNum(vo.getScheduleTimeNum() == null ? 0 : vo.getScheduleTimeNum());
        schedule.setScheduleTimeUnit(vo.getScheduleTimeUnit() == null ? 0 : vo.getScheduleTimeUnit());
        schedule.setNextExecuteTime(vo.getNextExecuteTime());
        schedule.setScheduleBenchmark(vo.getScheduleBenchmark() == null ? 0 : vo.getScheduleBenchmark());
        schedule.setScheduleBenchmarkCustomTime(vo.getScheduleBenchmarkCustomTime());
        schedule.setRemark(vo.getRemark());
        schedule.setDelFlag("0");
        schedule.setCreateBy(vo.getCreateBy());
        schedule.setUpdateBy(vo.getCreateBy());
        schedule.setCreateTime(now);
        schedule.setUpdateTime(now);
        schedule.setOrgid(vo.getOrgid());
        schedule.setCampusid(vo.getCampusid());
        serviceTaskScheduleMapper.insertServiceTaskSchedule(schedule);
        // 3. æ˜Žç»†è½åº“
        List<ServiceTaskScheduleDetail> detailList = vo.getDetailList();
        int seq = 1;
        for (ServiceTaskScheduleDetail detail : detailList) {
            detail.setTaskid(vo.getTaskid());
            detail.setScheduleid(schedule.getId());
            if (detail.getSeq() == null) {
                detail.setSeq(seq);
            }
            if (detail.getDayOffset() == null) {
                throw new BaseException("计划明细 seq=" + detail.getSeq() + " çš„ dayOffset ä¸èƒ½ä¸ºç©º");
            }
            detail.setDelFlag("0");
            detail.setCreateBy(vo.getCreateBy());
            detail.setUpdateBy(vo.getCreateBy());
            detail.setCreateTime(now);
            detail.setUpdateTime(now);
            detail.setOrgid(vo.getOrgid());
            detail.setCampusid(vo.getCampusid());
            seq++;
        }
        serviceTaskScheduleDetailMapper.batchInsertServiceTaskScheduleDetail(detailList);
        log.info("[任务组] taskid={} è®¡åˆ’保存完成, scheduleId={}, detail æ¡æ•°={}",
                vo.getTaskid(), schedule.getId(), detailList.size());
        return schedule;
    }
    @Override
    public ServiceTaskScheduleVO getScheduleByTaskid(Long taskid) {
        ServiceTaskSchedule schedule = serviceTaskScheduleMapper.selectByTaskid(taskid);
        if (schedule == null) {
            return null;
        }
        ServiceTaskScheduleVO vo = new ServiceTaskScheduleVO();
        vo.setId(schedule.getId());
        vo.setTaskid(schedule.getTaskid());
        vo.setMaxLoopCount(schedule.getMaxLoopCount());
        vo.setCurrentLoopCount(schedule.getCurrentLoopCount());
        vo.setCurrentSeq(schedule.getCurrentSeq());
        vo.setNextSeq(schedule.getNextSeq());
        vo.setScheduleStyle(schedule.getScheduleStyle());
        vo.setScheduleTimeNum(schedule.getScheduleTimeNum());
        vo.setScheduleTimeUnit(schedule.getScheduleTimeUnit());
        vo.setNextExecuteTime(schedule.getNextExecuteTime());
        vo.setScheduleBenchmark(schedule.getScheduleBenchmark());
        vo.setScheduleBenchmarkCustomTime(schedule.getScheduleBenchmarkCustomTime());
        vo.setRemark(schedule.getRemark());
        vo.setOrgid(schedule.getOrgid());
        vo.setCampusid(schedule.getCampusid());
        vo.setDetailList(serviceTaskScheduleDetailMapper.selectByScheduleid(schedule.getId()));
        return vo;
    }
    @Override
    public ServiceTaskSchedule selectByTaskid(Long taskid) {
        return serviceTaskScheduleMapper.selectByTaskid(taskid);
    }
    @Override
    public List<ServiceTaskScheduleDetail> selectDetailByScheduleid(Long scheduleid) {
        return serviceTaskScheduleDetailMapper.selectByScheduleid(scheduleid);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeByTaskid(Long taskid) {
        int n = serviceTaskScheduleMapper.deleteByTaskid(taskid);
        serviceTaskScheduleDetailMapper.deleteByTaskid(taskid);
        return n;
    }
    @Override
    public int rollCycleTasks() {
        List<ServiceTaskSchedule> schedules = serviceTaskScheduleMapper.selectActiveCycleSchedules(ROLL_BATCH_LIMIT);
        if (CollectionUtils.isEmpty(schedules)) {
            return 0;
        }
        log.info("[任务组-滚动] æ‰«æåˆ° {} ä¸ªå¾…评估的循环计划", schedules.size());
        int rolled = 0;
        for (ServiceTaskSchedule schedule : schedules) {
            try {
                // é€šè¿‡ AOP ä»£ç†è°ƒç”¨ï¼Œç¡®ä¿ @Transactional ç”Ÿæ•ˆ
                if (SpringUtils.getAopProxy(this).rollOneSchedule(schedule)) {
                    rolled++;
                }
            } catch (Exception e) {
                // å•条失败不影响其它计划,记日志继续
                log.error("[任务组-滚动] scheduleId={} æ»šåŠ¨å¤±è´¥ï¼š{}", schedule.getId(), e.getMessage(), e);
            }
        }
        log.info("[任务组-滚动] æœ¬æ¬¡æŽ¨è¿› {} ä¸ªè®¡åˆ’", rolled);
        return rolled;
    }
    /**
     * å•个计划的滚动:本轮全部 finalize æ‰æŽ¨è¿›ï¼Œæ¯æ¬¡ä»…推进 1 è½®ã€‚
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean rollOneSchedule(ServiceTaskSchedule schedule) {
        Long scheduleId = schedule.getId();
        Long currentLoop = schedule.getCurrentLoopCount() == null ? 0L : schedule.getCurrentLoopCount();
        // ä¸Šé™æ ¡éªŒ
        Long max = schedule.getMaxLoopCount();
        if (max != null && max > 0 && currentLoop + 1 >= max) {
            // æ³¨æ„ï¼šå…ˆåˆ¤æ–­"再开一轮是否会超限"——currentLoop æ˜¯å·²å®Œæˆè½®æ¬¡ï¼Œä¸‹ä¸€è½®å· = currentLoop+1
            // å½“ currentLoop+1 == max æ—¶æ­£å¥½å¤„于最后一轮,不再产生新一轮
            if (currentLoop >= max) {
                log.info("[任务组-滚动] scheduleId={} å·²è¾¾ maxLoopCount={}, è·³è¿‡", scheduleId, max);
                return false;
            }
        }
        // æœ¬è½®æ˜¯å¦å®Œæˆ
        int active = serviceSubtaskMapper.countActiveByScheduleIdAndLoop(scheduleId, currentLoop);
        if (active > 0) {
            log.debug("[任务组-滚动] scheduleId={} loop={} ä»æœ‰ {} æ¡ subtask æœªç»“束, è·³è¿‡", scheduleId, currentLoop, active);
            return false;
        }
        // æ‹‰æœ¬è½® subtask åšå…‹éš†æ¨¡æ¿ï¼ˆå–去重后的患者集合)
        List<ServiceSubtask> currentLoopSubtasks =
                serviceSubtaskMapper.selectByScheduleIdAndLoop(scheduleId, currentLoop);
        if (CollectionUtils.isEmpty(currentLoopSubtasks)) {
            log.warn("[任务组-滚动] scheduleId={} loop={} æ‰¾ä¸åˆ°æœ¬è½® subtask, è·³è¿‡", scheduleId, currentLoop);
            return false;
        }
        // æ‹‰æœ¬è®¡åˆ’明细:seq -> detail,用来定位下一轮每条 subtask ç”¨å“ªä¸ªæ¨¡æ¿
        List<ServiceTaskScheduleDetail> detailList =
                serviceTaskScheduleDetailMapper.selectByScheduleid(scheduleId);
        if (CollectionUtils.isEmpty(detailList)) {
            log.warn("[任务组-滚动] scheduleId={} æ˜Žç»†ä¸ºç©º, è·³è¿‡", scheduleId);
            return false;
        }
        // æŽ¨è¿›æ­¥é•¿ï¼ˆè½®é—´éš”)
        int stepNum = schedule.getScheduleTimeNum() == null ? 0 : schedule.getScheduleTimeNum();
        int stepUnit = schedule.getScheduleTimeUnit() == null ? 1 : schedule.getScheduleTimeUnit();
        if (stepNum <= 0) {
            log.warn("[任务组-滚动] scheduleId={} scheduleTimeNum={} éžæ³•, è·³è¿‡", scheduleId, stepNum);
            return false;
        }
        long nextLoop = currentLoop + 1;
        // æŒ‰ patid+inhospid åŽ»é‡ï¼ˆåŒæ‚£è€…æœ¬è½®å¯èƒ½æœ‰ N æ¡ detail,模板任选其一即可——克隆时按 seq å¤ç”¨æ˜Žç»†ï¼‰
        // ä¸ºç®€åŒ–:直接按 schedule_seq å¤åˆ¶ N æ¡ï¼Œæ¯æ¡ç”¨å¯¹åº” detail。
        Date now = DateUtils.getNowDate();
        // æŠŠ detailList æŒ‰ seq ç´¢å¼•
        java.util.Map<Integer, ServiceTaskScheduleDetail> detailBySeq = new java.util.HashMap<>(detailList.size());
        for (ServiceTaskScheduleDetail d : detailList) {
            detailBySeq.put(d.getSeq(), d);
        }
        int produced = 0;
        for (ServiceSubtask src : currentLoopSubtasks) {
            ServiceTaskScheduleDetail detail = detailBySeq.get(src.getScheduleSeq());
            if (detail == null) {
                log.warn("[任务组-滚动] scheduleId={} æ‰¾ä¸åˆ° seq={} å¯¹åº”的明细, è·³è¿‡ subtask id={}",
                        scheduleId, src.getScheduleSeq(), src.getId());
                continue;
            }
            ServiceSubtask copy = cloneForNextLoop(src, detail, nextLoop, stepNum, stepUnit, now);
            serviceSubtaskMapper.insertServiceSubtask(copy);
            // å¤åˆ¶ preachform
            copyPreachform(src.getId(), copy);
            produced++;
        }
        // æŽ¨è¿› schedule çš„ current_loop_count / next_seq / next_execute_time
        ServiceTaskSchedule upd = new ServiceTaskSchedule();
        upd.setId(scheduleId);
        upd.setCurrentLoopCount(nextLoop);
        upd.setCurrentSeq(1);
        upd.setNextSeq(detailList.size() > 1 ? 2 : 1);
        upd.setNextExecuteTime(advance(now, stepNum, stepUnit));
        upd.setUpdateTime(now);
        serviceTaskScheduleMapper.updateServiceTaskSchedule(upd);
        log.info("[任务组-滚动] scheduleId={} æŽ¨è¿›åˆ°ç¬¬ {} è½®, æ–°å»º {} æ¡ subtask", scheduleId, nextLoop, produced);
        return true;
    }
    /**
     * å…‹éš† subtask åˆ°ä¸‹ä¸€è½®ï¼šæ¸…主键、清回签字段、推进 visit_time、设置 loop_count。
     */
    private ServiceSubtask cloneForNextLoop(ServiceSubtask src, ServiceTaskScheduleDetail detail,
                                            long nextLoop, int stepNum, int stepUnit, Date now) {
        ServiceSubtask copy = JSON.parseObject(JSON.toJSONString(src), ServiceSubtask.class);
        copy.setId(null);
        copy.setSenduuid(null);
        copy.setResult(null);
        copy.setFinishtime(null);
        copy.setExrecallcount(null);
        copy.setCurrentPreachform(null);
        copy.setSendstate(2L);
        copy.setLoopCount(nextLoop);
        copy.setScheduleDetailId(detail.getId());
        // æ¨¡æ¿ï¼šdetail ä¼˜å…ˆ
        if (detail.getTemplateid() != null) {
            copy.setTemplateid(detail.getTemplateid());
            copy.setTemplatename(detail.getTemplatename());
        }
        if (detail.getLibtemplateid() != null) {
            copy.setLibtemplateid(detail.getLibtemplateid());
        }
        Date base = src.getVisitTime() != null ? src.getVisitTime() : now;
        Date nextVisit = advance(base, stepNum, stepUnit);
        copy.setVisitTime(nextVisit);
        copy.setSenddate(nextVisit);
        copy.setLongSendTime(nextVisit);
        copy.setCreateTime(now);
        copy.setUpdateTime(now);
        return copy;
    }
    /**
     * å¤åˆ¶æº subtask çš„发送方式行到新 subtask。
     */
    private void copyPreachform(Long srcSubId, ServiceSubtask newSubtask) {
        ServiceSubtaskPreachform q = new ServiceSubtaskPreachform();
        q.setSubid(srcSubId);
        q.setTaskid(newSubtask.getTaskid());
        List<ServiceSubtaskPreachform> list = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(q);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        for (ServiceSubtaskPreachform src : list) {
            ServiceSubtaskPreachform pf = new ServiceSubtaskPreachform();
            pf.setSort(src.getSort());
            pf.setPreachform(src.getPreachform());
            pf.setCompensateTime(src.getCompensateTime());
            pf.setTaskid(newSubtask.getTaskid());
            pf.setSubid(newSubtask.getId());
            pf.setSendstate("1");
            pf.setOrgid(newSubtask.getOrgid());
            pf.setCreateTime(new Date());
            serviceSubtaskPreachformMapper.insertServiceSubtaskPreachform(pf);
        }
    }
    /**
     * æŒ‰ schedule_time_unit æŽ¨è¿›æ—¶é—´ï¼š1-天 2-周 3-月 4-å¹´
     */
    private Date advance(Date base, int num, int unit) {
        Calendar c = Calendar.getInstance();
        c.setTime(base);
        switch (unit) {
            case 2:
                c.add(Calendar.WEEK_OF_YEAR, num);
                break;
            case 3:
                c.add(Calendar.MONTH, num);
                break;
            case 4:
                c.add(Calendar.YEAR, num);
                break;
            case 1:
            default:
                c.add(Calendar.DAY_OF_MONTH, num);
        }
        return c.getTime();
    }
}
smartor/src/main/resources/mapper/smartor/PatMedInhospMapper.xml
@@ -52,6 +52,7 @@
        <result property="inDeptcheckFlag" column="in_deptcheck_flag"/>
        <result property="wardcheckFlag" column="wardcheck_flag"/>
        <result property="diagcheckFlag" column="diagcheck_flag"/>
        <result property="scheduleCheckFlag" column="schedulecheck_flag"/>
        <result property="age" column="age"/>
        <result property="sex" column="sex"/>
        <result property="telcode" column="telcode"/>
@@ -76,10 +77,16 @@
        <result property="managementDoctorCode" column="management_doctor_code"/>
        <result property="campusid" column="campusid"/>
        <result property="inhospMydFlag" column="inhosp_myd_flag"/>
        <result property="encounterSourceId" column="encounter_source_id"/>
        <result property="importanceFlagCode" column="importance_flag_code"/>
        <result property="emergencyLevelCode" column="emergency_level_code"/>
    </resultMap>
    <sql id="selectPatMedInhospVo">
        select inhospid,
               encounter_source_id,
               importance_flag_code,
               emergency_level_code,
               patname,
               inhosp_myd_flag,
               campusid,
@@ -105,6 +112,7 @@
               in_deptcheck_flag,
               in_wardcheck_flag,
               diagcheck_flag,
               schedulecheck_flag,
               inhospstate,
               patno,
               long_task_reason,
@@ -166,6 +174,7 @@
        b.in_deptcheck_flag,
        b.in_wardcheck_flag,
        b.diagcheck_flag,
        b.schedulecheck_flag,
        b.inhospstate,
        b.patno,
        b.inhospno,
@@ -216,6 +225,9 @@
        b.fuadvice,
        b.fuspecialadvice,
        b.inhosp_myd_flag,
        b.encounter_source_id,
        b.importance_flag_code,
        b.emergency_level_code,
        a.idcardno
        FROM
        pat_med_inhosp b
@@ -257,10 +269,14 @@
        <if test="nurseId != null ">and b.nurse_id = #{nurseId}</if>
        <if test="nurseName != null and nurseName != ''">and b.nurse_name = #{nurseName}</if>
        <if test="deptcheckFlag != null ">and b.deptcheck_flag = #{deptcheckFlag}</if>
        <if test="scheduleCheckFlag != null ">and b.schedulecheck_flag = #{scheduleCheckFlag}</if>
        <if test="wardcheckFlag != null ">and b.wardcheck_flag = #{wardcheckFlag}</if>
        <if test="inDeptcheckFlag != null ">and b.in_deptcheck_flag = #{inDeptcheckFlag}</if>
        <if test="inWardcheckFlag != null ">and b.in_wardcheck_flag = #{inWardcheckFlag}</if>
        <if test="diagcheckFlag != null ">and b.diagcheck_flag = #{diagcheckFlag}</if>
        <if test="encounterSourceId != null ">and b.encounter_source_id = #{encounterSourceId}</if>
        <if test="importanceFlagCode != null ">and b.importance_flag_code = #{importanceFlagCode}</if>
        <if test="emergencyLevelCode != null ">and b.emergency_level_code = #{emergencyLevelCode}</if>
        <if test="cry != null and cry == 0 ">and b.endtime is null</if>
        <if test="cry != null and cry == 1 ">and b.inhospstate=1</if>
        <if test="cry != null and cry == 2 ">and b.inhospstate=2</if>
@@ -316,6 +332,13 @@
                #{deptcode}
            </foreach>
        </if>
        <if test="icd10codeList != null and icd10codeList.size()>0">
            AND b.leaveicd10code IN
            <foreach collection="icd10codeList" item="icd10code" open="(" separator=","
                     close=")">
                #{icd10code}
            </foreach>
        </if>
        GROUP BY
        b.inhospid,
        a.age,
@@ -342,6 +365,9 @@
        select
        b.inhospid,
        b.nurse_id,
        b.encounter_source_id,
        b.importance_flag_code,
        b.emergency_level_code,
        b.nurse_name,
        b.patname,
        b.management_doctor,
@@ -354,6 +380,7 @@
        b.in_deptcheck_flag,
        b.in_wardcheck_flag,
        b.diagcheck_flag,
        b.schedulecheck_flag,
        b.inhospstate,
        b.patno,
        b.inhospno,
@@ -410,6 +437,15 @@
        <if test="orgid != null and orgid != ''">
            and orgid = #{orgid}
        </if>
        <if test="encounterSourceId != null and encounterSourceId != ''">
            and b.encounter_source_id = #{encounterSourceId}
        </if>
        <if test="importanceFlagCode != null and importanceFlagCode != ''">
            and b.importance_flag_code = #{importanceFlagCode}
        </if>
        <if test="emergencyLevelCode != null and emergencyLevelCode != ''">
            and b.emergency_level_code = #{emergencyLevelCode}
        </if>
        <if test="serialnum != null and serialnum != ''">
            and b.serialnum = #{serialnum}
        </if>
@@ -421,6 +457,9 @@
        select CONCAT( a.age, a.age_unit ) AS age,
        a.telcode as telcode,
        b.inhospid,
        b.encounter_source_id,
        b.importance_flag_code,
        b.emergency_level_code,
        b.management_doctor,
        b.management_doctor_code,
        b.patname,
@@ -494,6 +533,15 @@
        and a.id = b.patid
        AND a.idcardno != ''
        <if test="inhospMydFlag != null ">and b.inhosp_myd_flag = #{inhospMydFlag}</if>
        <if test="encounterSourceId != null and encounterSourceId != ''">
            and b.encounter_source_id = #{encounterSourceId}
        </if>
        <if test="importanceFlagCode != null and importanceFlagCode != ''">
            and b.importance_flag_code = #{importanceFlagCode}
        </if>
        <if test="emergencyLevelCode != null and emergencyLevelCode != ''">
            and b.emergency_level_code = #{emergencyLevelCode}
        </if>
        <if test="orgid != null and orgid != ''">
            and a.orgid = #{orgid}
        </if>
@@ -515,6 +563,7 @@
        <if test="campusid != null ">and b.campusid = #{campusid}</if>
        <if test="diagcheckFlag != null ">and b.diagcheck_flag = #{diagcheckFlag}</if>
        <if test="deptcheckFlag != null ">and b.deptcheck_flag = #{deptcheckFlag}</if>
        <if test="scheduleCheckFlag != null ">and b.schedulecheck_flag = #{scheduleCheckFlag}</if>
        <if test="wardcheckFlag != null ">and b.wardcheck_flag = #{wardcheckFlag}</if>
        <if test="inDeptcheckFlag != null ">and b.in_deptcheck_flag = #{inDeptcheckFlag}</if>
        <if test="inWardcheckFlag != null ">and b.in_wardcheck_flag = #{inWardcheckFlag}</if>
@@ -626,6 +675,9 @@
        <if test="managementDoctor != null ">and management_doctor = #{managementDoctor}</if>
        <if test="managementDoctorCode != null ">and management_doctor_code = #{managementDoctorCode}</if>
        <if test="campusid != null ">and campusid = #{campusid}</if>
        <if test="importanceFlagCode != null ">and importance_flag_code = #{importanceFlagCode}</if>
        <if test="emergencyLevelCode != null ">and emergency_level_code = #{emergencyLevelCode}</if>
        <if test="encounterSourceId != null ">and encounter_source_id = #{encounterSourceId}</if>
    </select>
@@ -699,6 +751,9 @@
            <if test="managementDoctorCode != null ">management_doctor_code,</if>
            <if test="campusid != null ">campusid,</if>
            <if test="inhospMydFlag != null ">inhosp_myd_flag,</if>
            <if test="importanceFlagCode != null ">importance_flag_code,</if>
            <if test="emergencyLevelCode != null ">emergency_level_code,</if>
            <if test="encounterSourceId != null ">encounter_source_id,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="serialnum != null">#{serialnum},</if>
@@ -766,7 +821,9 @@
            <if test="managementDoctor != null ">#{managementDoctor},</if>
            <if test="managementDoctorCode != null ">#{managementDoctorCode},</if>
            <if test="campusid != null ">#{campusid},</if>
            <if test="inhospMydFlag != null ">#{inhospMydFlag},</if>
            <if test="importanceFlagCode != null ">#{importanceFlagCode},</if>
            <if test="emergencyLevelCode != null ">#{emergencyLevelCode},</if>
            <if test="encounterSourceId != null ">#{encounterSourceId},</if>
        </trim>
    </insert>
@@ -785,7 +842,7 @@
        nurse_id, nurse_name, out_way_id, out_way_name, guid,
        operator, operator_id, inhospno, remark,
        fuflag, fudate, fuperiod, futypecode, futypedesc, fuadvice, fuspecialadvice, management_doctor,
        management_doctor_doctor,campusid, inhosp_myd_flag
        management_doctor_doctor,campusid, inhosp_myd_flag, importance_flag_code, emergency_level_code, encounter_source_id
        )
        values
        <foreach collection="list" item="item" separator=",">
@@ -807,7 +864,8 @@
            #{item.nurseId}, #{item.nurseName}, #{item.outWayId}, #{item.outWayName}, #{item.guid},
            #{item.operator}, #{item.operatorId}, #{item.inhospno}, #{item.remark},
            #{item.fuflag}, #{item.fudate}, #{item.fuperiod}, #{item.futypecode}, #{item.futypedesc}, #{item.fuadvice},
            #{item.fuspecialadvice}, #{item.managementDoctor}, #{item.managementDoctorCode}, #{item.campusid}, #{item.inhospMydFlag}
            #{item.fuspecialadvice}, #{item.managementDoctor}, #{item.managementDoctorCode}, #{item.campusid}, #{item.inhospMydFlag},
            #{item.importanceFlagCode}, #{item.emergencyLevelCode}, #{item.encounterSourceId}
            )
        </foreach>
    </insert>
@@ -857,6 +915,7 @@
            <if test="patno != null">patno = #{patno},</if>
            <if test="inhospstate != null">inhospstate = #{inhospstate},</if>
            <if test="deptcheckFlag != null">deptcheck_flag = #{deptcheckFlag},</if>
            <if test="scheduleCheckFlag != null">schedulecheck_flag = #{scheduleCheckFlag},</if>
            <if test="wardcheckFlag != null">wardcheck_flag = #{wardcheckFlag},</if>
            <if test="inDeptcheckFlag != null">in_deptcheck_flag = #{inDeptcheckFlag},</if>
            <if test="inWardcheckFlag != null">in_wardcheck_flag = #{inWardcheckFlag},</if>
@@ -881,6 +940,9 @@
            <if test="managementDoctorCode != null ">management_doctor_code = #{managementDoctorCode},</if>
            <if test="campusid != null ">campusid = #{campusid},</if>
            <if test="inhospMydFlag != null ">inhosp_myd_flag = #{inhospMydFlag},</if>
            <if test="importanceFlagCode != null ">importance_flag_code = #{importanceFlagCode},</if>
            <if test="emergencyLevelCode != null ">emergency_level_code = #{emergencyLevelCode},</if>
            <if test="encounterSourceId != null ">encounter_source_id = #{encounterSourceId},</if>
        </trim>
        where inhospid = #{inhospid}
    </update>
smartor/src/main/resources/mapper/smartor/PatMedOperationItemMapper.xml
@@ -486,6 +486,27 @@
        <if test="patid != null">
            and pmo.patid = #{patid}
        </if>
        <if test="deptCodes != null and deptCodes.size()>0">
            AND pmo.deptcode IN
            <foreach collection="deptCodes" item="deptcode" open="(" separator=","
                     close=")">
                #{deptcode}
            </foreach>
        </if>
        <if test="wardCodes != null and wardCodes.size()>0">
            AND pmo.hospitaldistrictcode IN
            <foreach collection="wardCodes" item="wardCode" open="(" separator=","
                     close=")">
                #{wardCode}
            </foreach>
        </if>
        <if test="opLevelCodes != null and opLevelCodes.size()>0">
            AND pmoi.oplevelcode IN
            <foreach collection="opLevelCodes" item="levelCode" open="(" separator=","
                     close=")">
                #{levelCode}
            </foreach>
        </if>
    </select>
</mapper>
smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
@@ -94,6 +94,10 @@
        <result property="continueCount" column="continue_count"/>
        <result property="continueTimeNext" column="continue_time_next"/>
        <result property="operationItemId" column="operation_item_id"/>
        <result property="scheduleId" column="schedule_id"/>
        <result property="scheduleDetailId" column="schedule_detail_id"/>
        <result property="scheduleSeq" column="schedule_seq"/>
        <result property="loopCount" column="loop_count"/>
    </resultMap>
    <resultMap type="com.smartor.domain.ServiceSubtaskCount" id="ServiceSubtaskResult2">
@@ -238,6 +242,10 @@
               continue_count,
               continue_time_next,
               operation_item_id,
               schedule_id,
               schedule_detail_id,
               schedule_seq,
               loop_count,
               task_situation
        from service_subtask
    </sql>
@@ -961,6 +969,10 @@
            <if test="continueTimeNext != null ">continue_time_next,</if>
            <if test="continueContent != null ">continue_content,</if>
            <if test="operationItemId != null ">operation_item_id,</if>
            <if test="scheduleId != null ">schedule_id,</if>
            <if test="scheduleDetailId != null ">schedule_detail_id,</if>
            <if test="scheduleSeq != null ">schedule_seq,</if>
            <if test="loopCount != null ">loop_count,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="sendname != null">#{sendname},</if>
@@ -1053,6 +1065,10 @@
            <if test="continueTimeNext != null ">#{continueTimeNext,jdbcType=TIMESTAMP},</if>
            <if test="continueContent != null ">#{continueContent},</if>
            <if test="operationItemId != null ">#{operationItemId},</if>
            <if test="scheduleId != null ">#{scheduleId},</if>
            <if test="scheduleDetailId != null ">#{scheduleDetailId},</if>
            <if test="scheduleSeq != null ">#{scheduleSeq},</if>
            <if test="loopCount != null ">#{loopCount},</if>
        </trim>
    </insert>
@@ -1150,6 +1166,10 @@
            <if test="continueTimeNext != null ">continue_time_next = #{continueTimeNext,jdbcType=TIMESTAMP},</if>
            <if test="continueContent != null ">continue_content = #{continueContent},</if>
            <if test="operationItemId != null ">operation_item_id = #{operationItemId},</if>
            <if test="scheduleId != null ">schedule_id = #{scheduleId},</if>
            <if test="scheduleDetailId != null ">schedule_detail_id = #{scheduleDetailId},</if>
            <if test="scheduleSeq != null ">schedule_seq = #{scheduleSeq},</if>
            <if test="loopCount != null ">loop_count = #{loopCount},</if>
        </trim>
        where id = #{id}
    </update>
@@ -1484,6 +1504,8 @@
        orgid,
        drcode,
        drname,
        management_doctor_code,
        management_doctor,
        leavehospitaldistrictcode,
        leavehospitaldistrictname,
        deptcode,
@@ -2886,8 +2908,8 @@
        <if test="sendstate != null">
            AND sendstate = #{sendstate}
        </if>
        <if test="isFinished != null and isFinished == '1'">
            AND finishtime is not null
        <if test="isFinished != null and isFinished != ''">
            and finishtime is not null
        </if>
        <if test="starttime != null">AND starttime &gt;= #{starttime}</if>
        <if test="endtime != null">AND endtime &lt;= #{endtime}</if>
@@ -2916,7 +2938,26 @@
        </choose>
    </select>
    <select id="gethelibraryCountHyperlink" parameterType="com.smartor.domain.ServiceSubtaskCountReq"
    <!-- ä»»åŠ¡ç»„ï¼ˆappltype=5)滚动调度用:本轮仍在跑的数量 -->
    <select id="countActiveByScheduleIdAndLoop" resultType="int">
        select count(1)
        from service_subtask
        where schedule_id = #{scheduleId}
          and loop_count = #{loopCount}
          and (del_flag is null or del_flag = '0')
          and sendstate in (1, 2, 3)
    </select>
    <!-- ä»»åŠ¡ç»„ï¼ˆappltype=5)滚动调度用:拉本轮全量 subtask,作为下一轮的克隆模板 -->
    <select id="selectByScheduleIdAndLoop" resultMap="ServiceSubtaskResult">
        <include refid="selectServiceSubtaskVo"/>
        where schedule_id = #{scheduleId}
          and loop_count = #{loopCount}
          and (del_flag is null or del_flag = '0')
        order by schedule_seq asc, id asc
    </select>
    <select id="gethelibraryCountHyperlink" parameterType="com.smartor.domain.VO.HeLibraryCountVO"
            resultMap="ServiceSubtaskResult">
        select id,
        visit_count,
@@ -2966,8 +3007,8 @@
        <if test="sendstate != null">
            AND sendstate = #{sendstate}
        </if>
        <if test="isFinished != null and isFinished == '1'">
            AND finishtime is not null
        <if test="isFinished != null and isFinished != ''">
            and finishtime is not null
        </if>
        <if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
            AND leavehospitaldistrictcode IN
smartor/src/main/resources/mapper/smartor/ServiceTaskScheduleDetailMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.smartor.mapper.ServiceTaskScheduleDetailMapper">
    <resultMap type="com.smartor.domain.ServiceTaskScheduleDetail" id="ServiceTaskScheduleDetailResult">
        <id property="id" column="id"/>
        <result property="taskid" column="taskid"/>
        <result property="scheduleid" column="scheduleid"/>
        <result property="seq" column="seq"/>
        <result property="dayOffset" column="day_offset"/>
        <result property="templateid" column="templateid"/>
        <result property="libtemplateid" column="libtemplateid"/>
        <result property="templatename" column="templatename"/>
        <result property="content" column="content"/>
        <result property="nextExecuteTime" column="next_execute_time"/>
        <result property="remark" column="remark"/>
        <result property="delFlag" column="del_flag"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time"/>
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
        <result property="orgid" column="orgid"/>
        <result property="campusid" column="campusid"/>
    </resultMap>
    <sql id="selectServiceTaskScheduleDetailVo">
        select id,
               taskid,
               scheduleid,
               seq,
               day_offset,
               templateid,
               libtemplateid,
               templatename,
               content,
               next_execute_time,
               remark,
               del_flag,
               create_by,
               create_time,
               update_by,
               update_time,
               orgid,
               campusid
        from service_task_schedule_detail
    </sql>
    <select id="selectServiceTaskScheduleDetailById" parameterType="Long"
            resultMap="ServiceTaskScheduleDetailResult">
        <include refid="selectServiceTaskScheduleDetailVo"/>
        where id = #{id} and del_flag = '0'
    </select>
    <select id="selectServiceTaskScheduleDetailList"
            parameterType="com.smartor.domain.ServiceTaskScheduleDetail"
            resultMap="ServiceTaskScheduleDetailResult">
        <include refid="selectServiceTaskScheduleDetailVo"/>
        where del_flag = '0'
        <if test="taskid != null">and taskid = #{taskid}</if>
        <if test="scheduleid != null">and scheduleid = #{scheduleid}</if>
        <if test="seq != null">and seq = #{seq}</if>
        <if test="templateid != null">and templateid = #{templateid}</if>
        order by seq asc
    </select>
    <select id="selectByScheduleid" resultMap="ServiceTaskScheduleDetailResult">
        <include refid="selectServiceTaskScheduleDetailVo"/>
        where scheduleid = #{scheduleid} and del_flag = '0'
        order by seq asc
    </select>
    <select id="selectByTaskid" resultMap="ServiceTaskScheduleDetailResult">
        <include refid="selectServiceTaskScheduleDetailVo"/>
        where taskid = #{taskid} and del_flag = '0'
        order by seq asc
    </select>
    <insert id="insertServiceTaskScheduleDetail" parameterType="com.smartor.domain.ServiceTaskScheduleDetail"
            useGeneratedKeys="true" keyProperty="id">
        insert into service_task_schedule_detail
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="taskid != null">taskid,</if>
            <if test="scheduleid != null">scheduleid,</if>
            <if test="seq != null">seq,</if>
            <if test="dayOffset != null">day_offset,</if>
            <if test="templateid != null">templateid,</if>
            <if test="libtemplateid != null">libtemplateid,</if>
            <if test="templatename != null">templatename,</if>
            <if test="content != null">content,</if>
            <if test="nextExecuteTime != null">next_execute_time,</if>
            <if test="remark != null">remark,</if>
            <if test="delFlag != null">del_flag,</if>
            <if test="createBy != null">create_by,</if>
            <if test="createTime != null">create_time,</if>
            <if test="updateBy != null">update_by,</if>
            <if test="updateTime != null">update_time,</if>
            <if test="orgid != null">orgid,</if>
            <if test="campusid != null">campusid,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="taskid != null">#{taskid},</if>
            <if test="scheduleid != null">#{scheduleid},</if>
            <if test="seq != null">#{seq},</if>
            <if test="dayOffset != null">#{dayOffset},</if>
            <if test="templateid != null">#{templateid},</if>
            <if test="libtemplateid != null">#{libtemplateid},</if>
            <if test="templatename != null">#{templatename},</if>
            <if test="content != null">#{content},</if>
            <if test="nextExecuteTime != null">#{nextExecuteTime},</if>
            <if test="remark != null">#{remark},</if>
            <if test="delFlag != null">#{delFlag},</if>
            <if test="createBy != null">#{createBy},</if>
            <if test="createTime != null">#{createTime},</if>
            <if test="updateBy != null">#{updateBy},</if>
            <if test="updateTime != null">#{updateTime},</if>
            <if test="orgid != null">#{orgid},</if>
            <if test="campusid != null">#{campusid},</if>
        </trim>
    </insert>
    <insert id="batchInsertServiceTaskScheduleDetail" useGeneratedKeys="true" keyProperty="id">
        insert into service_task_schedule_detail
        (taskid, scheduleid, seq, day_offset, templateid, libtemplateid, templatename, content,
         next_execute_time, remark, del_flag, create_by, create_time, update_by, update_time, orgid, campusid)
        values
        <foreach collection="list" item="item" separator=",">
            (#{item.taskid}, #{item.scheduleid}, #{item.seq}, #{item.dayOffset},
             #{item.templateid}, #{item.libtemplateid}, #{item.templatename}, #{item.content},
             #{item.nextExecuteTime}, #{item.remark},
             <choose>
                 <when test="item.delFlag != null">#{item.delFlag}</when>
                 <otherwise>'0'</otherwise>
             </choose>,
             #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime},
             #{item.orgid}, #{item.campusid})
        </foreach>
    </insert>
    <update id="updateServiceTaskScheduleDetail" parameterType="com.smartor.domain.ServiceTaskScheduleDetail">
        update service_task_schedule_detail
        <trim prefix="SET" suffixOverrides=",">
            <if test="taskid != null">taskid = #{taskid},</if>
            <if test="scheduleid != null">scheduleid = #{scheduleid},</if>
            <if test="seq != null">seq = #{seq},</if>
            <if test="dayOffset != null">day_offset = #{dayOffset},</if>
            <if test="templateid != null">templateid = #{templateid},</if>
            <if test="libtemplateid != null">libtemplateid = #{libtemplateid},</if>
            <if test="templatename != null">templatename = #{templatename},</if>
            <if test="content != null">content = #{content},</if>
            <if test="nextExecuteTime != null">next_execute_time = #{nextExecuteTime},</if>
            <if test="remark != null">remark = #{remark},</if>
            <if test="delFlag != null">del_flag = #{delFlag},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
            <if test="orgid != null">orgid = #{orgid},</if>
            <if test="campusid != null">campusid = #{campusid},</if>
        </trim>
        where id = #{id}
    </update>
    <update id="deleteServiceTaskScheduleDetailById" parameterType="Long">
        update service_task_schedule_detail
        set del_flag = '1',
            update_time = now()
        where id = #{id}
    </update>
    <update id="deleteByScheduleid">
        update service_task_schedule_detail
        set del_flag = '1',
            update_time = now()
        where scheduleid = #{scheduleid}
          and del_flag = '0'
    </update>
    <update id="deleteByTaskid">
        update service_task_schedule_detail
        set del_flag = '1',
            update_time = now()
        where taskid = #{taskid}
          and del_flag = '0'
    </update>
</mapper>
smartor/src/main/resources/mapper/smartor/ServiceTaskScheduleMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.smartor.mapper.ServiceTaskScheduleMapper">
    <resultMap type="com.smartor.domain.ServiceTaskSchedule" id="ServiceTaskScheduleResult">
        <id property="id" column="id"/>
        <result property="taskid" column="taskid"/>
        <result property="maxLoopCount" column="max_loop_count"/>
        <result property="currentLoopCount" column="current_loop_count"/>
        <result property="currentSeq" column="current_seq"/>
        <result property="nextSeq" column="next_seq"/>
        <result property="scheduleStyle" column="schedule_style"/>
        <result property="scheduleTimeNum" column="schedule_time_num"/>
        <result property="scheduleTimeUnit" column="schedule_time_unit"/>
        <result property="nextExecuteTime" column="next_execute_time"/>
        <result property="scheduleBenchmark" column="schedule_benchmark"/>
        <result property="scheduleBenchmarkCustomTime" column="schedule_benchmark_custom_time"/>
        <result property="deptCodes" column="dept_codes"/>
        <result property="wardCodes" column="ward_codes"/>
        <result property="icd10Codes" column="icd10_codes"/>
        <result property="oplevelCodes" column="oplevel_codes"/>
        <result property="remark" column="remark"/>
        <result property="delFlag" column="del_flag"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time"/>
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
        <result property="orgid" column="orgid"/>
        <result property="campusid" column="campusid"/>
    </resultMap>
    <sql id="selectServiceTaskScheduleVo">
        select id,
               taskid,
               max_loop_count,
               current_loop_count,
               current_seq,
               next_seq,
               schedule_style,
               schedule_time_num,
               schedule_time_unit,
               next_execute_time,
               schedule_benchmark,
               schedule_benchmark_custom_time,
               dept_codes,
               ward_codes,
               icd10_codes,
               oplevel_codes,
               remark,
               del_flag,
               create_by,
               create_time,
               update_by,
               update_time,
               orgid,
               campusid
        from service_task_schedule
    </sql>
    <select id="selectServiceTaskScheduleById" parameterType="Long" resultMap="ServiceTaskScheduleResult">
        <include refid="selectServiceTaskScheduleVo"/>
        where id = #{id} and del_flag = '0'
    </select>
    <select id="selectByTaskid" resultMap="ServiceTaskScheduleResult">
        <include refid="selectServiceTaskScheduleVo"/>
        where taskid = #{taskid} and del_flag = '0'
        order by id desc
        limit 1
    </select>
    <select id="selectServiceTaskScheduleList" parameterType="com.smartor.domain.ServiceTaskSchedule"
            resultMap="ServiceTaskScheduleResult">
        <include refid="selectServiceTaskScheduleVo"/>
        where del_flag = '0'
        <if test="taskid != null">and taskid = #{taskid}</if>
        <if test="scheduleStyle != null">and schedule_style = #{scheduleStyle}</if>
        <if test="deptCode != null">and INSTR(dept_codes,  #{deptCode}) > 0</if>
        <if test="wardCode != null">and INSTR(ward_codes,  #{wardCode}) > 0</if>
        <if test="icd10Code != null">and INSTR(icd10_codes,  #{icd10Code}) > 0</if>
        <if test="oplevelCode != null">and INSTR(oplevel_codes,  #{oplevelCode}) > 0</if>
        <if test="orgid != null and orgid != ''">and orgid = #{orgid}</if>
        <if test="campusid != null and campusid != ''">and campusid = #{campusid}</if>
        order by id desc
    </select>
    <insert id="insertServiceTaskSchedule" parameterType="com.smartor.domain.ServiceTaskSchedule"
            useGeneratedKeys="true" keyProperty="id">
        insert into service_task_schedule
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="taskid != null">taskid,</if>
            <if test="maxLoopCount != null">max_loop_count,</if>
            <if test="currentLoopCount != null">current_loop_count,</if>
            <if test="currentSeq != null">current_seq,</if>
            <if test="nextSeq != null">next_seq,</if>
            <if test="scheduleStyle != null">schedule_style,</if>
            <if test="scheduleTimeNum != null">schedule_time_num,</if>
            <if test="scheduleTimeUnit != null">schedule_time_unit,</if>
            <if test="nextExecuteTime != null">next_execute_time,</if>
            <if test="scheduleBenchmark != null">schedule_benchmark,</if>
            <if test="scheduleBenchmarkCustomTime != null">schedule_benchmark_custom_time,</if>
            <if test="deptCodes != null">dept_codes,</if>
            <if test="wardCodes != null">ward_codes,</if>
            <if test="icd10Codes != null">icd10_codes,</if>
            <if test="oplevelCodes != null">oplevel_codes,</if>
            <if test="remark != null">remark,</if>
            <if test="delFlag != null">del_flag,</if>
            <if test="createBy != null">create_by,</if>
            <if test="createTime != null">create_time,</if>
            <if test="updateBy != null">update_by,</if>
            <if test="updateTime != null">update_time,</if>
            <if test="orgid != null">orgid,</if>
            <if test="campusid != null">campusid,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="taskid != null">#{taskid},</if>
            <if test="maxLoopCount != null">#{maxLoopCount},</if>
            <if test="currentLoopCount != null">#{currentLoopCount},</if>
            <if test="currentSeq != null">#{currentSeq},</if>
            <if test="nextSeq != null">#{nextSeq},</if>
            <if test="scheduleStyle != null">#{scheduleStyle},</if>
            <if test="scheduleTimeNum != null">#{scheduleTimeNum},</if>
            <if test="scheduleTimeUnit != null">#{scheduleTimeUnit},</if>
            <if test="nextExecuteTime != null">#{nextExecuteTime},</if>
            <if test="scheduleBenchmark != null">#{scheduleBenchmark},</if>
            <if test="scheduleBenchmarkCustomTime != null">#{scheduleBenchmarkCustomTime},</if>
            <if test="deptCodes != null">#{deptCodes},</if>
            <if test="wardCodes != null">#{wardCodes},</if>
            <if test="icd10Codes != null">#{icd10Codes},</if>
            <if test="oplevelCodes != null">#{oplevelCodes},</if>
            <if test="remark != null">#{remark},</if>
            <if test="delFlag != null">#{delFlag},</if>
            <if test="createBy != null">#{createBy},</if>
            <if test="createTime != null">#{createTime},</if>
            <if test="updateBy != null">#{updateBy},</if>
            <if test="updateTime != null">#{updateTime},</if>
            <if test="orgid != null">#{orgid},</if>
            <if test="campusid != null">#{campusid},</if>
        </trim>
    </insert>
    <update id="updateServiceTaskSchedule" parameterType="com.smartor.domain.ServiceTaskSchedule">
        update service_task_schedule
        <trim prefix="SET" suffixOverrides=",">
            <if test="taskid != null">taskid = #{taskid},</if>
            <if test="maxLoopCount != null">max_loop_count = #{maxLoopCount},</if>
            <if test="currentLoopCount != null">current_loop_count = #{currentLoopCount},</if>
            <if test="currentSeq != null">current_seq = #{currentSeq},</if>
            <if test="nextSeq != null">next_seq = #{nextSeq},</if>
            <if test="scheduleStyle != null">schedule_style = #{scheduleStyle},</if>
            <if test="scheduleTimeNum != null">schedule_time_num = #{scheduleTimeNum},</if>
            <if test="scheduleTimeUnit != null">schedule_time_unit = #{scheduleTimeUnit},</if>
            <if test="nextExecuteTime != null">next_execute_time = #{nextExecuteTime},</if>
            <if test="scheduleBenchmark != null">schedule_benchmark = #{scheduleBenchmark},</if>
            <if test="scheduleBenchmarkCustomTime != null">
                schedule_benchmark_custom_time = #{scheduleBenchmarkCustomTime},
            </if>
            <if test="deptCodes != null">dept_codes = #{deptCodes},</if>
            <if test="wardCodes != null">ward_codes = #{wardCodes},</if>
            <if test="icd10Codes != null">icd10_codes = #{icd10Codes},</if>
            <if test="oplevelCodes != null">oplevel_codes = #{oplevelCodes},</if>
            <if test="remark != null">remark = #{remark},</if>
            <if test="delFlag != null">del_flag = #{delFlag},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
            <if test="orgid != null">orgid = #{orgid},</if>
            <if test="campusid != null">campusid = #{campusid},</if>
        </trim>
        where id = #{id}
    </update>
    <update id="deleteServiceTaskScheduleById" parameterType="Long">
        update service_task_schedule
        set del_flag = '1',
            update_time = now()
        where id = #{id}
    </update>
    <update id="deleteByTaskid">
        update service_task_schedule
        set del_flag = '1',
            update_time = now()
        where taskid = #{taskid}
          and del_flag = '0'
    </update>
    <select id="selectActiveCycleSchedules" resultMap="ServiceTaskScheduleResult">
        <include refid="selectServiceTaskScheduleVo"/>
        where del_flag = '0'
          and schedule_style = 1
          and (max_loop_count is null
                or max_loop_count = 0
                or current_loop_count &lt; max_loop_count)
        order by id asc
        limit #{limit}
    </select>
</mapper>