已修改36个文件
已添加6个文件
1339 ■■■■■ 文件已修改
ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/tools/DingTalkController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/DingAsyncSendMsgReq.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/DingAsyncSendMsgResp.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/DingTokenResp.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/core/service/IDingTalkService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/dx/MessageSend.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DingTalkUtils.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/DTO/QuestionCountKsOrBqDTO.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/IvrLibaTemplateScript.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/IvrLibaTemplateScriptVO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/IvrTaskTemplateScript.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/IvrTaskTemplateScriptVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/ServiceSubtaskDetailRatioExport.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyLibTemplateScript.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyLibTemplateScriptVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyLibTemplateScriptWjx.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyTaskScript.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyTaskScriptoption.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyTaskTemplateScript.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyTaskTemplateScriptVO.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/SvyTopic.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/VO/QuestionCountKsOrBqVO.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/VO/QuestionResultVO.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/DingTalkService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/IPatMedOuthospService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/IServiceSubtaskDetailService.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/IServiceSubtaskService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/DingTalkServiceImpl.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/PatMedOuthospServiceImpl.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceTaskServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/IvrLibaTemplateScriptMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/IvrTaskTemplateScriptMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/SvyTaskTemplateScriptMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/component/RedisMqReceiver.java
@@ -390,15 +390,14 @@
                        serviceOutPath.setDeptName(serviceSubtask.getDeptname());
                        serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname());
                        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
                        String url = "";
                        String format = String.format("%03X", serviceOutPath.getId());
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUpdateTime(new Date());
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                        //需要通过模板ID去判断要发的内容是宣教还是通知
                        HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid());
                        if (heLibrary.getHetype().equals("1")) {
                            sendMagParam.setPhone(serviceSubtask.getPhone());
                            sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/xj?p=" + format : ip + "/xj?p=" + format);
                            url = StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/xj?p=" + format : ip + "/xj?p=" + format;
                            sendMagParam.setUrl(url);
                            SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("xj.sms.template");
@@ -421,6 +420,10 @@
                            sendMagParam.setPhone(serviceSubtask.getPhone());
                            sendMagParam.setContent(sc);
                        }
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUpdateTime(new Date());
                        serviceOutPath.setUrl(url);
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    }
                    //短信还需要模板
