陈昶聿
4 天以前 8107dedd85ceec29491293d8ebf69f7d7213aa6b
Merge remote-tracking branch 'origin/master'
已修改14个文件
已添加3个文件
1500 ■■■■■ 文件已修改
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/DTO/MydTrendReqDTO.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/DTO/QuestionCountKsOrBqDTO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/DTO/QuestionResultDTO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/VO/MydTrendReqVO.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/VO/QuestionCountKsOrBqVO.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/VO/ServiceSubtaskVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/domain/VO/SltdMydTotalVO.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/IServiceSubtaskService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java 397 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java 390 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskController.java
@@ -194,13 +194,14 @@
    //@PreAuthorize("@ss.hasPermi('system:taskcall:export')")
    @Log(title = "单一任务", businessType = BusinessType.EXPORT)
    @PostMapping("/patItemExport")
    public void patItemExport(HttpServletResponse response, ServiceSubtaskEntity serviceSubtaskVO) {
    public void patItemExport(HttpServletResponse response, ServiceSubtaskVO serviceSubtaskVO) {
        LoginUser loginUser = getLoginUser();
        SysUser user = loginUser.getUser();
        serviceSubtaskVO.setOrgid(user.getOrgid());
        List<ServiceSubtaskRes> serviceSubtaskList = null;
        if (serviceSubtaskVO != null) {
            serviceSubtaskList = serviceSubtaskService.patItem(serviceSubtaskVO);
           ServiceSubtaskEntity serviceSubtaskEntity = DtoConversionUtils.sourceToTarget(serviceSubtaskVO, ServiceSubtaskEntity.class);
            serviceSubtaskList = serviceSubtaskService.patItem(serviceSubtaskEntity);
        }
        List<ServiceSubtaskExport> serviceSubtaskExports = null;
        List<ServiceSubtaskDetailRatioExport> serviceSubtaskDetailRatioExports = null;
@@ -220,11 +221,11 @@
                    serviceSubtaskExport.setEndDay(endDay);
                }
            }
            QuestionResultVO questionResultVO = new QuestionResultVO();
            questionResultVO.setServiceType(serviceSubtaskVO.getServiceType());
            questionResultVO.setEndOutHospTime(serviceSubtaskVO.getEndOutHospTime());
            questionResultVO.setStartOutHospTime(serviceSubtaskVO.getStartOutHospTime());
            serviceSubtaskDetailRatioExports = serviceSubtaskService.getDetailRatio(questionResultVO, serviceSubtaskList);
            SltdMydTotalVO sltdMydTotalVO = new SltdMydTotalVO();
            sltdMydTotalVO.setServiceTypeList(Arrays.asList(serviceSubtaskVO.getServiceType()));
            sltdMydTotalVO.setEndOutHospTime(serviceSubtaskVO.getEndOutHospTime());
            sltdMydTotalVO.setStartOutHospTime(serviceSubtaskVO.getStartOutHospTime());
            serviceSubtaskDetailRatioExports = serviceSubtaskService.getDetailRatio(sltdMydTotalVO, serviceSubtaskList);
        }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/smartor/ServiceSubtaskDetailController.java
