陈昶聿
7 小时以前 235cf590b8ac4c77d0a9a715d026bc591d9df133
smartor/src/main/java/com/smartor/service/impl/ServiceSubtaskServiceImpl.java
@@ -12,7 +12,6 @@
import com.ruoyi.common.dx.MessageSend;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.core.service.IConfigService;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.SysConfig;
@@ -23,7 +22,6 @@
import com.smartor.common.ScheduleSubtaskBuilder;
import com.smartor.config.PhoneUtils;
import com.smartor.domain.DTO.QuestionCountKsOrBqDTO;
import com.smartor.domain.DTO.QuestionResultDTO;
import com.smartor.domain.DTO.ServiceSubtaskDetailDTO;
import com.smartor.domain.*;
import com.smartor.domain.VO.*;
@@ -34,9 +32,7 @@
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
@@ -44,10 +40,8 @@
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
@@ -207,12 +201,11 @@
    @Value("${spring.profiles.active}")
    private String active;
    @Autowired
    private PatMedOperationMapper patMedOperationMapper;
    @Autowired
    private PatMedOperationItemMapper patMedOperationItemMapper;
    @Autowired
    private ServiceOutPathMapper serviceOutPathMapper;
    private static final String KEY_SEP = "\u0001";
    /**
     * 查询单一任务(随访)
@@ -5062,48 +5055,78 @@
     * 根据科室或病区统计问卷选项(科室、题目查询的科室评分表)
     */
    @Override
    public List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO questionCountKsOrBqVO) {
        List<QuestionCountKsOrBqDTO> questionCountKsOrBqDTOS = serviceSubtaskMapper.statQuestionOptionByKsOrBq(questionCountKsOrBqVO);
        // 处理 targetvalue:按 & 分割成多条记录
        List<QuestionCountKsOrBqDTO> result = new ArrayList<>();
        for (QuestionCountKsOrBqDTO questionCountKsOrBqDTO : questionCountKsOrBqDTOS) {
            if (StringUtils.isNotEmpty(questionCountKsOrBqDTO.getTargetvalue()) && questionCountKsOrBqDTO.getTargetvalue().contains("&")) {
                String[] values = questionCountKsOrBqDTO.getTargetvalue().split("&");
                // 如果有多条目标值,拆分成多行
                for (String value : values) {
                    //先去 result 中查一下,有没有这个 questiontext 和对应的 targetvalue
                    QuestionCountKsOrBqDTO existingExport = result.stream().filter(e -> e.getQeustionText().equals(questionCountKsOrBqDTO.getQeustionText()) && value.trim().equals(e.getTargetvalue())).findFirst().orElse(null);
                    if (existingExport != null && existingExport.getAnswerCount().equals("0") && existingExport.getSingleScore().equals("0")) {
                        //如果存在,则将 result 里的这个问题所对应的 Targetvalue=value 这条数据更新成当前这条数据
                        if (value.equals(questionCountKsOrBqDTO.getAsrtext())) {
                            existingExport.setAsrtext(questionCountKsOrBqDTO.getAsrtext());
                            existingExport.setAnswerCount(questionCountKsOrBqDTO.getAnswerCount());
                            existingExport.setSingleScore(questionCountKsOrBqDTO.getSingleScore());
                            existingExport.setAvgScore(questionCountKsOrBqDTO.getAvgScore());
                        }
                    } else if (existingExport != null && !existingExport.getAnswerCount().equals("0")) {
                        continue;
                    } else {
                        QuestionCountKsOrBqDTO qcDto = DtoConversionUtils.sourceToTarget(questionCountKsOrBqDTO, QuestionCountKsOrBqDTO.class);
                        qcDto.setTargetvalue(value.trim()); // targetvalue 显示单个选项
                        if (!value.equals(qcDto.getAsrtext())) {
                            existingExport.setAsrtext(null);
                            existingExport.setAnswerCount("0");
                            existingExport.setSingleScore("0");
                            existingExport.setAvgScore("0");
                        }
                        result.add(qcDto);
                    }
                }
            } else {
                // targetvalue 不包含 &,直接添加到结果
                result.add(questionCountKsOrBqDTO);
            }
    public List<QuestionCountKsOrBqDTO> statQuestionOptionByKsOrBq(QuestionCountKsOrBqVO vo) {
        List<QuestionCountKsOrBqDTO> sourceList = serviceSubtaskMapper.statQuestionOptionByKsOrBq(vo);
        if (CollectionUtils.isEmpty(sourceList)) {
            return Collections.emptyList();
        }
        return result;
        boolean byDept = vo.getLeaveldeptcodes() != null;
        boolean byDistrict = !byDept && vo.getLeavehospitaldistrictcodes() != null;
        if (!byDept && !byDistrict) {
            return Collections.emptyList();
        }
        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());
            for (String raw : dto.getTargetvalue().split("&")) {
                String option = trimAll(raw);      // ← 修复点:用 trimAll 而不是 trim
                if (option.isEmpty()) {
                    continue;
                }
                String key = buildKey(groupName, option, questionKey);
                QuestionCountKsOrBqDTO item = map.get(key);
                if (item == null) {
                    item = DtoConversionUtils.sourceToTarget(dto, QuestionCountKsOrBqDTO.class);
                    item.setTargetvalue(option);       // 输出的 targetvalue 就是当前选项
                    item.setAsrtext(option);
                    item.setAnswerCount("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()))));
                }
            }
        }
        ArrayList<QuestionCountKsOrBqDTO> questionCountKsOrBqDTOS = new ArrayList<>(map.values());
        for (QuestionCountKsOrBqDTO questionCountKsOrBqDTO : questionCountKsOrBqDTOS) {
            String singleScore = questionCountKsOrBqDTO.getSingleScore();
            String answerCount = questionCountKsOrBqDTO.getAnswerCount();
            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)
                        .divide(new BigDecimal(answerCount.trim()), 2, RoundingMode.HALF_UP);
            }
            questionCountKsOrBqDTO.setAvgScore(avg.toPlainString());
        }
        return questionCountKsOrBqDTOS;
    }
    @Override
    public List<ServiceSubtaskDetailRatioExport> statQuestionOptionBySubtaskIds(List<Long> subtaskIds, Date startOutHospTime, Date endOutHospTime, String scriptContent, Double scoreStart, Double scoreEnd, String valueType) {
@@ -5122,8 +5145,17 @@
                // 如果有多条目标值,拆分成多行
                for (String value : values) {
                    //先去 result 中查一下,有没有这个 questiontext 和对应的 targetvalue
                    ServiceSubtaskDetailRatioExport existingExport = result.stream().filter(e -> e.getQuestiontext().equals(export.getQuestiontext()) && value.trim().equals(e.getTargetvalue())).findFirst().orElse(null);
                    if (existingExport != null && existingExport.getRatio().equals("0") && existingExport.getCount().equals("0")) {
                    ServiceSubtaskDetailRatioExport existingExport = result.stream().filter(e -> {
                        if (e == null || export == null) {
                            return false;
                        }
                        String q1 = e.getQuestiontext() != null ? e.getQuestiontext() : "";
                        String q2 = export.getQuestiontext() != null ? export.getQuestiontext() : "";
                        String t1 = value.trim();
                        String t2 = e.getTargetvalue() != null ? e.getTargetvalue() : "";
                        return q1.equals(q2) && t1.equals(t2);
                    }).findFirst().orElse(null);
                    if (existingExport != null && "0".equals(existingExport.getRatio()) && "0".equals(existingExport.getCount())) {
                        //如果存在,则将 result 里的这个问题所对应的 Targetvalue=value 这条数据更新成当前这条数据
                        if (value.equals(export.getOptionresult())) {
                            existingExport.setRatio(export.getRatio());
@@ -5131,7 +5163,7 @@
                            existingExport.setCount(export.getCount());
                            existingExport.setOptionresult(export.getOptionresult());
                        }
                    } else if (existingExport != null && !existingExport.getRatio().equals("0")) {
                    } else if (existingExport != null && !"0".equals(existingExport.getRatio())) {
                        continue;
                    } else {
                        ServiceSubtaskDetailRatioExport newExport = DtoConversionUtils.sourceToTarget(export, ServiceSubtaskDetailRatioExport.class);
@@ -5842,7 +5874,7 @@
    /**
     * 问题结果占比
     *
     * @param serviceSubtaskEntity
     * @param questionResultVO
     * @param serviceSubtaskRes
     * @return
     */
@@ -5899,4 +5931,44 @@
        }
        log.info("ai匹配成功,匹配结果是:" + matchedText);
    }
    private static String trimAll(String s) {
        if (s == null) {
            return "";
        }
        int start = 0;
        int end = s.length();
        while (start < end && isBlankChar(s.charAt(start))) {
            start++;
        }
        while (end > start && isBlankChar(s.charAt(end - 1))) {
            end--;
        }
        return s.substring(start, end);
    }
    private static Boolean isBlankChar(char c) {
        return c == '\u3000'          // 全角空格
                || 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 static int parseCount(String s) {
        if (StringUtils.isEmpty(s)) {
            return 0;
        }
        try {
            return Integer.parseInt(s.trim());
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}