@@ -598,8 +601,9 @@
                        String format = String.format("%03X", serviceOutPath.getId());
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUpdateTime(new Date());
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                        url = ip + ":" + req_path + "/sf?p=" + format;
                        serviceOutPath.setUrl(url);
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    } else if (type == 2) {
                        //问券
                        ServiceOutPath serviceOutPath = new ServiceOutPath();
@@ -615,13 +619,16 @@
                        serviceOutPath.setWardName(serviceSubtask.getLeavehospitaldistrictname());
                        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
                        String format = String.format("%03X", serviceOutPath.getId());
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUpdateTime(new Date());
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                        url = StringUtils.isNotEmpty(req_path) ? ip + ":" + req_path + "/wt?p=" + format : ip + "/wt?p=" + format;
                        //如果type是语音随访的话(说明补偿发送方式中有电话随访的方式,这里的外链就地址只能用/sf)
                        if (serviceSubtask.getType().equals("1"))
                            sendMagParam.setUrl(ip + ":" + req_path + "/sf?p=" + format);
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUrl(url);
                        serviceOutPath.setUpdateTime(new Date());
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    } else if (type == 3) {
                        //宣教
                        ServiceOutPath serviceOutPath = new ServiceOutPath();
@@ -637,9 +644,6 @@
                        serviceOutPath.setOrgid(serviceSubtask.getOrgid());
                        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
                        String format = String.format("%03X", serviceOutPath.getId());
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUpdateTime(new Date());
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                        //需要通过模板ID去判断要发的内容是宣教还是通知
//                        HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid());
@@ -659,6 +663,10 @@
//                        }
                        url = ip + ":" + req_path + "/xj?p=" + format;
                        serviceOutPath.setRadix(format);
                        serviceOutPath.setUpdateTime(new Date());
                        serviceOutPath.setUrl(url);
                        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    }
                    if (StringUtils.isEmpty(patArchive.getPatidHis())) {
                        serviceSubtask.setCurrentPreachform(sendPreachform);
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java
@@ -12,6 +12,7 @@
import com.smartor.domain.*;
import com.smartor.domain.DTO.QuestionResultDTO;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.VO.QuestionCountKsOrBqVO;
import com.smartor.domain.VO.QuestionResultVO;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import com.smartor.service.IServiceSubtaskDetailService;
@@ -221,8 +222,7 @@
        // æŒ‰ questiontext åˆ†ç»„后转换为 QuestionResultVO
        List<QuestionResultDTO> result = new ArrayList<>();
        if (!detailList.isEmpty()) {
            Map<String, List<ServiceSubtaskDetailRatioExport>> groupedMap = detailList.stream()
                    .collect(Collectors.groupingBy(ServiceSubtaskDetailRatioExport::getQuestiontext));
            Map<String, List<ServiceSubtaskDetailRatioExport>> groupedMap = detailList.stream().collect(Collectors.groupingBy(ServiceSubtaskDetailRatioExport::getQuestiontext));
            groupedMap.forEach((questionText, exportList) -> {
                QuestionResultDTO questionResultDTO = new QuestionResultDTO();
@@ -234,4 +234,10 @@
        return success(result);
    }
    @ApiOperation("省立同德满意度数据统计通过科室或病区")
    @PostMapping("/statQuestionOptionByKsOrBq")
    public Map<String, Object> statQuestionOptionByKsOrBq(@RequestBody QuestionCountKsOrBqVO questionResultVO) {
        return success(serviceSubtaskService.statQuestionOptionByKsOrBq(questionResultVO));
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/tools/DingTalkController.java
@@ -48,5 +48,19 @@
        return aBoolean;
    }
    /**
     * å‘送钉钉消息
     *
     * @param dingTalkReqVo å‘送内容
     * @throws ApiException
     */
    @ApiOperation("发送钉钉消息")
    @PostMapping("/sendDingTalkText")
    public void sendDingTalkText(@RequestBody DingTalkReqVo dingTalkReqVo) throws Exception {
//        String userid = dingTalkService.getDingTalkUserByMobile(dingTalkReqVo.getNumber());
        String userid = "214563391024684607";
        dingTalkService.sendDingTalkText("景宁发送钉钉消息测试", userid);
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/DingAsyncSendMsgReq.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.common.core.domain;
import lombok.Data;
import java.util.Map;
@Data
public class DingAsyncSendMsgReq {
    /** åº”用agentId */
    private Long agent_id;
    /** æŽ¥æ”¶äººuserid列表,多个逗号分隔;与dept_id_list二选一 */
    private String userid_list;
    /** æŽ¥æ”¶éƒ¨é—¨id列表,多个逗号分隔 */
    private String dept_id_list;
    /** æ˜¯å¦å‘送给所有员工,true则userid_list、dept_id_list失效 */
    private Boolean to_all_user;
    /** æ¶ˆæ¯ä½“ */
    private Map<String, Object> msg;
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/DingAsyncSendMsgResp.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package com.ruoyi.common.core.domain;
import lombok.Data;
@Data
public class DingAsyncSendMsgResp {
    private Integer errcode;
    private String errmsg;
    /** ä»»åŠ¡id,后续回调会带回这个task_id */
    private Long task_id;
}
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/DingTokenResp.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package com.ruoyi.common.core.domain;
import lombok.Data;
@Data
public class DingTokenResp {
    private Integer errcode;
    private String errmsg;
    private String access_token;
    private Long expires_in;
}
ruoyi-common/src/main/java/com/ruoyi/common/core/service/IDingTalkService.java
@@ -13,4 +13,19 @@
     * @return æ˜¯å¦æˆåŠŸ
     */
    Boolean sendNotification(DingTalkReqVo dingTalkReqVo);
    /**
     * å‘送钉钉消息-景宁
     * @param sMessageContent
     * @throws Exception
     */
    void sendDingTalkText(String sMessageContent, String userId) throws Exception;
    /**
     * æ ¹æ®ç”µè¯èŽ·å–ç”¨æˆ·
     * @param mobile
     * @return
     * @throws Exception
     */
    String getDingTalkUserByMobile(String mobile) throws Exception;
}
ruoyi-common/src/main/java/com/ruoyi/common/dx/MessageSend.java
@@ -1,5 +1,9 @@
package com.ruoyi.common.dx;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.ruoyi.common.utils.uuid.UUID;
import lombok.extern.slf4j.Slf4j;
@@ -31,7 +35,8 @@
                result = soap.i5GSend("202508291634227086", "T202508291635259440", UUID.randomUUID().toString(), sMessageContent, sMessageType, sUserNumber, sScheduleTime);
                log.info("----短信返回的数据为:{},    ----sMessageContent çš„值为:{}", result,UUID.randomUUID().toString());
            } else if ("7".equals(sMessageType)) {
                result = soap.i5GSend("202508291634227086", "T202607211306131891", UUID.randomUUID().toString(), sMessageContent, sMessageType, sUserNumber, sScheduleTime);
                result = soap.i5GSend("202508291634227086", "T202607211306131891",
                        UUID.randomUUID().toString(), sMessageContent, sMessageType, sUserNumber, sScheduleTime);
                log.info("----钉钉返回的原始数据为:{}", result);
            } else {
ruoyi-common/src/main/java/com/ruoyi/common/utils/DingTalkUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
package com.ruoyi.common.utils;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.domain.DingAsyncSendMsgReq;
import com.ruoyi.common.core.domain.DingAsyncSendMsgResp;
import com.ruoyi.common.core.domain.DingTokenResp;
import okhttp3.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class DingTalkUtils {
    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .build();
    /**
     * èŽ·å–ä¼ä¸šaccess_token
     * @param corpid ä¼ä¸šID
     * @param corpsecret åº”用的凭证密钥
     * @return DingTokenResp
     */
    public static DingTokenResp getAccessToken(String corpid, String corpsecret) throws IOException {
        String url = "https://oapi.dingtalk.com/gettoken?corpid=" + corpid + "&corpsecret=" + corpsecret;
        Request request = new Request.Builder()
                .url(url)
                .get()
                .build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            String body = response.body().string();
            return JSON.parseObject(body, DingTokenResp.class);
        }
    }
    /**
     * å¼‚步发送企业会话消息 asyncsend_v2
     */
    public static DingAsyncSendMsgResp asyncSendCorpMsg(String accessToken, DingAsyncSendMsgReq req) throws IOException {
        String url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=" + accessToken;
        String jsonBody = JSON.toJSONString(req);
        RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            String respBody = response.body().string();
            return JSON.parseObject(respBody, DingAsyncSendMsgResp.class);
        }
    }
    // ========== æž„建消息示例:文本消息 ==========
    public static Map<String, Object> buildTextMsg(String content) {
        Map<String, Object> msgMap = new HashMap<>();
        msgMap.put("msgtype", "text");
        Map<String, Object> text = new HashMap<>();
        text.put("content", content);
        msgMap.put("text", text);
        return msgMap;
    }
    // ========== æž„建消息示例:markdown消息 ==========
    public static Map<String, Object> buildMarkdownMsg(String title, String text) {
        Map<String, Object> msgMap = new HashMap<>();
        msgMap.put("msgtype", "markdown");
        Map<String, Object> markdown = new HashMap<>();
        markdown.put("title", title);
        markdown.put("text", text);
        msgMap.put("markdown", markdown);
        return msgMap;
    }
}
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -9,6 +9,7 @@
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.core.service.IDingTalkService;
import com.ruoyi.common.dx.MessageSend;
import com.ruoyi.common.enums.MsgLSEnum;
import com.ruoyi.common.enums.ServiceFromEnum;
@@ -104,6 +105,9 @@
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private IDingTalkService dingTalkService;
    @Value("${localIP}")
@@ -266,6 +270,44 @@
            for (String dutyDeptPersonCode : dutyDeptPersonCodeList) {
                log.info("【sendSLTDMYDExceptInfo】发送人工号:{}", dutyDeptPersonCode);
                String data = MessageSend.sendMsg(exceptContent, "7", dutyDeptPersonCode, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
            }
        }
    }
    /**
     * å®šæ—¶å‘送异常信息-景宁
     */
    public void sendExceptInfo() throws Exception {
        //1.获取发送人工号
        ServiceSubtaskDetailTraceVO subtaskDetailTraceVO = new ServiceSubtaskDetailTraceVO();
        subtaskDetailTraceVO.setHandleFlag("0");
        List<ServiceSubtaskDetailTrace> serviceSubtaskDetailTraces =
                serviceSubtaskDetailTraceService.selectServiceSubtaskDetailTtraceList(subtaskDetailTraceVO);
        // æŠŠ dutyDeptPersonCode æ•´ç†åˆ° list ä¸­ï¼ˆå¦‚果多个人用逗号分割,则展开并去重)
        List<String> dutyDeptPersonCodeList = serviceSubtaskDetailTraces.stream()
                .map(ServiceSubtaskDetailTrace::getDutyDeptPersonCode)
                .filter(StringUtils::isNotBlank)
                .flatMap(code -> Arrays.stream(code.split(",")))
                .map(String::trim)
                .filter(StringUtils::isNotBlank).distinct()  // åŽ»é‡
                .collect(Collectors.toList());
        // èŽ·å–â€œå¼‚å¸¸å†…å®¹æé†’"
        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("send.except.content");
        String exceptContent = sysConfig.getConfigValue();
        // èŽ·å–â€œå†…å®¹æé†’æµ‹è¯•äººå·¥å·â€
        String testPerson = sysConfigMapper.checkConfigKeyUnique("send.test.person").getConfigValue();
        if (StringUtils.isNotBlank(testPerson)) {
            String[] split = testPerson.split(",");
            if (CollectionUtils.isEmpty(dutyDeptPersonCodeList)) dutyDeptPersonCodeList = Arrays.asList(split);
            else dutyDeptPersonCodeList.addAll(Arrays.asList(split));
        }
        if (CollectionUtils.isNotEmpty(dutyDeptPersonCodeList)) {
            for (String dutyDeptPersonCode : dutyDeptPersonCodeList) {
                log.info("【sendExceptInfo】发送人工号:{}", dutyDeptPersonCode);
                String dutyDeptPerson = dingTalkService.getDingTalkUserByMobile(dutyDeptPersonCode);
                dingTalkService.sendDingTalkText(exceptContent, dutyDeptPerson);
            }
        }
    }
@@ -1027,18 +1069,17 @@
                    serviceOutPath.setCreateTime(new Date());
                    serviceOutPath.setOrgid(serviceSubtask.getOrgid());
                    iServiceOutPathService.insertServiceOutPath(serviceOutPath);
                    String url = "";
                    String format = String.format("%03X", serviceOutPath.getId());
                    serviceOutPath.setRadix(format);
                    serviceOutPath.setUpdateTime(new Date());
                    iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    //先判断一下发的是不是宣教
                    if (!"3".equals(serviceSubtask.getType())) {
                        sendMagParam.setPhone(serviceSubtask.getPhone());
                        sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format);
                        url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format;
                        sendMagParam.setUrl(url);
                        //如果type是语音随访的话(说明补偿发送方式中有电话随访的方式,这里的外链就地址只能用/sf)
                        if (serviceSubtask.getType().equals("1"))
                            sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/sf?p=" + format : localIP + "/sf?p=" + format);
                            url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/sf?p=" + format : localIP + "/sf?p=" + format;
                            sendMagParam.setUrl(url);
//                        SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template");
                        SysConfig sysConfig = new SysConfig();
@@ -1058,7 +1099,9 @@
                        HeLibrary heLibrary = heLibraryMapper.selectHeLibraryById(serviceSubtask.getLibtemplateid());
                        if (heLibrary.getHetype().equals("1")) {
                            sendMagParam.setPhone(serviceSubtask.getPhone());
                            sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/xj?p=" + format : localIP + "/xj?p=" + format);
                            url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/xj?p=" + format : localIP + "/xj?p=" + format;
                            sendMagParam.setUrl(url);
                            SysConfig sysConfig = sysConfigMapper.checkConfigKeyUnique("xj.sms.template");
                            if (!Objects.isNull(sysConfig)) {
@@ -1076,6 +1119,11 @@
                        }
                    }
                    serviceOutPath.setRadix(format);
                    serviceOutPath.setUpdateTime(new Date());
                    serviceOutPath.setUrl(url);
                    iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    String isSuccess = null;
                    log.info("active的值为:{}", active);
                    if (active.equals("xh")) {
@@ -1249,6 +1297,7 @@
                    String format = String.format("%03X", serviceOutPath.getId());
                    serviceOutPath.setRadix(format);
                    serviceOutPath.setUpdateTime(new Date());
                    serviceOutPath.setUrl(url);
                    iServiceOutPathService.updateServiceOutPath(serviceOutPath);
                    //获取微信公众号请求信息根据机构ID
smartor/src/main/java/com/smartor/domain/DTO/QuestionCountKsOrBqDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
package com.smartor.domain.DTO;
import com.ruoyi.common.core.domain.BaseEntity;
import com.smartor.domain.ServiceSubtaskDetailRatioExport;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * é—®å·ç»“æžœ
 *
 * @author ruoyi
 * @date 2024-02-02
 */
@ApiModel(value = "QuestionResultDTO", description = "问卷结果")
@Data
public class QuestionCountKsOrBqDTO extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * é—®å·é¢˜ç›®
     */
    @ApiModelProperty(value = "问卷题目")
    private String qeustionText;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "任务id")
    private Long taskid;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "部门名称")
    private String deptname;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "病区名称")
    private String leavehospitaldistrictname;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "选项")
    private String targetvalue;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "选项结果")
    private String asrtext;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "回答数量")
    private String answerCount;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "单题得分")
    private String singleScore;
    /**
     * å¹³å‡å¾—分
     */
    @ApiModelProperty(value = "平均得分")
    private String avgScore;
}
smartor/src/main/java/com/smartor/domain/IvrLibaTemplateScript.java
@@ -329,9 +329,9 @@
    /**
     * æ˜¯å¦å¿…填(给人工用的,AI不用遵守)
     */
    @Excel(name = "是否必填(给人工用的,AI不用遵守)")
    @ApiModelProperty(value = "是否必填(给人工用的,AI不用遵守)")
    private String isMust;
    @Excel(name = "是否必填   1必填   2不必填(默认)(给人工用的,AI不用遵守)")
    @ApiModelProperty(value = "是否必填   1必填   2不必填(默认)")
    private String ismandatory;
    /**
     * ç»„别
smartor/src/main/java/com/smartor/domain/IvrLibaTemplateScriptVO.java
@@ -357,9 +357,9 @@
    /**
     * æ˜¯å¦å¿…填(给人工用的,AI不用遵守)
     */
    @Excel(name = "是否必填(给人工用的,AI不用遵守)")
    @ApiModelProperty(value = "是否必填(给人工用的,AI不用遵守)")
    private String isMust;
    @Excel(name = "是否必填   1必填   2不必填(默认)是否必填(给人工用的,AI不用遵守)")
    @ApiModelProperty(value = "是否必填   1必填   2不必填(默认)  ç»™äººå·¥ç”¨çš„,AI不用遵守)")
    private String ismandatory;
    /**
     * é—®é¢˜ç»“果(给“值类型”是文本或者数值用的)
smartor/src/main/java/com/smartor/domain/IvrTaskTemplateScript.java
@@ -276,7 +276,7 @@
     */
    @Excel(name = "是否必填,1:必填    2:可以不填    ", readConverterExp = "给=人工用的,AI不用遵守")
    @ApiModelProperty(value = "是否必填,1:必填    2:可以不填    ï¼ˆç»™äººå·¥ç”¨çš„,AI不用遵守)")
    private String isMust;
    private String ismandatory;
    /**
     * é—®é¢˜ç»“果(给“值类型”是文本或者数值用的)
smartor/src/main/java/com/smartor/domain/IvrTaskTemplateScriptVO.java
@@ -320,7 +320,7 @@
     */
    @Excel(name = "是否必填,1:必填    2:可以不填    ", readConverterExp = "给=人工用的,AI不用遵守")
    @ApiModelProperty(value = "是否必填,1:必填    2:可以不填    ï¼ˆç»™äººå·¥ç”¨çš„,AI不用遵守)")
    private String isMust;
    private String ismandatory;
    /**
     * é—®é¢˜ç»“果(给“值类型”是文本或者数值用的)
smartor/src/main/java/com/smartor/domain/ServiceSubtaskDetailRatioExport.java
@@ -50,4 +50,30 @@
    @Excel(name = "任务编号")
    private String taskid;
    /**
     * éƒ¨é—¨code
     */
    @Excel(name = "  éƒ¨é—¨code")
    @ApiModelProperty(value = "部门code")
    private String deptcode;
    /**
     * ç§‘室名称
     */
    @Excel(name = "科室名称")
    @ApiModelProperty(value = "科室名称")
    private String deptname;
    /**
     * å‡ºé™¢ç—…区编号
     */
    @ApiModelProperty(value = "出院病区编号")
    private String leavehospitaldistrictcode;
    /**
     * å‡ºé™¢ç—…区名称
     */
    @ApiModelProperty(value = "出院病区名称")
    @Excel(name = " å‡ºé™¢ç—…区名称 ")
    private String leavehospitaldistrictname;
}
smartor/src/main/java/com/smartor/domain/SvyLibTemplateScript.java
@@ -96,8 +96,8 @@
    /**
     * æ˜¯å¦å¿…å¡«   0必填   1不必填
     */
    @Excel(name = " æ˜¯å¦å¿…å¡«   0必填   1不必填")
    @ApiModelProperty("是否必填   0必填   1不必填")
    @Excel(name = " æ˜¯å¦å¿…å¡«   1必填   2不必填(默认)")
    @ApiModelProperty("是否必填   1必填   2不必填(默认)")
    private String ismandatory;
    /**
smartor/src/main/java/com/smartor/domain/SvyLibTemplateScriptVO.java
@@ -132,8 +132,8 @@
    /**
     * æ˜¯å¦å¿…å¡«   0必填   1不必填
     */
    @Excel(name = " æ˜¯å¦å¿…å¡«   0必填   1不必填")
    @ApiModelProperty("是否必填   0必填   1不必填")
    @Excel(name = " æ˜¯å¦å¿…å¡«   1必填   2不必填(默认)")
    @ApiModelProperty("是否必填   1必填   2不必填(默认)")
    private String ismandatory;
    /**
smartor/src/main/java/com/smartor/domain/SvyLibTemplateScriptWjx.java
@@ -89,7 +89,7 @@
    /**
     * æ˜¯å¦å¿…å¡«   0必填   1不必填
     */
    @ApiModelProperty(value = "是否必填   0必填   1不必填")
    @ApiModelProperty(value = "是否必填   1必填   2不必填(默认)")
    private String ismandatory;
    /**
smartor/src/main/java/com/smartor/domain/SvyTaskScript.java
@@ -64,8 +64,8 @@
    /**
     * æ˜¯å¦å¿…å¡«
     */
    @Excel(name = " æ˜¯å¦å¿…å¡« ")
    @ApiModelProperty(value = "是否必填")
    @Excel(name = " æ˜¯å¦å¿…å¡«   1必填   2不必填(默认) ")
    @ApiModelProperty(value = "是否必填   1必填   2不必填(默认)")
    private Long ismandatory;
    /**
smartor/src/main/java/com/smartor/domain/SvyTaskScriptoption.java
@@ -78,8 +78,8 @@
    /**
     * æ˜Žç»†æ˜¯å¦å¿…å¡«
     */
    @Excel(name = " æ˜Žç»†æ˜¯å¦å¿…å¡« ")
    @ApiModelProperty(value = "明细是否必填")
    @Excel(name = " æ˜¯å¦å¿…å¡«   1必填   2不必填(默认) ")
    @ApiModelProperty(value = "是否必填   1必填   2不必填(默认)")
    private Long detailismandatory;
    /**
smartor/src/main/java/com/smartor/domain/SvyTaskTemplateScript.java
@@ -104,7 +104,7 @@
     * æ˜¯å¦å¿…å¡«,1:必填    2:可以不填    ï¼ˆç»™äººå·¥ç”¨çš„,AI不用遵守)
     */
    @ApiModelProperty(value = "是否必填,1:必填    2:可以不填  ")
    private String isMust;
    private String ismandatory;
    /**
     * æ˜¯å¦å­˜åœ¨æ“ä½œï¼š1 æ–°å¢ž 2修改 3删除
smartor/src/main/java/com/smartor/domain/SvyTaskTemplateScriptVO.java
@@ -95,14 +95,6 @@
    @ApiModelProperty(value = "话术内容")
    private String scriptContent;
    /**
     * æ˜¯å¦å¿…å¡«,1:必填    2:可以不填    ï¼ˆç»™äººå·¥ç”¨çš„,AI不用遵守)
     */
    @ApiModelProperty(value = "是否必填,1:必填    2:可以不填 ")
    private String isMust;
    /**
     * åˆ é™¤æ ‡è®°
     */