@@ -12,17 +12,21 @@
import com.smartor.domain.*;
import com.smartor.domain.DTO.QuestionResultDTO;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.VO.MydTrendReqVO;
import com.smartor.domain.VO.QuestionCountKsOrBqVO;
import com.smartor.domain.VO.QuestionResultVO;
import com.smartor.domain.VO.SltdMydTotalVO;
import com.smartor.domain.entity.ServiceSubtaskEntity;
import com.smartor.service.IServiceSubtaskDetailService;
import com.smartor.service.IServiceSubtaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@@ -204,32 +208,56 @@
     * æŸ¥è¯¢æ‚£è€…随访信息
     */
    @ApiOperation("省立同德满意度数据统计")
    @PostMapping("/sltaMydTotalByScore")
    public Map<String, Object> sltaMydTotal(@RequestBody QuestionResultVO questionResultVO) {
    @PostMapping("/sltdMydTotalByScore")
    public Map<String, Object> sltdMydTotalByScore(@RequestBody SltdMydTotalVO sltdMydTotalVO) {
        List<ServiceSubtaskRes> serviceSubtaskResList = null;
        ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
        serviceSubtaskEntity.setServiceType(questionResultVO.getServiceType());
        serviceSubtaskEntity.setEndOutHospTime(questionResultVO.getEndOutHospTime());
        serviceSubtaskEntity.setStartOutHospTime(questionResultVO.getStartOutHospTime());
        serviceSubtaskEntity.setDeptOrDistrict(questionResultVO.getDeptOrDistrict());
        serviceSubtaskEntity.setLeavehospitaldistrictcodes(questionResultVO.getLeavehospitaldistrictcodes());
        if (serviceSubtaskEntity != null) {
            List<ServiceSubtask> serviceSubtasks = serviceSubtaskService.getServiceSubtasks(serviceSubtaskEntity);
            serviceSubtaskResList = DtoConversionUtils.sourceToTarget(serviceSubtasks, ServiceSubtaskRes.class);
        if (CollectionUtils.isNotEmpty(sltdMydTotalVO.getServiceTypeList())) {
            //serviceType可能会出现多个,不想多写方法了,一个一个查询吧
            for (String st : sltdMydTotalVO.getServiceTypeList()) {
                ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
                serviceSubtaskEntity.setServiceType(st);
                serviceSubtaskEntity.setEndOutHospTime(sltdMydTotalVO.getEndOutHospTime());
                serviceSubtaskEntity.setStartOutHospTime(sltdMydTotalVO.getStartOutHospTime());
                serviceSubtaskEntity.setDeptOrDistrict(sltdMydTotalVO.getDeptOrDistrict());
                serviceSubtaskEntity.setLeavehospitaldistrictcodes(sltdMydTotalVO.getLeavehospitaldistrictcodes());
                serviceSubtaskEntity.setLeaveldeptcodes(sltdMydTotalVO.getLeaveldeptcodes());
                if (serviceSubtaskEntity != null) {
                    List<ServiceSubtask> serviceSubtasks = serviceSubtaskService.getServiceSubtasks(serviceSubtaskEntity);
                    List<ServiceSubtaskRes> serviceSubtaskRes = DtoConversionUtils.sourceToTarget(serviceSubtasks, ServiceSubtaskRes.class);
                    if (CollectionUtils.isNotEmpty(serviceSubtaskResList)) {
                        serviceSubtaskResList.addAll(serviceSubtaskRes);
                    } else {
                        if (CollectionUtils.isEmpty(serviceSubtaskResList)) serviceSubtaskResList = serviceSubtaskRes;
                    }
                }
            }
        }
        List<ServiceSubtaskDetailRatioExport> detailList = serviceSubtaskService.getDetailRatio(questionResultVO, serviceSubtaskResList);
        // æŒ‰ questiontext åˆ†ç»„后转换为 QuestionResultVO
        List<QuestionResultDTO> result = new ArrayList<>();
        if (!detailList.isEmpty()) {
            Map<String, List<ServiceSubtaskDetailRatioExport>> groupedMap = detailList.stream().collect(Collectors.groupingBy(ServiceSubtaskDetailRatioExport::getQuestiontext));
        if (CollectionUtils.isNotEmpty(serviceSubtaskResList)) {
            List<ServiceSubtaskDetailRatioExport> detailList = serviceSubtaskService.getDetailRatio(sltdMydTotalVO, serviceSubtaskResList);
            groupedMap.forEach((questionText, exportList) -> {
                QuestionResultDTO questionResultDTO = new QuestionResultDTO();
                questionResultDTO.setQeustionText(questionText);
                questionResultDTO.setSubtaskDetailRatioExportList(exportList);
                result.add(questionResultDTO);
            });
            if (CollectionUtils.isNotEmpty(detailList)) {
                Map<String, List<ServiceSubtaskDetailRatioExport>> groupedMap = detailList.stream().collect(Collectors.groupingBy(ServiceSubtaskDetailRatioExport::getQuestiontext));
                groupedMap.forEach((questionText, exportList) -> {
                    QuestionResultDTO questionResultDTO = new QuestionResultDTO();
                    questionResultDTO.setQeustionText(questionText);
                    questionResultDTO.setSubtaskDetailRatioExportList(exportList);
                    BigDecimal allCount = new BigDecimal("0");
                    BigDecimal allScore = new BigDecimal("0.00");
                    for (ServiceSubtaskDetailRatioExport ssdre : exportList) {
                        if (StringUtils.isNotEmpty(ssdre.getCount()))
                            allCount.add(BigDecimal.valueOf(Long.valueOf(ssdre.getCount())));
                        allScore.add(BigDecimal.valueOf(Double.valueOf(ssdre.getScore())));
                    }
                    if (allCount.compareTo(BigDecimal.ZERO) > 0)
                        questionResultDTO.setAvgScore(allScore.divide(allCount, 2).toString());
                    result.add(questionResultDTO);
                });
            }
        }
        return success(result);
@@ -240,4 +268,17 @@
    public Map<String, Object> statQuestionOptionByKsOrBq(@RequestBody QuestionCountKsOrBqVO questionResultVO) {
        return success(serviceSubtaskService.statQuestionOptionByKsOrBq(questionResultVO));
    }
    @ApiOperation("省立同德患者满意度趋势")
    @PostMapping("/mydTrend")
    public Map<String, Object> mydTrend(@RequestBody MydTrendReqVO mydTrendReqVO) {
        return success(serviceSubtaskService.mydTrend(mydTrendReqVO));
    }
    @ApiOperation("省立同德患者满意度维护")
    @PostMapping("/sltdMydTotalByDimension")
    public Map<String, Object> sltdMydTotalByDimension(@RequestBody MydTrendReqVO mydTrendReqVO) {
        return success(serviceSubtaskService.sltdMydTotalByDimension(mydTrendReqVO));
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -20,6 +20,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.view.RedirectView;
@@ -58,6 +59,9 @@
    @Autowired
    @Qualifier("sysUserDeptSystemMapper")
    private SysUserDeptMapper sysUserDeptMapper;
    @Value("${spring.profiles.active}")
    private String active;
//    @Value("${wx_appid}")
//    private String wxAppid;
@@ -125,14 +129,21 @@
//    @IpWhitelist
    @GetMapping("/SSOLogin")
    public RedirectView SSOLogin(@RequestParam(required = false) String campusid, @RequestParam(required = false) String deptId, @RequestParam(required = false) String systype, String orgid, String userName, String token) {
      log.info("SSOLogin的入参,campusid:{},  deptId:{},  systype:{},  orgid:{},  userName:{},  token:{}",campusid,deptId,systype,orgid,userName,token);
        log.info("SSOLogin的入参,campusid:{},  deptId:{},  systype:{},  orgid:{},  userName:{},  token:{}", campusid, deptId, systype, orgid, userName, token);
        if (StringUtils.isEmpty(userName) && StringUtils.isEmpty(token) && StringUtils.isEmpty(orgid)) {
            throw new BaseException("参数不能为空");
        }
        String path = null;
        if (StringUtils.isEmpty(systype)) path = sysConfigService.selectConfigByKey("sys.qddz");
        else path = sysConfigService.selectConfigByKey("sys.qddz.yd");
        log.info("qddz的查询值为,path:{}",path);
        if (active.equals("nhfy")){
            //南华附一的,先不走免登,直接跳到登陆页
            path = sysConfigService.selectConfigByKey("sys.qddz.yd");
            log.info("【NHFYSSO登录】重定向地址:{}", path);
            return buildRedirect(path);
        }
            log.info("qddz的查询值为,path:{}", path);
        if (StringUtils.isEmpty(path)) {
            throw new BaseException("请配置前端地址");
ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
@@ -2,6 +2,8 @@
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.entity.SysDictData;
@@ -10,11 +12,10 @@
/**
 * å­—典工具类
 *
 *
 * @author ruoyi
 */
public class DictUtils
{
public class DictUtils {
    /**
     * åˆ†éš”符
     */
@@ -22,26 +23,23 @@
    /**
     * è®¾ç½®å­—典缓存
     *
     * @param key å‚æ•°é”®
     *
     * @param key       å‚æ•°é”®
     * @param dictDatas å­—典数据列表
     */
    public static void setDictCache(String key, List<SysDictData> dictDatas)
    {
        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
    public static void setDictCache(String key, List<SysDictData> dictDatas) {
        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas, 120, TimeUnit.MINUTES);
    }
    /**
     * èŽ·å–å­—å…¸ç¼“å­˜
     *
     *
     * @param key å‚æ•°é”®
     * @return dictDatas å­—典数据列表
     */
    public static List<SysDictData> getDictCache(String key)
    {
    public static List<SysDictData> getDictCache(String key) {
        JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
        if (StringUtils.isNotNull(arrayCache))
        {
        if (StringUtils.isNotNull(arrayCache)) {
            return arrayCache.toList(SysDictData.class);
        }
        return null;
@@ -49,63 +47,51 @@
    /**
     * æ ¹æ®å­—典类型和字典值获取字典标签
     *
     * @param dictType å­—典类型
     *
     * @param dictType  å­—典类型
     * @param dictValue å­—典值
     * @return å­—典标签
     */
    public static String getDictLabel(String dictType, String dictValue)
    {
    public static String getDictLabel(String dictType, String dictValue) {
        return getDictLabel(dictType, dictValue, SEPARATOR);
    }
    /**
     * æ ¹æ®å­—典类型和字典标签获取字典值
     *
     * @param dictType å­—典类型
     *
     * @param dictType  å­—典类型
     * @param dictLabel å­—典标签
     * @return å­—典值
     */
    public static String getDictValue(String dictType, String dictLabel)
    {
    public static String getDictValue(String dictType, String dictLabel) {
        return getDictValue(dictType, dictLabel, SEPARATOR);
    }
    /**
     * æ ¹æ®å­—典类型和字典值获取字典标签
     *
     * @param dictType å­—典类型
     *
     * @param dictType  å­—典类型
     * @param dictValue å­—典值
     * @param separator åˆ†éš”符
     * @return å­—典标签
     */
    public static String getDictLabel(String dictType, String dictValue, String separator)
    {
    public static String getDictLabel(String dictType, String dictValue, String separator) {
        StringBuilder propertyString = new StringBuilder();
        List<SysDictData> datas = getDictCache(dictType);
        if (StringUtils.isNotNull(datas))
        {
            if (StringUtils.containsAny(separator, dictValue))
            {
                for (SysDictData dict : datas)
                {
                    for (String value : dictValue.split(separator))
                    {
                        if (value.equals(dict.getDictValue()))
                        {
        if (StringUtils.isNotNull(datas)) {
            if (StringUtils.containsAny(separator, dictValue)) {
                for (SysDictData dict : datas) {
                    for (String value : dictValue.split(separator)) {
                        if (value.equals(dict.getDictValue())) {
                            propertyString.append(dict.getDictLabel()).append(separator);
                            break;
                        }
                    }
                }
            }
            else
            {
                for (SysDictData dict : datas)
                {
                    if (dictValue.equals(dict.getDictValue()))
                    {
            } else {
                for (SysDictData dict : datas) {
                    if (dictValue.equals(dict.getDictValue())) {
                        return dict.getDictLabel();
                    }
                }
@@ -116,37 +102,28 @@
    /**
     * æ ¹æ®å­—典类型和字典标签获取字典值
     *
     * @param dictType å­—典类型
     *
     * @param dictType  å­—典类型
     * @param dictLabel å­—典标签
     * @param separator åˆ†éš”符
     * @return å­—典值
     */
    public static String getDictValue(String dictType, String dictLabel, String separator)
    {
    public static String getDictValue(String dictType, String dictLabel, String separator) {
        StringBuilder propertyString = new StringBuilder();
        List<SysDictData> datas = getDictCache(dictType);
        if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
        {
            for (SysDictData dict : datas)
            {
                for (String label : dictLabel.split(separator))
                {
                    if (label.equals(dict.getDictLabel()))
                    {
        if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) {
            for (SysDictData dict : datas) {
                for (String label : dictLabel.split(separator)) {
                    if (label.equals(dict.getDictLabel())) {
                        propertyString.append(dict.getDictValue()).append(separator);
                        break;
                    }
                }
            }
        }
        else
        {
            for (SysDictData dict : datas)
            {
                if (dictLabel.equals(dict.getDictLabel()))
                {
        } else {
            for (SysDictData dict : datas) {
                if (dictLabel.equals(dict.getDictLabel())) {
                    return dict.getDictValue();
                }
            }
@@ -156,31 +133,28 @@
    /**
     * åˆ é™¤æŒ‡å®šå­—典缓存
     *
     *
     * @param key å­—典键
     */
    public static void removeDictCache(String key)
    {
    public static void removeDictCache(String key) {
        SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
    }
    /**
     * æ¸…空字典缓存
     */
    public static void clearDictCache()
    {
    public static void clearDictCache() {
        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");
        SpringUtils.getBean(RedisCache.class).deleteObject(keys);
    }
    /**
     * è®¾ç½®cache key
     *
     *
     * @param configKey å‚æ•°é”®
     * @return ç¼“存键key
     */
    public static String getCacheKey(String configKey)
    {
    public static String getCacheKey(String configKey) {
        return CacheConstants.SYS_DICT_KEY + configKey;
    }
}
smartor/src/main/java/com/smartor/domain/DTO/MydTrendReqDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package com.smartor.domain.DTO;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
 * æ»¡æ„åº¦è¶‹åŠ¿è¯·æ±‚å¯¹è±¡
 *
 * @author ls
 * @date 2026-09-11
 */
@ApiModel(value = "MydTrendReqVO", description = "满意度趋势请求对象")
@Data
public class MydTrendReqDTO extends BaseEntity {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "分类")
    private String period;
    @ApiModelProperty(value = "开始日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date startDate;
    @ApiModelProperty(value = "结束日期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date endDate;
    @ApiModelProperty(value = "维度")
    private String dimension;
    @ApiModelProperty(value = "总分(平均分)")
    private String totalScore;
}
smartor/src/main/java/com/smartor/domain/DTO/QuestionCountKsOrBqDTO.java
@@ -24,7 +24,7 @@
     * é—®å·é¢˜ç›®
     */
    @ApiModelProperty(value = "问卷题目")
    private String qeustionText;
    private String questionText;
    /**
     * é—®å·ç»“果集合
smartor/src/main/java/com/smartor/domain/DTO/QuestionResultDTO.java
@@ -27,6 +27,12 @@
    private String qeustionText;
    /**
     * å¹³å‡åˆ†
     */
    @ApiModelProperty(value = "平均分")
    private String avgScore;
    /**
     * é—®å·ç»“果集合
     */
    @ApiModelProperty(value = "问卷结果集合")
smartor/src/main/java/com/smartor/domain/VO/MydTrendReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
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 io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
 * æ»¡æ„åº¦è¶‹åŠ¿è¯·æ±‚å¯¹è±¡
 *
 * @author ls
 * @date 2026-09-11
 */
@ApiModel(value = "MydTrendReqVO", description = "满意度趋势请求对象")
@Data
public class MydTrendReqVO extends BaseEntity {
    private static final long serialVersionUID = 1L;
    /**
     * å¼€å§‹å‡ºé™¢æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "开始日期")
    private Date startFinishTime;
    /**
     * ç»“束出院日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束日期")
    private Date endFinishTime;
    @ApiModelProperty(value = "区间类型:天,周,月,年")
    private String type;
    @ApiModelProperty(value = "维度类型:1:维度  2:院区")
    private String dimensionType;
}
smartor/src/main/java/com/smartor/domain/VO/QuestionCountKsOrBqVO.java
@@ -50,7 +50,6 @@
    @ApiModelProperty(value = "部门code集合")
    private List<String> leaveldeptcodes;
    /**
     * å¼€å§‹å‡ºé™¢æ—¥æœŸ
     */
@@ -70,4 +69,7 @@
    @ApiModelProperty(value = "问题类型(1.单选 2多选 3问答 4填空  5其它)")
    private String valueType;
    @ApiModelProperty(value = "任务模板ID")
    private String taskTemplateid;
}
smartor/src/main/java/com/smartor/domain/VO/ServiceSubtaskVO.java
@@ -8,6 +8,7 @@
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
@@ -296,6 +297,7 @@
     * å®Œæˆæ—¶é—´
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "完成时间(开始查询)")
    private Date finishtimeStart;
@@ -303,6 +305,7 @@
     * å®Œæˆæ—¶é—´(结束查询)
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "完成时间(结束查询)")
    private Date finishtimeEnd;
smartor/src/main/java/com/smartor/domain/VO/SltdMydTotalVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
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 io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
 * é—®é¢˜ç»“æžœDTO
 *
 * @author ruoyi
 * @date 2024-02-02
 */
@ApiModel(value = "QuestionResultVO", description = "问题结果VO")
@Data
public class SltdMydTotalVO 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 = "出院病区集合(和部门二选一必填)")
    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 startOutHospTime;
    /**
     * ç»“束出院日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束出院日期")
    private Date endOutHospTime;
    /**
     * å¼€å§‹å‡ºé™¢æ—¥æœŸ
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "开始完成日期")
    private Date startFinishTime;
    /**
     * ç»“束出院日期
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @ApiModelProperty(value = "结束完成日期")
    private Date endFinishTime;
    /**
     * é—®é¢˜å†…容
     */
    @ApiModelProperty(value = "问题内容")
    private String questionContent;
    /**
     * é—®é¢˜å†…容
     */
    @ApiModelProperty(value = "开始查询分数")
    private Double startScore;
    /**
     * é—®é¢˜å†…容
     */
    @ApiModelProperty(value = "结束查询分数")
    private Double endScore;
    /**
     * æœåŠ¡ç±»åž‹(1、监测评估;2、出院随访;3、门诊随访;4、宣教关怀;5、复诊通知;6、满意度调查;7、患者报告; 8、其他通知)
     */
    @Excel(name = "服务类型(1、监测评估;2、出院随访;3、门诊随访;4、宣教关怀;5、复诊管理;6、满意度调查;7、患者报告; 8、其他通知 9体检随访 10.医技随访  11,影像专科随访  12、心电专科随访, 13专科随访)")
    @ApiModelProperty(value = "必填服务类型(1、监测评估;2、出院随访;3、门诊随访;4、宣教关怀;5、复诊管理;6、满意度调查;7、患者报告; 8、其他通知 9体检随访 10.医技随访  11,影像专科随访  12、心电专科随访, 13专科随访)")
    private List<String> serviceTypeList;
    @ApiModelProperty(value = "问题类型(1.单选 2多选 3问答 4填空  5其它)")
    private String valueType;
}
smartor/src/main/java/com/smartor/mapper/ServiceSubtaskMapper.java
@@ -1,6 +1,7 @@
package com.smartor.mapper;
import com.smartor.domain.*;
import com.smartor.domain.DTO.MydTrendReqDTO;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.VO.PatSatisfactionReqVO;
import com.smartor.domain.VO.HeLibraryCountVO;
@@ -81,6 +82,12 @@
     * @param loopCount  è½®æ¬¡ï¼ˆ0=首轮)
     */
    public int countActiveByScheduleIdAndLoop(@Param("scheduleId") Long scheduleId, @Param("loopCount") Long loopCount);
    public  List<MydTrendReqDTO> mydTrend(@Param("startFinishTime") Date startFinishTime, @Param("endFinishTime") Date endFinishTime, @Param("type") String type);
    public  List<MydTrendReqDTO> sltdMydTotalByDimension(@Param("startFinishTime") Date startFinishTime, @Param("endFinishTime") Date endFinishTime, @Param("type") String type);
    public  List<MydTrendReqDTO> sltdMydTotalByYQ(@Param("startFinishTime") Date startFinishTime, @Param("endFinishTime") Date endFinishTime, @Param("type") String type);
    /**
     * ä»»åŠ¡ç»„ï¼ˆappltype=5):拉取某一轮次的全部 subtask(用于克隆到下一轮)。
@@ -264,7 +271,7 @@
     * @param endOutHospTime
     * @return
     */
    List<ServiceSubtaskDetailRatioExport> statQuestionOption(@Param("taskIds") List<Long> taskIds, @Param("startOutHospTime") Date startOutHospTime, @Param("endOutHospTime") Date endOutHospTime, @Param("scoreStart") Double scoreStart, @Param("scoreEnd") Double scoreEnd, @Param("questiontext") String questiontext, @Param("valueType") String valueType);
    List<ServiceSubtaskDetailRatioExport> statQuestionOption(@Param("taskIds") List<Long> taskIds, @Param("startOutHospTime") Date startOutHospTime, @Param("endOutHospTime") Date endOutHospTime, @Param("startFinishTime") Date startFinishTime, @Param("endFinishTime") Date endFinishTime, @Param("scoreStart") Double scoreStart, @Param("scoreEnd") Double scoreEnd, @Param("questiontext") String questiontext, @Param("valueType") String valueType);
    /**
     * æ ¹æ®å­ä»»åŠ¡ ID ç»Ÿè®¡é—®é¢˜çš„选项的百分比(用于满意度统计 serviceType=6)
@@ -274,7 +281,7 @@
     * @param endOutHospTime
     * @return
     */
    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);
    List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(@Param("subtaskIds") List<Long> subtaskIds, @Param("startOutHospTime") Date startOutHospTime, @Param("endOutHospTime") Date endOutHospTime, @Param("startFinishTime") Date startFinishTime, @Param("endFinishTime") Date endFinishTime, @Param("scoreStart") Double scoreStart, @Param("scoreEnd") Double scoreEnd, @Param("questiontext") String questiontext, @Param("valueType") String valueType);
    /**
     * æ ¹æ®ç§‘室、病区、题目类型统计的科室、病区评分
smartor/src/main/java/com/smartor/service/IServiceSubtaskService.java
@@ -2,6 +2,7 @@
import com.ruoyi.common.core.domain.AjaxResult;
import com.smartor.domain.*;
import com.smartor.domain.DTO.MydTrendReqDTO;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.DTO.QuestionResultDTO;
import com.smartor.domain.ServiceSubtask;
@@ -143,7 +144,7 @@
     * @param serviceSubtaskRes
     * @return
     */
    public List<ServiceSubtaskDetailRatioExport> getDetailRatio(QuestionResultVO questionResultVO, List<ServiceSubtaskRes> serviceSubtaskRes);
    public List<ServiceSubtaskDetailRatioExport> getDetailRatio(SltdMydTotalVO sltdMydTotalVO, List<ServiceSubtaskRes> serviceSubtaskRes);
    /**
@@ -224,7 +225,7 @@
     * @param taskIds
     * @return
     */
    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 startFinishTime, Date endFinishTime, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType);
    /**
     * æ ¹æ®å­ä»»åŠ¡ ID ç»Ÿè®¡é—®é¢˜çš„选项的百分比(用于满意度统计 serviceType=6)
@@ -232,11 +233,20 @@
     * @param subtaskIds å­ä»»åŠ¡ ID åˆ—表
     * @return
     */
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType);
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, Date startFinishTime, Date endFinishTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType);
    public List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO questionCountKsOrBqVO);
    public  Map<String, Map<String, List<QuestionCountKsOrBqDTO>>> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO questionCountKsOrBqVO);
    public String scanGenerateSubtask(ServiceTask serviceTaskVo);
    public List<MydTrendReqDTO> mydTrend(MydTrendReqVO mydTrendReqVO);
    /**
     * æ ¹æ®æ—¶é—´ç»™åº¦è¿›è¡Œå¯¹æ¯”满意度分数
     * @param mydTrendReqVO
     * @return
     */
    public List<MydTrendReqDTO> sltdMydTotalByDimension(MydTrendReqVO mydTrendReqVO);
    public Integer matchOptionIndex(String url, String questionText, String voiceText, List<IvrTaskTemplateTargetoption> options, String uuid);
}
smartor/src/main/java/com/smartor/service/impl/ServiceSLTDHealthcareRecordServiceImpl.java
@@ -8,6 +8,7 @@
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.SysUserDept;
import com.ruoyi.common.core.domain.entity.SysUserRole;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.smartor.common.enums.EmergencyLevelEnum;
import com.smartor.common.enums.ImportFlagEnum;
@@ -85,6 +86,10 @@
    @Value("${spring.profiles.active}")
    private String active;
    @Autowired
    private ServiceSubtaskServiceImpl serviceSubtaskServiceImpl;
    @Autowired
    private ServiceSubtaskMapper serviceSubtaskMapper;
    @Override
    public List<ServiceSLTDInhospResDTO> queryHealthcareRecordList(ServiceSLTDInhospReqVO reqVO) {
@@ -709,6 +714,23 @@
                    queryInhosp.setInhospstate("1");
                    patMedInhospList = patMedInhospService.selectPatMedInhosp(queryInhosp);
                    if (CollectionUtils.isNotEmpty(patMedInhospList)) {
                        //如果不为空,则将入院时间进行更新
                        PatMedInhosp pmOut = patMedInhospList.get(0);
                        PatMedInhosp pmIn = existingInhosps.get(0);
                        pmOut.setStarttime(pmIn.getStarttime());
                        pmOut.setUpdateTime(new Date());
                        patMedInhospService.updatePatMedInhosp(pmOut);
                        //省立同德需要将开始日期与入院日期相等的任务,改成不执行
                        try {
                            if ("sltd".equals(active) && DateUtils.isSameDay(pmOut.getStarttime(), pmIn.getEndtime())) {
                                ServiceSubtask serviceSubtask = new ServiceSubtask();
                                serviceSubtask.setInhospid(pmOut.getInhospid());
                                serviceSubtask.setSendstate(4L);
                                serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
                            }
                        } catch (Exception e) {
                            log.error("将出院时间等于入院时间的inhospid的任务更新失败了, inhospid={}", pmOut.getInhospid(), e);
                        }
                        return;
                    }
                }
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskAnswerServiceImpl.java
@@ -168,7 +168,7 @@
     * ä¿å­˜é—®å·ç­”案 (异步处理,快速返回)
     *
     * @param serviceSubTaskAnswerReq ç­”案请求
     * @param flag æ ‡å¿—位
     * @param flag                    æ ‡å¿—位
     * @return ç»“æžœ
     */
    @Override
@@ -177,239 +177,240 @@
        String threadName = Thread.currentThread().getName();
        log.info("[{}] å¼€å§‹å¼‚步处理保存问卷答案", threadName);
        try {
        //参数解密
        Long tid = null;
        Long pid = null;
        Long subid = null;
        if (ObjectUtils.isNotEmpty(serviceSubTaskAnswerReq)) {
            RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
            //参数解密
            Long tid = null;
            Long pid = null;
            Long subid = null;
            if (ObjectUtils.isNotEmpty(serviceSubTaskAnswerReq)) {
                RSAPublicKeyExample rsaPublicKeyExample = new RSAPublicKeyExample();
            if (flag == 0) {
                tid = Long.valueOf(rsaPublicKeyExample.decryptedData(serviceSubTaskAnswerReq.getParam1(), pri_key));
                pid = Long.valueOf(rsaPublicKeyExample.decryptedData(serviceSubTaskAnswerReq.getParam2(), pri_key));
                if (StringUtils.isNotEmpty(serviceSubTaskAnswerReq.getParam6()))
                    subid = Long.valueOf(rsaPublicKeyExample.decryptedData(serviceSubTaskAnswerReq.getParam6(), pri_key));
            } else if (flag == 1) {
                tid = Long.valueOf(serviceSubTaskAnswerReq.getParam1());
                pid = Long.valueOf(serviceSubTaskAnswerReq.getParam2());
                subid = Long.valueOf(serviceSubTaskAnswerReq.getParam6());
                if (flag == 0) {
                    tid = Long.valueOf(rsaPublicKeyExample.decryptedData(serviceSubTaskAnswerReq.getParam1(), pri_key));
                    pid = Long.valueOf(rsaPublicKeyExample.decryptedData(serviceSubTaskAnswerReq.getParam2(), pri_key));
                    if (StringUtils.isNotEmpty(serviceSubTaskAnswerReq.getParam6()))
                        subid = Long.valueOf(rsaPublicKeyExample.decryptedData(serviceSubTaskAnswerReq.getParam6(), pri_key));
                } else if (flag == 1) {
                    tid = Long.valueOf(serviceSubTaskAnswerReq.getParam1());
                    pid = Long.valueOf(serviceSubTaskAnswerReq.getParam2());
                    subid = Long.valueOf(serviceSubTaskAnswerReq.getParam6());
                }
            }
        }
        //根据 PID、TID、SUBID æž„建需要处理的 cache key
        String scriptCacheKeyPrefix = pid + "-" + tid + "-" + subid;
        Set<String> targetKeys = new HashSet<>();
            //根据 PID、TID、SUBID æž„建需要处理的 cache key
            String scriptCacheKeyPrefix = pid + "-" + tid + "-" + subid;
            Set<String> targetKeys = new HashSet<>();
        if (serviceSubTaskAnswerReq != null && serviceSubTaskAnswerReq.getType() != null) {
            if (serviceSubTaskAnswerReq.getType() == 2) {
                targetKeys.add(scriptCacheKeyPrefix + "-WJscriptCache");
            } else if (serviceSubTaskAnswerReq.getType() == 1) {
                targetKeys.add(scriptCacheKeyPrefix + "-SFscriptCache");
            if (serviceSubTaskAnswerReq != null && serviceSubTaskAnswerReq.getType() != null) {
                if (serviceSubTaskAnswerReq.getType() == 2) {
                    targetKeys.add(scriptCacheKeyPrefix + "-WJscriptCache");
                } else if (serviceSubTaskAnswerReq.getType() == 1) {
                    targetKeys.add(scriptCacheKeyPrefix + "-SFscriptCache");
                }
            } else {
                //如果没有 type,则遍历所有 key(保留原有兼容性)
                Set<String> allKeys = redisCache.getAllKeys();
                for (String key : allKeys) {
                    try {
                        if (key.contains(scriptCacheKeyPrefix) && (key.endsWith("-WJscriptCache") || key.endsWith("-SFscriptCache"))) {
                            targetKeys.add(key);
                        }
                    } catch (Exception e) {
                        continue;
                    }
                }
            }
        } else {
            //如果没有 type,则遍历所有 key(保留原有兼容性)
            Set<String> allKeys = redisCache.getAllKeys();
            for (String key : allKeys) {
            //用于批量更新的子任务列表(避免在循环中重复查询)
            Map<String, ServiceSubtask> subtaskCache = new HashMap<>();
            String subtaskCacheKey = subid != null ? subid.toString() : pid + "-" + tid;
            //先查询一次子任务信息
            ServiceSubtaskEntity ssVO = new ServiceSubtaskEntity();
            if (subid != null) {
                ssVO.setSubId(subid);
            } else {
                ssVO.setTaskid(tid);
                ssVO.setPatid(pid);
            }
            List<ServiceSubtask> initialSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(ssVO);
            if (CollectionUtils.isNotEmpty(initialSubtaskList)) {
                subtaskCache.put(subtaskCacheKey, initialSubtaskList.get(0));
            }
            String score = "0";
            Long nextScriptno = null;
            aa:
            for (String key : targetKeys) {
                String[] split = key.split("-");
                //先判断,是不是当前提交人的,不是当前提交人的,跳过
                try {
                    if (key.contains(scriptCacheKeyPrefix) && (key.endsWith("-WJscriptCache") || key.endsWith("-SFscriptCache"))) {
                        targetKeys.add(key);
                    if (ObjectUtils.isNotEmpty(split[0]) && ObjectUtils.isNotEmpty(split[1]) && !Long.valueOf(split[0]).equals(pid) && !Long.valueOf(split[1]).equals(tid) && !Objects.isNull(split[2]) && !Long.valueOf(split[2]).equals(subid)) {
                        continue;
                    }
                } catch (Exception e) {
                    //这里之所以要处理异常,是因为有的KEY就不是我们要的KEY,没有去截取;有异常不处理,直接下一个
                    continue;
                }
            }
        }
                if (key.contains("-WJscriptCache")) {
                    List<SvyTaskTemplateScriptVO> cacheList = redisCache.getCacheList(key);
                    cacheList.sort(Comparator.comparingLong(SvyTaskTemplateScriptVO::getSort));
                    log.info("问卷回答结果:{}", CollectionUtils.isEmpty(cacheList) ? null : cacheList.size());
        //用于批量更新的子任务列表(避免在循环中重复查询)
        Map<String, ServiceSubtask> subtaskCache = new HashMap<>();
        String subtaskCacheKey = subid != null ? subid.toString() : pid + "-" + tid;
                    //校验一下题的序号是否有问题 (如果根据选项无序跳转,就会导致错误)
                    cacheList = checkQuestionSort(cacheList);
        //先查询一次子任务信息
        ServiceSubtaskEntity ssVO = new ServiceSubtaskEntity();
        if (subid != null) {
            ssVO.setSubId(subid);
        } else {
            ssVO.setTaskid(tid);
            ssVO.setPatid(pid);
        }
        List<ServiceSubtask> initialSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(ssVO);
        if (CollectionUtils.isNotEmpty(initialSubtaskList)) {
            subtaskCache.put(subtaskCacheKey, initialSubtaskList.get(0));
        }
                    for (int i = 0; i < cacheList.size(); i++) {
                        if (i == 0) {
                            //这个时间要找到第一题
                            for (SvyTaskTemplateScriptVO svyTaskTemplateScriptVO : cacheList) {
                                if (svyTaskTemplateScriptVO.getSort() == 1L) {
                                    //说明是第一题
                                    List<SvyTaskTemplateTargetoption> svyTaskTemplateTargetoptions = cacheList.get(0).getSvyTaskTemplateTargetoptions();
                                    svyTaskTemplateScriptVO.setSvyTaskTemplateTargetoptions(svyTaskTemplateTargetoptions);
                                    Map<String, String> map = setWJInfo(svyTaskTemplateScriptVO, tid, pid, subid);
                                    if (map == null) continue aa;
                                    if (!Objects.isNull(map.get("nextScriptNo")))
                                        nextScriptno = Long.valueOf(map.get("nextScriptNo"));
                                    if (score == null || score.isEmpty()) {
                                        score = map.get("score");
                                    } else {
                                        score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
                                    }
                                }
                            }
        String score = "0";
        Long nextScriptno = null;
        aa:
        for (String key : targetKeys) {
            String[] split = key.split("-");
            //先判断,是不是当前提交人的,不是当前提交人的,跳过
            try {
                if (ObjectUtils.isNotEmpty(split[0]) && ObjectUtils.isNotEmpty(split[1]) && !Long.valueOf(split[0]).equals(pid) && !Long.valueOf(split[1]).equals(tid) && !Objects.isNull(split[2]) && !Long.valueOf(split[2]).equals(subid)) {
                    continue;
                }
            } catch (Exception e) {
                //这里之所以要处理异常,是因为有的KEY就不是我们要的KEY,没有去截取;有异常不处理,直接下一个
                continue;
            }
            if (key.contains("-WJscriptCache")) {
                List<SvyTaskTemplateScriptVO> cacheList = redisCache.getCacheList(key);
                cacheList.sort(Comparator.comparingLong(SvyTaskTemplateScriptVO::getSort));
                log.info("问卷回答结果:{}", CollectionUtils.isEmpty(cacheList) ? null : cacheList.size());
                        } else {
                            SvyTaskTemplateScriptVO svyTaskTemplateScriptVO = cacheList.get(i);
                            log.info("svyTaskTemplateScriptVO的信息为:{},i的值为:{}", svyTaskTemplateScriptVO.getScriptno(), i);
                            List<SvyTaskTemplateTargetoption> svyTaskTemplateTargetoptions = cacheList.get(i).getSvyTaskTemplateTargetoptions();
                            svyTaskTemplateScriptVO.setSvyTaskTemplateTargetoptions(svyTaskTemplateTargetoptions);
                //校验一下题的序号是否有问题 (如果根据选项无序跳转,就会导致错误)
                cacheList = checkQuestionSort(cacheList);
                for (int i = 0; i < cacheList.size(); i++) {
                    if (i == 0) {
                        //这个时间要找到第一题
                        for (SvyTaskTemplateScriptVO svyTaskTemplateScriptVO : cacheList) {
                            if (svyTaskTemplateScriptVO.getSort() == 1L) {
                                //说明是第一题
                                List<SvyTaskTemplateTargetoption> svyTaskTemplateTargetoptions = cacheList.get(0).getSvyTaskTemplateTargetoptions();
                                svyTaskTemplateScriptVO.setSvyTaskTemplateTargetoptions(svyTaskTemplateTargetoptions);
                                Map<String, String> map = setWJInfo(svyTaskTemplateScriptVO, tid, pid, subid);
                                if (map == null) continue aa;
                            if (svyTaskTemplateScriptVO.getSort() != null && svyTaskTemplateScriptVO.getSort().equals(nextScriptno)) {
                                Map<String, String> map = setWJInfo(svyTaskTemplateScriptVO, Long.valueOf(split[1]), Long.valueOf(split[0]), Objects.isNull(split[2]) ? null : Long.valueOf(split[2]));
                                log.error("nextScriptNo的信息为:{}", map.get("nextScriptNo"));
                                if (!Objects.isNull(map.get("nextScriptNo")))
                                    nextScriptno = Long.valueOf(map.get("nextScriptNo"));
                                if (score == null || score.isEmpty()) {
                                if (score == null) {
                                    score = map.get("score");
                                } else {
                                    score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
                                }
                            }
                        }
                    } else {
                        SvyTaskTemplateScriptVO svyTaskTemplateScriptVO = cacheList.get(i);
                        log.info("svyTaskTemplateScriptVO的信息为:{},i的值为:{}", svyTaskTemplateScriptVO.getScriptno(), i);
                        List<SvyTaskTemplateTargetoption> svyTaskTemplateTargetoptions = cacheList.get(i).getSvyTaskTemplateTargetoptions();
                        svyTaskTemplateScriptVO.setSvyTaskTemplateTargetoptions(svyTaskTemplateTargetoptions);
                        if (svyTaskTemplateScriptVO.getSort() != null && svyTaskTemplateScriptVO.getSort().equals(nextScriptno)) {
                            Map<String, String> map = setWJInfo(svyTaskTemplateScriptVO, Long.valueOf(split[1]), Long.valueOf(split[0]), Objects.isNull(split[2]) ? null : Long.valueOf(split[2]));
                            log.error("nextScriptNo的信息为:{}", map.get("nextScriptNo"));
                            if (!Objects.isNull(map.get("nextScriptNo")))
                                nextScriptno = Long.valueOf(map.get("nextScriptNo"));
                            if (score == null) {
                                score = map.get("score");
                            } else {
                                score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
                            }
                        }
                    }
                }
            } else if (key.contains("-SFscriptCache")) {
                List<IvrTaskTemplateScriptVO> cacheList = redisCache.getCacheList(key);
                cacheList.sort(Comparator.comparingLong(IvrTaskTemplateScriptVO::getSort));
                log.error("电话随访问卷回答结果:{}", CollectionUtils.isEmpty(cacheList) ? null : cacheList.size());
                for (int i = 0; i < cacheList.size(); i++) {
                    if (i == 0) {
                        //这个时间要找到第一题
                        for (IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO : cacheList) {
                            if (ivrTaskTemplateScriptVO.getSort() == 1L) {
                                //说明是第一题
                                List<IvrTaskTemplateTargetoption> ivrTaskTemplateTargetoptions = cacheList.get(0).getIvrTaskScriptTargetoptionList();
                                ivrTaskTemplateScriptVO.setIvrTaskScriptTargetoptionList(ivrTaskTemplateTargetoptions);
                                Map<String, String> map = setSFInfo(ivrTaskTemplateScriptVO, tid, pid, subid);
                } else if (key.contains("-SFscriptCache")) {
                    List<IvrTaskTemplateScriptVO> cacheList = redisCache.getCacheList(key);
                    cacheList.sort(Comparator.comparingLong(IvrTaskTemplateScriptVO::getSort));
                    log.error("电话随访问卷回答结果:{}", CollectionUtils.isEmpty(cacheList) ? null : cacheList.size());
                    for (int i = 0; i < cacheList.size(); i++) {
                        if (i == 0) {
                            //这个时间要找到第一题
                            for (IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO : cacheList) {
                                if (ivrTaskTemplateScriptVO.getSort() == 1L) {
                                    //说明是第一题
                                    List<IvrTaskTemplateTargetoption> ivrTaskTemplateTargetoptions = cacheList.get(0).getIvrTaskScriptTargetoptionList();
                                    ivrTaskTemplateScriptVO.setIvrTaskScriptTargetoptionList(ivrTaskTemplateTargetoptions);
                                    Map<String, String> map = setSFInfo(ivrTaskTemplateScriptVO, tid, pid, subid);
                                    if (!Objects.isNull(map.get("nextScriptNo")))
                                        nextScriptno = Long.valueOf(map.get("nextScriptNo"));
                                    if (score == null || score.isEmpty()) {
                                        score = map.get("score");
                                    } else {
                                        score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
                                    }
                                }
                            }
                        } else {
                            IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO = DtoConversionUtils.sourceToTarget(cacheList.get(i), IvrTaskTemplateScriptVO.class);
                            List<IvrTaskTemplateTargetoption> ivrTaskTemplateTargetoptions = DtoConversionUtils.sourceToTarget(cacheList.get(i).getIvrTaskScriptTargetoptionList(), IvrTaskTemplateTargetoption.class);
                            ivrTaskTemplateScriptVO.setIvrTaskScriptTargetoptionList(ivrTaskTemplateTargetoptions);
                            if (ivrTaskTemplateScriptVO.getSort() != null && Long.valueOf(ivrTaskTemplateScriptVO.getSort()).equals(nextScriptno)) {
                                Map<String, String> map = setSFInfo(ivrTaskTemplateScriptVO, Long.valueOf(split[1]), Long.valueOf(split[0]), Objects.isNull(split[2]) ? null : Long.valueOf(split[2]));
                                log.error("----nextScriptNo2的信息为:{}", map.get("nextScriptNo"));
                                if (!Objects.isNull(map.get("nextScriptNo")))
                                    nextScriptno = Long.valueOf(map.get("nextScriptNo"));
                                if (score == null || score.isEmpty()) {
                                if (score == null) {
                                    score = map.get("score");
                                } else {
                                    score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
                                }
                            }
                        }
                    } else {
                        IvrTaskTemplateScriptVO ivrTaskTemplateScriptVO = DtoConversionUtils.sourceToTarget(cacheList.get(i), IvrTaskTemplateScriptVO.class);
                        List<IvrTaskTemplateTargetoption> ivrTaskTemplateTargetoptions = DtoConversionUtils.sourceToTarget(cacheList.get(i).getIvrTaskScriptTargetoptionList(), IvrTaskTemplateTargetoption.class);
                        ivrTaskTemplateScriptVO.setIvrTaskScriptTargetoptionList(ivrTaskTemplateTargetoptions);
                        if (ivrTaskTemplateScriptVO.getSort() != null && Long.valueOf(ivrTaskTemplateScriptVO.getSort()).equals(nextScriptno)) {
                            Map<String, String> map = setSFInfo(ivrTaskTemplateScriptVO, Long.valueOf(split[1]), Long.valueOf(split[0]), Objects.isNull(split[2]) ? null : Long.valueOf(split[2]));
                            log.error("----nextScriptNo2的信息为:{}", map.get("nextScriptNo"));
                            if (!Objects.isNull(map.get("nextScriptNo")))
                                nextScriptno = Long.valueOf(map.get("nextScriptNo"));
                            if (score == null) {
                                score = map.get("score");
                            } else {
                                score = String.valueOf(Double.parseDouble(score) + Double.parseDouble(map.get("score")));
                            }
                        }
                    }
                }
            } else {
                continue;
            }
            //将该 key å’Œ value ä»Ž redis ä¸­ï¼Œåˆ é™¤
            redisCache.deleteObject(key);
            //查询出该任务中正在执行的患者信息(使用缓存)
            String currentSubtaskKey = subid != null ? subid.toString() : pid + "-" + tid;
            ServiceSubtask serviceSubtask;
            if (!subtaskCache.containsKey(currentSubtaskKey)) {
                ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
                if (subid != null) {
                    serviceSubtaskEntity.setSubId(subid);
                } else {
                    serviceSubtaskEntity.setTaskid(tid);
                    serviceSubtaskEntity.setPatid(pid);
                    continue;
                }
                //将该 key å’Œ value ä»Ž redis ä¸­ï¼Œåˆ é™¤
                redisCache.deleteObject(key);
                //查询出该任务中正在执行的患者信息(使用缓存)
                String currentSubtaskKey = subid != null ? subid.toString() : pid + "-" + tid;
                ServiceSubtask serviceSubtask;
                if (!subtaskCache.containsKey(currentSubtaskKey)) {
                    ServiceSubtaskEntity serviceSubtaskEntity = new ServiceSubtaskEntity();
                    if (subid != null) {
                        serviceSubtaskEntity.setSubId(subid);
                    } else {
                        serviceSubtaskEntity.setTaskid(tid);
                        serviceSubtaskEntity.setPatid(pid);
                    }
//            ssVO.setSendstate(3L);
                List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity);
                if (CollectionUtils.isNotEmpty(serviceSubtaskList)) {
                    serviceSubtask = serviceSubtaskList.get(0);
                    subtaskCache.put(currentSubtaskKey, serviceSubtask);
                    List<ServiceSubtask> serviceSubtaskList = serviceSubtaskMapper.selectServiceSubtaskList(serviceSubtaskEntity);
                    if (CollectionUtils.isNotEmpty(serviceSubtaskList)) {
                        serviceSubtask = serviceSubtaskList.get(0);
                        subtaskCache.put(currentSubtaskKey, serviceSubtask);
                    } else {
                        continue;
                    }
                } else {
                    continue;
                    serviceSubtask = subtaskCache.get(currentSubtaskKey);
                }
            } else {
                serviceSubtask = subtaskCache.get(currentSubtaskKey);
            }
            serviceSubtask.setIsabnormal(serviceSubTaskAnswerReq.getIsabnormal());
            serviceSubtask.setSendstate(6L);
            serviceSubtask.setExcep(serviceSubTaskAnswerReq.getExcep());
            serviceSubtask.setFinishtime(new Date());
            serviceSubtask.setUpdateTime(new Date());
            log.error("将该key和value从redis中,serviceSubtask的值为--------:{}", serviceSubtask);
            if (score != null && !score.isEmpty()) serviceSubtask.setScore(score);
            serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
                serviceSubtask.setIsabnormal(serviceSubTaskAnswerReq.getIsabnormal());
                serviceSubtask.setSendstate(6L);
                serviceSubtask.setExcep(serviceSubTaskAnswerReq.getExcep());
                serviceSubtask.setFinishtime(new Date());
                serviceSubtask.setUpdateTime(new Date());
                log.error("将该key和value从redis中,serviceSubtask的值为--------:{}", serviceSubtask);
                if (score != null && !score.isEmpty()) serviceSubtask.setScore(score);
                serviceSubtaskMapper.updateServiceSubtaskByCondition(serviceSubtask);
            //将当前发送状态改成 9 å®Œæˆï¼ˆç¼“å­˜ preachform æŸ¥è¯¢ï¼‰
            String currentPreachform = serviceSubtask.getCurrentPreachform();
            if (StringUtils.isNotEmpty(currentPreachform)) {
                ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
                serviceSubtaskPreachform.setPreachform(currentPreachform);
                if (subid != null) {
                    serviceSubtaskPreachform.setSubid(subid);
                } else {
                    Long id = serviceSubtask.getId();
                    Long tid_ = serviceSubtask.getTaskid();
                    if (id != null) {
                        serviceSubtaskPreachform.setSubid(id);
                    } else if (tid_ != null) {
                        serviceSubtaskPreachform.setTaskid(tid_);
                //将当前发送状态改成 9 å®Œæˆï¼ˆç¼“å­˜ preachform æŸ¥è¯¢ï¼‰
                String currentPreachform = serviceSubtask.getCurrentPreachform();
                if (StringUtils.isNotEmpty(currentPreachform)) {
                    ServiceSubtaskPreachform serviceSubtaskPreachform = new ServiceSubtaskPreachform();
                    serviceSubtaskPreachform.setPreachform(currentPreachform);
                    if (subid != null) {
                        serviceSubtaskPreachform.setSubid(subid);
                    } else {
                        Long id = serviceSubtask.getId();
                        Long tid_ = serviceSubtask.getTaskid();
                        if (id != null) {
                            serviceSubtaskPreachform.setSubid(id);
                        } else if (tid_ != null) {
                            serviceSubtaskPreachform.setTaskid(tid_);
                        }
                    }
                    List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
                    if (CollectionUtils.isNotEmpty(serviceSubtaskPreachforms)) {
                        ServiceSubtaskPreachform ssp = serviceSubtaskPreachforms.get(0);
                        ssp.setSendstate("9");
                        serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(ssp);
                    }
                }
                List<ServiceSubtaskPreachform> serviceSubtaskPreachforms = serviceSubtaskPreachformMapper.selectServiceSubtaskPreachformList(serviceSubtaskPreachform);
                if (CollectionUtils.isNotEmpty(serviceSubtaskPreachforms)) {
                    ServiceSubtaskPreachform ssp = serviceSubtaskPreachforms.get(0);
                    ssp.setSendstate("9");
                    serviceSubtaskPreachformMapper.updateServiceSubtaskPreachform(ssp);
                }
            }
            }
            log.info("[{}] å®Œæˆå¼‚步处理保存问卷答案", Thread.currentThread().getName());
            return 1;
        } catch (Exception e) {
            log.error("[{}] å¼‚步处理保存问卷答案发生异常 : {},请求的对象为:{}", Thread.currentThread().getName(), e.getMessage(), e, serviceSubTaskAnswerReq);
            throw new RuntimeException("保存问卷答案失败", e);
        }
        log.info("[{}] å®Œæˆå¼‚步处理保存问卷答案", Thread.currentThread().getName());
        return 1;
    } catch (Exception e) {
        log.error("[{}] å¼‚步处理保存问卷答案发生异常 : {},请求的对象为:{}", Thread.currentThread().getName(), e.getMessage(), e,serviceSubTaskAnswerReq);
        throw new RuntimeException("保存问卷答案失败", e);
    }
}
    @Override
    public Integer saveQuestionDetail(ServiceSubTaskCacheReq serviceSubTaskCacheReq, Long flag) {
        Long tid = Long.valueOf(serviceSubTaskCacheReq.getParam1());
@@ -1019,6 +1020,8 @@
        serviceSubtaskDetailVO.setQuestiontext(svyTaskTemplateScriptVO.getScriptContent());
        serviceSubtaskDetailVO.setIsMydException(svyTaskTemplateScriptVO.getIsMydException());
        serviceSubtaskDetailVO.setDimension(svyTaskTemplateScriptVO.getDimension());
        if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getScore()))
            serviceSubtaskDetailVO.setScore(svyTaskTemplateScriptVO.getScore().replaceFirst("^0+(?!$)", ""));
        serviceSubtaskDetailVO.setCategoryid(svyTaskTemplateScriptVO.getCategoryid());
        serviceSubtaskDetailVO.setTaskid(Long.valueOf(taskid));
        serviceSubtaskDetailVO.setTargetid(svyTaskTemplateScriptVO.getTargetid() != null ? svyTaskTemplateScriptVO.getTargetid().intValue() : null);
@@ -1069,16 +1072,15 @@
        String orgid = selectServiceSubtaskList.get(0).getOrgid();
        //景宁-随访异常提示 å…¶ä»–-异常满意度提示
        boolean addTrace = false;
        if(StringUtils.isNotEmpty(orgid) && orgid.equals("47255004333112711A1001")){
        if (StringUtils.isNotEmpty(orgid) && orgid.equals("47255004333112711A1001")) {
            if (stt != null) {
                addTrace = Long.valueOf(1L).equals(stt.getIsabnormal());
            }
        }else {
        } else {
            addTrace = StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getIsMydException());
        }
        //判断一下当前的问题是不是满意度问题,并且 dutyDeptCode æ˜¯å¦æœ‰å€¼ï¼Œå¹¶ä¸”选项是不是异常选项,如果全符合,则往满意度问题异常表新增
        if (StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getDutyDeptCode()) && stt != null && Long.valueOf(1L).equals(stt.getIsabnormal()) || StringUtils.isNotEmpty(svyTaskTemplateScriptVO.getDutyDeptCode())
                && addTrace) {
        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());
@@ -1357,16 +1359,15 @@
        String orgid = selectServiceSubtaskList.get(0).getOrgid();
        //景宁-随访异常提示 å…¶ä»–-异常满意度提示
        boolean addTrace = false;
        if(StringUtils.isNotEmpty(orgid) && orgid.equals("47255004333112711A1001")){
        if (StringUtils.isNotEmpty(orgid) && orgid.equals("47255004333112711A1001")) {
            if (stt != null) {
                addTrace = Long.valueOf(1L).equals(stt.getIsabnormal());
            }
        }else {
        } else {
            addTrace = StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getIsMydException());
        }
        //判断一下当前的问题是不是满意度问题,并且dutyDeptCode是否有值,并且选项是不是异常选项,如果全符合,则往满意度问题异常表新增
        if (StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getDutyDeptCode()) && 1 == stt.getIsabnormal() || StringUtils.isNotEmpty(ivrTaskTemplateScriptVO.getDutyDeptCode())
                && addTrace) {
        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
@@ -21,6 +21,7 @@
import com.smartor.common.MtSubmitSmUtil;
import com.smartor.common.ScheduleSubtaskBuilder;
import com.smartor.config.PhoneUtils;
import com.smartor.domain.DTO.MydTrendReqDTO;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.*;
@@ -785,6 +786,7 @@
        serviceSubtask.setUpdateTime(DateUtils.getNowDate());
        if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() == 6)
            serviceSubtask.setFinishtime(new Date());
        return serviceSubtaskMapper.updateServiceSubtask(serviceSubtask);
    }
@@ -5136,13 +5138,13 @@
    }
    @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 startFinishTime, Date endFinishTime, 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.statQuestionOption(taskIds, startOutHospTime, endOutHospTime, scoreStart, scoreEnd, scriptContent, valueType);
        List<ServiceSubtaskDetailRatioExport> serviceSubtaskDetailRatioExports = serviceSubtaskMapper.statQuestionOption(taskIds, startOutHospTime, endOutHospTime, startFinishTime, endFinishTime, scoreStart, scoreEnd, scriptContent, valueType);
        // å¤„理 targetvalue:按 & åˆ†å‰²æˆå¤šæ¡è®°å½•
        List<ServiceSubtaskDetailRatioExport> result = new ArrayList<>();
@@ -5187,88 +5189,135 @@
     * æ ¹æ®ç§‘室或病区统计问卷选项(科室、题目查询的科室评分表)
     */
    @Override
    public List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO vo) {
    public Map<String, Map<String, List<QuestionCountKsOrBqDTO>>> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO vo) {
        // 1. æŸ¥æ˜Žç»†
        List<QuestionCountKsOrBqDTO> sourceList = serviceSubtaskMapper.statQuestionOptionByKsOrBq(vo);
        if (CollectionUtils.isEmpty(sourceList)) {
            return Collections.emptyList();
            return Collections.emptyMap();
        }
        // 2. åˆ¤æ–­æŒ‰ç§‘室还是按病区
        boolean byDept = vo.getLeaveldeptcodes() != null;
        boolean byDistrict = !byDept && vo.getLeavehospitaldistrictcodes() != null;
        if (!byDept && !byDistrict) {
            return Collections.emptyList();
            return Collections.emptyMap();
        }
        // 3. key = ç§‘室/病区 + é¢˜ç›® + é€‰é¡¹
        Map<String, QuestionCountKsOrBqDTO> map = new LinkedHashMap<>();
        for (QuestionCountKsOrBqDTO dto : sourceList) {
            if (StringUtils.isEmpty(dto.getTargetvalue())) {
                continue;
            }
            // åˆ†ç»„名:科室 æˆ– ç—…区
            String groupName = byDept ? dto.getDeptname() : dto.getLeavehospitaldistrictname();
            if (StringUtils.isEmpty(groupName)) {
                continue;
            }
            // å…³é”®ï¼šä¸¤è¾¹éƒ½ç”¨ trimAll,兼容全角空格
            String asrtext = trimAll(dto.getAsrtext());
            String questionKey = dto.getTaskid() + "\u0001" + trimAll(dto.getQeustionText());
            String asrtext = trimAll(dto.getAsrtext());            // ç”¨æˆ·å®žé™…选中的选项
            String questionText = trimAll(dto.getQuestionText());  // é¢˜ç›®
            if (StringUtils.isEmpty(questionText)) {
                continue;
            }
            // æ‹†åˆ† targetvalue,每个选项都要有一条记录
            for (String raw : dto.getTargetvalue().split("&")) {
                String option = trimAll(raw);      // â† ä¿®å¤ç‚¹ï¼šç”¨ trimAll è€Œä¸æ˜¯ trim
                String option = trimAll(raw);
                if (option.isEmpty()) {
                    continue;
                }
                String key = buildKey(groupName, option, questionKey);
                // key = ç§‘室/病区 + é¢˜ç›® + é€‰é¡¹
                String key = buildKey(groupName, questionText, option);
                QuestionCountKsOrBqDTO item = map.get(key);
                if (item == null) {
                    item = DtoConversionUtils.sourceToTarget(dto, QuestionCountKsOrBqDTO.class);
                    item.setTargetvalue(option);       // è¾“出的 targetvalue å°±æ˜¯å½“前选项
                    item.setTargetvalue(option);
                    item.setAsrtext(option);
                    item.setQuestionText(dto.getQuestionText());
                    item.setAnswerCount("0");
                    item.setSingleScore("0");
                    map.put(key, item);
                }
                // åªæœ‰å½“前选项 == ç”¨æˆ·å®žé™…选中的选项,才累加
                if (option.equals(asrtext)) {
                    item.setAnswerCount(String.valueOf(parseCount(item.getAnswerCount()) + 1));
                    item.setSingleScore(String.valueOf(new BigDecimal(item.getSingleScore()).add(new BigDecimal(dto.getSingleScore()))));
                    int count = parseCount(item.getAnswerCount()) + 1;
                    item.setAnswerCount(String.valueOf(count));
                    BigDecimal totalScore = new BigDecimal(item.getSingleScore())
                            .add(new BigDecimal(dto.getSingleScore() == null ? "0" : dto.getSingleScore()));
                    item.setSingleScore(totalScore.toPlainString());
                }
            }
        }
        ArrayList<QuestionCountKsOrBqDTO> questionCountKsOrBqDTOS = new ArrayList<>(map.values());
        for (QuestionCountKsOrBqDTO questionCountKsOrBqDTO : questionCountKsOrBqDTOS) {
            String singleScore = questionCountKsOrBqDTO.getSingleScore();
            String answerCount = questionCountKsOrBqDTO.getAnswerCount();
        // 4. è®¡ç®—平均分
        for (QuestionCountKsOrBqDTO dto : map.values()) {
            String answerCount = dto.getAnswerCount();
            String singleScore = dto.getSingleScore();
            BigDecimal avg;
            if (StringUtils.isEmpty(answerCount)
                    || BigDecimal.ZERO.compareTo(new BigDecimal(answerCount.trim())) == 0) {
                // é™¤æ•°ä¸º 0,避免 / by zero
                avg = BigDecimal.ZERO;
            } else {
                avg = new BigDecimal(singleScore)
                avg = new BigDecimal(singleScore == null ? "0" : singleScore)
                        .divide(new BigDecimal(answerCount.trim()), 2, RoundingMode.HALF_UP);
            }
            questionCountKsOrBqDTO.setAvgScore(avg.toPlainString());
            dto.setAvgScore(avg.toPlainString());
        }
        return questionCountKsOrBqDTOS;
        // 5. è½¬æˆ Map<String, Map<String, List<QuestionCountKsOrBqDTO>>>
        //    ç¬¬ä¸€å±‚ key:科室/病区
        //    ç¬¬äºŒå±‚ key:题目
        //    ç¬¬äºŒå±‚ value:该题目下的所有选项列表
        Map<String, Map<String, List<QuestionCountKsOrBqDTO>>> result = new LinkedHashMap<>();
        for (QuestionCountKsOrBqDTO dto : map.values()) {
            // åˆ†ç»„名
            String groupName = byDept ? dto.getDeptname() : dto.getLeavehospitaldistrictname();
            if (StringUtils.isEmpty(groupName)) {
                continue;
            }
            // é¢˜ç›®å
            String questionText = dto.getQuestionText();
            if (StringUtils.isEmpty(questionText)) {
                continue;
            }
            // ç¬¬ä¸€å±‚:科室/病区
            Map<String, List<QuestionCountKsOrBqDTO>> questionMap =
                    result.computeIfAbsent(groupName, k -> new LinkedHashMap<>());
            // ç¬¬äºŒå±‚:题目
            List<QuestionCountKsOrBqDTO> optionList =
                    questionMap.computeIfAbsent(questionText, k -> new ArrayList<>());
            optionList.add(dto);
        }
        return result;
    }
    @Override
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType) {
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, Date startFinishTime, Date endFinishTime, 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, startFinishTime, endFinishTime, scoreStart, scoreEnd, scriptContent, valueType);
        // å¤„理 targetvalue:按 & åˆ†å‰²æˆå¤šæ¡è®°å½•
        List<ServiceSubtaskDetailRatioExport> result = new ArrayList<>();
        for (ServiceSubtaskDetailRatioExport export : serviceSubtaskDetailRatioExports) {
@@ -5537,6 +5586,34 @@
        }
        return content;
    }
    /**
     * æ»¡æ„åº¦è¶‹åŠ¿æŸ¥è¯¢
     *
     * @param mydTrendReqVO
     * @return
     */
    @Override
    public List<MydTrendReqDTO> mydTrend(MydTrendReqVO mydTrendReqVO) {
        List<MydTrendReqDTO> list = serviceSubtaskMapper.mydTrend(mydTrendReqVO.getStartFinishTime(), mydTrendReqVO.getEndFinishTime(), mydTrendReqVO.getType());
        if (mydTrendReqVO.getType().equals("week")) list = getWeekDate(mydTrendReqVO, list);
        if (mydTrendReqVO.getType().equals("year")) list = getYearDate(mydTrendReqVO, list);
        if (mydTrendReqVO.getType().equals("month")) list = getMonthDate(mydTrendReqVO, list);
        if (mydTrendReqVO.getType().equals("day")) list = getDayDate(mydTrendReqVO, list);
        return list;
    }
    @Override
    public List<MydTrendReqDTO> sltdMydTotalByDimension(MydTrendReqVO mydTrendReqVO) {
        List<MydTrendReqDTO> list = null;
        if (mydTrendReqVO.getDimensionType().equals("1"))
            list = serviceSubtaskMapper.sltdMydTotalByDimension(mydTrendReqVO.getStartFinishTime(), mydTrendReqVO.getEndFinishTime(), mydTrendReqVO.getType());
        else if (mydTrendReqVO.getDimensionType().equals("2"))
            list = serviceSubtaskMapper.sltdMydTotalByYQ(mydTrendReqVO.getStartFinishTime(), mydTrendReqVO.getEndFinishTime(), mydTrendReqVO.getType());
        return list;
    }
    public ServiceSubtask boxedServiceSubtask(ServiceTask serviceTask, ServiceTaskdept serviceTaskdept, PatArchive patArchive) {
        ServiceSubtask serviceSubtask = DtoConversionUtils.sourceToTarget(serviceTask, ServiceSubtask.class);
@@ -6006,20 +6083,23 @@
    /**
     * é—®é¢˜ç»“果占比
     *
     * @param questionResultVO
     * @param sltdMydTotalVO
     * @param serviceSubtaskRes
     * @return
     */
    public List<ServiceSubtaskDetailRatioExport> getDetailRatio(QuestionResultVO questionResultVO, List<ServiceSubtaskRes> serviceSubtaskRes) {
    public List<ServiceSubtaskDetailRatioExport> getDetailRatio(SltdMydTotalVO sltdMydTotalVO, List<ServiceSubtaskRes> serviceSubtaskRes) {
        List<ServiceSubtaskDetailRatioExport> serviceSubtaskDetailRatioExports = null;
        if (StringUtils.isNotEmpty(questionResultVO.getServiceType()) && questionResultVO.getServiceType().equals("2")) {
        if (CollectionUtils.isNotEmpty(sltdMydTotalVO.getServiceTypeList()) && sltdMydTotalVO.getServiceTypeList().contains("2") && (sltdMydTotalVO.getServiceTypeList().contains("6") || sltdMydTotalVO.getServiceTypeList().contains("14"))) {
            //serviceType,即有随访又有满意度,暂时没法统计
            return serviceSubtaskDetailRatioExports;
        } else if (CollectionUtils.isNotEmpty(sltdMydTotalVO.getServiceTypeList()) && sltdMydTotalVO.getServiceTypeList().contains("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());
        } else if (StringUtils.isNotEmpty(questionResultVO.getServiceType()) && questionResultVO.getServiceType().equals("6")) {
            serviceSubtaskDetailRatioExports = statQuestionOption(taskIds, sltdMydTotalVO.getStartFinishTime(), sltdMydTotalVO.getEndFinishTime(), sltdMydTotalVO.getStartOutHospTime(), sltdMydTotalVO.getEndOutHospTime(), sltdMydTotalVO.getQuestionContent(), sltdMydTotalVO.getStartScore(), sltdMydTotalVO.getEndScore(), sltdMydTotalVO.getValueType());
        } else if (CollectionUtils.isNotEmpty(sltdMydTotalVO.getServiceTypeList()) && sltdMydTotalVO.getServiceTypeList().contains("6") || sltdMydTotalVO.getServiceTypeList().contains("14")) {
            //满意度统计 ï¼ˆé€šè¿‡ 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, sltdMydTotalVO.getStartOutHospTime(), sltdMydTotalVO.getEndOutHospTime(), sltdMydTotalVO.getStartFinishTime(), sltdMydTotalVO.getEndFinishTime(), sltdMydTotalVO.getQuestionContent(), sltdMydTotalVO.getStartScore(), sltdMydTotalVO.getEndScore(), sltdMydTotalVO.getValueType());
        }
        return serviceSubtaskDetailRatioExports;
    }
@@ -6082,15 +6162,12 @@
    private static Boolean isBlankChar(char c) {
        return c == '\u3000'          // å…¨è§’空格
                || c == ' '            // åŠè§’空格
                || c == '\t'
                || c == '\n'
                || c == '\r'
                || c == '\f'
                || Character.isWhitespace(c);
                || c == '\t' || c == '\n' || c == '\r' || c == '\f' || Character.isWhitespace(c);
    }
    private String buildKey(String groupName, String option, String questionKey) {
        return questionKey + KEY_SEP + groupName + KEY_SEP + option;
    private String buildKey(String groupName, String questionText, String option) {
        return groupName + "\u0001" + questionText + "\u0001" + option;
    }
    private static int parseCount(String s) {
@@ -6103,4 +6180,239 @@
            return 0;
        }
    }
    private List<MydTrendReqDTO> getWeekDate(MydTrendReqVO mydTrendReqVO, List<MydTrendReqDTO> list) {
        // 1. è®¡ç®—总周数(和 SQL é‡Œçš„公式保持一致)
        long days = (mydTrendReqVO.getEndFinishTime().getTime() - mydTrendReqVO.getStartFinishTime().getTime()) / (1000L * 60 * 60 * 24);
        int totalWeeks = (int) (days / 7) + 1;
        // 2. å·²æœ‰æ•°æ®ï¼šperiod -> totalScore
        Map<Integer, String> exist = new HashMap<>();
        for (MydTrendReqDTO row : list) {
            // period æ˜¯æ•°å­—,可能是 Integer / Long / BigDecimal,统一转 int
            int p = Integer.parseInt(StringUtils.isNotEmpty(row.getPeriod()) ? row.getPeriod() : "0");
            exist.put(p, row.getTotalScore() != null ? row.getTotalScore() : "0");
            // ä¸‹é¢è¿™è¡ŒæŒ‰ä½ çš„原逻辑保留(虽然看起来有点多余)
            exist.put(p, String.valueOf(row.getTotalScore() != null ? row.getTotalScore() : 0));
        }
        // 3. è¡¥å…¨ 1..totalWeeks
        List<MydTrendReqDTO> result = new ArrayList<>(totalWeeks);
        // èŽ·å–æ•´ä½“çš„å¼€å§‹æ—¶é—´
        long startTimeMillis = mydTrendReqVO.getStartFinishTime().getTime();
        long endTimeMillis = mydTrendReqVO.getEndFinishTime().getTime();
        long oneWeekMillis = 7L * 24 * 60 * 60 * 1000; // ä¸€å‘¨çš„æ¯«ç§’æ•°
        for (int i = 1; i <= totalWeeks; i++) {
            MydTrendReqDTO row = new MydTrendReqDTO();
            row.setPeriod(String.valueOf(i));
            row.setTotalScore(exist.getOrDefault(i, "0"));
            // -------- æ–°å¢žï¼šè®¾ç½®æ¯å‘¨çš„ startDate å’Œ endDate --------
            // å½“前周开始时间 = æ•´ä½“开始时间 + (i - 1) * 7天
            long currentStartMillis = startTimeMillis + (long) (i - 1) * oneWeekMillis;
            // å½“前周结束时间 = å½“前周开始时间 + 7天 - 1毫秒(保证是这一周的最后一刻)
            long currentEndMillis = currentStartMillis + oneWeekMillis - 1;
            // å¦‚果是最后一周,结束时间不能超过整体的 endTime
            if (i == totalWeeks) {
                currentEndMillis = endTimeMillis;
            }
            row.setStartDate(new Date(currentStartMillis));
            row.setEndDate(new Date(currentEndMillis));
            // ----------------------------------------------------
            result.add(row);
        }
        return result;
    }
    private List<MydTrendReqDTO> getYearDate(MydTrendReqVO mydTrendReqVO, List<MydTrendReqDTO> list) {
        // èŽ·å–æ•´ä½“å¼€å§‹å’Œç»“æŸæ—¶é—´
        Date startTime = mydTrendReqVO.getStartFinishTime();
        Date endTime = mydTrendReqVO.getEndFinishTime();
        // 1. è®¡ç®—年份范围
        // ä½¿ç”¨ Calendar èŽ·å–èµ·å§‹å¹´ä»½å’Œç»“æŸå¹´ä»½
        Calendar cal = Calendar.getInstance();
        cal.setTime(startTime);
        int startYear = cal.get(Calendar.YEAR);
        cal.setTime(endTime);
        int endYear = cal.get(Calendar.YEAR);
        // æ€»å¹´æ•° (包含首尾)
        int totalYears = endYear - startYear + 1;
        // 2. å·²æœ‰æ•°æ®ï¼šperiod -> totalScore (假设 period å­˜çš„æ˜¯å¹´ä»½å­—符串,如 "2024")
        Map<String, String> exist = new HashMap<>();
        for (MydTrendReqDTO row : list) {
            String period = row.getPeriod() != null ? row.getPeriod() : "";
            exist.put(period, row.getTotalScore() != null ? row.getTotalScore() : "0");
        }
        // 3. è¡¥å…¨æ‰€æœ‰å¹´ä»½
        List<MydTrendReqDTO> result = new ArrayList<>(totalYears);
        for (int i = 0; i < totalYears; i++) {
            int currentYear = startYear + i;
            String periodKey = String.valueOf(currentYear);
            MydTrendReqDTO row = new MydTrendReqDTO();
            row.setPeriod(periodKey);
            // å¦‚果没有该年份的数据,默认给 "0"
            row.setTotalScore(exist.getOrDefault(periodKey, "0"));
            // -------- è®¾ç½®è¯¥å¹´ä»½çš„ startDate å’Œ endDate --------
            Calendar yearCal = Calendar.getInstance();
            // è®¾ç½®ä¸ºè¯¥å¹´çš„ 1月1日 00:00:00
            yearCal.set(currentYear, Calendar.JANUARY, 1, 0, 0, 0);
            yearCal.set(Calendar.MILLISECOND, 0);
            row.setStartDate(yearCal.getTime());
            // è®¾ç½®ä¸ºè¯¥å¹´çš„ 12月31日 23:59:59
            yearCal.set(currentYear, Calendar.DECEMBER, 31, 23, 59, 59);
            yearCal.set(Calendar.MILLISECOND, 999);
            row.setEndDate(yearCal.getTime());
            // ----------------------------------------------------
            result.add(row);
        }
        return result;
    }
    private List<MydTrendReqDTO> getMonthDate(MydTrendReqVO mydTrendReqVO, List<MydTrendReqDTO> list) {
        // èŽ·å–æ•´ä½“å¼€å§‹å’Œç»“æŸæ—¶é—´
        Date startTime = mydTrendReqVO.getStartFinishTime();
        Date endTime = mydTrendReqVO.getEndFinishTime();
        // 1. è®¡ç®—月份范围
        Calendar cal = Calendar.getInstance();
        cal.setTime(startTime);
        int startYear = cal.get(Calendar.YEAR);
        int startMonth = cal.get(Calendar.MONTH); // æ³¨æ„ï¼šCalendar.MONTH ä»Ž 0 å¼€å§‹
        cal.setTime(endTime);
        int endYear = cal.get(Calendar.YEAR);
        int endMonth = cal.get(Calendar.MONTH);
        // æ€»æœˆæ•° = (结束年 - å¼€å§‹å¹´) * 12 + (结束月 - å¼€å§‹æœˆ) + 1
        int totalMonths = (endYear - startYear) * 12 + (endMonth - startMonth) + 1;
        // 2. å·²æœ‰æ•°æ®ï¼šperiod -> totalScore (period å­˜çš„æ˜¯æœˆä»½å­—符串,如 "2024-06")
        Map<String, String> exist = new HashMap<>();
        for (MydTrendReqDTO row : list) {
            String period = row.getPeriod() != null ? row.getPeriod() : "";
            exist.put(period, row.getTotalScore() != null ? row.getTotalScore() : "0");
        }
        // 3. è¡¥å…¨æ‰€æœ‰æœˆä»½
        List<MydTrendReqDTO> result = new ArrayList<>(totalMonths);
        Calendar monthCal = Calendar.getInstance();
        monthCal.set(startYear, startMonth, 1, 0, 0, 0);
        monthCal.set(Calendar.MILLISECOND, 0);
        for (int i = 0; i < totalMonths; i++) {
            int currentYear = monthCal.get(Calendar.YEAR);
            int currentMonth = monthCal.get(Calendar.MONTH) + 1; // è½¬æˆ 1-12 æœˆ
            // æ‹¼æŽ¥ period,格式:yyyy-MM,比如 "2024-06"
            // å¦‚果你希望是 "2024-6",可以把 String.format æ”¹æˆ currentMonth
            String periodKey = String.format("%04d-%02d", currentYear, currentMonth);
            MydTrendReqDTO row = new MydTrendReqDTO();
            row.setPeriod(periodKey);
            row.setTotalScore(exist.getOrDefault(periodKey, "0"));
            // -------- è®¾ç½®è¯¥æœˆçš„ startDate å’Œ endDate --------
            // å½“月开始时间:1号 00:00:00.000
            Calendar startCal = (Calendar) monthCal.clone();
            row.setStartDate(startCal.getTime());
            // å½“月结束时间:下个月1号 00:00:00.000 å‡ 1 æ¯«ç§’
            Calendar endCal = (Calendar) monthCal.clone();
            endCal.add(Calendar.MONTH, 1);
            endCal.add(Calendar.MILLISECOND, -1);
            row.setEndDate(endCal.getTime());
            // ----------------------------------------------------
            result.add(row);
            // è¿›å…¥ä¸‹ä¸€ä¸ªæœˆ
            monthCal.add(Calendar.MONTH, 1);
        }
        return result;
    }
    private List<MydTrendReqDTO> getDayDate(MydTrendReqVO mydTrendReqVO, List<MydTrendReqDTO> list) {
        // èŽ·å–æ•´ä½“å¼€å§‹å’Œç»“æŸæ—¶é—´
        Date startTime = mydTrendReqVO.getStartFinishTime();
        Date endTime = mydTrendReqVO.getEndFinishTime();
        // 1. è®¡ç®—总天数
        long oneDayMillis = 24L * 60 * 60 * 1000;
        // æ³¨æ„ï¼šè¿™é‡Œåªç®—日期差,不考虑时分秒,否则可能差一天
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startTime);
        startCal.set(Calendar.HOUR_OF_DAY, 0);
        startCal.set(Calendar.MINUTE, 0);
        startCal.set(Calendar.SECOND, 0);
        startCal.set(Calendar.MILLISECOND, 0);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endTime);
        endCal.set(Calendar.HOUR_OF_DAY, 0);
        endCal.set(Calendar.MINUTE, 0);
        endCal.set(Calendar.SECOND, 0);
        endCal.set(Calendar.MILLISECOND, 0);
        long days = (endCal.getTimeInMillis() - startCal.getTimeInMillis()) / oneDayMillis;
        int totalDays = (int) days + 1;
        // 2. å·²æœ‰æ•°æ®ï¼šperiod -> totalScore (period å­˜çš„æ˜¯æ—¥æœŸå­—符串,如 "2024-06-01")
        Map<String, String> exist = new HashMap<>();
        for (MydTrendReqDTO row : list) {
            String period = row.getPeriod() != null ? row.getPeriod() : "";
            exist.put(period, row.getTotalScore() != null ? row.getTotalScore() : "0");
        }
        // 3. è¡¥å…¨æ‰€æœ‰æ—¥æœŸ
        List<MydTrendReqDTO> result = new ArrayList<>(totalDays);
        Calendar dayCal = (Calendar) startCal.clone();
        for (int i = 0; i < totalDays; i++) {
            // æ‹¼æŽ¥ period,格式:yyyy-MM-dd
            String periodKey = String.format("%04d-%02d-%02d", dayCal.get(Calendar.YEAR), dayCal.get(Calendar.MONTH) + 1, dayCal.get(Calendar.DAY_OF_MONTH));
            MydTrendReqDTO row = new MydTrendReqDTO();
            row.setPeriod(periodKey);
            row.setTotalScore(exist.getOrDefault(periodKey, "0"));
            // -------- è®¾ç½®è¯¥å¤©çš„ startDate å’Œ endDate --------
            Calendar startOfDay = (Calendar) dayCal.clone();
            row.setStartDate(startOfDay.getTime());
            Calendar endOfDay = (Calendar) dayCal.clone();
            endOfDay.set(Calendar.HOUR_OF_DAY, 23);
            endOfDay.set(Calendar.MINUTE, 59);
            endOfDay.set(Calendar.SECOND, 59);
            endOfDay.set(Calendar.MILLISECOND, 999);
            row.setEndDate(endOfDay.getTime());
            // ----------------------------------------------------
            result.add(row);
            // è¿›å…¥ä¸‹ä¸€å¤©
            dayCal.add(Calendar.DAY_OF_MONTH, 1);
        }
        return result;
    }
}
smartor/src/main/resources/mapper/smartor/ServiceSubtaskMapper.xml
@@ -1386,6 +1386,9 @@
            <if test="id != null ">
                and id = #{id}
            </if>
            <if test="inhospid != null ">
                and inhospid = #{inhospid}
            </if>
        </where>
    </update>
@@ -2585,6 +2588,12 @@
        <if test="phone != null and phone != ''">
            AND phone = #{phone}
        </if>
        <if test="finishtimeStart != null">
            AND date_format(finishtime,'%y%m%d') &gt;= date_format(#{finishtimeStart},'%y%m%d')
        </if>
        <if test="finishtimeEnd != null">
            AND date_format(finishtime,'%y%m%d') &lt;= date_format(#{finishtimeEnd},'%y%m%d')
        </if>
        <if test="deptOrDistrict==1">
            <if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0">
                AND leavehospitaldistrictcode IN
@@ -3007,6 +3016,117 @@
          and sendstate in (1, 2, 3)
    </select>
    <select id="mydTrend" resultType="com.smartor.domain.DTO.MydTrendReqDTO">
        SELECT CASE #{type}
                   WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
                   WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
                   WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
                   WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
                   ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
                   END                AS period,
               ROUND(avg(d.score), 2) AS totalScore
        FROM service_subtask_detail d
                 JOIN service_task t ON d.taskid = t.taskid
        WHERE t.service_type IN (6, 14)
          AND t.del_flag = 0
          AND d.del_flag = 0
          AND d.create_time >= #{startFinishTime}
          AND d.create_time &lt; DATE_ADD(#{endFinishTime}, INTERVAL 1 DAY)
        GROUP BY period
        ORDER BY period;
    </select>
    <select id="sltdMydTotalByDimension" resultType="com.smartor.domain.DTO.MydTrendReqDTO">
        SELECT
        p.period,
        dim.dimension,
        IFNULL(ROUND(SUM(d.score), 2), 0) AS totalScore
        FROM (
        <!-- ç”ŸæˆæŸ¥è¯¢èŒƒå›´å†…实际出现过的时间段 -->
        SELECT DISTINCT
        CASE #{type}
        WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
        WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
        WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
        WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
        ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
        END AS period
        FROM service_subtask_detail d
        WHERE d.del_flag = 0
        AND d.create_time >= #{startFinishTime}
        AND d.create_time &lt; #{endFinishTime}
        ) p
        CROSS JOIN (
        <!-- æ‰€æœ‰éœ€è¦å±•示的 dimension -->
        SELECT DISTINCT dimension
        FROM service_subtask_detail
        WHERE del_flag = 0
        AND dimension IS NOT NULL
        ) dim
        LEFT JOIN service_task t
        ON t.service_type IN (6, 14)
        AND t.del_flag = 0
        LEFT JOIN service_subtask_detail d
        ON d.taskid = t.taskid
        AND d.del_flag = 0
        AND d.dimension = dim.dimension
        AND CASE #{type}
        WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
        WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
        WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
        WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
        ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
        END = p.period
        AND d.create_time >= #{startFinishTime}
        AND d.create_time &lt; #{endFinishTime}
        GROUP BY p.period, dim.dimension
        ORDER BY p.period, dim.dimension
    </select>
    <select id="sltdMydTotalByYQ" resultType="com.smartor.domain.DTO.MydTrendReqDTO">
        SELECT p.period,
               c.campusid,
               IFNULL(ROUND(AVG(d.score), 2), 0) AS totalScore
        FROM (
                 -- ç”ŸæˆæŸ¥è¯¢èŒƒå›´å†…实际出现过的时间段
                 SELECT DISTINCT CASE #{type}
                                     WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
                                     WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
                                     WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
                                     WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
                                     ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
                                     END AS period
                 FROM service_subtask_detail d
                 WHERE d.del_flag = 0
                   AND d.create_time >= #{startFinishTime}
                   AND d.create_time &lt; #{endFinishTime}) p
                 CROSS JOIN (
            -- æ‰€æœ‰éœ€è¦å±•示的院区
            SELECT DISTINCT campusid
            FROM service_task
            WHERE service_type IN (6, 14)
              AND del_flag = 0
              AND campusid IS NOT NULL) c
                 LEFT JOIN service_task t
                           ON t.campusid = c.campusid
                               AND t.service_type IN (6, 14)
                               AND t.del_flag = 0
                 LEFT JOIN service_subtask_detail d
                           ON d.taskid = t.taskid
                               AND d.del_flag = 0
                               AND CASE #{type}
                                       WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
                                       WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
                                       WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
                                       WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
                                       ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
                                       END = p.period
                               AND d.create_time >= #{startFinishTime}
                               AND d.create_time &lt; #{endFinishTime}
        GROUP BY p.period, c.campusid
        ORDER BY p.period, c.campusid;
    </select>
    <!-- ä»»åŠ¡ç»„ï¼ˆappltype=5)滚动调度用:拉本轮全量 subtask,作为下一轮的克隆模板 -->
    <select id="selectByScheduleIdAndLoop" resultMap="ServiceSubtaskResult">
        <include refid="selectServiceSubtaskVo"/>
@@ -3162,6 +3282,12 @@
        <if test="endOutHospTime != null">
            AND date_format(s.endtime,'%y%m%d') &lt;= date_format(#{endOutHospTime},'%y%m%d')
        </if>
        <if test="startFinishTime != null">
            AND date_format(s.finishtime,'%y%m%d') &gt;= date_format(#{startFinishTime},'%y%m%d')
        </if>
        <if test="endFinishTime != null">
            AND date_format(s.finishtime,'%y%m%d') &lt;= date_format(#{endFinishTime},'%y%m%d')
        </if>
        GROUP BY
        t.taskid,
        d.questiontext,
@@ -3240,12 +3366,24 @@
        <if test="endOutHospTime != null">
            AND date_format(s.endtime,'%y%m%d') &lt;= date_format(#{endOutHospTime},'%y%m%d')
        </if>
        <if test="startFinishTime != null">
            AND date_format(s.finishtime,'%y%m%d') &gt;= date_format(#{startFinishTime},'%y%m%d')
        </if>
        <if test="endFinishTime != null">
            AND date_format(s.finishtime,'%y%m%d') &lt;= date_format(#{endFinishTime},'%y%m%d')
        </if>
        GROUP BY
        t.taskid,
        d.questiontext,
        d.score,
        d.targetvalue,
        d.asrtext
        d.asrtext,
        t.task_name,
        s.deptcode,
        s.deptname,
        s.leavehospitaldistrictcode,
        s.leavehospitaldistrictname,
        d.value_type
        ORDER BY
        d.questiontext,
        t.taskid
@@ -3253,50 +3391,61 @@
    <select id="statQuestionOptionByKsOrBq" resultType="com.smartor.domain.DTO.QuestionCountKsOrBqDTO"
            parameterType="com.smartor.domain.VO.QuestionCountKsOrBqVO">
        SELECT questiontext,
        d.taskid,
        s.deptname,
        d.create_time as createTime,
        s.leavehospitaldistrictname,
        d.targetvalue,
        d.asrtext,
        COUNT(d.asrtext) AS answercount,
        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
        SELECT
        s.deptname AS deptname,
        s.leavehospitaldistrictname AS leavehospitaldistrictname,
        d.questiontext AS questionText,
        d.targetvalue AS targetvalue, -- æ‰€æœ‰é€‰é¡¹æ‹¼æŽ¥
        d.asrtext AS asrtext, -- ç”¨æˆ·å®žé™…选中的选项
        d.score AS singleScore -- å•条记录的分数
        FROM service_subtask_detail d
        JOIN service_subtask s ON d.sub_id = s.id
        WHERE s.del_flag = 0
        AND d.del_flag = 0
        AND s.service_type IN ('6', '14')
        <if test="taskTemplateid != null">
            AND s.templateid = #{taskTemplateid}
        </if>
        <if test="endFinishTime != null">
            AND d.create_time &lt; #{endFinishTime}
        </if>
        <if test="startFinishTime != null">
            AND  d.create_time &gt;= #{startFinishTime}
            AND d.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 test="deptOrDistrict ==1">
            <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>
        </if>
        <if test=" leaveldeptcodes != null and leaveldeptcodes.size()>0">
            AND deptcode IN
            <foreach collection="leaveldeptcodes" item="leaveldeptcode" open="(" separator=","
                     close=")">
                #{leaveldeptcode}
            </foreach>
        <if test="deptOrDistrict ==2">
            <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">
                OR deptcode IN
                <foreach collection="leaveldeptcodes" item="leaveldeptcode" open="(" separator=","
                         close=")">
                    #{leaveldeptcode}
                </foreach>
            </if>
        </if>
        GROUP BY d.questiontext,
        d.taskid,
        d.score,
        s.deptname,
        d.targetvalue,
        d.create_time,
        s.leavehospitaldistrictname,
        d.asrtext
        ORDER BY d.taskid
    </select>
    <select id="selectServiceSubtaskListDeadLine" parameterType="com.smartor.domain.entity.ServiceSubtaskEntity"
@@ -3308,5 +3457,6 @@
        and endtime
    </select>
</mapper>