package com.xinelu.manage.service.statistics.impl;

import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.core.domain.entity.SysUser;
import com.xinelu.common.enums.NodeTypeEnum;
import com.xinelu.common.enums.PhoneDialMethodEnum;
import com.xinelu.common.enums.QuestionSubjectTypeEnum;
import com.xinelu.common.enums.QuestionTypeEnum;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.manage.domain.agency.Agency;
import com.xinelu.manage.domain.department.Department;
import com.xinelu.manage.dto.signpatientmanageroutenode.UploadRobotPublishRecordDto;
import com.xinelu.manage.dto.statistics.FollowUpRateDto;
import com.xinelu.manage.dto.statistics.QuestionnaireTaskStatisticsDto;
import com.xinelu.manage.mapper.department.DepartmentMapper;
import com.xinelu.manage.mapper.patientvisitrecord.PatientVisitRecordMapper;
import com.xinelu.manage.mapper.phonedialrecord.PhoneDialRecordMapper;
import com.xinelu.manage.mapper.questionsubject.QuestionSubjectMapper;
import com.xinelu.manage.mapper.shortmessagesendrecord.ShortMessageSendRecordMapper;
import com.xinelu.manage.mapper.signpatientmanageroutenode.SignPatientManageRouteNodeMapper;
import com.xinelu.manage.mapper.subscribemessagesendrecord.SubscribeMessageSendRecordMapper;
import com.xinelu.manage.service.agency.IAgencyService;
import com.xinelu.manage.service.department.IDepartmentService;
import com.xinelu.manage.service.statistics.IStatisticsService;
import com.xinelu.manage.vo.patientvisitrecord.PatientVisitRecordStatisticVo;
import com.xinelu.manage.vo.phonedialrecord.PhoneDialRecordVo;
import com.xinelu.manage.vo.signpatientmanageroutenode.PatientFollowUpPlanVo;
import com.xinelu.manage.vo.signpatientmanageroutenode.UploadRobotPublishRecordVo;
import com.xinelu.manage.vo.statistics.*;
import com.xinelu.system.mapper.SysUserMapper;
import com.xinelu.system.service.ISysUserService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

/**
 * @description: 统计模块Service业务层处理
 * @author: haown
 * @create: 2024-10-31 11:24
 **/
@Service
public class StatisticsServiceImpl implements IStatisticsService {

	@Resource
	private PhoneDialRecordMapper phoneDialRecordMapper;
	@Resource
	private ShortMessageSendRecordMapper shortMessageSendRecordMapper;
	@Resource
	private SubscribeMessageSendRecordMapper subscribeMessageSendRecordMapper;
	@Resource
	private PatientVisitRecordMapper patientVisitRecordMapper;
	@Resource
	private SignPatientManageRouteNodeMapper signPatientManageRouteNodeMapper;
	@Resource
	private IAgencyService agencyService;
	@Resource
	private IDepartmentService departmentService;
	@Resource
	private ISysUserService userService;
	@Resource
	private DepartmentMapper departmentMapper;
	@Resource
	private SysUserMapper sysUserMapper;
	@Resource
	private QuestionSubjectMapper questionSubjectMapper;