@@ -311,10 +303,10 @@
    private Long categoryid;
    /**
     * æ˜¯å¦å¿…å¡«   0必填   1不必填
     * æ˜¯å¦å¿…å¡«  1必填   2不必填
     */
    @Excel(name = " æ˜¯å¦å¿…å¡«   0必填   1不必填")
    @ApiModelProperty("是否必填   0必填   1不必填")
    @Excel(name = " æ˜¯å¦å¿…å¡«  1必填   2不必填")
    @ApiModelProperty("是否必填  1必填   2不必填")
    private String ismandatory;
smartor/src/main/java/com/smartor/domain/SvyTopic.java
@@ -55,9 +55,9 @@
    private Long sort;
    /**
     * æ˜¯å¦å¿…å¡«
     * æ˜¯å¦å¿…å¡«   1必填   2不必填(默认)
     */
    @Excel(name = " æ˜¯å¦å¿…å¡« ")
    @Excel(name = " æ˜¯å¦å¿…å¡«   1必填   2不必填(默认) ")
    private Long ismandatory;
    /**
smartor/src/main/java/com/smartor/domain/VO/QuestionCountKsOrBqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
package com.smartor.domain.VO;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
import com.smartor.domain.ServiceSubtaskDetailRatioExport;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.ibatis.annotations.Param;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
 * é—®é¢˜ç»Ÿè®¡æ ¹æ®ç§‘室或病区查询
 *
 * @author ls
 * @date 2026-09-11
 */
@ApiModel(value = "QuestionCountKsOrBqVO", description = "问题统计根据科室或病区查询")
@Data
public class QuestionCountKsOrBqVO extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * ç§‘室与病区的查询是or还是and:   1:and(默认)(离院病区与离院科室组合)     2:or(离院病区与离院科室组合)    3:and(离院病区与随访科室组合)   4:or(离院病区与随访科室组合)
     */
    @ApiModelProperty(value = "科室与病区的查询是or还是and:   1:and(默认)(离院病区与离院科室组合)     2:or(离院病区与离院科室组合)    3:and(离院病区与随访科室组合)   4:or(离院病区与随访科室组合)")
    private String deptOrDistrict = "1";
    /**
     *
     */
    @ApiModelProperty(value = "主键id")
    private Long subId;
    /**
     * å‡ºé™¢ç—…区编号
     */
    @ApiModelProperty(value = "出院病区集合(必填)")
    private List<String> leavehospitaldistrictcodes;
    /**
     * éƒ¨é—¨code
     */
    @Excel(name = "  éƒ¨é—¨code")
    @ApiModelProperty(value = "部门code集合")
    private List<String> leaveldeptcodes;
    /**
     * å¼€å§‹å‡ºé™¢æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "开始完成日期")
    private Date startFinisTime;
    /**
     * ç»“束出院日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束完成日期")
    private Date endFinishTime;
    @ApiModelProperty(value = "问题类型(1.单选 2多选 3问答 4填空  5其它)")
    private String valueType;
}
smartor/src/main/java/com/smartor/domain/VO/QuestionResultVO.java
@@ -41,6 +41,13 @@
    @ApiModelProperty(value = "出院病区集合(必填)")
    private List<String> leavehospitaldistrictcodes;
    /**
     * éƒ¨é—¨code
     */
    @Excel(name = "  éƒ¨é—¨code")
    @ApiModelProperty(value = "部门code集合")
    private List<String> leaveldeptcodes;
    /**
     * ä¸»é”®id集合
@@ -64,7 +71,6 @@
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束出院日期")
    private Date endOutHospTime;
    /**
     * é—®é¢˜å†…容
smartor/src/main/java/com/smartor/domain/entity/ServiceSubtaskEntity.java
@@ -818,4 +818,12 @@
    @ApiModelProperty(value = "手术记录id集合")
    private List<Long> operationItemIds;
    /**
     * å¹´é¾„
     */
    @Excel(name = " å‡ºé™¢ç—…人记录ID集合")
    @ApiModelProperty(value = "出院病人记录ID集合")
    private List<Long> inhospids;
}
smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java
@@ -1,8 +1,10 @@
package com.smartor.mapper;
import com.smartor.domain.*;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.VO.PatSatisfactionReqVO;
import com.smartor.domain.VO.HeLibraryCountVO;
import com.smartor.domain.VO.QuestionCountKsOrBqVO;
import com.smartor.domain.VO.ServiceSubtaskCotinueCountVO;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import com.smartor.domain.entity.ServiceSubtaskSatisfactionEntity;
@@ -274,4 +276,11 @@
     */
    List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(@Param("subtaskIds") List<Long> subtaskIds, @Param("startOutHospTime") Date startOutHospTime, @Param("endOutHospTime") Date endOutHospTime, @Param("scoreStart") Double scoreStart, @Param("scoreEnd") Double scoreEnd, @Param("questiontext") String questiontext, @Param("valueType") String valueType);
    /**
     * æ ¹æ®ç§‘室、病区、题目类型统计的科室、病区评分
     * @param questionCountKsOrBqVO
     * @return
     */
    List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO questionCountKsOrBqVO);
}
smartor/src/main/java/com/smartor/service/DingTalkService.java
@@ -21,4 +21,19 @@
     * @param dingTalkReqVo
     */
    public Boolean sendNotification(DingTalkReqVo dingTalkReqVo);
    /**
     * å‘送钉钉消息-景宁
     * @param sMessageContent
     * @throws Exception
     */
    public void sendDingTalkText(String sMessageContent, String userId) throws Exception;
    /**
     * æ ¹æ®ç”µè¯èŽ·å–ç”¨æˆ·
     * @param mobile
     * @return
     * @throws Exception
     */
    public String getDingTalkUserByMobile(String mobile) throws Exception;
}
smartor/src/main/java/com/smartor/service/IPatMedOuthospService.java
@@ -83,7 +83,7 @@
     * @param patMedOuthosp
     * @return
     */
    public Integer followUpAgainByPatMedOuthosp(PatMedOuthosp patMedOuthosp, Integer visitTimeNum);
    public Integer followUpAgainByPatMedOuthosp(PatMedOuthosp patMedOuthosp, Integer visitTimeNum, List<Long> inhospids);
    /**
     * é—¨è¯Šè®°å½•处理
smartor/src/main/java/com/smartor/service/IServiceSubtaskDetailService.java
@@ -31,6 +31,7 @@
    public Map<String, Object> selectServiceSubtaskDetailList(ServiceSubtaskDetail serviceSubtaskDetail);
    public List<Map<String, Object>> getServiceSubtaskDetails(ServiceSubtaskDetailVO serviceSubtaskDetailVo);
    /**
     * æ–°å¢žè¯­éŸ³ä»»åŠ¡å‘¼å«æ˜Žç»†
     *
smartor/src/main/java/com/smartor/service/IServiceSubtaskService.java
@@ -2,12 +2,10 @@
import com.ruoyi.common.core.domain.AjaxResult;
import com.smartor.domain.*;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.DTO.QuestionResultDTO;
import com.smartor.domain.ServiceSubtask;
import com.smartor.domain.VO.HeLibraryCountVO;
import com.smartor.domain.VO.QuestionResultVO;
import com.smartor.domain.VO.ServiceSubtaskCotinueCountVO;
import com.smartor.domain.VO.TransferDeptVO;
import com.smartor.domain.VO.*;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import org.springframework.web.bind.annotation.RequestBody;
@@ -236,6 +234,8 @@
     */
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType);
    public List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO questionCountKsOrBqVO);
    public String scanGenerateSubtask(ServiceTask serviceTaskVo);
    public Integer matchOptionIndex(String url, String questionText, String voiceText, List<IvrTaskTemplateTargetoption> options, String uuid);
smartor/src/main/java/com/smartor/service/impl/DingTalkServiceImpl.java
@@ -12,7 +12,11 @@
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiUserListidResponse;
import com.dingtalk.api.response.OapiV2UserGetbymobileResponse;
import com.ruoyi.common.core.domain.DingAsyncSendMsgReq;
import com.ruoyi.common.core.domain.DingAsyncSendMsgResp;
import com.ruoyi.common.core.domain.DingTalkReqVo;
import com.ruoyi.common.core.domain.DingTokenResp;
import com.ruoyi.common.utils.DingTalkUtils;
import com.ruoyi.common.utils.StringUtils;
import com.smartor.service.DingTalkService;
import com.taobao.api.ApiException;
@@ -40,6 +44,9 @@
    @Value("${dingAppSecret}")
    private String dingAppSecret;
    @Value("${dingAppAgentId}")
    private Long dingAppAgentId;
    @Override
    public Boolean sendNotification(DingTalkReqVo dingTalkReqVo) {
@@ -158,4 +165,105 @@
        OapiGettokenResponse response = client.execute(request);
        return response.getAccessToken();
    }
    /**
     * èŽ·å–post access_token
     */
    private String getAccessTokenPost() throws ApiException {
        DefaultDingTalkClient client = new DefaultDingTalkClient("https://api.dingtalk.com/v1.0/oauth2/{corpId}/token");
        OapiGettokenRequest request = new OapiGettokenRequest();
        //Appkey
        request.setAppkey(dingAppid);
        //Appsecret
        request.setAppsecret(dingAppSecret);
        /*请求方式*/
        request.setHttpMethod("Post");
        OapiGettokenResponse response = client.execute(request);
        return response.getAccessToken();
    }
