| | |
| | | import com.ruoyi.common.exception.base.BaseException; |
| | | import com.ruoyi.common.utils.*; |
| | | import com.ruoyi.common.utils.http.HttpUtils; |
| | | import com.ruoyi.common.utils.sms.smsUtils; |
| | | import com.ruoyi.common.utils.sms.SmsUtils; |
| | | import com.ruoyi.common.utils.spring.SpringUtils; |
| | | import com.ruoyi.system.domain.SysConfig; |
| | | import com.ruoyi.system.mapper.SysConfigMapper; |
| | |
| | | } finally { |
| | | unlockAgainTask(serviceSubtask.getId(), lockToken); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 首次随访任务超时后,按下一任务自动生成再次随访任务(随访中心)。 |
| | | * <p> |
| | | * 定时任务入口 {@code RyTask#dealSubtaskDeadline} 使用。与手动入口一致的部分: |
| | | * 表单/发送方式取下一任务、链路 upid + visit_count、发送方式明细初始化; |
| | | * 差异:随访中心科室未配置时回退原任务科室,原任务置为发送失败(sendstate=5)。 |
| | | * <p> |
| | | * 幂等:同一原任务只允许生成一条再次随访(Redis 锁 + upid 校验 + 原任务条件更新), |
| | | * 多节点/多线程同时扫描时,后到的事务会在条件更新处拿到 0 行并回滚本次插入。 |
| | | * |
| | | * @param serviceSubtask 已超时的首次随访子任务 |
| | | * @return 结果描述 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public String addSubTaskAgainByDeadline(ServiceSubtask serviceSubtask) { |
| | | if (ObjectUtils.isEmpty(serviceSubtask) || ObjectUtils.isEmpty(serviceSubtask.getId())) { |
| | | return "再次随访任务创建失败,原任务不存在"; |
| | | } |
| | | String lockToken = tryLockAgainTask(serviceSubtask.getId()); |
| | | if (lockToken == null) { |
| | | return "再次随访任务正在创建中,请勿重复提交"; |
| | | } |
| | | try { |
| | | // 幂等校验:同一原任务只允许生成一条再次随访 |
| | | ServiceSubtaskEntity againQuery = new ServiceSubtaskEntity(); |
| | | againQuery.setUpid(serviceSubtask.getId().intValue()); |
| | | if (CollectionUtils.isNotEmpty(serviceSubtaskMapper.selectServiceSubtaskList(againQuery))) { |
| | | return "无需再次随访,该任务已经再次随访过了"; |
| | | } |
| | | // 原任务已被标记为不再随访(手动入口写过 is_visit_again=2) |
| | | if (ObjectUtils.isNotEmpty(serviceSubtask.getIsVisitAgain()) && serviceSubtask.getIsVisitAgain() == 2) { |
| | | return "无需再次随访,该任务已经再次随访过了"; |
| | | } |
| | | ServiceTask serviceTask = serviceTaskService.selectServiceTaskByTaskid(serviceSubtask.getTaskid()); |
| | | if (ObjectUtils.isEmpty(serviceTask)) { |
| | | return "再次随访任务创建失败,找不到对应任务 taskid = " + serviceSubtask.getTaskid(); |
| | | } |
| | | if (ObjectUtils.isEmpty(serviceTask.getNexttaskid())) { |
| | | return "再次随访任务创建失败,任务缺少 nexttaskid, taskid = " + serviceSubtask.getTaskid(); |
| | | } |
| | | ServiceTask nextServiceTask = serviceTaskService.selectServiceTaskByTaskid(serviceTask.getNexttaskid()); |
| | | if (ObjectUtils.isEmpty(nextServiceTask)) { |
| | | return "再次随访任务创建失败,找不到对应任务 nexttaskid = " + serviceTask.getNexttaskid(); |
| | | } |
| | | PatMedInhosp patMedInhosp = selectOutHospRecord(serviceSubtask); |
| | | if (ObjectUtils.isEmpty(patMedInhosp)) { |
| | | return "再次随访任务创建失败,任务缺少对应的出院记录, taskid = " + serviceSubtask.getTaskid(); |
| | | } |
| | | PatArchive patArchive = patArchiveService.selectPatArchiveByPatid(serviceSubtask.getPatid()); |
| | | if (ObjectUtils.isEmpty(patArchive)) { |
| | | return "再次随访任务创建失败,未找到患者档案, subTaskId = " + serviceSubtask.getId(); |
| | | } |
| | | // 随访中心科室:未配置(或科室不存在)时回退原任务科室,保持超时入口原有行为 |
| | | SysDept visitDept = selectCenterDept(serviceSubtask.getOrgid()); |
| | | String config = configService.selectConfigByKey("visit.early.day"); |
| | | ServiceSubtask serviceSubtaskAgain = patMedInhospService.boxedServiceSubtask(nextServiceTask, |
| | | patMedInhosp, patArchive, config, 1); |
| | | if (ObjectUtils.isEmpty(serviceSubtaskAgain) || ObjectUtils.isEmpty(serviceSubtaskAgain.getTaskid())) { |
| | | return "再次随访任务创建失败,患者出院记录不完整或下一任务配置异常, subTaskId = " + serviceSubtask.getId(); |
| | | } |
| | | Date now = new Date(); |
| | | serviceSubtaskAgain.setId(null); |
| | | serviceSubtaskAgain.setUpid(serviceSubtask.getId().intValue()); |
| | | serviceSubtaskAgain.setVisitCount(ObjectUtils.isNotEmpty(serviceSubtask.getVisitCount()) |
| | | ? serviceSubtask.getVisitCount() + 1 : 2); |
| | | serviceSubtaskAgain.setSendstate(2L); |
| | | serviceSubtaskAgain.setIsVisitAgain(1); |
| | | serviceSubtaskAgain.setCreateTime(now); |
| | | serviceSubtaskAgain.setUpdateTime(now); |
| | | serviceSubtaskAgain.setVisitType(serviceSubtask.getVisitType()); |
| | | if (ObjectUtils.isNotEmpty(visitDept)) { |
| | | serviceSubtaskAgain.setVisitDeptCode(visitDept.getDeptCode()); |
| | | serviceSubtaskAgain.setVisitDeptName(visitDept.getDeptName()); |
| | | } else { |
| | | serviceSubtaskAgain.setVisitDeptCode(serviceSubtask.getVisitDeptCode()); |
| | | serviceSubtaskAgain.setVisitDeptName(serviceSubtask.getVisitDeptName()); |
| | | } |
| | | if (serviceSubtaskMapper.insertServiceSubtask(serviceSubtaskAgain) != 1) { |
| | | return "再次随访任务创建失败,再请次重试"; |
| | | } |
| | | // 初始化发送方式明细,补偿(compensateTask)和超时判断依赖该表 |
| | | patMedInhospService.addServiceSubtaskPreachform(serviceSubtaskAgain, null); |
| | | // 条件更新原任务:0 行说明已被其他请求生成,抛异常回滚本次插入的重复数据 |
| | | if (serviceSubtaskMapper.updateIsVisitAgainById(serviceSubtask.getId(), 2) != 1) { |
| | | throw new BaseException("无需再次随访,该任务已经再次随访过了"); |
| | | } |
| | | // 原任务超时,置为发送失败 |
| | | ServiceSubtask originUpdate = new ServiceSubtask(); |
| | | originUpdate.setId(serviceSubtask.getId()); |
| | | originUpdate.setSendstate(5L); |
| | | originUpdate.setUpdateTime(now); |
| | | serviceSubtaskMapper.updateServiceSubtask(originUpdate); |
| | | return "再次随访任务创建成功"; |
| | | } finally { |
| | | unlockAgainTask(serviceSubtask.getId(), lockToken); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 按 orgid + inhospid 取出院记录(超时再次随访用)。 |
| | | */ |
| | | private PatMedInhosp selectOutHospRecord(ServiceSubtask serviceSubtask) { |
| | | PatMedInhosp patMedInhospVo = new PatMedInhosp(); |
| | | patMedInhospVo.setOrgid(serviceSubtask.getOrgid()); |
| | | patMedInhospVo.setInhospid(serviceSubtask.getInhospid()); |
| | | patMedInhospVo.setCry(1); |
| | | List<PatMedInhosp> patMedInhospList = patMedInhospService.selectPatMedInhospList(patMedInhospVo); |
| | | if (CollectionUtils.isEmpty(patMedInhospList)) { |
| | | return null; |
| | | } |
| | | return patMedInhospList.get(0); |
| | | } |
| | | |
| | | /** |
| | | * 取随访中心科室,未配置或科室不存在时返回 null(由调用方回退原任务科室)。 |
| | | */ |
| | | private SysDept selectCenterDept(String orgid) { |
| | | String centerDept = configService.selectConfigByKey("sys.smartor.center.dept", orgid); |
| | | if (StringUtils.isEmpty(centerDept)) { |
| | | return null; |
| | | } |
| | | SysDept sysDeptVo = new SysDept(); |
| | | sysDeptVo.setDeptType("1"); |
| | | sysDeptVo.setOrgid(orgid); |
| | | sysDeptVo.setDeptCode(centerDept); |
| | | List<SysDept> sysDepts = sysDeptService.selectDeptList(sysDeptVo); |
| | | return CollectionUtils.isEmpty(sysDepts) ? null : sysDepts.get(0); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { |
| | | serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); |
| | | } |
| | | //及时随访人次:已完成且未超时 |
| | | if (isTimelyFollowUp(serviceSubtask)) { |
| | | serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); |
| | | } |
| | | |
| | | //人工已拨通总量 |
| | | if (ObjectUtils.isNotEmpty(serviceSubtask.getIsManuallyCalled()) |
| | |
| | | } |
| | | |
| | | /** |
| | | * 是否属于「及时随访」:随访已完成且完成时状态为正常完成(未超时)。 |
| | | * <p> |
| | | * finish_state:1-正常完成 2-延期完成 3-超时完成,只有 1 计入及时随访。 |
| | | * |
| | | * @param serviceSubtask 随访子任务 |
| | | * @return true-计入及时随访人次 |
| | | */ |
| | | private boolean isTimelyFollowUp(ServiceSubtask serviceSubtask) { |
| | | return serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate().equals(6L) |
| | | && serviceSubtask.getFinishState() != null && serviceSubtask.getFinishState().equals(1L); |
| | | } |
| | | |
| | | /** |
| | | * 首次随访统计 |
| | | * |
| | | * @param serviceSubtaskList |
| | |
| | | //应随访人次 |
| | | if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { |
| | | serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); |
| | | } |
| | | //及时随访人次:已完成且未超时 |
| | | if (isTimelyFollowUp(serviceSubtask)) { |
| | | serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); |
| | | } |
| | | |
| | | //首次出院随访 |
| | |
| | | //应随访人次 |
| | | if (serviceSubtask.getSendstate() != null && serviceSubtask.getSendstate() != 4) { |
| | | serviceSubtaskStatistic.setFollowUpNeeded(serviceSubtaskStatistic.getFollowUpNeeded() + 1L); |
| | | } |
| | | //及时随访人次:已完成且未超时 |
| | | if (isTimelyFollowUp(serviceSubtask)) { |
| | | serviceSubtaskStatistic.setTimelyFollowUp(serviceSubtaskStatistic.getTimelyFollowUp() + 1L); |
| | | } |
| | | |
| | | //再次出院随访 |
| | |
| | | serviceSubtaskStatistic.setDrname(serviceSubtaskList.get(0).getDrname()); |
| | | serviceSubtaskStatistic.setJoyCount(0); |
| | | serviceSubtaskStatistic.setJoyAllCount(0); |
| | | |
| | | //出院人次 |
| | | serviceSubtaskStatistic.setDischargeCount(serviceSubtaskList.size()); |
| | | //获取随访统计 |
| | | if (subCounts == null) { |
| | | subCounts = new ArrayList<>(); |
| | |
| | | * pendingFollowUpInfo - visitCount = 1 && sendstate = 2 |
| | | * followUpSuccessInfo - visitCount = 1 && sendstate = 6 |
| | | * followUpFailInfo - visitCount = 1 && (sendstate = 5 || sendstate = 7) |
| | | * timelyFollowUpInfo - sendstate = 6 && finish_state = 1(沿用请求的 visitCount 口径) |
| | | * manualInfo - visitCount = 1 && currentPreachForm = "1" |
| | | * voiceInfo - visitCount = 1 && currentPreachForm = "3" |
| | | * smsInfo - visitCount = 1 && currentPreachForm = "4" |
| | |
| | | } |
| | | |
| | | private void applyHyperLinkInfoType(ServiceSubtaskCountReq serviceSubtaskCountReq, String hyperLinkInfoType) { |
| | | //及时随访明细需要沿用请求的首次/再次口径 |
| | | Integer originVisitCount = serviceSubtaskCountReq.getVisitCount(); |
| | | serviceSubtaskCountReq.setVisitCount(null); |
| | | serviceSubtaskCountReq.setSendstates(null); |
| | | serviceSubtaskCountReq.setCurrentPreachform(null); |
| | | serviceSubtaskCountReq.setExcep(null); |
| | | serviceSubtaskCountReq.setTaskSituation(null); |
| | | serviceSubtaskCountReq.setFinishState(null); |
| | | |
| | | switch (hyperLinkInfoType) { |
| | | case "dischargeCountInfo": |
| | | break; |
| | | case "timelyFollowUpInfo": |
| | | serviceSubtaskCountReq.setVisitCount(originVisitCount); |
| | | serviceSubtaskCountReq.setSendstates(new ArrayList<>(Collections.singletonList(6L))); |
| | | serviceSubtaskCountReq.setFinishState(1L); |
| | | break; |
| | | case "followUpNeededAllInfo": |
| | | serviceSubtaskCountReq.setSendstates(new ArrayList<>(Arrays.asList(1L, 2L, 3L, 5L, 6L, 7L))); |
| | |
| | | * @return |
| | | */ |
| | | @Override |
| | | @Cacheable(value = "getSfStatisticsScript", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") |
| | | // @Cacheable(value = "getSfStatisticsScript", key = "T(org.springframework.util.DigestUtils).md5DigestAsHex(#serviceSubtaskCountReq.toString().getBytes())", unless = "#result == null or #result.isEmpty()") |
| | | public List<ServiceSubtaskStatistic> getSfStatisticsScript(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | log.info("getSfStatisticsScript的入参为:{}", serviceSubtaskCountReq); |
| | | List<ServiceSubtaskStatistic> serviceSubtaskStatistics = new ArrayList<>(); |
| | |
| | | // 根据条件进行分组 |
| | | Map<String, List<ServiceSubtask>> collect = new HashMap<>(); |
| | | String groupKey = "drcode"; |
| | | if (serviceSubtaskCountReq.getLeavehospitaldistrictcodes() != null && !serviceSubtaskCountReq.getLeavehospitaldistrictcodes().isEmpty()) { |
| | | if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 1) { |
| | | if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { |
| | | groupKey = "drcode"; |
| | | } else { |
| | | groupKey = "leavehospitaldistrictcode"; |
| | | } |
| | | } else if (serviceSubtaskCountReq.getDeptcodes() != null && !serviceSubtaskCountReq.getDeptcodes().isEmpty()) { |
| | | } else if (serviceSubtaskCountReq.getStatisticaltype() != null && serviceSubtaskCountReq.getStatisticaltype() == 2) { |
| | | if (serviceSubtaskCountReq.getDrcode() != null && !serviceSubtaskCountReq.getDrcode().isEmpty()) { |
| | | groupKey = "drcode"; |
| | | } else { |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, ServiceSubtaskScriptCount> getSfStatisticsScriptDetails(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | Map<String, ServiceSubtaskScriptCount> result = new HashMap<>(); |
| | | public Map<String, Object> getSfStatisticsScriptDetails(ServiceSubtaskCountReq serviceSubtaskCountReq) { |
| | | List<ServiceSubtaskScriptCount> allCounts = new ArrayList<>(); |
| | | List<ServiceSubtaskScriptCount> allItemCounts = new ArrayList<>(); |
| | | String type = serviceSubtaskCountReq.getType(); |
| | |
| | | allItemCounts = serviceSubtaskMapper.getSfStatisticsScriptItemDetails(serviceSubtaskCountReq); |
| | | } |
| | | |
| | | for (ServiceSubtaskScriptCount count : allCounts) { |
| | | //返回结构是 Map,且不传 type 时会执行两条 SQL,PageHelper 没法对整体分页, |
| | | //所以在题目合并完成之后按题目(scriptid)在这里分页,保证 total 和每页数据都是题目维度的。 |
| | | allCounts.sort(Comparator |
| | | .comparing(ServiceSubtaskScriptCount::getSubtaskType, Comparator.nullsLast(String::compareTo)) |
| | | .thenComparing(ServiceSubtaskScriptCount::getScriptid, Comparator.nullsLast(Long::compareTo))); |
| | | |
| | | int pageNum = ObjectUtils.isNotEmpty(serviceSubtaskCountReq.getPageNum()) && serviceSubtaskCountReq.getPageNum() > 0 |
| | | ? serviceSubtaskCountReq.getPageNum() : 1; |
| | | int pageSize = ObjectUtils.isNotEmpty(serviceSubtaskCountReq.getPageSize()) && serviceSubtaskCountReq.getPageSize() > 0 |
| | | ? serviceSubtaskCountReq.getPageSize() : 10; |
| | | int total = allCounts.size(); |
| | | int fromIndex = (int) Math.min((long) (pageNum - 1) * pageSize, total); |
| | | int toIndex = Math.min(fromIndex + pageSize, total); |
| | | List<ServiceSubtaskScriptCount> pageCounts = allCounts.subList(fromIndex, toIndex); |
| | | |
| | | Map<String, ServiceSubtaskScriptCount> pageData = new LinkedHashMap<>(); |
| | | for (ServiceSubtaskScriptCount count : pageCounts) { |
| | | Map<String, ServiceSubtaskScriptCount> itemCountMap = new HashMap<>(); |
| | | //问卷加上空白选项 |
| | | if (ObjectUtils.isNotEmpty(count.getTemplateid()) && ObjectUtils.isNotEmpty(count.getSubtaskType()) && count.getSubtaskType().equals("2")) { |
| | |
| | | } |
| | | } |
| | | allItemCounts.forEach(itemCount -> { |
| | | if (ObjectUtils.isNotEmpty(count.getScriptid()) && ObjectUtils.isNotEmpty(itemCount.getScriptid())) { |
| | | if (count.getScriptid().equals(itemCount.getScriptid())) { |
| | | //放入统计信息 |
| | | itemCount.setScriptContent(count.getScriptContent()); |
| | | itemCount.setScriptType(count.getScriptType()); |
| | | itemCount.setSubtaskType(count.getSubtaskType()); |
| | | itemCount.setCompletedQuantity(count.getCompletedQuantity()); |
| | | itemCount.setAllQuantity(count.getAllQuantity()); |
| | | itemCount.setCompletedPercentage(count.getCompletedPercentage()); |
| | | itemCount.setTemplateid(count.getTemplateid()); |
| | | //计算选择比例 |
| | | int chosenQuantity = ObjectUtils.isNotEmpty(itemCount.getChosenQuantity()) ? itemCount.getChosenQuantity() : 0; |
| | | int completedQuantity = itemCount.getCompletedQuantity(); |
| | | if (ObjectUtils.isNotEmpty(completedQuantity) && completedQuantity != 0) { |
| | | BigDecimal chosenPercentage = (new BigDecimal(chosenQuantity)).divide(new BigDecimal(completedQuantity), 2, RoundingMode.HALF_UP); |
| | | itemCount.setChosenPercentage(chosenPercentage.toString()); |
| | | } |
| | | itemCountMap.put(itemCount.getOptionText(), itemCount); |
| | | //明细行已按“题目内容+任务类型”聚合并带出 script_content,不能用 scriptid 匹配: |
| | | //同一道题会被复制到多个任务模板,每个模板的 scriptid 都不同 |
| | | boolean sameQuestion = ObjectUtils.isNotEmpty(count.getScriptContent()) |
| | | && ObjectUtils.isNotEmpty(itemCount.getScriptContent()) |
| | | && count.getScriptContent().equals(itemCount.getScriptContent()) |
| | | && Objects.equals(count.getSubtaskType(), itemCount.getSubtaskType()); |
| | | if (sameQuestion) { |
| | | //放入统计信息 |
| | | itemCount.setScriptContent(count.getScriptContent()); |
| | | itemCount.setScriptType(count.getScriptType()); |
| | | itemCount.setSubtaskType(count.getSubtaskType()); |
| | | itemCount.setCompletedQuantity(count.getCompletedQuantity()); |
| | | itemCount.setAllQuantity(count.getAllQuantity()); |
| | | itemCount.setCompletedPercentage(count.getCompletedPercentage()); |
| | | itemCount.setTemplateid(count.getTemplateid()); |
| | | //计算选择比例 |
| | | int chosenQuantity = ObjectUtils.isNotEmpty(itemCount.getChosenQuantity()) ? itemCount.getChosenQuantity() : 0; |
| | | int completedQuantity = itemCount.getCompletedQuantity(); |
| | | if (ObjectUtils.isNotEmpty(completedQuantity) && completedQuantity != 0) { |
| | | BigDecimal chosenPercentage = (new BigDecimal(chosenQuantity)).divide(new BigDecimal(completedQuantity), 2, RoundingMode.HALF_UP); |
| | | itemCount.setChosenPercentage(chosenPercentage.toString()); |
| | | } |
| | | itemCountMap.put(itemCount.getOptionText(), itemCount); |
| | | } |
| | | }); |
| | | List<ServiceSubtaskScriptCount> itemCounts = new ArrayList<>(itemCountMap.values()); |
| | | count.setDetails(itemCounts); |
| | | result.put(count.getScriptid().toString(), count); |
| | | pageData.put(count.getScriptid().toString(), count); |
| | | } |
| | | Map<String, Object> result = new HashMap<>(); |
| | | // total 是题目总数(已按题目合并),rows/data 是当前页数据 |
| | | result.put("total", total); |
| | | result.put("pageNum", pageNum); |
| | | result.put("pageSize", pageSize); |
| | | result.put("rows", new ArrayList<>(pageCounts)); |
| | | result.put("data", pageData); |
| | | return result; |
| | | } |
| | | |
| | |
| | | total.setPendingFollowUp(0L); |
| | | total.setFollowUpSuccess(0L); |
| | | total.setFollowUpFail(0L); |
| | | total.setTimelyFollowUp(0L); |
| | | total.setManual(0L); |
| | | total.setSms(0L); |
| | | total.setWeChat(0L); |
| | |
| | | total.setPendingFollowUp(total.getPendingFollowUp() + (stat.getPendingFollowUp() != null ? stat.getPendingFollowUp() : 0L)); |
| | | total.setFollowUpSuccess(total.getFollowUpSuccess() + (stat.getFollowUpSuccess() != null ? stat.getFollowUpSuccess() : 0L)); |
| | | total.setFollowUpFail(total.getFollowUpFail() + (stat.getFollowUpFail() != null ? stat.getFollowUpFail() : 0L)); |
| | | total.setTimelyFollowUp(total.getTimelyFollowUp() + (stat.getTimelyFollowUp() != null ? stat.getTimelyFollowUp() : 0L)); |
| | | total.setManual(total.getManual() + (stat.getManual() != null ? stat.getManual() : 0L)); |
| | | total.setSms(total.getSms() + (stat.getSms() != null ? stat.getSms() : 0L)); |
| | | total.setWeChat(total.getWeChat() + (stat.getWeChat() != null ? stat.getWeChat() : 0L)); |