	/**
	 * @description 随访成功率统计
	 * @Param queryDto 随访成功率查询传输对象
	 * @return 随访成功率查询返回视图类
	 * @Author haown
	 * @Date 2024-11-1 10:48
	 */
	@Override
	public FollowUpRateVo getFollowUpRate(FollowUpRateDto queryDto) {
		if (queryDto.getStartDate() == null) {
			queryDto.setStartDate(LocalDate.now().withDayOfYear(1));
		}
		if (queryDto.getEndDate() == null) {
			queryDto.setEndDate(LocalDate.now());
		}
		FollowUpRateVo retObj = new FollowUpRateVo();
		List<PhoneDialRecordVo> phoneDialRecordVoList = phoneDialRecordMapper.getPhoneDialStatistic(queryDto);
		// 统计AI电话拨打次数、AI电话拨打次数成功率、AI拨打人数、AI拨打人数成功率、人工电话拨打次数、人工电话拨打次数成功率、人工拨打人数、人工拨打人数成功率
		retObj = getFollowUpRateVo(phoneDialRecordVoList);
		// 电话拨打总人数
		retObj.setSumPatientNum(retObj.getAiPatientNum() + retObj.getCommonPatientNum());
		// 短信发送数量
		List<MessageSendVo> messageSendList = shortMessageSendRecordMapper.getStatisticNum(queryDto);
		if (CollectionUtils.isNotEmpty(messageSendList)) {
			retObj.setSmsNum(messageSendList.size());
		}

		// 小程序推送数量
		List<MessageSendVo> subscribeRecordList = subscribeMessageSendRecordMapper.getStatisticNum(queryDto);
		if (CollectionUtils.isNotEmpty(subscribeRecordList)) {
			retObj.setSubscribeNum(subscribeRecordList.size());
		}

		// 数据趋势图
		List<FollowUpRateTrendVo> rateTrendVoList = new ArrayList<>();
		List<FollowUpNumTrendVo> numTrendVoList = new ArrayList<>();

		Map<String, List<PhoneDialRecordVo>> groupByDialTime = phoneDialRecordVoList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(PhoneDialRecordVo::getDialTimeMonth));