//    /**
//     * å‘送钉钉消息-景宁
//     * @param sMessageContent
//     * @throws Exception
//     */
//    public void sendDingTalkText(String sMessageContent) throws Exception {
//        String CORP_ID = "你的企业corpid";
//        String CORP_SECRET = "企业应用的corpsecret";
//        Long AGENT_ID = 4992829038L; // ä½ çš„应用agentId
//
//        try {
//            // 1. èŽ·å–access_token
//            DingTokenResp tokenResp = DingTalkUtils.getAccessToken(CORP_ID, CORP_SECRET);
//            if (tokenResp.getErrcode() != 0) {
//                System.err.println("获取token失败:" + tokenResp.getErrmsg());
//                return;
//            }
//            String accessToken = tokenResp.getAccess_token();
//            System.out.println("access_token=" + accessToken);
//
//            // 2. ç»„装发送请求
//            DingAsyncSendMsgReq sendReq = new DingAsyncSendMsgReq();
//            sendReq.setAgent_id(AGENT_ID);
//            sendReq.setUserid_list("user01,user02"); // æŽ¥æ”¶äººé’‰é’‰userId,多个逗号
//            sendReq.setTo_all_user(false);
//            // è®¾ç½®æ¶ˆæ¯å†…容,这里用文本消息
//            sendReq.setMsg(DingTalkUtils.buildTextMsg("你好,这是异步发送钉钉消息测试"));
//
//            // 3. è°ƒç”¨å¼‚步发送接口
//            DingAsyncSendMsgResp sendResp = DingTalkUtils.asyncSendCorpMsg(accessToken, sendReq);
//            if (sendResp.getErrcode() == 0) {
//                System.out.println("提交消息任务成功,task_id=" + sendResp.getTask_id());
//                System.out.println("消息实际发送结果,需要在钉钉后台配置回调接收");
//            } else {
//                System.err.println("提交消息任务失败:code=" + sendResp.getErrcode() + ",msg=" + sendResp.getErrmsg());
//            }
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
    /**
     * å‘送钉钉消息-景宁
     * @param sMessageContent
     * @throws Exception
     */
    @Override
    public void sendDingTalkText(String sMessageContent, String userId) throws Exception {
        Long agentId = dingAppAgentId;
        String accessToken = getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(agentId);
        request.setUseridList(userId);
        request.setToAllUser(false);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype("text");
        OapiMessageCorpconversationAsyncsendV2Request.Text text = new OapiMessageCorpconversationAsyncsendV2Request.Text();
        text.setContent(sMessageContent);
        msg.setText(text);
        request.setMsg(msg);
        OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(request, accessToken);
        System.out.println(rsp.getBody());
    }
    /**
     * æ ¹æ®ç”µè¯èŽ·å–ç”¨æˆ·
     * @param mobile
     * @return
     * @throws Exception
     */
    @Override
    public String getDingTalkUserByMobile(String mobile) throws Exception {
        String accessToken = getAccessToken();
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile");
        OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
        req.setMobile(mobile);
        OapiV2UserGetbymobileResponse rsp = client.execute(req, accessToken);
        return rsp.getBody();
    }
}
smartor/src/main/java/com/smartor/service/impl/PatMedInhospServiceImpl.java
@@ -897,7 +897,7 @@
        //封装serviceSubtask
        ServiceSubtask serviceSubtask = boxedServiceSubtaskForOp(serviceTask, patMedInhospList.get(0), patMedOperationItem, patArchive, config);
        if (ObjectUtils.isEmpty(serviceSubtask)) {
        if (ObjectUtils.isEmpty(serviceSubtask) || Objects.isNull(serviceSubtask.getTaskid())) {
            return;
        }
        if (StringUtils.isNotEmpty(patMedOperationItem.getLeaveldeptcode())) {
@@ -972,15 +972,18 @@
                patMedOperationItem2.setId(patMedOperationItem.getId());
                patMedOperationItem2.setOpercheckFlag("2");
                patMedOperationItem2.setLongTaskReason("生成子任务失败 4;");
                patMedOperationItem2.setUpdateTime(new Date());
                patMedOperationItemMapper.updatePatMedOperationItem(patMedOperationItem2);
            }
        } catch (Exception e) {
            //出错回滚事务
            log.info("生成子任务报错回滚sserviceSubtask的taskid为:{},patid为:{}", serviceSubtask.getTaskid(), serviceSubtask.getPatid());
            log.error("生成子任务报错回滚sserviceSubtask的taskid为:{},patid为:{},手术详情ID为:{}",
                    serviceSubtask.getTaskid(), serviceSubtask.getPatid(), patMedOperationItem.getId(), e);
            PatMedOperationItem patMedOperationItem2 = new PatMedOperationItem();
            patMedOperationItem2.setId(patMedOperationItem.getId());
            patMedOperationItem2.setOpercheckFlag("2");
            patMedOperationItem2.setUpdateTime(new Date());
            patMedOperationItem2.setLongTaskReason("生成子任务报错回滚 4;");
            patMedOperationItemMapper.updatePatMedOperationItem(patMedOperationItem2);
            e.printStackTrace();
@@ -990,6 +993,10 @@
    private Integer addServiceSubtaskPreachform(ServiceSubtask serviceSubtask, String sendstate) {
        //将preachformDesc的json对象,放到list集合中
        ServiceTask serviceTask = serviceTaskMapper.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
        if (Objects.isNull(serviceTask)) {
            log.error("addServiceSubtaskPreachform taskid={} æŸ¥ä¸åˆ°ä»»åŠ¡ï¼Œè·³è¿‡preachform子表生成", serviceSubtask.getTaskid());
            return 0;
        }
        String preachformDesc = serviceTask.getPreachformDesc();
        ObjectMapper objectMapper = new ObjectMapper();
@@ -1000,6 +1007,11 @@
                });
            } catch (JsonProcessingException e) {
                log.error("preachform转List<ServiceSubtaskPreachform>报错了:{}", e.getMessage());
            }
            if (CollectionUtils.isEmpty(serviceSubtaskPreachformList)) {
                log.error("preachformDesc解析后为空,跳过preachform子表生成,taskid为:{},preachformDesc为:{}",
                        serviceSubtask.getTaskid(), preachformDesc);
                return 0;
            }
            for (ServiceSubtaskPreachform serviceSubtaskPreachform : serviceSubtaskPreachformList) {
                serviceSubtaskPreachform.setTaskid(serviceSubtask.getTaskid());
@@ -1194,7 +1206,7 @@
//            patMedInhosp1.setRemark(patMedInhosp1.getRemark() + "& è¯¥æ‚£è€…手术出院时间为空,出院记录ID为:" + patMedInhosp1.getInhospid());
//            patMedInhospMapper.updatePatMedInhosp(patMedInhosp1);
            //如果出院时间为空,则返回一个新对象
            return new ServiceSubtask();
            return null;
        }
        serviceSubtask.setLongSendTime(newDate);
        serviceSubtask.setVisitTime(newDate);
@@ -1325,6 +1337,7 @@
                    PatMedOperationItem patMedOperationItem = patMedOperationItemMapper.selectPatMedOperationItemById(opItem.getId());
                    patMedOperationItem.setOpercheckFlag("2");
                    patMedOperationItem.setLongTaskReason("所患的手术未配置长期任务;");
                    patMedOperationItem.setUpdateTime(new Date());
                    patMedOperationItemMapper.updatePatMedOperationItem(patMedOperationItem);
                } else {
                    for (ServiceTaskoper serviceTaskoper : serviceTaskopers) {
@@ -1335,6 +1348,7 @@
            } catch (Exception e) {
                e.printStackTrace();
                log.error("人员手术处理出异常了:{}", e.getMessage());
                opItem.setUpdateTime(new Date());
                opItem.setOpercheckFlag("2");
                opItem.setLongTaskReason("人员手术处理异常");
                patMedOperationItemMapper.updatePatMedOperationItem(opItem);
smartor/src/main/java/com/smartor/service/impl/PatMedOuthospServiceImpl.java
@@ -21,6 +21,7 @@
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
 * æ‚£è€…门诊记录Service业务层处理
@@ -543,15 +544,45 @@
    @Override
    public Integer dealPatMedOuthosp(PatMedOuthosp patMedOuthosp, Integer visitTimeNum){
        Integer num = 0;
        ServiceSubtaskEntity serviceSubtask = new ServiceSubtaskEntity();
        serviceSubtask.setInhospid(patMedOuthosp.getId());
        serviceSubtask.setServiceType("3");
        serviceSubtask.setVisitCount(1);
        List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtask);
        if(CollectionUtils.isEmpty(serviceSubtasks)){
            num = followUpByPatMedOuthosp(patMedOuthosp, visitTimeNum);
        //景宁 å­˜åœ¨ç›¸åŒè¯Šæ–­çš„门诊记录则新增再次随访,否则新增随访
        if(ObjectUtils.isNotEmpty(patMedOuthosp.getOrgid()) &&
                patMedOuthosp.getOrgid().equals("47255004333112711A1001")){
            PatMedOuthosp patMedOuthospVo = new PatMedOuthosp();
            List<PatMedOuthosp> patMedOuthosps = new ArrayList<>();
            patMedOuthospVo.setOrgid(patMedOuthosp.getOrgid());
            patMedOuthospVo.setPatid(patMedOuthosp.getPatid());
            patMedOuthospVo.setIcd10code(patMedOuthosp.getIcd10code());
            // åŒä¸€ä¸ªæ‚£è€… + åŒä¸€ä¸ªè¯Šæ–­ï¼ŒåŽ†å²ä¸Šå·²ç»æœ‰é—¨è¯Šéšè®¿è®°å½•ï¼ˆæŽ’é™¤æœ¬æ¬¡å°±è¯Šï¼Œæœ¬æ¬¡åœ¨è°ƒç”¨å‰å·²è½åº“ï¼‰
            patMedOuthosps = selectPatMedOuthospList(patMedOuthospVo);
            Long currentId = patMedOuthosp.getId();
            List<Long> ids = patMedOuthosps.stream().map(PatMedOuthosp::getId).filter(ObjectUtils::isNotEmpty)
                    .filter(id -> !id.equals(currentId))
                    .distinct()
                    .collect(Collectors.toList());
            ServiceSubtaskEntity serviceSubtask = new ServiceSubtaskEntity();
            //景宁 åªè¦å­˜åœ¨ç›¸åŒè¯Šæ–­ã€æ‚£è€…的门诊记录则当再次随访处理
            serviceSubtask.setInhospids(ids);
            serviceSubtask.setServiceType("3");
            List<ServiceSubtask> serviceSubtasks = CollectionUtils.isEmpty(ids)
                    ? new ArrayList<>()
                    : serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtask);
            if(CollectionUtils.isEmpty(serviceSubtasks)){
                num = followUpByPatMedOuthosp(patMedOuthosp, visitTimeNum);
            }else {
                num = followUpAgainByPatMedOuthosp(patMedOuthosp, visitTimeNum, ids);
            }
        }else {
            num = followUpAgainByPatMedOuthosp(patMedOuthosp, visitTimeNum);
            ServiceSubtaskEntity serviceSubtask = new ServiceSubtaskEntity();
            serviceSubtask.setInhospid(patMedOuthosp.getId());
            serviceSubtask.setServiceType("3");
            serviceSubtask.setVisitCount(1);
            List<ServiceSubtask> serviceSubtasks = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtask);
            if(CollectionUtils.isEmpty(serviceSubtasks)){
                num = followUpByPatMedOuthosp(patMedOuthosp, visitTimeNum);
            }else {
                num = followUpAgainByPatMedOuthosp(patMedOuthosp, visitTimeNum, null);
            }
        }
        return num;
    }
@@ -610,7 +641,7 @@
     * @return
     */
    @Override
    public Integer followUpAgainByPatMedOuthosp(PatMedOuthosp patMedOuthosp, Integer visitTimeNum) {
    public Integer followUpAgainByPatMedOuthosp(PatMedOuthosp patMedOuthosp, Integer visitTimeNum, List<Long> inhospids) {
        Date adminDate = patMedOuthosp.getAdmitdate();
        Date newDate = addDays(adminDate, visitTimeNum);
@@ -622,32 +653,44 @@
        serviceSubtaskEntity0.setOrgid(patMedOuthosp.getOrgid());
        serviceSubtaskEntity0.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 7L)));
        serviceSubtaskEntity0.setPatid(patid);
        serviceSubtaskEntity0.setDeptcode(deptcode);
        //景宁根据诊断再次随访
        if(ObjectUtils.isNotEmpty(patMedOuthosp.getOrgid()) &&
                patMedOuthosp.getOrgid().equals("47255004333112711A1001") && !CollectionUtils.isEmpty(inhospids)){
            serviceSubtaskEntity0.setInhospids(inhospids);
        }else {
            serviceSubtaskEntity0.setDeptcode(deptcode);
        }
        serviceSubtaskEntity0.setSort(0);
        List<ServiceSubtask> serviceSubtaskList0 = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity0);
        if (!CollectionUtils.isEmpty(serviceSubtaskList0)) {
            ServiceSubtask serviceSubtask0 = serviceSubtaskList0.get(0);
            serviceSubtask0.setSendstate(6L);
            serviceSubtask0.setUpdateTime(new Date());
            serviceSubtask0.setFinishtime(adminDate);
            serviceSubtaskMapper.updateServiceSubtask(serviceSubtask0);
            for (ServiceSubtask serviceSubtask0 : serviceSubtaskList0) {
                serviceSubtask0.setSendstate(6L);
                serviceSubtask0.setUpdateTime(new Date());
                serviceSubtask0.setFinishtime(adminDate);
                serviceSubtaskMapper.updateServiceSubtask(serviceSubtask0);
            ServiceSubtask serviceSubtask1 = DtoConversionUtils.sourceToTarget(serviceSubtask0, ServiceSubtask.class);
            serviceSubtask1.setId(null);
            serviceSubtask1.setSendstate(2L);
            serviceSubtask1.setUpid(serviceSubtask0.getId().intValue());
            serviceSubtask1.setVisitCount(serviceSubtask0.getVisitCount() + 1);
            serviceSubtask1.setVisitType(serviceSubtask0.getVisitType());
            serviceSubtask1.setVisitDeptCode(serviceSubtask0.getVisitDeptCode());
            serviceSubtask1.setVisitDeptName(serviceSubtask0.getVisitDeptName());
            serviceSubtask1.setCreateTime(new Date());
            serviceSubtask1.setUpdateTime(new Date());
            serviceSubtask1.setFinishtime(null);
            serviceSubtask1.setAdmindate(adminDate);
                ServiceSubtask serviceSubtask1 = DtoConversionUtils.sourceToTarget(serviceSubtask0, ServiceSubtask.class);
                serviceSubtask1.setId(null);
                serviceSubtask1.setSendstate(2L);
                serviceSubtask1.setUpid(serviceSubtask0.getId().intValue());
                //老数据的visit_count可能为空,默认按第1次算
                Integer visitCount = ObjectUtils.isEmpty(serviceSubtask0.getVisitCount()) ? 1 : serviceSubtask0.getVisitCount();
                serviceSubtask1.setVisitCount(visitCount + 1);
                serviceSubtask1.setVisitType(serviceSubtask0.getVisitType());
                serviceSubtask1.setVisitDeptCode(serviceSubtask0.getVisitDeptCode());
                serviceSubtask1.setVisitDeptName(serviceSubtask0.getVisitDeptName());
                //新任务科室是当前出院科室
                serviceSubtask1.setDeptcode(patMedOuthosp.getDeptcode());
                serviceSubtask1.setCreateTime(new Date());
                serviceSubtask1.setUpdateTime(new Date());
                serviceSubtask1.setFinishtime(null);
                serviceSubtask1.setAdmindate(adminDate);
            serviceSubtask1.setVisitTime(newDate);
            serviceSubtask1.setLongSendTime(newDate);
            i = serviceSubtaskMapper.insertServiceSubtask(serviceSubtask1);
                serviceSubtask1.setVisitTime(newDate);
                serviceSubtask1.setLongSendTime(newDate);
                i = i + serviceSubtaskMapper.insertServiceSubtask(serviceSubtask1);
            }
        } else {
            //查看已完成的任务
//            ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
@@ -1066,8 +1066,19 @@
            }
        }
        String orgid = selectServiceSubtaskList.get(0).getOrgid();
        //景宁-随访异常提示 å…¶ä»–-异常满意度提示
        boolean addTrace = false;
        if(StringUtils.isNotEmpty(orgid) && orgid.equals("47255004333112711A1001")){
            if (stt != null) {
                addTrace = Long.valueOf(1L).equals(stt.getIsabnormal());
            }
        }else {
            addTrace = StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getIsMydException());
        }
        //判断一下当前的问题是不是满意度问题,并且 dutyDeptCode æ˜¯å¦æœ‰å€¼ï¼Œå¹¶ä¸”选项是不是异常选项,如果全符合,则往满意度问题异常表新增
        if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getDutyDeptCode()) && stt != null && Long.valueOf(1L).equals(stt.getIsabnormal()) || StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getDutyDeptCode()) && StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getIsMydException())) {
        if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getDutyDeptCode()) && stt != null && Long.valueOf(1L).equals(stt.getIsabnormal()) || StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getDutyDeptCode())
                && addTrace) {
            isabnormalFlag = 1L;
            ServiceSubtaskDetailTrace subtaskDetailTrace = new ServiceSubtaskDetailTrace();
            subtaskDetailTrace.setDetailId(serviceSubtaskDetail.getId());
@@ -1083,17 +1094,19 @@
            //获取所有选项
            subtaskDetailTrace.setTargetid(stt != null ? stt.getId() : null);
            subtaskDetailTrace.setTargetvalue(serviceSubtaskDetailVO.getTargetvalue());
            subtaskDetailTrace.setMatchedtext(stt != null ? stt.getOptioncontent() : svyTaskTemplateScriptVO.getIsMydException());
            subtaskDetailTrace.setGuid(svyTaskTemplateScriptVO.getGuid());
            subtaskDetailTrace.setValueType(serviceSubtaskDetail.getValueType());
            subtaskDetailTrace.setIsMydException(svyTaskTemplateScriptVO.getIsMydException());
            subtaskDetailTrace.setTemplateType(2);
            SvyLibScriptCategory svyLibScriptCategory = svyLibScriptCategoryMapper.selectSvyLibScriptCategoryById(svyTaskTemplateScriptVO.getCategoryid());
            subtaskDetailTrace.setType(svyLibScriptCategory != null ? svyLibScriptCategory.getType() : null);
            subtaskDetailTrace.setScriptid(svyTaskTemplateScriptVO.getId());
            //非满意度意见异常自动填入空
            subtaskDetailTrace.setMatchedtext(stt != null ? stt.getOptioncontent() : svyTaskTemplateScriptVO.getIsMydException());
            subtaskDetailTrace.setAsrtext(stt != null ? stt.getOptioncontent() : svyTaskTemplateScriptVO.getIsMydException());
            subtaskDetailTrace.setIsMydException(svyTaskTemplateScriptVO.getIsMydException());
            subtaskDetailTrace.setRecordpath(null);
            subtaskDetailTrace.setPatid(selectServiceSubtaskList.get(0).getPatid());
            JSONObject patdescJson1 = new JSONObject();
@@ -1341,9 +1354,19 @@
                stt = ivrTaskTemplateTargetoption;
        }
        String orgid = selectServiceSubtaskList.get(0).getOrgid();
        //景宁-随访异常提示 å…¶ä»–-异常满意度提示
        boolean addTrace = false;
        if(StringUtils.isNotEmpty(orgid) && orgid.equals("47255004333112711A1001")){
            if (stt != null) {
                addTrace = Long.valueOf(1L).equals(stt.getIsabnormal());
            }
        }else {
            addTrace = StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getIsMydException());
        }
        //判断一下当前的问题是不是满意度问题,并且dutyDeptCode是否有值,并且选项是不是异常选项,如果全符合,则往满意度问题异常表新增
        if (StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getDutyDeptCode()) && 1 == stt.getIsabnormal() || StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getDutyDeptCode()) && StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getIsMydException())) {
        if (StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getDutyDeptCode()) && 1 == stt.getIsabnormal() || StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getDutyDeptCode())
                && addTrace) {
            isabnormalFlag = "1";
            ServiceSubtaskDetailTrace subtaskDetailTrace = new ServiceSubtaskDetailTrace();
            subtaskDetailTrace.setDetailId(serviceSubtaskDetail.getId());
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -22,13 +22,11 @@
import com.smartor.common.MtSubmitSmUtil;
import com.smartor.common.ScheduleSubtaskBuilder;
import com.smartor.config.PhoneUtils;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.DTO.QuestionResultDTO;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.*;
import com.smartor.domain.VO.HeLibraryCountVO;
import com.smartor.domain.VO.QuestionResultVO;
import com.smartor.domain.VO.ServiceSubtaskCotinueCountVO;
import com.smartor.domain.VO.TransferDeptVO;
import com.smartor.domain.VO.*;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import com.smartor.mapper.*;
import com.smartor.service.*;
@@ -672,10 +670,8 @@
            //如果不存在,则新增
            ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid());
            if (ObjectUtils.isNotEmpty(serviceTask)) {
                serviceSubtask.setDeptcode(serviceTask.getDeptcode());
                serviceSubtask.setTaskDesc(serviceTask.getTaskDesc());
                serviceSubtask.setTaskName(serviceTask.getTaskName());
                serviceSubtask.setDeptname(serviceTask.getDeptname());
                serviceSubtask.setTemplatename(serviceTask.getTemplatename());
            }
@@ -2923,12 +2919,10 @@
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getDrcode()).orElse("Unknown")));
                break;
            case "management_doctor_code":
                rawData = rawData.stream()
                        .peek(item -> {
                            item.setDrname(item.getManagementDoctor());
                            item.setDrcode(item.getManagementDoctorCode());
                        })
                        .collect(Collectors.toList());
                rawData = rawData.stream().peek(item -> {
                    item.setDrname(item.getManagementDoctor());
                    item.setDrcode(item.getManagementDoctorCode());
                }).collect(Collectors.toList());
                collect = rawData.stream().collect(Collectors.groupingBy(subtask -> Optional.ofNullable(subtask.getManagementDoctorCode()).orElse("Unknown")));
                break;
            case "deptcode":
@@ -4088,12 +4082,15 @@
        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
        //转成16进制
        String format = String.format("%03X", serviceOutPath.getId());
        String url = "";
        SendMagParam sendMagParam = new SendMagParam();
        url = localIP + ":" + req_path + "/sf?p=" + format;
        sendMagParam.setUrl(url);
        sendMagParam.setContent("【新华医院】您好,邀请您填写出院随访调查表,请点击" + sendMagParam.getUrl() + "填写。感谢您配合!");
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        serviceOutPath.setUrl(url);
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        SendMagParam sendMagParam = new SendMagParam();
        sendMagParam.setUrl(localIP + ":" + req_path + "/sf?p=" + format);
        sendMagParam.setContent("【新华医院】您好,邀请您填写出院随访调查表,请点击" + sendMagParam.getUrl() + "填写。感谢您配合!");
        Map<String, String> map = new HashMap<>();
        map.put("phone", serviceSubtask.getPhone());
        map.put("content", sendMagParam.getContent());
@@ -4979,15 +4976,17 @@
        serviceOutPath.setOrgid(serviceSubtask.getOrgid());
        iServiceOutPathService.insertServiceOutPath(serviceOutPath);
        String format = String.format("%03X", serviceOutPath.getId());
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        String url = "";
        SendMagParam sendMagParam = new SendMagParam();
        sendMagParam.setType("4");
        sendMagParam.setPhone(serviceSubtask.getPhone());
        sendMagParam.setUrl(StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format);
        url = StringUtils.isNotEmpty(req_path) ? localIP + ":" + req_path + "/wt?p=" + format : localIP + "/wt?p=" + format;
        sendMagParam.setUrl(url);
        serviceOutPath.setRadix(format);
        serviceOutPath.setUpdateTime(new Date());
        serviceOutPath.setUrl(url);
        iServiceOutPathService.updateServiceOutPath(serviceOutPath);
        SysConfig sysConfig = new SysConfig();
        sysConfig = sysConfigMapper.checkConfigKeyUnique("wj.sms.template");