		Map<String, List<MessageSendVo>> megGroupBySendTime = messageSendList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(MessageSendVo::getSendTimeMonthStr));
		Map<String, List<MessageSendVo>> subGroupBySendTime = subscribeRecordList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(MessageSendVo::getSendTimeMonthStr));

		// 横坐标日期
		List<String> months = new ArrayList<>();
		LocalDate startDate = queryDto.getStartDate();
		while (!startDate.isAfter(queryDto.getEndDate())) {
			months.add(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM")));
			startDate = startDate.plus(1, ChronoUnit.MONTHS);
		}

		// 成功率趋势图
		for (String month : months) {
			List<PhoneDialRecordVo> monthDialList = groupByDialTime.get(month);
			FollowUpRateVo monthObj = getFollowUpRateVo(monthDialList);
			FollowUpRateTrendVo rateTrendVo = new FollowUpRateTrendVo();
			FollowUpNumTrendVo numTrendVo = new FollowUpNumTrendVo();

			rateTrendVo.setFollowUpMonth(month);
			rateTrendVo.setAiSuccessRate(monthObj.getAiSuccessRate());
			rateTrendVo.setCommonSuccessRate(monthObj.getCommonSuccessRate());
			rateTrendVo.setAiPatientSuccessRate(monthObj.getAiPatientSuccessRate());
			rateTrendVo.setCommonPatientSuccessRate(monthObj.getCommonPatientSuccessRate());
			rateTrendVoList.add(rateTrendVo);

			numTrendVo.setFollowUpMonth(month);
			numTrendVo.setAiPatientNum(monthObj.getAiPatientNum());
			numTrendVo.setCommonPatientNum(monthObj.getCommonPatientNum());

			// 短信发送数量
			List<MessageSendVo> megList = megGroupBySendTime.get(month);
			numTrendVo.setSmsNum(CollectionUtils.isEmpty(megList) ? 0 : megList.size());
			// 小程序发送数量
			List<MessageSendVo> subList = subGroupBySendTime.get(month);
			numTrendVo.setSubscribeNum(CollectionUtils.isEmpty(subList) ? 0 : subList.size());
			numTrendVoList.add(numTrendVo);
		}
		retObj.setRateTrendVoList(rateTrendVoList);
		retObj.setNumTrendVoList(numTrendVoList);
		return retObj;
	}

	/**
	 * @description 随访明细表统计查询
	 * @Param queryDto 随访成功率查询传输对象
	 * @return 随访明细表
	 * @Author haown
	 * @Date 2024-11-1 10:47
	 */
	@Override
	public List<FollowUpDetailVo> getFollowUpDetail(FollowUpRateDto queryDto) {
		if (queryDto.getStartDate() == null) {
			queryDto.setStartDate(LocalDate.now().withDayOfYear(1));
		}
		if (queryDto.getEndDate() == null) {
			queryDto.setEndDate(LocalDate.now());
		}
		List<FollowUpDetailVo> retList = new ArrayList<>();
		// 就诊患者列表查询
		List<PatientVisitRecordStatisticVo> patientVisitList = patientVisitRecordMapper.getVisitPatientList(queryDto);
		// 随访计划列表查询
		List<PatientFollowUpPlanVo> planList = signPatientManageRouteNodeMapper.getFollowUpPlan(queryDto);

		if (StringUtils.equals(queryDto.getType(), "dept")) {
			FollowUpDetailVo firstRow = new FollowUpDetailVo();
			firstRow.setRowName("总计");
			// 总计行预留位置
			retList.add(0, firstRow);

			// 就诊患者列表按照科室分组
			Map<Long, List<PatientVisitRecordStatisticVo>> groupByDept = new HashMap<>();
			if (CollectionUtils.isNotEmpty(patientVisitList)) {
				groupByDept = patientVisitList.stream().filter(item -> item.getDepartmentId() != null).collect(Collectors.groupingBy(PatientVisitRecordStatisticVo::getDepartmentId));
			}

			Map<Long, List<PatientFollowUpPlanVo>> planGroupByDept = new HashMap<>();
			if (CollectionUtils.isNotEmpty(planList)) {
				// 随访计划列表按照科室分组
				planGroupByDept = planList.stream().filter(item-> item.getDepartmentId() != null).collect(Collectors.groupingBy(PatientFollowUpPlanVo::getDepartmentId));
			}
			// 查询机构、科室、医生列表
			Agency agencyQuery = new Agency();
			agencyQuery.setId(queryDto.getHospitalAgencyId());
			List<Agency> agencyList = agencyService.selectAgencyByIdList(agencyQuery);
			for (Agency agency : agencyList) {
				// 根据机构列表查询科室
				Department deptQuery = new Department();
				deptQuery.setHospitalAgencyId(agency.getId());
				deptQuery.setNodeType(NodeTypeEnum.DEPARTMENT.getInfo());
				//List<Department> deptList = departmentService.selectDepartmentList(deptQuery);
				//2025/01/23 zh add start
				List<Department> deptList = departmentMapper.selectDepartmentList(deptQuery);
				List<Long> departmentIds = deptList.stream().filter(Objects::nonNull).map(Department::getId).distinct().collect(Collectors.toList());
				List<SysUser> sysUsers = sysUserMapper.selectUserListByHospitalAgencyId(agency.getId(), departmentIds);
				//2025/01/23 zh add end
				for (Department dept : deptList) {
					FollowUpDetailVo followUpDetailVo = new FollowUpDetailVo();
					followUpDetailVo.setRowName(dept.getDepartmentName());
					// 就诊人数
					List<PatientVisitRecordStatisticVo> deptVisitList = groupByDept.get(dept.getId());
					followUpDetailVo.setPatientNum(CollectionUtils.isEmpty(deptVisitList) ? 0 : groupByDept.get(dept.getId()).size());

					// 科室统计随访计划人数、随访覆盖率、随访成功人数、随访成功率
					List<PatientFollowUpPlanVo> deptPlanList = planGroupByDept.get(dept.getId());
					getFollowUpDetailVo(deptPlanList, followUpDetailVo);

					// 查询科室医生
//					SysUser userQuery = new SysUser();
//					userQuery.setHospitalAgencyId(dept.getHospitalAgencyId());
//					userQuery.setDepartmentId(dept.getId());
//					List<SysUser> userList = userService.selectUserList(userQuery);
					//2025/01/23 zh add start
					List<SysUser> userList = sysUsers.stream().filter(Objects::nonNull).filter(item -> item.getDepartmentId().equals(dept.getId())).collect(Collectors.toList());
					//2025/01/23 zh add end
					List<FollowUpDetailVo> childrenList = new ArrayList<>();

					Map<Long, List<PatientVisitRecordStatisticVo>> patientGroupByDoctor = new HashMap<>();
					Map<Long, List<PatientFollowUpPlanVo>> planGroupByDoctor = new HashMap<>();
					if (CollectionUtils.isNotEmpty(deptVisitList)) {
						patientGroupByDoctor = deptVisitList.stream().filter(item-> item.getAttendingPhysicianId() != null).collect(Collectors.groupingBy(PatientVisitRecordStatisticVo::getAttendingPhysicianId));
					}
					if (CollectionUtils.isNotEmpty(deptPlanList)) {
						planGroupByDoctor = deptPlanList.stream().filter(item-> item.getAttendingPhysicianId() != null).collect(Collectors.groupingBy(PatientFollowUpPlanVo::getAttendingPhysicianId));
					}

					for (SysUser user : userList) {
						FollowUpDetailVo childRow = new FollowUpDetailVo();
						childRow.setRowName(user.getNickName());

						List<PatientVisitRecordStatisticVo> doctorPatientList = patientGroupByDoctor.get(user.getUserId());
						if (CollectionUtils.isEmpty(doctorPatientList)) {
							childRow.setPatientNum(0);
						} else {
							Map<Long, List<PatientVisitRecordStatisticVo>> doctorGroupByPatient = doctorPatientList.stream().collect(Collectors.groupingBy(PatientVisitRecordStatisticVo::getPatientId));
							// 医生就诊人数
							childRow.setPatientNum(CollectionUtils.isEmpty(doctorPatientList) ? 0 : doctorGroupByPatient.keySet().size());
						}


						// 医生统计随访计划人数、随访覆盖率、随访成功人数、随访成功率
						List<PatientFollowUpPlanVo> doctorPlanList = planGroupByDoctor.get(user.getUserId());
						getFollowUpDetailVo(doctorPlanList, childRow);
						childrenList.add(childRow);
					}

					followUpDetailVo.setChilderenList(childrenList);
					retList.add(followUpDetailVo);

					// 计算总计行
					getTotalRow(firstRow, retList);
				}
			}
		} else if (StringUtils.equals(queryDto.getType(), "date")) {
			// 日期列表
			List<String> months = new ArrayList<>();
			LocalDate startDate = queryDto.getStartDate();
			while (!startDate.isAfter(queryDto.getEndDate())) {
				months.add(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM")));
				startDate = startDate.plus(1, ChronoUnit.MONTHS);
			}
			// 就诊患者列表按照就诊日期分组
			Map<String, List<PatientVisitRecordStatisticVo>> groupByVisitDate = new HashMap<>();
			if (CollectionUtils.isNotEmpty(patientVisitList)) {
				groupByVisitDate = patientVisitList.stream().collect(Collectors.groupingBy(PatientVisitRecordStatisticVo::getDischargeTimeMonthStr));
			}

			Map<String, List<PatientFollowUpPlanVo>> planGroupByExecuteDate = new HashMap<>();
			if (CollectionUtils.isNotEmpty(planList)) {
				// 随访计划列表按照计划日期分组
				planGroupByExecuteDate = planList.stream().collect(Collectors.groupingBy(PatientFollowUpPlanVo::getExecuteMonthStr));
			}
			for (String month : months) {
				FollowUpDetailVo followUpDetailVo = new FollowUpDetailVo();
				followUpDetailVo.setRowName(month);
				// 就诊人数
				followUpDetailVo.setPatientNum(groupByVisitDate.getOrDefault(month, new ArrayList<>()).size());
				// 有随访计划人数
				//followUpDetailVo.setFollowUpNum(planGroupByExecuteDate.getOrDefault(month, new ArrayList<>()).size());
				// 随访覆盖率
				//followUpDetailVo.setFollowUpCoverRate(new BigDecimal(followUpDetailVo.getFollowUpNum()).divide(new BigDecimal(followUpDetailVo.getPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
				// 随访计划人数、随访覆盖率、随访成功人数、随访成功率
				getFollowUpDetailVo(planGroupByExecuteDate.getOrDefault(month, new ArrayList<>()), followUpDetailVo);

				// 按随访方式统计
				List<PhoneDialRecordVo> phoneDialRecordVoList = phoneDialRecordMapper.getPhoneDialStatistic(queryDto);
				// 统计AI电话拨打次数、AI电话拨打次数成功率、人工电话拨打次数、人工电话拨打次数成功率
				FollowUpRateVo followUpRateVo = getFollowUpRateVo(phoneDialRecordVoList);
				followUpDetailVo.setAiNum(followUpRateVo.getAiNum());
				followUpDetailVo.setAiSuccessRate(followUpRateVo.getAiSuccessRate());
				followUpDetailVo.setCommonNum(followUpRateVo.getCommonNum());
				followUpDetailVo.setCommonSuccessRate(followUpRateVo.getCommonSuccessRate());

				retList.add(followUpDetailVo);
			}
		}

		return retList;
	}

	/**
	 * 问卷任务统计
	 *
	 * @param questionnaireTaskStatisticsDto 时间问卷信息
	 * @return AjaxResult
	 */
	@Override
	public AjaxResult questionnaireTaskStatistics(QuestionnaireTaskStatisticsDto questionnaireTaskStatisticsDto) {
		List<QuestionnaireTaskStatisticsVo> output = new ArrayList<>();
		//查询原问卷信息
		List<QuestionnaireTaskStatisticsVo> subjectAndOptionVos = questionSubjectMapper.selectQuestionnaireByQuestionnaireId(questionnaireTaskStatisticsDto.getQuestionInfoId());
		//空数据组装返回
		if (CollectionUtils.isEmpty(subjectAndOptionVos)) {
			return AjaxResult.success();
		}
		//查询问卷任务
		List<QuestionnaireTaskStatisticsVo> questionnaireTaskStatisticsVos = signPatientManageRouteNodeMapper.questionnaireTaskStatistics(questionnaireTaskStatisticsDto);
		//空数据返回原问卷信息
		List<Long> total = null;
		if (CollectionUtils.isNotEmpty(questionnaireTaskStatisticsVos)) {
			questionnaireTaskStatisticsVos = questionnaireTaskStatisticsVos.stream().filter(Objects::nonNull).filter(item -> Objects.nonNull(item.getQuestionSubjectOptionId())).collect(Collectors.toList());
			total = questionnaireTaskStatisticsVos.stream().filter(Objects::nonNull).map(QuestionnaireTaskStatisticsVo::getManageRouteNodeId).distinct().collect(Collectors.toList());
		}
		//遍历计算
		List<QuestionnaireTaskOptionStatisticsVo> optionStatisticsVos = new ArrayList<>();
		if (questionnaireTaskStatisticsVos.size() > 0 && total != null && total.size() > 0) {
			for (QuestionnaireTaskStatisticsVo subjectAndOptionVo : subjectAndOptionVos) {
				QuestionnaireTaskOptionStatisticsVo optionStatisticsVo = new QuestionnaireTaskOptionStatisticsVo();
				//根据 题目序号、选项已选择过滤
				List<QuestionnaireTaskStatisticsVo> choice = questionnaireTaskStatisticsVos.stream().filter(Objects::nonNull)
						.filter(item -> Objects.nonNull(item.getQuestionNumber()) && item.getQuestionNumber().equals(subjectAndOptionVo.getQuestionNumber())
								&& Objects.equals(item.getQuestionSubjectOptionId(), subjectAndOptionVo.getQuestionSubjectOptionId())
								&& item.getOptionChooseSign() == 0)
						.collect(Collectors.toList());
				if (choice.size() > 0) {
					subjectAndOptionVo.setChoiceProportion(new BigDecimal(choice.size()).divide(new BigDecimal(total.size()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
					optionStatisticsVo.setChoiceNumber((long) choice.size());
				} else {
					subjectAndOptionVo.setChoiceProportion(BigDecimal.ZERO);
					optionStatisticsVo.setChoiceNumber(0L);
				}
				optionStatisticsVo.setQuestionSubjectOptionId(subjectAndOptionVo.getQuestionSubjectOptionId());
				optionStatisticsVo.setQuestionInfoId(questionnaireTaskStatisticsDto.getQuestionInfoId());
				optionStatisticsVo.setOptionName(subjectAndOptionVo.getOptionName());
				optionStatisticsVo.setQuestionNumber(subjectAndOptionVo.getQuestionNumber());
				optionStatisticsVo.setChoiceProportion(subjectAndOptionVo.getChoiceProportion());
				optionStatisticsVos.add(optionStatisticsVo);
			}
		} else {
			//如果没数据返回问卷模板
			for (QuestionnaireTaskStatisticsVo subjectAndOptionVo : subjectAndOptionVos) {
				QuestionnaireTaskOptionStatisticsVo optionStatisticsVo = new QuestionnaireTaskOptionStatisticsVo();
				optionStatisticsVo.setQuestionInfoId(questionnaireTaskStatisticsDto.getQuestionInfoId());
				optionStatisticsVo.setQuestionSubjectOptionId(subjectAndOptionVo.getQuestionSubjectOptionId());
				optionStatisticsVo.setOptionName(subjectAndOptionVo.getOptionName());
				optionStatisticsVo.setQuestionNumber(subjectAndOptionVo.getQuestionNumber());
				optionStatisticsVo.setChoiceProportion(BigDecimal.ZERO);
				optionStatisticsVo.setChoiceNumber(0L);
				optionStatisticsVos.add(optionStatisticsVo);
			}
		}
		//根据题号组装数据类型
		List<BigDecimal> questionNumberList = subjectAndOptionVos.stream().filter(Objects::nonNull)
				.filter(item -> item.getQuestionType().equals(QuestionSubjectTypeEnum.MULTIPLE_CHOICE.getInfo()) || item.getQuestionType().equals(QuestionSubjectTypeEnum.MULTIPLE_CHOICE_QUESTIONS.getInfo()))
				.map(QuestionnaireTaskStatisticsVo::getQuestionNumber).distinct().collect(Collectors.toList());
		for (BigDecimal questionNumber : questionNumberList) {
			QuestionnaireTaskStatisticsVo questionnaireTaskStatisticsVo = new QuestionnaireTaskStatisticsVo();
			List<QuestionnaireTaskOptionStatisticsVo> collect = optionStatisticsVos.stream().filter(Objects::nonNull).filter(item -> questionNumber.equals(item.getQuestionNumber())).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(collect)) {
				questionnaireTaskStatisticsVo.setQuestionnaireName(collect.get(0).getQuestionnaireName());
				questionnaireTaskStatisticsVo.setCreateTime(collect.get(0).getCreateTime());
				questionnaireTaskStatisticsVo.setQuestionName(collect.get(0).getQuestionName());
				questionnaireTaskStatisticsVo.setQuestionNumber(collect.get(0).getQuestionNumber());
				questionnaireTaskStatisticsVo.setQuestionnaireTaskOptionStatisticsVos(collect);
				output.add(questionnaireTaskStatisticsVo);
			}
		}
		return AjaxResult.success(output);
	}

	/**
	 * 问卷任务统计选项统计
	 *
	 * @param uploadRobotPublishRecordDto 时间信息
	 * @return UploadRobotPublishRecordVo
	 */
	@Override
	public List<UploadRobotPublishRecordVo> questionnaireTaskOptionList(UploadRobotPublishRecordDto uploadRobotPublishRecordDto) {
        if (Objects.nonNull(uploadRobotPublishRecordDto)){
			// sql查询反馈意见使用
			uploadRobotPublishRecordDto.setQuestionType(QuestionTypeEnum.FEEDBACK_BLANKS_SUBJECT.getInfo());
			//选项已选择
			uploadRobotPublishRecordDto.setOptionChooseSign(0);
		}
		return signPatientManageRouteNodeMapper.selectTaskOptionContented(uploadRobotPublishRecordDto);
	}

	/**
	 * @description 统计AI电话拨打次数、AI电话拨打次数成功率、AI拨打人数、AI拨打人数成功率、人工电话拨打次数、人工电话拨打次数成功率、人工拨打人数、人工拨打人数成功率
	 * @Param 拨打电话记录列表
	 * @return 随访成功率查询返回视图类
	 * @Author haown
	 * @Date 2024-11-1 9:31
	*/
	private FollowUpRateVo getFollowUpRateVo(List<PhoneDialRecordVo> phoneDialRecordVoList) {
		FollowUpRateVo retObj = new FollowUpRateVo();
		if (CollectionUtils.isEmpty(phoneDialRecordVoList)) {
			return retObj;
		}
		// 按照拨打方式分组
		Map<String, List<PhoneDialRecordVo>> groupByDialMethod = phoneDialRecordVoList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(PhoneDialRecordVo::getPhoneDialMethod));
		List<PhoneDialRecordVo> aiDialList = groupByDialMethod.get(PhoneDialMethodEnum.AI.getInfo());
		List<PhoneDialRecordVo> commonDialList = groupByDialMethod.get(PhoneDialMethodEnum.COMMON.getInfo());
		if (CollectionUtils.isNotEmpty(aiDialList)) {
			// 筛选成功数量
			List<PhoneDialRecordVo> aiSuccessList = aiDialList.stream().filter(item -> item.getErrorCode() == 0).collect(Collectors.toList());
			// 统计AI电话拨打次数
			retObj.setAiNum(aiDialList.size());
			// 统计AI电话拨打次数成功率
			retObj.setAiSuccessRate(CollectionUtils.isEmpty(aiSuccessList) ? BigDecimal.ZERO :
				new BigDecimal(aiSuccessList.size()).divide(new BigDecimal(retObj.getAiNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));

			// 统计AI拨打人数
			Map<Long, List<PhoneDialRecordVo>> groupByPatient = aiDialList.stream().collect(Collectors.groupingBy(PhoneDialRecordVo::getPatientId));
			retObj.setAiPatientNum(groupByPatient.keySet().size());
			// AI拨打人数成功率
			if (CollectionUtils.isNotEmpty(aiSuccessList)) {
				Map<Long, List<PhoneDialRecordVo>> aiSuccessGroupByPatient = aiSuccessList.stream().collect(Collectors.groupingBy(PhoneDialRecordVo::getPatientId));
				retObj.setAiPatientSuccessRate((retObj.getAiPatientNum() == null || retObj.getAiPatientNum() == 0) ? BigDecimal.ZERO :new BigDecimal(aiSuccessGroupByPatient.keySet().size()).divide(new BigDecimal(retObj.getAiPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
			}
		}

		if (CollectionUtils.isNotEmpty(commonDialList)) {
			// 筛选成功数量
			List<PhoneDialRecordVo> commonSuccessList = commonDialList.stream().filter(item -> item.getErrorCode() == 0).collect(Collectors.toList());
			// 统计人工电话拨打次数
			retObj.setCommonNum(commonDialList.size());
			// 统计人工电话拨打次数成功率
			retObj.setCommonSuccessRate(CollectionUtils.isEmpty(commonSuccessList) ? BigDecimal.ZERO :
				new BigDecimal(commonSuccessList.size()).divide(new BigDecimal(commonDialList.size()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));

			// 统计人工拨打人数
			Map<Long, List<PhoneDialRecordVo>> groupByPatient = commonDialList.stream().collect(Collectors.groupingBy(PhoneDialRecordVo::getPatientId));
			retObj.setAiPatientNum(groupByPatient.keySet().size());
			// 人工拨打人数成功率
			if (CollectionUtils.isNotEmpty(commonSuccessList)) {
				Map<Long, List<PhoneDialRecordVo>> commonSuccessGroupByPatient = commonSuccessList.stream().collect(Collectors.groupingBy(PhoneDialRecordVo::getPatientId));
				retObj.setCommonPatientSuccessRate((retObj.getCommonPatientNum() == null || retObj.getCommonPatientNum()== 0) ? BigDecimal.ZERO : new BigDecimal(commonSuccessGroupByPatient.keySet().size()).divide(new BigDecimal(retObj.getCommonPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
			}
		}
		return retObj;
	}

	/**
	 * @description 统计随访计划人数、随访覆盖率、随访成功人数、随访成功率
	 * @Param planList 随访计划
	 * @Param followUpDetailVo 随访明细表
	 * @Author haown
	 * @Date 2024-11-4 11:13
	*/
	private FollowUpDetailVo getFollowUpDetailVo(List<PatientFollowUpPlanVo> planList, FollowUpDetailVo followUpDetailVo) {
		if (followUpDetailVo.getPatientNum() == 0 || CollectionUtils.isEmpty(planList)) {
			followUpDetailVo.setFollowUpNum(0);
			followUpDetailVo.setFollowUpCoverRate(BigDecimal.ZERO);
			followUpDetailVo.setFollowUpSuccessNum(0);
			followUpDetailVo.setFollowUpSuccessRate(BigDecimal.ZERO);
			return followUpDetailVo;
		}
		// 按照patientId分组
		Map<Long, List<PatientFollowUpPlanVo>> groupByPatient = planList.stream().collect(Collectors.groupingBy(PatientFollowUpPlanVo::getPatientId));
		// 有随访计划人数
		followUpDetailVo.setFollowUpNum(groupByPatient.keySet().size());
		// 随访覆盖率
		followUpDetailVo.setFollowUpCoverRate(new BigDecimal(followUpDetailVo.getFollowUpNum()).divide(new BigDecimal(followUpDetailVo.getPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));

		// 随访成功人数
		Map<Long, List<PatientFollowUpPlanVo>> groupByFinishStatus = planList.stream().filter(item -> item.getTaskFinishStatus() == 1).collect(Collectors.groupingBy(PatientFollowUpPlanVo::getPatientId));
		followUpDetailVo.setFollowUpSuccessNum(groupByFinishStatus.keySet().size());
		// 随访成功率
		followUpDetailVo.setFollowUpSuccessRate(new BigDecimal(followUpDetailVo.getFollowUpSuccessNum()).divide(new BigDecimal(followUpDetailVo.getPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));

		return followUpDetailVo;
	}

	/**
	 * @description 计算总计行就诊人数、随访计划人数、随访覆盖率、随访成功人数、随访成功率
	 * @Param  * @param null
	 * @return 列表数据
	 * @Author haown
	 * @Date 2024-11-4 11:29
	*/
	private List<FollowUpDetailVo> getTotalRow(FollowUpDetailVo firstRow, List<FollowUpDetailVo> followUpDetailVoList) {
		firstRow.setRowName("总计");
		// 就诊人数
		//firstRow.setPatientNum(followUpDetailVoList.stream().map(FollowUpDetailVo::getPatientNum).reduce(Integer::sum).get());
		firstRow.setPatientNum(followUpDetailVoList.stream().filter(item -> !item.getRowName().equals("总计")).map(FollowUpDetailVo::getPatientNum).reduce(Integer::sum).get());//2025/01/23 zh add
		// 随访计划人数
		//firstRow.setFollowUpNum(followUpDetailVoList.stream().map(FollowUpDetailVo::getFollowUpNum).reduce(Integer::sum).get());
		firstRow.setFollowUpNum(followUpDetailVoList.stream().filter(item -> !item.getRowName().equals("总计")).map(FollowUpDetailVo::getFollowUpNum).reduce(Integer::sum).get());//2025/01/23 zh add
		// 随访覆盖率
		if (firstRow.getPatientNum() != null && firstRow.getPatientNum() > 0) {
			firstRow.setFollowUpCoverRate(new BigDecimal(firstRow.getFollowUpNum()).divide(new BigDecimal(firstRow.getPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
		}

		// 随访成功人数
		//firstRow.setFollowUpSuccessNum(followUpDetailVoList.stream().map(FollowUpDetailVo::getFollowUpSuccessNum).reduce(Integer::sum).get());
		firstRow.setFollowUpSuccessNum(followUpDetailVoList.stream().filter(item -> !item.getRowName().equals("总计")).map(FollowUpDetailVo::getFollowUpSuccessNum).reduce(Integer::sum).get());//2025/01/23 zh add
		// 随访成功率
		if (firstRow.getPatientNum() != null && firstRow.getPatientNum() > 0) {
			firstRow.setFollowUpSuccessRate(new BigDecimal(firstRow.getFollowUpSuccessNum()).divide(new BigDecimal(firstRow.getPatientNum()), 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100")));
		}
		followUpDetailVoList.set(0, firstRow);
		return followUpDetailVoList;
	}

}