@@ -5012,7 +5011,7 @@
    }
    @Override
    public List<ServiceSubtaskDetailRatioExport> statQuestionOption(List<Long> taskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd,String valueType) {
    public List<ServiceSubtaskDetailRatioExport> statQuestionOption(List<Long> taskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType) {
        //先清理一下重复数据
        List<Long> repeatIds = serviceSubtaskDetailMapper.selectRepeatDetailIds();
        if (!CollectionUtils.isEmpty(repeatIds)) {
@@ -5028,14 +5027,10 @@
                // å¦‚果有多条目标值,拆分成多行
                for (String value : values) {
                    //先去 result ä¸­æŸ¥ä¸€ä¸‹ï¼Œæœ‰æ²¡æœ‰è¿™ä¸ª questiontext å’Œå¯¹åº”çš„ targetvalue
                    ServiceSubtaskDetailRatioExport existingExport = result.stream()
                            .filter(e -> e.getQuestiontext().equals(export.getQuestiontext())
                                    && value.trim().equals(e.getTargetvalue()))
                            .findFirst()
                            .orElse(null);
                    ServiceSubtaskDetailRatioExport existingExport = result.stream().filter(e -> e.getQuestiontext().equals(export.getQuestiontext()) && value.trim().equals(e.getTargetvalue())).findFirst().orElse(null);
                    if (existingExport != null && existingExport.getRatio().equals("0") && existingExport.getCount().equals("0")) {
                        //如果存在,则将 result é‡Œçš„这个问题所对应的 Targetvalue=value è¿™æ¡æ•°æ®æ›´æ–°æˆå½“前这条数据
                        if(value.equals(export.getOptionresult())) {
                        if (value.equals(export.getOptionresult())) {
                            existingExport.setRatio(export.getRatio());
                            existingExport.setScore(export.getScore());
                            existingExport.setCount(export.getCount());
@@ -5063,15 +5058,62 @@
        return result;
    }
    /*
     * æ ¹æ®ç§‘室或病区统计问卷选项(科室、题目查询的科室评分表)
     */
    @Override
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd,String valueType) {
    public List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO questionCountKsOrBqVO) {
        List<QuestionCountKsOrBqDTO> questionCountKsOrBqDTOS = serviceSubtaskMapper.statQuestionOptionByKsOrBq(questionCountKsOrBqVO);
        // å¤„理 targetvalue:按 & åˆ†å‰²æˆå¤šæ¡è®°å½•
        List<QuestionCountKsOrBqDTO> result = new ArrayList<>();
        for (QuestionCountKsOrBqDTO questionCountKsOrBqDTO : questionCountKsOrBqDTOS) {
            if (StringUtils.isNotEmpty(questionCountKsOrBqDTO.getTargetvalue()) && questionCountKsOrBqDTO.getTargetvalue().contains("&")) {
                String[] values = questionCountKsOrBqDTO.getTargetvalue().split("&");
                // å¦‚果有多条目标值,拆分成多行
                for (String value : values) {
                    //先去 result ä¸­æŸ¥ä¸€ä¸‹ï¼Œæœ‰æ²¡æœ‰è¿™ä¸ª questiontext å’Œå¯¹åº”çš„ targetvalue
                    QuestionCountKsOrBqDTO existingExport = result.stream().filter(e -> e.getQeustionText().equals(questionCountKsOrBqDTO.getQeustionText()) && value.trim().equals(e.getTargetvalue())).findFirst().orElse(null);
                    if (existingExport != null && existingExport.getAnswerCount().equals("0") && existingExport.getSingleScore().equals("0")) {
                        //如果存在,则将 result é‡Œçš„这个问题所对应的 Targetvalue=value è¿™æ¡æ•°æ®æ›´æ–°æˆå½“前这条数据
                        if (value.equals(questionCountKsOrBqDTO.getAsrtext())) {
                            existingExport.setAsrtext(questionCountKsOrBqDTO.getAsrtext());
                            existingExport.setAnswerCount(questionCountKsOrBqDTO.getAnswerCount());
                            existingExport.setSingleScore(questionCountKsOrBqDTO.getSingleScore());
                            existingExport.setAvgScore(questionCountKsOrBqDTO.getAvgScore());
                        }
                    } else if (existingExport != null && !existingExport.getAnswerCount().equals("0")) {
                        continue;
                    } else {
                        QuestionCountKsOrBqDTO qcDto = DtoConversionUtils.sourceToTarget(questionCountKsOrBqDTO, QuestionCountKsOrBqDTO.class);
                        qcDto.setTargetvalue(value.trim()); // targetvalue æ˜¾ç¤ºå•个选项
                        if (!value.equals(qcDto.getAsrtext())) {
                            existingExport.setAsrtext(null);
                            existingExport.setAnswerCount("0");
                            existingExport.setSingleScore("0");
                            existingExport.setAvgScore("0");
                        }
                        result.add(qcDto);
                    }
                }
            } else {
                // targetvalue ä¸åŒ…含 &,直接添加到结果
                result.add(questionCountKsOrBqDTO);
            }
        }
        return result;
    }
    @Override
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType) {
        //先清理一下重复数据
        List<Long> repeatIds = serviceSubtaskDetailMapper.selectRepeatDetailIds();
        if (!CollectionUtils.isEmpty(repeatIds)) {
            serviceSubtaskDetailMapper.deleteRepeatDetailByIds(repeatIds);
        }
        List<ServiceSubtaskDetailRatioExport> serviceSubtaskDetailRatioExports = serviceSubtaskMapper.statQuestionOptionBySubtaskIds(subtaskIds, startOutHospTime, endOutHospTime, scoreStart, scoreEnd, scriptContent,valueType);
        List<ServiceSubtaskDetailRatioExport> serviceSubtaskDetailRatioExports = serviceSubtaskMapper.statQuestionOptionBySubtaskIds(subtaskIds, startOutHospTime, endOutHospTime, scoreStart, scoreEnd, scriptContent, valueType);
        // å¤„理 targetvalue:按 & åˆ†å‰²æˆå¤šæ¡è®°å½•
        List<ServiceSubtaskDetailRatioExport> result = new ArrayList<>();
        for (ServiceSubtaskDetailRatioExport export : serviceSubtaskDetailRatioExports) {
@@ -5080,14 +5122,10 @@
                // å¦‚果有多条目标值,拆分成多行
                for (String value : values) {
                    //先去 result ä¸­æŸ¥ä¸€ä¸‹ï¼Œæœ‰æ²¡æœ‰è¿™ä¸ª questiontext å’Œå¯¹åº”çš„ targetvalue
                    ServiceSubtaskDetailRatioExport existingExport = result.stream()
                            .filter(e -> e.getQuestiontext().equals(export.getQuestiontext())
                                    && value.trim().equals(e.getTargetvalue()))
                            .findFirst()
                            .orElse(null);
                    ServiceSubtaskDetailRatioExport existingExport = result.stream().filter(e -> e.getQuestiontext().equals(export.getQuestiontext()) && value.trim().equals(e.getTargetvalue())).findFirst().orElse(null);
                    if (existingExport != null && existingExport.getRatio().equals("0") && existingExport.getCount().equals("0")) {
                        //如果存在,则将 result é‡Œçš„这个问题所对应的 Targetvalue=value è¿™æ¡æ•°æ®æ›´æ–°æˆå½“前这条数据
                        if(value.equals(export.getOptionresult())) {
                        if (value.equals(export.getOptionresult())) {
                            existingExport.setRatio(export.getRatio());
                            existingExport.setScore(export.getScore());
                            existingExport.setCount(export.getCount());
@@ -5813,11 +5851,11 @@
        if (StringUtils.isNotEmpty(questionResultVO.getServiceType()) && questionResultVO.getServiceType().equals("2")) {
            //获取serviceSubtaskList中的所有taskid
            List<Long> taskIds = serviceSubtaskRes.stream().map(ServiceSubtaskRes::getTaskid).filter(ObjectUtils::isNotEmpty).distinct().collect(Collectors.toList());
            serviceSubtaskDetailRatioExports = statQuestionOption(taskIds, questionResultVO.getStartOutHospTime(), questionResultVO.getEndOutHospTime(), questionResultVO.getQuestionContent(), questionResultVO.getStartScore(), questionResultVO.getEndScore(),questionResultVO.getValueType());
            serviceSubtaskDetailRatioExports = statQuestionOption(taskIds, questionResultVO.getStartOutHospTime(), questionResultVO.getEndOutHospTime(), questionResultVO.getQuestionContent(), questionResultVO.getStartScore(), questionResultVO.getEndScore(), questionResultVO.getValueType());
        } else if (StringUtils.isNotEmpty(questionResultVO.getServiceType()) && questionResultVO.getServiceType().equals("6")) {
            //满意度统计 ï¼ˆé€šè¿‡ subtask çš„ id åŽ»ç»Ÿè®¡ï¼‰
            List<Long> subtaskIds = serviceSubtaskRes.stream().map(ServiceSubtaskRes::getId).collect(Collectors.toList());
            serviceSubtaskDetailRatioExports = statQuestionOptionBySubtaskIds(subtaskIds, questionResultVO.getStartOutHospTime(), questionResultVO.getEndOutHospTime(), questionResultVO.getQuestionContent(), questionResultVO.getStartScore(), questionResultVO.getEndScore(),questionResultVO.getValueType());
            serviceSubtaskDetailRatioExports = statQuestionOptionBySubtaskIds(subtaskIds, questionResultVO.getStartOutHospTime(), questionResultVO.getEndOutHospTime(), questionResultVO.getQuestionContent(), questionResultVO.getStartScore(), questionResultVO.getEndScore(), questionResultVO.getValueType());
        }
        return serviceSubtaskDetailRatioExports;
    }
smartor/src/main/java/com/smartor/service/impl/ServiceTaskServiceImpl.java
@@ -496,7 +496,7 @@
        }
        //通过患者信息和任务信息中的textParam对问题中的变量进行填充
        //通过患者信息和任务信息中的 textParam å¯¹é—®é¢˜ä¸­çš„变量进行填充
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Map<String, String>> ivrTaskMap = null;
        try {
@@ -504,28 +504,36 @@
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        List<Map<String, String>> mapList = new ArrayList<>();
        // ä¼˜åŒ– 1: é¢„先合并所有替换规则为一个 Map,避免多次遍历
        Map<String, String> replaceMap = new HashMap<>();
        if (ivrTaskMap != null) {
            for (Map<String, String> map : ivrTaskMap.values()) {
                mapList.add(map);
                replaceMap.putAll(map);
            }
        }
        //将模板问题话术里的通配符替换
        for (SvyTaskTemplateScriptVO svyTaskTemplateScriptVO : svyTaskTemplateScriptVOS) {
            if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getScriptContent())) {
                for (Map<String, String> map : mapList) {
                    for (String key : map.keySet()) {
                        svyTaskTemplateScriptVO.setScriptContent(svyTaskTemplateScriptVO.getScriptContent().replace(key, StringUtils.isNotEmpty(map.get(key)) ? map.get(key) : ""));
                    }
                // ä¼˜åŒ– 2: ä½¿ç”¨æ­£åˆ™ PatternMatcher æ‰¹é‡æ›¿æ¢ï¼Œæå‡æ€§èƒ½
                String scriptContent = svyTaskTemplateScriptVO.getScriptContent();
                // æ‰¹é‡æ›¿æ¢ IVR ä»»åŠ¡å‚æ•°
                for (Map.Entry<String, String> entry : replaceMap.entrySet()) {
                    String value = StringUtils.isNotEmpty(entry.getValue()) ? entry.getValue() : "";
                    scriptContent = scriptContent.replace(entry.getKey(), value);
                }
                //替换患者个人信息数据
                log.info("问题id:{},   é—®é¢˜å†…容:{}", svyTaskTemplateScriptVO.getId(), svyTaskTemplateScriptVO.getScriptContent());
                if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getScriptContent()) && ObjectUtils.isNotEmpty(patArchive)) {
                    svyTaskTemplateScriptVO.setScriptContent(svyTaskTemplateScriptVO.getScriptContent().replace("${name}", StringUtils.isNotEmpty(patArchive.getName()) ? patArchive.getName() : ""));
                    svyTaskTemplateScriptVO.setScriptContent(svyTaskTemplateScriptVO.getScriptContent().replace("${dzz}", StringUtils.isNotEmpty(patArchive.getPlaceOfResidence()) ? patArchive.getPlaceOfResidence() : ""));
                    svyTaskTemplateScriptVO.setScriptContent(svyTaskTemplateScriptVO.getScriptContent().replace("${dhh}", StringUtils.isNotEmpty(patArchive.getTelcode()) ? patArchive.getTelcode() : ""));
                log.info("问题 id:{},   é—®é¢˜å†…容:{}", svyTaskTemplateScriptVO.getId(), scriptContent);
                if (ObjectUtils.isNotEmpty(patArchive)) {
                    // ä¼˜åŒ– 3: å‡å°‘不必要的非空判断(patArchive å·²ç»åˆ¤è¿‡ï¼‰
                    scriptContent = scriptContent.replace("${name}", StringUtils.defaultString(patArchive.getName()));
                    scriptContent = scriptContent.replace("${dzz}", StringUtils.defaultString(patArchive.getPlaceOfResidence()));
                    scriptContent = scriptContent.replace("${dhh}", StringUtils.defaultString(patArchive.getTelcode()));
                }
                svyTaskTemplateScriptVO.setScriptContent(scriptContent);
                //获取问题选项
                SvyTaskTemplateTargetoption svyTaskTemplateTargetoption = new SvyTaskTemplateTargetoption();
                svyTaskTemplateTargetoption.setScriptid(svyTaskTemplateScriptVO.getId());
smartor/src/main/resources/mapper/smartor/IvrLibaTemplateScriptMapper.xml
@@ -40,7 +40,7 @@
        <result property="scriptTopic" column="script_topic"/>
        <result property="nextScriptno" column="next_scriptno"/>
        <result property="otherdata" column="otherdata"/>
        <result property="isMust" column="is_must"/>
        <result property="ismandatory" column="ismandatory"/>
        <result property="scriptDesc" column="script_desc"/>
        <result property="scriptType" column="script_type"/>
        <result property="branchFlag" column="branch_flag"/>
@@ -107,7 +107,7 @@
               next_scriptno,
               otherdata,
               score,
               is_must,
               ismandatory,
               playWavOnly,
               del_flag,
               update_by,
@@ -181,7 +181,7 @@
        <if test="guid != null  and guid != ''">and guid = #{guid}</if>
        <if test="targetid != null ">and targetid = #{targetid}</if>
        <if test="targetvalue != null  and targetvalue != ''">and targetvalue = #{targetvalue}</if>
        <if test="isMust != null  and isMust != ''">and is_must = #{isMust}</if>
        <if test="ismandatory != null  and ismandatory != ''">and ismandatory = #{ismandatory}</if>
        <if test="scriptType != null">and script_type = #{scriptType}</if>
        <if test="sort != null">and sort = #{sort}</if>
        <if test="score != null">and score = #{score}</if>
@@ -273,7 +273,7 @@
            <if test="scriptTopic != null">script_topic,</if>
            <if test="nextScriptno != null">next_scriptno,</if>
            <if test="otherdata != null">otherdata,</if>
            <if test="isMust != null  and isMust != ''">is_must,</if>
            <if test="ismandatory != null  and ismandatory != ''">ismandatory,</if>
            <if test="scriptDesc != null ">script_desc,</if>
            <if test="scriptType != null ">script_type,</if>
            <if test="branchFlag != null  and branchFlag != ''">branch_flag,</if>
@@ -329,7 +329,7 @@
            <if test="scriptTopic != null">#{scriptTopic},</if>
            <if test="nextScriptno != null">#{nextScriptno},</if>
            <if test="otherdata != null">#{otherdata},</if>
            <if test="isMust != null  and isMust != ''">#{isMust},</if>
            <if test="ismandatory != null  and ismandatory != ''">#{ismandatory},</if>
            <if test="scriptDesc != null ">#{scriptDesc},</if>
            <if test="scriptType != null ">#{scriptType},</if>
            <if test="branchFlag != null  and branchFlag != ''">#{branchFlag},</if>
@@ -394,7 +394,7 @@
            <if test="scriptTopic != null">script_topic = #{scriptTopic},</if>
            <if test="nextScriptno != null">next_scriptno = #{nextScriptno},</if>
            <if test="otherdata != null">otherdata = #{otherdata},</if>
            <if test="isMust != null  and isMust != ''">is_must = #{isMust},</if>
            <if test="ismandatory != null  and ismandatory != ''">ismandatory = #{ismandatory},</if>
            <if test="scriptDesc != null ">script_desc = #{scriptDesc},</if>
            <if test="scriptType != null ">script_type = #{scriptType},</if>
            <if test="isMydException != null  and isMydException != ''">is_myd_exception = #{isMydException},</if>
smartor/src/main/resources/mapper/smartor/IvrTaskTemplateScriptMapper.xml
@@ -36,7 +36,7 @@
        <result property="targetid" column="targetid"/>
        <result property="targetvalue" column="targetvalue"/>
        <result property="otherdata" column="otherdata"/>
        <result property="isMust" column="is_must"/>
        <result property="ismandatory" column="ismandatory"/>
        <result property="questionResult" column="question_result"/>
        <result property="branchFlag" column="branch_flag"/>
        <result property="branchNextscriptno" column="branch_nextscriptno"/>
@@ -99,7 +99,7 @@
               noClearlyText,
               noClearlyVoice,
               script_assortname,
               targetOptions, language, playWavOnly, value_type, del_flag, update_by, update_time, create_by, create_time, isupload, upload_time, orgid, pid, guid, targettype, targetid, targetvalue, otherdata, is_must, question_result
               targetOptions, language, playWavOnly, value_type, del_flag, update_by, update_time, create_by, create_time, isupload, upload_time, orgid, pid, guid, targettype, targetid, targetvalue, otherdata, ismandatory, question_result
        from ivr_task_template_script
    </sql>
@@ -157,7 +157,7 @@
        <if test="targetid != null ">and targetid = #{targetid}</if>
        <if test="targetvalue != null  and targetvalue != ''">and targetvalue = #{targetvalue}</if>
        <if test="otherdata != null  and otherdata != ''">and otherdata = #{otherdata}</if>
        <if test="isMust != null  and isMust != ''">and is_must = #{isMust}</if>
        <if test="ismandatory != null  and ismandatory != ''">and ismandatory = #{ismandatory}</if>
        <if test="questionResult != null  and questionResult != ''">and question_result = #{questionResult}</if>
        <if test="branchFlag != null  and branchFlag != ''">and branch_flag = #{branchFlag}</if>
        <if test="scriptType != null  and scriptType != ''">and script_type = #{scriptType}</if>
@@ -231,7 +231,7 @@
            <if test="targetid != null">targetid,</if>
            <if test="targetvalue != null">targetvalue,</if>
            <if test="otherdata != null">otherdata,</if>
            <if test="isMust != null">is_must,</if>
            <if test="ismandatory != null">ismandatory,</if>
            <if test="questionResult != null">question_result,</if>
            <if test="branchFlag != null  and branchFlag != ''">branch_flag,</if>
            <if test="branchNextscriptno != null  and branchNextscriptno != ''">branch_nextscriptno,</if>
@@ -287,7 +287,7 @@
            <if test="targetid != null">#{targetid},</if>
            <if test="targetvalue != null">#{targetvalue},</if>
            <if test="otherdata != null">#{otherdata},</if>
            <if test="isMust != null">#{isMust},</if>
            <if test="ismandatory != null">#{ismandatory},</if>
            <if test="questionResult != null">#{questionResult},</if>
            <if test="branchFlag != null  and branchFlag != ''">#{branchFlag},</if>
            <if test="branchNextscriptno != null  and branchNextscriptno != ''">#{branchNextscriptno},</if>
@@ -347,7 +347,7 @@
            <if test="targetid != null">targetid = #{targetid},</if>
            <if test="targetvalue != null">targetvalue = #{targetvalue},</if>
            <if test="otherdata != null">otherdata = #{otherdata},</if>
            <if test="isMust != null">is_must = #{isMust},</if>
            <if test="ismandatory != null">ismandatory = #{ismandatory},</if>
            <if test="questionResult != null">question_result = #{questionResult},</if>
            <if test="branchFlag != null  and branchFlag != ''">branch_flag = #{branchFlag},</if>
            <if test="branchNextscriptno != null  and branchNextscriptno != ''">branch_nextscriptno =
smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
@@ -213,7 +213,6 @@
               create_time,
               isupload,
               upload_time,
               orgid,
               pid,
               guid,
               text_param,
@@ -236,8 +235,6 @@
               leaveicd10code,
               orgid,
               visit_type,
               management_doctor,
               management_doctor_code,
               continue_flag,
               continue_time_now,
               continue_content,
@@ -362,6 +359,12 @@
            AND operation_item_id IN
            <foreach collection="operationItemIds" item="operationItemIdItem" open="(" separator="," close=")">
                #{operationItemIdItem}
            </foreach>
        </if>
        <if test="inhospids != null and inhospids.size() > 0">
            AND inhospid IN
            <foreach collection="inhospids" item="inhospidItem" open="(" separator="," close=")">
                #{inhospidItem}
            </foreach>
        </if>
        <if test="templateid != null  and templateid != ''">and templateid = #{templateid}</if>
@@ -752,7 +755,8 @@
        <if test="groupKey != null and groupKey != ''">
            ss.${groupKey} as groupKey,
        </if>
        SUM(CASE WHEN ss.finishtime IS NOT NULL AND DATE(ss.visit_time) &lt;= DATE(ss.finishtime) THEN 1 ELSE 0 END) / COUNT(*) AS finishRate,
        SUM(CASE WHEN ss.finishtime IS NOT NULL AND DATE(ss.visit_time) &lt;= DATE(ss.finishtime) THEN 1 ELSE 0 END) /
        COUNT(*) AS finishRate,
        <if test="rateDay != null">
            SUM(CASE WHEN ss.finishtime IS NOT NULL
            AND DATEDIFF(ss.finishtime, ss.endtime) &lt;= #{rateDay} + COALESCE(cp.compensate_days, 0)
@@ -1793,132 +1797,132 @@
    <select id="getSfStatisticsHyperlink" parameterType="com.smartor.domain.ServiceSubtaskCountReq"
            resultMap="ServiceSubtaskResult">
            select id,
            visit_count,
            is_visit_again,
            type,
            orgid,
            drcode,
            drname,
            leavehospitaldistrictcode,
            leavehospitaldistrictname,
            deptcode,
            deptname,
            sendstate,
            preachform,
            current_preachform,
            excep,
            nurse_id,
            nurse_name,
            taskid,
            task_name,
            visit_time,
            finishtime,
            endtime,
            senddate,
            suggest,
            result,
            templateid,
            templatename,
            patid,
            sendname,
            send_type,
            recordid,
            exrecallcount,
            continue_flag,
            continue_time_now,
            continue_content,
            continue_count,
            continue_time_next,
            task_situation,
            remark
            from service_subtask
            where 1=1
            and del_flag = 0
            <if test="orgid != null and orgid != ''">
                and orgid = #{orgid}
        select id,
        visit_count,
        is_visit_again,
        type,
        orgid,
        drcode,
        drname,
        leavehospitaldistrictcode,
        leavehospitaldistrictname,
        deptcode,
        deptname,
        sendstate,
        preachform,
        current_preachform,
        excep,
        nurse_id,
        nurse_name,
        taskid,
        task_name,
        visit_time,
        finishtime,
        endtime,
        senddate,
        suggest,
        result,
        templateid,
        templatename,
        patid,
        sendname,
        send_type,
        recordid,
        exrecallcount,
        continue_flag,
        continue_time_now,
        continue_content,
        continue_count,
        continue_time_next,
        task_situation,
        remark
        from service_subtask
        where 1=1
        and del_flag = 0
        <if test="orgid != null and orgid != ''">
            and orgid = #{orgid}
        </if>
        <if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0">
            AND leavehospitaldistrictcode IN
            <foreach collection="leavehospitaldistrictcodes" item="leavehospitaldistrictcode" open="(" separator=","
                     close=")">
                #{leavehospitaldistrictcode}
            </foreach>
        </if>
        <if test="deptcodes != null and deptcodes.size() > 0">
            AND deptcode IN
            <foreach collection="deptcodes" item="deptcode" open="(" separator=","
                     close=")">
                #{deptcode}
            </foreach>
        </if>
        <if test="serviceType != null and serviceType.size() > 0">
            AND service_type IN
            <foreach collection="serviceType" item="serviceType" open="(" separator=","
                     close=")">
                #{serviceType}
            </foreach>
        </if>
        <if test="startTime != null and endTime!=null">
            AND visit_time >= DATE(#{startTime})
            AND visit_time &lt; DATE_ADD(DATE(#{endTime}), INTERVAL 1 DAY)
        </if>
        <if test="visitDeptCode != null">and visit_dept_code = #{visitDeptCode}</if>
        <if test="visitDeptName != null">and visit_dept_name = #{visitDeptName}</if>
        <if test="isabnormal != null">and isabnormal = #{isabnormal}</if>
        <if test="continueFlag != null ">and continue_flag = #{continueFlag}</if>
        <if test="continueTimeNow != null ">and continue_time_now = #{continueTimeNow,jdbcType=TIMESTAMP}</if>
        <if test="continueCount != null ">and continue_count = #{continueCount}</if>
        <if test="continueTimeNext != null ">and continue_time_next = #{continueTimeNext,jdbcType=TIMESTAMP}</if>
        <!-- ç›®å‰åªç»Ÿè®¡è¯­éŸ³å’Œé—®å· -->
        <if test="type != null">
            and type = #{type}
        </if>
        <if test="visitCount != null and visitCount == 1">
            AND visit_count = 1
        </if>
        <if test="visitCount != null and visitCount > 1">
            AND visit_count > 1
        </if>
        <if test="groupKey != null and groupKey != '' and groupKeyList != null and groupKeyList.size>0">
            AND ${groupKey} IN
            <foreach collection="groupKeyList" item="key" open="(" separator=","
                     close=")">
                #{key}
            </foreach>
        </if>
        AND sendstate IS NOT NULL
        <if test="sendstates != null and sendstates.size() > 0">
            AND sendstate IN
            <foreach collection="sendstates" item="state" open="(" separator="," close=")">
                #{state}
            </foreach>
        </if>
        <if test="currentPreachform != null">
            AND current_preachform = #{currentPreachform}
            <if test="followUpCountStyle != null and followUpCountStyle = '1'">
                AND sendstate != 4
            </if>
            <if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0">
                AND leavehospitaldistrictcode IN
                <foreach collection="leavehospitaldistrictcodes" item="leavehospitaldistrictcode" open="(" separator=","
                         close=")">
                    #{leavehospitaldistrictcode}
                </foreach>
            </if>
            <if test="deptcodes != null and deptcodes.size() > 0">
                AND deptcode IN
                <foreach collection="deptcodes" item="deptcode" open="(" separator=","
                         close=")">
                    #{deptcode}
                </foreach>
            </if>
            <if test="serviceType != null and serviceType.size() > 0">
                AND service_type IN
                <foreach collection="serviceType" item="serviceType" open="(" separator=","
                         close=")">
                    #{serviceType}
                </foreach>
            </if>
            <if test="startTime != null and endTime!=null">
                AND visit_time >= DATE(#{startTime})
                AND visit_time &lt; DATE_ADD(DATE(#{endTime}), INTERVAL 1 DAY)
            </if>
            <if test="visitDeptCode != null">and visit_dept_code = #{visitDeptCode}</if>
            <if test="visitDeptName != null">and visit_dept_name = #{visitDeptName}</if>
            <if test="isabnormal != null">and isabnormal = #{isabnormal}</if>
            <if test="continueFlag != null ">and continue_flag = #{continueFlag}</if>
            <if test="continueTimeNow != null ">and continue_time_now = #{continueTimeNow,jdbcType=TIMESTAMP}</if>
            <if test="continueCount != null ">and continue_count = #{continueCount}</if>
            <if test="continueTimeNext != null ">and continue_time_next = #{continueTimeNext,jdbcType=TIMESTAMP}</if>
            <!-- ç›®å‰åªç»Ÿè®¡è¯­éŸ³å’Œé—®å· -->
            <if test="type != null">
                and type = #{type}
            </if>
            <if test="visitCount != null and visitCount == 1">
                AND visit_count = 1
            </if>
            <if test="visitCount != null and visitCount > 1">
                AND visit_count > 1
            </if>
            <if test="groupKey != null and groupKey != '' and groupKeyList != null and groupKeyList.size>0">
                AND ${groupKey} IN
                <foreach collection="groupKeyList" item="key" open="(" separator=","
                         close=")">
                    #{key}
                </foreach>
            </if>
            AND sendstate IS NOT NULL
            <if test="sendstates != null and sendstates.size() > 0">
                AND sendstate IN
                <foreach collection="sendstates" item="state" open="(" separator="," close=")">
                    #{state}
                </foreach>
            </if>
            <if test="currentPreachform != null">
                AND current_preachform = #{currentPreachform}
                <if test="followUpCountStyle != null and followUpCountStyle = '1'">
                    AND sendstate != 4
                </if>
            </if>
            <if test="excep != null and excep != ''">
                AND excep = #{excep}
            </if>
            <if test="taskSituation != null">
                AND task_situation = #{taskSituation}
            </if>
            <if test="drcode != null and drcode != ''">
                AND drcode = #{drcode}
            </if>
            <if test="leavehospitaldistrictcode != null and leavehospitaldistrictcode != ''">
                AND leavehospitaldistrictcode = #{leavehospitaldistrictcode}
            </if>
            <if test="deptcode != null and deptcode != ''">
                AND deptcode = #{deptcode}
            </if>
            order by endtime desc
            <if test="pageSize != null  and pageNum != null">
                limit ${pageSize} OFFSET ${pageNum}
            </if>
        </if>
        <if test="excep != null and excep != ''">
            AND excep = #{excep}
        </if>
        <if test="taskSituation != null">
            AND task_situation = #{taskSituation}
        </if>
        <if test="drcode != null and drcode != ''">
            AND drcode = #{drcode}
        </if>
        <if test="leavehospitaldistrictcode != null and leavehospitaldistrictcode != ''">
            AND leavehospitaldistrictcode = #{leavehospitaldistrictcode}
        </if>
        <if test="deptcode != null and deptcode != ''">
            AND deptcode = #{deptcode}
        </if>
        order by endtime desc
        <if test="pageSize != null  and pageNum != null">
            limit ${pageSize} OFFSET ${pageNum}
        </if>
    </select>
    <select id="getSfStatisticsJoy" parameterType="com.smartor.domain.ServiceSubtaskCountReq"
@@ -2966,8 +2970,8 @@
    <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')
        and loop_count = #{loopCount}
        and (del_flag is null or del_flag = '0')
        order by schedule_seq asc, id asc
    </select>
@@ -3134,6 +3138,10 @@
        t.task_name AS taskName,
        d.asrtext AS optionresult,
        d.score AS score,
        s.deptcode AS deptcode,
        s.deptname AS deptname,
        s.leavehospitaldistrictcode AS leavehospitaldistrictcode,
        s.leavehospitaldistrictname AS leavehospitaldistrictname,
        d.targetvalue AS targetvalue,
        d.value_type AS valueType,
        COUNT(*) AS count,
@@ -3144,43 +3152,47 @@
        INNER JOIN service_subtask_detail d ON d.sub_id = s.id
        INNER JOIN (
        SELECT
            d.questiontext,
            COUNT(*) AS total_count
        d.questiontext,
        COUNT(*) AS total_count
        FROM
            service_task t
            INNER JOIN service_subtask s ON s.taskid = t.taskid
            INNER JOIN service_subtask_detail d ON d.sub_id = s.id
            WHERE 1=1
            <if test="subtaskIds != null and subtaskIds.size() > 0">
        service_task t
        INNER JOIN service_subtask s ON s.taskid = t.taskid
        INNER JOIN service_subtask_detail d ON d.sub_id = s.id
        WHERE 1=1
        <if test="subtaskIds != null and subtaskIds.size() > 0">
            AND s.id IN
            <foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
                #{subtaskId}
            </foreach>
            </if>
        </if>
        <if test="valueType != null">AND d.value_type &gt;= #{valueType}</if>
        <if test="scoreStart != null">AND d.score = #{scoreStart}</if>
        <if test="scoreEnd != null">AND d.score &lt;= #{scoreEnd}</if>
        <if test="questiontext != null  and questiontext != ''">and d.questiontext like concat('%', #{questiontext}, '%')</if>
            AND s.sendstate = 6
            AND d.del_flag=0
            GROUP BY d.questiontext
        <if test="questiontext != null  and questiontext != ''">and d.questiontext like concat('%', #{questiontext},
            '%')
        </if>
        AND s.sendstate = 6
        AND d.del_flag=0
        GROUP BY d.questiontext
        ) t2 ON t2.questiontext = d.questiontext
        WHERE 1=1
        <if test="subtaskIds != null and subtaskIds.size() > 0">
        AND s.id IN
        <foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
            #{subtaskId}
        </foreach>
            AND s.id IN
            <foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
                #{subtaskId}
            </foreach>
        </if>
        AND s.sendstate = 6
        AND d.del_flag=0
        <if test="valueType != null">AND d.value_type &gt;= #{valueType}</if>
        <if test="scoreStart != null">AND d.score &gt;= #{scoreStart}</if>
        <if test="scoreEnd != null">AND d.score &lt;= #{scoreEnd}</if>
        <if test="questiontext != null  and questiontext != ''">and d.questiontext like concat('%', #{questiontext}, '%')</if>
      <if test="startOutHospTime != null">
        AND date_format(s.endtime,'%y%m%d') &gt;= date_format(#{startOutHospTime},'%y%m%d')
    </if>
        <if test="questiontext != null  and questiontext != ''">and d.questiontext like concat('%', #{questiontext},
            '%')
        </if>
        <if test="startOutHospTime != null">
            AND date_format(s.endtime,'%y%m%d') &gt;= date_format(#{startOutHospTime},'%y%m%d')
        </if>
        <if test="endOutHospTime != null">
            AND date_format(s.endtime,'%y%m%d') &lt;= date_format(#{endOutHospTime},'%y%m%d')
        </if>
@@ -3195,6 +3207,48 @@
        t.taskid
    </select>
    <select id="statQuestionOptionByKsOrBq" resultType="com.smartor.domain.DTO.QuestionCountKsOrBqDTO"
            parameterType="com.smartor.domain.VO.QuestionCountKsOrBqVO">
        SELECT questiontext,
        d.taskid,
        s.deptname,
        s.leavehospitaldistrictname,
        d.targetvalue,
        d.asrtext,
        COUNT(d.asrtext) AS answercount,
        SUM(d.score) AS singleScore
        FROM service_subtask_detail d,
        service_task s
        WHERE d.taskid = s.taskid
        AND deptname IS NOT NULL
        AND leavehospitaldistrictname IS NOT NULL
        <if test="endFinishTime != null">
            AND create_time &lt; #{endFinishTime}
        </if>
        <if test="startFinishTime != null">
            AND create_time &gt;= #{startFinishTime}
        </if>
        <if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0">
            AND leavehospitaldistrictcode IN
            <foreach collection="leavehospitaldistrictcodes" item="leavehospitaldistrictcode" open="("
                     separator=","
                     close=")">
                #{leavehospitaldistrictcode}
            </foreach>
        </if>
        <if test=" leaveldeptcodes != null and leaveldeptcodes.size()>0">
            AND deptcode IN
            <foreach collection="leaveldeptcodes" item="leaveldeptcode" open="(" separator=","
                     close=")">
                #{leaveldeptcode}
            </foreach>
        </if>
        GROUP BY d.questiontext,
        d.taskid,
        d.asrtext
        ORDER BY d.taskid
    </select>
    <select id="selectServiceSubtaskListDeadLine" parameterType="com.smartor.domain.entity.ServiceSubtaskEntity"
            resultMap="ServiceSubtaskResult">
        <include refid="selectServiceSubtaskVo"/>
smartor/src/main/resources/mapper/smartor/SvyTaskTemplateScriptMapper.xml
@@ -15,7 +15,7 @@
        <result property="language" column="language"/>
        <result property="categoryName" column="categoryName"/>
        <result property="scriptContent" column="script_content"/>
        <result property="isMust" column="is_must"/>
        <result property="ismandatory" column="ismandatory"/>
        <result property="delFlag" column="del_flag"/>
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
@@ -82,7 +82,7 @@
               scriptno,
               templateID,
               scriptid,
               script_topic, language, categoryName, script_content, is_must, del_flag, update_by, update_time, create_by, create_time, isupload, upload_time, orgid, pid, guid, value_type, targetoptions, script_type, targetid, targetvalue, next_scriptno, script_result, otherdata, picture_path
               script_topic, language, categoryName, script_content, ismandatory, del_flag, update_by, update_time, create_by, create_time, isupload, upload_time, orgid, pid, guid, value_type, targetoptions, script_type, targetid, targetvalue, next_scriptno, script_result, otherdata, picture_path
                , duty_dept_person_name, duty_dept_person_code, report_dept_person_name, report_dept_person_code
                 , circulation_dept_person_code, circulation_dept_person_name
        from svy_task_template_script
@@ -118,7 +118,7 @@
                '%')
            </if>
            <if test="scriptContent != null  and scriptContent != ''">and script_content = #{scriptContent}</if>
            <if test="isMust != null  and isMust != ''">and is_must = #{isMust}</if>
            <if test="ismandatory != null  and ismandatory != ''">and ismandatory = #{ismandatory}</if>
            <if test="isupload != null ">and isupload = #{isupload}</if>
            <if test="uploadTime != null ">and upload_time = #{uploadTime}</if>
            <if test="orgid != null  and orgid != ''">and orgid = #{orgid}</if>
@@ -180,7 +180,7 @@
            <if test="language != null">language,</if>
            <if test="categoryName != null">categoryName,</if>
            <if test="scriptContent != null">script_content,</if>
            <if test="isMust != null">is_must,</if>
            <if test="ismandatory != null">ismandatory,</if>
            <if test="delFlag != null">del_flag,</if>
            <if test="updateBy != null">update_by,</if>
            <if test="updateTime != null">update_time,</if>
@@ -233,7 +233,7 @@
            <if test="language != null">#{language},</if>
            <if test="categoryName != null">#{categoryName},</if>
            <if test="scriptContent != null">#{scriptContent},</if>
            <if test="isMust != null">#{isMust},</if>
            <if test="ismandatory != null">#{ismandatory},</if>
            <if test="delFlag != null">#{delFlag},</if>
            <if test="updateBy != null">#{updateBy},</if>
            <if test="updateTime != null">#{updateTime},</if>
@@ -290,7 +290,7 @@
            <if test="language != null">language = #{language},</if>
            <if test="categoryName != null">categoryName = #{categoryName},</if>
            <if test="scriptContent != null">script_content = #{scriptContent},</if>
            <if test="isMust != null">is_must = #{isMust},</if>
            <if test="ismandatory != null">ismandatory = #{ismandatory},</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>