package cn.iocoder.yudao.module.pms.service.iotrydailyreport;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.module.pms.constant.PmsConstants;
import cn.iocoder.yudao.module.pms.controller.admin.depttype.vo.IotDeptTypePageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicecategorytemplateattrs.vo.IotDeviceProperty;
import cn.iocoder.yudao.module.pms.controller.admin.iotopeationfill.vo.IotOpeationFillPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotprojecttask.vo.IotProjectTaskPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreport.vo.*;
import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreportdetail.vo.IotRyDailyReportDetailPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreportdetail.vo.IotRyDailyReportDetailRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotrydailyreportdetail.vo.IotRyDailyReportDetailSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDevicePageReqVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.depttype.IotDeptTypeDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotopeationfill.IotOpeationFillDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttask.IotProjectTaskDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotprojecttaskattrs.IotTaskAttrModelProperty;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotrydailyreport.IotRyDailyReportDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotrydailyreportdetail.IotRyDailyReportDetailDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.depttype.IotDeptTypeMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotopeationfill.IotOpeationFillMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotprojecttask.IotProjectTaskMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotrydailyreport.IotRyDailyReportMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotrydailyreportdetail.IotRyDailyReportDetailMapper;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.util.LocalTimeUtils;
import cn.iocoder.yudao.module.supplier.enums.common.SupplierAuditStatusEnum;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictTypeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.dict.DictTypeService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.*;
import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;


/**
 * 瑞鹰日报 Service 实现类
 *
 * @author ruiqi
 */
@Service
@Validated
public class IotRyDailyReportServiceImpl implements IotRyDailyReportService {

    @Resource
    private IotRyDailyReportMapper iotRyDailyReportMapper;
    @Resource
    private IotProjectTaskMapper iotProjectTaskMapper;
    @Resource
    private DictTypeService dictTypeService;
    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private DeptService deptService;
    @Resource
    private IotDeptTypeMapper iotDeptTypeMapper;
    @Resource
    private AdminUserService adminUserService;
    @Resource
    private RoleService roleService;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource(name = PMS_THREAD_POOL_TASK_EXECUTOR)
    private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
    @Resource
    private PmsMessage pmsMessage;
    @Resource
    private IotOpeationFillMapper iotOpeationFillMapper;
    @Resource
    private IotRyDailyReportDetailMapper iotRyDailyReportDetailMapper;


    @Override
    public Long createIotRyDailyReport(IotRyDailyReportSaveReqVO createReqVO) {
        // 插入
        IotRyDailyReportDO iotRyDailyReport = BeanUtils.toBean(createReqVO, IotRyDailyReportDO.class);
        LocalDateTime reportDate = createReqVO.getFillOrderCreateTime();
        if (ObjUtil.isEmpty(reportDate)) {
            throw exception(IOT_RH_DAILY_REPORT_NO_DATE);
        }
        if (ObjUtil.isEmpty(createReqVO.getDeptId())) {
            throw exception(IOT_RH_DAILY_REPORT_NO_DEPT);
        }
        if ((StrUtil.isBlank(createReqVO.getProjectClassification()) || "1".equals(createReqVO.getProjectClassification()))
                && ObjUtil.isEmpty(createReqVO.getCurrentDepth())) {
            // 钻井类型日报必须 填写当前井深
            throw exception(IOT_RY_DAILY_REPORT_CURRENT_DEPTH_NOT_EXISTS);
        }
        // 如果是编辑状态 不要设置 日报状态 和 审核状态
        if (StrUtil.isBlank(createReqVO.getEditFlag())) {
            // 设置 日报填写状态 审核状态
            iotRyDailyReport.setStatus(1);
            // 设置 日报审批状态为 审批中 auditStatus = 10
            iotRyDailyReport.setAuditStatus(10);
        }
        // 根据日报的 施工队伍 deptId 查询队伍所在的 项目 任务
        // 根据日报的施工状态 更新 对应任务的 状态
        Long taskId = null; // Long.MIN_VALUE;
        Set<Long> deviceIds = new HashSet<>();
        List<IotProjectTaskDO> tasks = new ArrayList<>();
        IotProjectTaskPageReqVO reqVO = new IotProjectTaskPageReqVO();
        if (ObjUtil.isEmpty(createReqVO.getTaskId())) {
            reqVO.setDeptId(createReqVO.getDeptId());
            // 只筛选未施工完成的任务
            reqVO.setJobFlag("Y");
        } else {
            List<Long> taskIds = new ArrayList<>();
            taskIds.add(createReqVO.getTaskId());
            reqVO.setTaskIds(taskIds);
        }
        // 查询包含当前日报施工队伍的任务
        tasks = iotProjectTaskMapper.selectList(reqVO);
        // 井号
        String wellName;
        if (CollUtil.isNotEmpty(tasks)) {
            IotProjectTaskDO task = tasks.get(0);
            wellName = task.getWellName();
            // 暂时只考虑1个施工队伍只属于1个任务
            iotRyDailyReport.setProjectId(task.getProjectId());
            iotRyDailyReport.setTaskId(task.getId());
            taskId = task.getId();
            // 根据日报状态 查询 日报所属任务的状态 瑞鹰任务状态数据字典 rigStatus
            if (ObjUtil.isNotEmpty(createReqVO.getRigStatus())) {
                // ry任务施工状态 需要与 任务施工状态 匹配 钻井施工状态
                task.setStatus(createReqVO.getRigStatus());
                task.setRigStatus(createReqVO.getRigStatus());
                // 更新任务状态
                iotProjectTaskMapper.updateById(task);
            }
            if (ObjUtil.isNotEmpty(createReqVO.getRepairStatus())) {
                task.setStatus(createReqVO.getRepairStatus());
                task.setRepairStatus(createReqVO.getRepairStatus());
                // 更新任务状态
                iotProjectTaskMapper.updateById(task);
            }
            // 查询任务的设备列表
            deviceIds = task.getDeviceIds();
        } else {
            wellName = StrUtil.EMPTY;
            // 当前队伍没有关联任务 不生成日报
        }

        if (StrUtil.isBlank(createReqVO.getProjectClassification()) || "1".equals(createReqVO.getProjectClassification())) {
            // 钻井类型日报 需要根据当前井深 计算 日进尺 月进尺 年累计进尺
            // 切换新井号时 当前井深=日进尺 根据施工队伍计算月累进尺、年累进尺
            // 计算月进尺 年累计进尺 reportDate对应的前一天的 年-月份 对应的日报记录日进尺的累加值
            // 查询指定部门、指定时间段 填写的日报记录的 ’月进尺数据‘(逻辑细则：reportDate 所在的月份与数据表的字段 construction_start_date
            // 所在的月份相匹配 且 create_time < reportDate 的记录的 ’daily_footage‘ 字段值累加计算得出
            BigDecimal historyMonthlyFootage = iotRyDailyReportMapper.monthlyFootages(createReqVO.getDeptId(), reportDate);
            BigDecimal monthStartFootage = iotRyDailyReportMapper.monthStartFootage(createReqVO.getDeptId(), reportDate);

            // 查询指定部门、指定时间段 填写的日报记录的 ’年进尺数据‘(逻辑细则：reportDate 所在的年份与数据表的字段 construction_start_date
            // 所在的年份相匹配 且 create_time < reportDate 的记录的 ’daily_footage‘ 字段值累加计算得出
            BigDecimal historyAnnualFootage = iotRyDailyReportMapper.annualFootages(createReqVO.getDeptId(), reportDate);
            BigDecimal yearStartFootage = iotRyDailyReportMapper.yearStartFootage(createReqVO.getDeptId(), reportDate);

            // 当前井深 计算 日进尺 月进尺 年累计进尺
            // （当前井深 - 前一天日报中填写的 ‘当前井深’）= 日进尺
            // 将 reportDate 减去1天 得到日期 date(yyyy-MM-dd) 查询date对应的日报记录
            IotRyDailyReportDO lastReport = iotRyDailyReportMapper.selectLatestReportBeforeDate(
                    createReqVO.getDeptId(), taskId, reportDate);
            BigDecimal dailyFootage = BigDecimal.ZERO;
            if (ObjUtil.isNotEmpty(lastReport) && ObjUtil.isNotEmpty(lastReport.getCurrentDepth())) {
                // 井号已经产生过日报 当前井深-前一天日报的当前井深 = 日进尺
                dailyFootage = createReqVO.getCurrentDepth().subtract(lastReport.getCurrentDepth());
                iotRyDailyReport.setDailyFootage(dailyFootage);
            } else {
                // 新井号 如果没有查询到数据 则设置 日进尺 为 当前井深 后期可修复数据
                dailyFootage = createReqVO.getCurrentDepth();
                // 月进尺 = 当前队伍 施工日期所在月份的日进尺加和
                // iotRyDailyReport.setMonthlyFootage(BigDecimal.ZERO);
                // 年累计进尺 = 当前队伍 施工日期所在年份的日进尺加和
                // iotRyDailyReport.setAnnualFootage(BigDecimal.ZERO);
            }
            iotRyDailyReport.setDailyFootage(dailyFootage);
            iotRyDailyReport.setMonthlyFootage(dailyFootage.add(historyMonthlyFootage));
            iotRyDailyReport.setAnnualFootage(dailyFootage.add(historyAnnualFootage));
        }

        // 设置瑞鹰日报类型 钻井 修井
        if (StrUtil.isBlank(createReqVO.getProjectClassification())) {
            iotRyDailyReport.setProjectClassification("1");
        }

        // 当天如果已经有此小队的记录 新增 当天如果没有此小队的日报记录 修改
        // deptId - taskId - createTime(yyyy-MM-dd) 确定唯一一条记录 不能使用 LocalDateTime.now() 来查询，应该使用 运行记录工单的创建日期查询
        IotRyDailyReportDO existReport = iotRyDailyReportMapper.selectExistReport(createReqVO.getDeptId(), null, reportDate);
        LocalDateTime reportDetailDate;
        if (ObjUtil.isEmpty(existReport)) {

            // reportDate 所代表日期前1天的7点
            LocalDateTime today7am = reportDate.withHour(7).withMinute(0).withSecond(0).withNano(0);
            reportDetailDate = reportDate;
            // reportDate 所代表日期的7点
            LocalDateTime yesterday7am = today7am.minusDays(1);
            iotRyDailyReport.setConstructionStartDate(yesterday7am);
            iotRyDailyReport.setConstructionEndDate(today7am);
            iotRyDailyReport.setCreateTime(reportDate);
            iotRyDailyReport.setUpdateTime(reportDate);
            iotRyDailyReportMapper.insert(iotRyDailyReport);
        } else {
            // 修改现有记录
            iotRyDailyReport.setId(existReport.getId());
            reportDetailDate = existReport.getCreateTime();
            iotRyDailyReportMapper.updateById(iotRyDailyReport);
        }
        // 保存日报生产动态明细
        if (CollUtil.isNotEmpty(createReqVO.getReportDetails())) {
            List<IotRyDailyReportDetailSaveReqVO> reportDetails = createReqVO.getReportDetails();
            // 先删除明细 再新增
            int count = iotRyDailyReportDetailMapper.deleteByMap(ImmutableMap.of(
                    "report_id", iotRyDailyReport.getId()
            ));
            // 新增生产动态明细
            List<IotRyDailyReportDetailDO> reportDOs = new ArrayList<>();
            reportDetails.forEach(detail -> {
                String detailEndTime = detail.getEndTime();
                if (StrUtil.isNotBlank(detailEndTime)) {
                    String[] timeAttr = detailEndTime.split(":");
                    if ("24".equals(timeAttr[0])) {
                        detail.setEndTime("23:59:59");
                    }
                }
                IotRyDailyReportDetailDO tempDetail = BeanUtils.toBean(detail, IotRyDailyReportDetailDO.class);
                tempDetail.setDeptId(iotRyDailyReport.getDeptId());
                tempDetail.setTaskId(iotRyDailyReport.getTaskId());
                tempDetail.setReportId(iotRyDailyReport.getId());
                if (ObjUtil.isNotEmpty(detail.getReportDate())) {
                    tempDetail.setReportDate(detail.getReportDate());
                }
                if (ObjUtil.isNotEmpty(detail.getStartDateTime())) {
                    tempDetail.setReportDate(detail.getStartDateTime());
                }
                // 计算定额时效 = 定额时长/实际时长
                if (ObjUtil.isNotEmpty(detail.getAllocatedTime()) && ObjUtil.isNotEmpty(detail.getDuration()) && detail.getDuration().compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal subtrahend = detail.getAllocatedTime().divide(detail.getDuration(), 4, RoundingMode.HALF_UP);
                    tempDetail.setAllocatedEfficiency(subtrahend);
                }
                reportDOs.add(tempDetail);
            });
            // 插入日报明细记录
            if (CollUtil.isNotEmpty(reportDOs)) {
                iotRyDailyReportDetailMapper.insertBatch(reportDOs);
            }
        }
        // 生成消息提醒 到 项目部审批人员 站内信 钉钉
        if (StrUtil.isBlank(createReqVO.getEditFlag())) {
            // 日报管理员编辑审批后的日报 不需要发送钉钉消息提醒
            Long deptId = createReqVO.getDeptId();
            DataPermissionUtils.executeIgnore(() -> {
                DeptDO dept = deptService.getDept(deptId);
                if (ObjUtil.isEmpty(dept)) {
                    System.out.println("当前查询到的部门是NULL：" + deptId);
                }
                Long parentId = dept.getParentId();
                if (ObjUtil.isNotEmpty(parentId)) {
                    DeptDO projectDept = deptService.getDept(parentId);
                    // 当前部门的上级部门如果 不是项目部 再向上找一级 煤层气 项目
                    if (!"2".equals(projectDept.getType())) {
                        DeptDO newLevelDept = deptService.getDept(projectDept.getParentId());
                        // 将 newLevelDept 对象 关键字段赋值给 projectDept
                        projectDept.setId(newLevelDept.getId());
                        projectDept.setType(newLevelDept.getType());
                    }
                    // 查找队伍上级项目部 拥有‘项目部日报审批RY’角色 的审批人 如果查找不到 则使用 瑞鹰国际 下拥有‘项目部日报审批RY’角色的审批人
                    if (ObjUtil.isNotEmpty(projectDept) && "2".equals(projectDept.getType())) {
                        // 查询项目部下具有 项目部日报审批RY 角色的人员 如果查找不到 查询 瑞鹰国际下 拥有‘项目部日报审批RY’角色的审批人
                        // 瑞鹰国际 158
                        Set<Long> projectIds = new HashSet<>();
                        projectIds.add(projectDept.getId());
                        projectIds.add(158l);
                        List<AdminUserDO> receivedMsgUsers = adminUserService.getUserListByDeptIds(projectIds);
                        if (CollUtil.isNotEmpty(receivedMsgUsers)) {
                            Set<Long> userIds = new HashSet<>();
                            receivedMsgUsers.forEach(user -> {
                                userIds.add(user.getId());
                            });
                            RoleDO role;
                            if ("1".equals(iotRyDailyReport.getProjectClassification())) {
                                // 钻井
                                role = roleService.getRoleByCode("项目部日报审批RY");
                            } else {
                                // 修井
                                role = roleService.getRoleByCode("项目部日报审批RYXJ");
                            }
                            if (ObjUtil.isNotEmpty(role)) {
                                Set<Long> roleIds = new HashSet<>();
                                roleIds.add(role.getId());
                                List<UserRoleDO> userRoles = userRoleMapper.selectListByRoleIds(roleIds);
                                if (CollUtil.isNotEmpty(userRoles)) {
                                    // 提取有审批角色的所有用户ID（去重+空值过滤）
                                    Set<Long> roleUserIds = userRoles.stream()
                                            .map(UserRoleDO::getUserId)
                                            .filter(Objects::nonNull) // 过滤空userId
                                            .collect(Collectors.toSet());
                                    // 计算两个集合的交集，得到最终目标用户ID
                                    Set<Long> targetUserIds = userIds.stream()
                                            .filter(roleUserIds::contains)
                                            .collect(Collectors.toSet());
                                    // 异步发送 站内信 钉钉消息
                                    if (CollUtil.isNotEmpty(targetUserIds)) {
                                        Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(targetUserIds);
                                        // 给多个用户发送 相同 的 提醒消息
                                        if (CollUtil.isNotEmpty(users)) {
                                            // 生成消息提醒标题 部门名称-井号
                                            String msgTitle = dept.getName();
                                            if (StrUtil.isNotBlank(wellName)) {
                                                msgTitle = StrUtil.join("-", msgTitle, wellName);
                                            }
                                            CountDownLatch latch = new CountDownLatch(users.size());
                                            String finalMsgTitle = msgTitle;
                                            String constant;
                                            if ("1".equals(iotRyDailyReport.getProjectClassification())) {
                                                // 钻井
                                                constant = PmsConstants.RY_DAILY_REPORT_APPROVAL;
                                            } else {
                                                // 修井
                                                constant = PmsConstants.RY_XJ_DAILY_REPORT_APPROVAL;
                                            }
                                            users.forEach((userId, user) -> {
                                                pmsThreadPoolTaskExecutor.execute(() -> {
                                                    try {
                                                        String mobile = user.getMobile();
                                                        // 没有手机号也可以发送站内信消息
                                                        if (StrUtil.isNotBlank(finalMsgTitle)) {
                                                            pmsMessage.sendMessage(iotRyDailyReport.getId(), finalMsgTitle, constant,
                                                                    userId, mobile);
                                                        }
                                                    } finally {
                                                        latch.countDown();
                                                    }
                                                });
                                            });
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            });
        }
        // 返回
        return iotRyDailyReport.getId();
    }

    @Override
    public void updateIotRyDailyReport(IotRyDailyReportSaveReqVO updateReqVO) {
        // 校验存在
        validateIotRyDailyReportExists(updateReqVO.getId());
        // 更新
        IotRyDailyReportDO updateObj = BeanUtils.toBean(updateReqVO, IotRyDailyReportDO.class);
        iotRyDailyReportMapper.updateById(updateObj);
    }

    @Override
    public void deleteIotRyDailyReport(Long id) {
        // 校验存在
        validateIotRyDailyReportExists(id);
        // 删除
        iotRyDailyReportMapper.deleteById(id);
    }

    private IotRyDailyReportDO validateIotRyDailyReportExists(Long id) {
        IotRyDailyReportDO dailyReport = iotRyDailyReportMapper.selectById(id);
        if (ObjUtil.isEmpty(dailyReport)) {
            throw exception(IOT_RY_DAILY_REPORT_NOT_EXISTS);
        }
        return dailyReport;
    }

    @Override
    public IotRyDailyReportDO getIotRyDailyReport(Long id) {
        return iotRyDailyReportMapper.selectById(id);
    }

    @Override
    public List<IotRyDailyReportDetailRespVO> ryDailyReportDetails(LocalDateTime currentDate, Long deptId, Long reportId) {
        List<IotRyDailyReportDetailRespVO> result = new ArrayList<>();
        // 运行记录中查询生产动态详情使用 日期只匹配 yyyy-MM-dd 的值
        // 查询日报的生产动态详情
        IotRyDailyReportDetailPageReqVO detailReqVO = new IotRyDailyReportDetailPageReqVO();
        detailReqVO.setDeptId(deptId);
        detailReqVO.setReportId(reportId);
        detailReqVO.setFillOrderReportDate(currentDate);
        detailReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        PageResult<IotRyDailyReportDetailDO> reportDetailsPage = iotRyDailyReportDetailMapper.selectPages(detailReqVO);
        List<IotRyDailyReportDetailDO> reportDetails = reportDetailsPage.getList();
        if (CollUtil.isNotEmpty(reportDetails)) {
            List<IotRyDailyReportDetailRespVO> reportDetailsResp = BeanUtils.toBean(reportDetails, IotRyDailyReportDetailRespVO.class);
            return reportDetailsResp;
        }
        return result;
    }

    @Override
    public PageResult<IotRyDailyReportDO> getIotRyDailyReportPage(IotRyDailyReportPageReqVO pageReqVO) {
        // 查询选择部门下面所有子部门
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }

        // searchKey 兼容移动端查询的情况
        if (StrUtil.isNotBlank(pageReqVO.getSearchKey())) {
            if (CollUtil.isEmpty(pageReqVO.getProjectIds()) && CollUtil.isEmpty(pageReqVO.getTaskIds())) {
                return new PageResult<>(Collections.emptyList(), 0L);
            }
        } else {
            // 检查contractName不为空但projectIds为空的情况
            if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
                return new PageResult<>(Collections.emptyList(), 0L);
            }
            // 检查taskName不为空但taskIds为空的情况
            if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
                return new PageResult<>(Collections.emptyList(), 0L);
            }
        }

        return iotRyDailyReportMapper.selectPage(pageReqVO);
    }

    @Override
    public Map<Long, String> queryEquipmentType(List<Long> deptIds) {
        Map<Long, String> equipmentTypePair = new HashMap<>();
        // 找到当前小队下的 电驱增压机 分类下设备的产能 计算 运行时效
        DictTypeDO dictType = dictTypeService.getDictType("rq_iot_derrick_device_category");
        AtomicReference<String> capacity = new AtomicReference<>();
        if (ObjUtil.isNotEmpty(dictType)) {
            if (StrUtil.isNotBlank(dictType.getRemark())) {
                IotDevicePageReqVO capacityReqVO = new IotDevicePageReqVO();
                capacityReqVO.setDeptIds(deptIds);
                capacityReqVO.setAssetClass(Long.valueOf(dictType.getRemark()));
                List<IotDeviceDO> capacityDevices = iotDeviceMapper.selectList(capacityReqVO);
                if (CollUtil.isNotEmpty(capacityDevices)) {
                    // 解析每个设备的 扩展属性 找出 已经设置 了产能的设备并提取值
                    capacityDevices.forEach(device -> {
                        if (StrUtil.isNotBlank(device.getTemplateJson())) {
                            Gson gson = new Gson();
                            Type listType = new TypeToken<List<IotDeviceProperty>>(){}.getType();
                            List<IotDeviceProperty> deviceProperties = gson.fromJson(device.getTemplateJson(), listType);
                            if (CollUtil.isNotEmpty(deviceProperties)) {
                                deviceProperties.forEach(property -> {
                                    if ("型号".equals(property.getName()) && StrUtil.isNotBlank(property.getValue())) {
                                        // 当前扩展属性已经维护了 型号 值
                                        capacity.set(property.getValue());
                                    }
                                    equipmentTypePair.put(device.getDeptId(), capacity.get());
                                });
                            }
                        }
                    });
                }
            }
        }
        return equipmentTypePair;
    }

    @Override
    public List<IotRyDailyReportDO> latestWellDoneTimes(IotRyDailyReportPageReqVO reqVO) {
        return iotRyDailyReportMapper.latestWellDoneTimes(reqVO);
    }

    @Override
    public List<IotRyDailyReportTaskCountVO> countTasksByDept() {
        return iotRyDailyReportMapper.countTasksByDept();
    }

    @Override
    public List<IotRyDailyReportTaskCountVO> countRepairTasksByDept(IotRyDailyReportPageReqVO pageReqVO) {
        return iotRyDailyReportMapper.countRepairTasksByDept(pageReqVO);
    }

    @Override
    public List<IotRyDailyReportTaskCountVO> countDateRepairTasksByDept() {
        return iotRyDailyReportMapper.countDateRepairTasksByDept();
    }

    @Override
    public List<IotRyDailyReportTaskCountVO> countDateRigTasksByDept() {
        return iotRyDailyReportMapper.countDateRigTasksByDept();
    }

    @Override
    public List<IotRyDailyReportTaskCountVO> countDateDrillTasksByDept() {
        return iotRyDailyReportMapper.countDateDrillTasksByDept();
    }

    @Override
    public List<IotRyDailyReportTaskCountVO> countDateRigTasksByDepartment() {
        return iotRyDailyReportMapper.countDateRigTasksByDepartment();
    }

    @Override
    public List<IotRyDailyReportStatisticsRespVO> statistics(IotRyDailyReportPageReqVO pageReqVO) {
        List<IotRyDailyReportStatisticsRespVO> result = new ArrayList<>();
        // 不分页统计所有数据
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            // 找到所有子部门对象集合
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        // 检查contractName不为空但projectIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
            return new ArrayList<>();
        }
        // 检查taskName不为空但taskIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
            return new ArrayList<>();
        }

        // 时间查询区间内如果包含 未发生的时间段(今年 本季度) 则设置 结束时间为 当前日期
        // 【调用公共方法】矫正未来时间区间
        LocalDateTimeUtils.correctFutureTimeRange(pageReqVO.getCreateTime());

        PageResult<IotRyDailyReportDO> page = iotRyDailyReportMapper.selectPage(pageReqVO);
        List<IotRyDailyReportDO> dailyReports = page.getList();

        // 默认显示所有项目部的汇总数据
        // 点击项目部 显示 下属队伍的数据
        // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认查询所有项目部数据
        if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
            result = statisticsByProjectDept(pageReqVO, dailyReports, 158L);
        } else {
            // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
            DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
            if ("1".equals(selectedDept.getType())) {
                // 以项目部为维度汇总数据
                result = statisticsByProjectDept(pageReqVO, dailyReports, pageReqVO.getDeptId());
            } else if ("2".equals(selectedDept.getType())) {
                // 以队伍为维度汇总数据
                result = statisticsByProjectDepartment(pageReqVO, dailyReports);
            } else if ("3".equals(selectedDept.getType())) {
                // 显示单个队伍的汇总数据
                result = statisticsByProjectDepartment(pageReqVO, dailyReports);
            } else {
                // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
                // 以项目部为维度汇总数据
                result = statisticsByProjectDept(pageReqVO, dailyReports, pageReqVO.getDeptId());
            }
        }
        // 根据result集合内对象的 sort 属性正序排列 sort 类型为 integer 类型
        if (CollUtil.isNotEmpty(result)) {
            result.sort(Comparator.comparing(
                    IotRyDailyReportStatisticsRespVO::getSort,
                    Comparator.nullsLast(Comparator.naturalOrder())
            ));
        }
        return result;
    }

    @Override
    public List<IotRyDailyReportStatisticsVO> ryDailyReportStatistics(IotRyDailyReportPageReqVO pageReqVO) {
        if (pageReqVO.getCreateTime().length == 0) {
            // 必须传递时间区间参数
            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
        }
        List<IotRyDailyReportStatisticsVO> results = new ArrayList<>();
        // 查询 瑞鹰158l 所有存在设备的队伍
        // 查询瑞鹰下所有部门
        List<IotDeviceDO> devices = devices();

        // 所有需要填报日报的 瑞鹰 队伍集合
        Set<Long> deptIds = new HashSet<>();
        if (CollUtil.isNotEmpty(devices)){
            // 1钻井  2修井
            String projectClassification = pageReqVO.getProjectClassification();
            // 查询钻井部门 修井 部门
            IotDeptTypePageReqVO reqVO = new IotDeptTypePageReqVO();
            if ("1".equals(projectClassification)) {
                reqVO.setType("zj");
            } else {
                reqVO.setType("xj");
            }
            List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(reqVO);
            List<Long> zjOrXjDeptIds = new ArrayList<>();
            if (CollUtil.isNotEmpty(deptTypes)) {
                deptTypes.forEach(dept -> {
                    zjOrXjDeptIds.add(dept.getDeptId());
                });
            }

            // 以运行记录表中 指定 时间范围内的 名称中包含 ‘生产日报’ 工单的部门为基数
            // 瑞鹰钻井 rq_iot_opeation_fill rq_iot_opeation_fill_order 关联查询
            // 瑞鹰修井 需要结合 挂靠队伍 日报
            IotOpeationFillPageReqVO fillReqVO = new IotOpeationFillPageReqVO();
            fillReqVO.setCreateTime(pageReqVO.getCreateTime());
            fillReqVO.setDeptIds(zjOrXjDeptIds);
            List<IotOpeationFillDO> fills = iotOpeationFillMapper.countFills(fillReqVO);
            // 钻修井日报总数
            Integer zxjTotalCount = 0;
            // 钻修井已填报完成日报总数
            AtomicReference<Integer> zxjFinishedCount = new AtomicReference<>(0);
            // 钻修井未填报完成日报总数
            AtomicReference<Integer> zxjUnfinishedCount = new AtomicReference<>(0);
            if (CollUtil.isNotEmpty(fills)) {
                zxjTotalCount = fills.size();
                fills.forEach(fill -> {
                    // 找出所有已经填报完成的队伍
                    if (1 == fill.getIsFill()) {
                        // 填报完成
                        zxjFinishedCount.set(zxjFinishedCount.get() + 1);
                    } else {
                        // 填报中属于未填报完成
                        zxjUnfinishedCount.set(zxjUnfinishedCount.get() + 1);
                    }
                });
            }

            devices.forEach(device -> {
                deptIds.add(device.getDeptId());
            });
            // 根据部门id集合查询所有部门信息
            // 查询所有部门信息
            // Map<Long, DeptDO> allDepts = deptService.getDeptMap(deptIds);
            // 过滤后的所有部门信息
            Map<Long, DeptDO> filteredDepts = new HashMap<>();
            // 过滤掉部门中的 ‘项目部’...
            /* if (CollUtil.isNotEmpty(allDepts)) {
                allDepts.forEach((deptId, dept) -> {
                    // 将不属于 队伍 的组织部门过滤掉
                    if ("3".equals(dept.getType()) && zjOrXjDeptIds.contains(deptId)) {
                        filteredDepts.put(deptId, dept);
                    }
                });
            } */

            // 比如有20个队伍 某个时间区间D内 必须有20*D份日报 时间区间最好是1天
            // 查询出指定时间区间内 已经填写的日报数量
            // List<IotRyDailyReportDO> dailyReports = iotRyDailyReportMapper.dailyReports(pageReqVO);
            // 根据指定的时间区间 计算出天数
            LocalDateTime[] createTimes = pageReqVO.getCreateTime();
            // 获取开始时间和结束时间
            LocalDateTime startTime = createTimes[0];
            LocalDateTime endTime = createTimes[1];
            // 截断到日期（忽略时分秒）
            LocalDate startDate = startTime.toLocalDate();
            LocalDate endDate = endTime.toLocalDate();
            // 计算天数：日期差 + 1（包含首尾两天）
            long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
            // 计算指定时间区间内所有日报数量总数
            long totalRequiredReports = (long) filteredDepts.size() * days;
            // 获取【实际已报的日报数量】
            // long totalReportedReports = CollUtil.isNotEmpty(dailyReports) ? dailyReports.size() : 0l;
            // 计算指定时间区间内未填报的日报数量
            // long notReportedCount = totalRequiredReports - totalReportedReports;
            IotRyDailyReportStatisticsVO allReports = new IotRyDailyReportStatisticsVO();
            allReports.setGroupName("总数");
            allReports.setCount(zxjTotalCount);
            IotRyDailyReportStatisticsVO haveReported = new IotRyDailyReportStatisticsVO();
            haveReported.setGroupName("已填报");
            haveReported.setCount(zxjFinishedCount.get());
            IotRyDailyReportStatisticsVO notReported = new IotRyDailyReportStatisticsVO();
            notReported.setGroupName("未填报");
            notReported.setCount(zxjUnfinishedCount.get());
            results.add(allReports);
            results.add(haveReported);
            results.add(notReported);
        }
        return results;
    }

    @Override
    public List<IotRyDailyReportStatisticsVO> ryUnReportedDetails(IotRyDailyReportPageReqVO pageReqVO) {
        // 查询所有未填报日报的队伍名称 40001队, 40005队...
        // 首先必须传递了日期范围
        if (pageReqVO.getCreateTime().length == 0) {
            // 必须传递时间区间参数
            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
        }
        List<IotRyDailyReportStatisticsVO> results = new ArrayList<>();
        // List<IotDeviceDO> devices = devices();
        // 所有需要填报日报的 瑞鹰 队伍集合
        Set<Long> deptIds = new HashSet<>();
        List<String> reportDates = new ArrayList<>();
        // 1钻井  2修井
        String projectClassification = pageReqVO.getProjectClassification();
        // 查询钻井部门 修井 部门
        IotDeptTypePageReqVO reqVO = new IotDeptTypePageReqVO();
        if ("1".equals(projectClassification)) {
            reqVO.setType("zj");
        } else {
            reqVO.setType("xj");
        }
        List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(reqVO);
        List<Long> zjOrXjDeptIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(deptTypes)) {
            deptTypes.forEach(dept -> {
                zjOrXjDeptIds.add(dept.getDeptId());
            });
        }

        /* devices.forEach(device -> {
            deptIds.add(device.getDeptId());
        }); */

        // 以运行记录表中 指定 时间范围内的 名称中包含 ‘生产日报’ 工单的部门为基数
        // 瑞鹰钻井 rq_iot_opeation_fill rq_iot_opeation_fill_order 关联查询
        // 瑞鹰修井 需要结合 挂靠队伍 日报
        IotOpeationFillPageReqVO fillReqVO = new IotOpeationFillPageReqVO();
        fillReqVO.setCreateTime(pageReqVO.getCreateTime());
        fillReqVO.setDeptIds(zjOrXjDeptIds);
        List<IotOpeationFillDO> fills = iotOpeationFillMapper.countFills(fillReqVO);

        // 根据指定的时间区间 计算出天数
        LocalDateTime[] createTimes = pageReqVO.getCreateTime();
        // 获取开始时间和结束时间
        LocalDateTime startTime = createTimes[0];
        LocalDateTime endTime = createTimes[1];
        // 截断到日期（忽略时分秒）
        LocalDate startDate = startTime.toLocalDate();
        LocalDate endDate = endTime.toLocalDate();
        // 将时间区间拆分成具体的每天 计算每天未填报日报的队伍明细
        Set<LocalDate> dateSet = new HashSet<>();
        LocalDate currentDate = startDate;
        // 循环添加从开始日期到结束日期的所有日期（包含两端）
        while (!currentDate.isAfter(endDate)) {
            dateSet.add(currentDate);
            currentDate = currentDate.plusDays(1); // 日期加1天
        }
        // 转换为字符串格式的日期集合（如：2025-10-06）
        reportDates = dateSet.stream()
                .map(date -> date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                .collect(Collectors.toList());
        // 比如有20个队伍 某个时间区间D内 必须有20*D份日报 时间区间最好是1天
        // 查询出指定时间区间内 已经填写的日报数量
        List<IotRyDailyReportDO> dailyReports = iotRyDailyReportMapper.dailyReports(pageReqVO);
        // key日期   value对应日期已经填报的队伍名称集合
        Map<String, List<String>> reportedDeptNames = new HashMap<>();
        // key日期    value对应日期未填报完成的队伍名称集合
        Map<String, List<String>> unReportedDeptNames = new HashMap<>();
        // 查询所有部门信息
        Map<Long, DeptDO> allDepts = deptService.getDeptMap(zjOrXjDeptIds);
        // 过滤后的所有部门信息
        Map<Long, DeptDO> filteredDepts = new HashMap<>();
        // 过滤掉部门中的 ‘项目部’
        /* if (CollUtil.isNotEmpty(allDepts)) {
            allDepts.forEach((deptId, dept) -> {
                if ("3".equals(dept.getType()) && zjOrXjDeptIds.contains(deptId)) {
                    filteredDepts.put(deptId, dept);
                }
            });
        } */
        /* if (CollUtil.isNotEmpty(dailyReports)) {
            // 组装每天填写的日报集合 从而统计出每天未填写日报的队伍
            dailyReports.forEach(report -> {
                Long tempDeptId = report.getDeptId();
                if (filteredDepts.containsKey(tempDeptId)) {
                    String deptName = filteredDepts.get(tempDeptId).getName();
                    LocalDateTime createTime = report.getCreateTime();
                    LocalDate tempDate = createTime.toLocalDate();
                    String tempReportDate = tempDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    if (reportedDeptNames.containsKey(tempReportDate)) {
                        List<String> tempDeptNames = reportedDeptNames.get(tempReportDate);
                        tempDeptNames.add(deptName);
                        reportedDeptNames.put(tempReportDate, tempDeptNames);
                    } else {
                        List<String> tempDeptNames = new ArrayList<>();
                        tempDeptNames.add(deptName);
                        reportedDeptNames.put(tempReportDate, tempDeptNames);
                    }
                }
            });
        } */
        // 遍历所有时间区间的日期 组装每个日期中 未填写日报的队伍名称集合
        /* if (CollUtil.isNotEmpty(reportDates)) {
            reportDates.forEach(dateStr -> {
                // 对时间区间内每个日期 都经过已经填报日报的过滤
                if (reportedDeptNames.containsKey(dateStr)) {
                    List<String> tempReportedDeptNames = reportedDeptNames.get(dateStr);
                    filteredDepts.forEach((deptId, dept) -> {
                        if (!tempReportedDeptNames.contains(dept.getName())) {
                            if (unReportedDeptNames.containsKey(dateStr)) {
                                List<String> tempDeptNames = unReportedDeptNames.get(dateStr);
                                tempDeptNames.add(dept.getName());
                                unReportedDeptNames.put(dateStr, tempDeptNames);
                            } else {
                                List<String> tempDeptNames = new ArrayList<>();
                                tempDeptNames.add(dept.getName());
                                unReportedDeptNames.put(dateStr, tempDeptNames);
                            }
                        }
                    });
                } else {
                    // 当天没有任何队伍填写日报
                    filteredDepts.forEach((deptId, dept) -> {
                        List<String> tempDeptNames = new ArrayList<>();
                        tempDeptNames.add(dept.getName());
                        unReportedDeptNames.put(dateStr, tempDeptNames);
                    });
                }
            });
        } */

        if (CollUtil.isNotEmpty(fills)) {
            fills.forEach(fill -> {
                if (1 != fill.getIsFill()) {
                    // 未完成填报
                    LocalDate tempDate = fill.getCreateTime().toLocalDate();
                    String tempDateStr = tempDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    if (allDepts.containsKey(fill.getDeptId())) {
                        DeptDO dept = allDepts.get(fill.getDeptId());
                        if (unReportedDeptNames.containsKey(tempDateStr)) {
                            List<String> tempDeptNames = unReportedDeptNames.get(tempDateStr);
                            tempDeptNames.add(dept.getName());
                            unReportedDeptNames.put(tempDateStr, tempDeptNames);
                        } else {
                            List<String> tempDeptNames = new ArrayList<>();
                            tempDeptNames.add(dept.getName());
                            unReportedDeptNames.put(tempDateStr, tempDeptNames);
                        }
                    }
                }
            });
        }

        // 将集合中的未填报日报的队伍集合转换成 逗号 分隔的字符串
        if (CollUtil.isNotEmpty(unReportedDeptNames)) {
            unReportedDeptNames.forEach((reportDate, deptList) -> {
                IotRyDailyReportStatisticsVO dailyReportVO = new IotRyDailyReportStatisticsVO();
                dailyReportVO.setReportDate(reportDate);
                dailyReportVO.setDeptNames(deptList.stream().collect(Collectors.joining(",")));
                dailyReportVO.setCount(deptList.size());
                results.add(dailyReportVO);
            });
            // 使用Comparator进行排序
            results.sort(Comparator
                    .comparing(IotRyDailyReportStatisticsVO::getReportDate,
                            Comparator.nullsLast(Comparator.reverseOrder())));
        }
        return results;
    }

    @Override
    public List<IotRyDailyReportPolylineVO> polylineStatistics(IotRyDailyReportPageReqVO pageReqVO) {
        List<IotRyDailyReportPolylineVO> result = new ArrayList<>();
        // 不分页统计所有数据
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            // 找到所有子部门对象集合
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        // 检查contractName不为空但projectIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
            return new ArrayList<>();
        }
        // 检查taskName不为空但taskIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
            return new ArrayList<>();
        }
        PageResult<IotRyDailyReportDO> page = iotRyDailyReportMapper.selectPage(pageReqVO);
        List<IotRyDailyReportDO> dailyReports = page.getList();
        if (CollUtil.isEmpty(dailyReports)) {
            return result;
        }
        // 默认显示所有项目部的汇总数据
        // 点击项目部 显示 下属队伍的数据
        // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认查询所有项目部数据
        if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
            result = polylineStatisticsByProjectDept(pageReqVO, dailyReports, 158L, pageReqVO.getCreateTime());
        } else {
            // 判断点击的组织树中的部门类型 (公司级1 项目部2 队伍3)
            DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
            if ("1".equals(selectedDept.getType())) {
                // 以项目部为维度汇总数据
                result = polylineStatisticsByProjectDept(pageReqVO, dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
            } else if ("2".equals(selectedDept.getType())) {
                // 以队伍为维度汇总数据
                result = polylineStatisticsByProjectDepartment(pageReqVO, dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
            } else if ("3".equals(selectedDept.getType())) {
                // 显示单个队伍的汇总数据
                result = polylineStatisticsByProjectDepartment(pageReqVO, dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
            } else {
                // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
                // 以项目部为维度汇总数据
                result = polylineStatisticsByProjectDept(pageReqVO, dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
            }
        }
        // 根据result集合内对象的 日期 属性正序排列
        return result;
    }

    @Override
    public void approvalRyDailyReport(IotRyDailyReportSaveReqVO updateReqVO) {
        // 审核瑞恒日报
        // 如果审批拒绝 修改日报 填报状态 status = 0 填写中  审批状态 auditStatus = 30
        // 审批通过 设置 日报审批状态 auditStatus = 20
        IotRyDailyReportDO dailyReport = validateIotRyDailyReportExists(updateReqVO.getId());
        dailyReport.setAuditStatus(updateReqVO.getAuditStatus());
        dailyReport.setOpinion(updateReqVO.getOpinion());
        dailyReport.setConstructionBrief(updateReqVO.getConstructionBrief());
        if (SupplierAuditStatusEnum.REJECT.getStatus().equals(updateReqVO.getAuditStatus())) {
            dailyReport.setStatus(0);
            // 审批拒绝后需要向 日报填报人 发送消息提醒 驳回到日报创建人
            Long deptId = dailyReport.getDeptId();
            Long taskId = dailyReport.getTaskId();
            DeptDO dept = deptService.getDept(deptId);
            // 当前日报创建人
            String creator = dailyReport.getCreator();
            // 消息标题
            String msgTitle = dept.getName();
            if (ObjUtil.isNotEmpty(taskId)) {
                IotProjectTaskDO task = iotProjectTaskMapper.selectById(taskId);
                msgTitle = StrUtil.join("-", msgTitle, task.getWellName());
            }
            // 查询当前部门 deptId 部门下的人员
            Set<Long> deptIds = new HashSet<>();
            deptIds.add(deptId);
            List<AdminUserDO> users = adminUserService.getUserListByDeptIds(deptIds);
            if (CollUtil.isNotEmpty(users)) {
                AdminUserDO user = users.get(0);
                String mobile = user.getMobile();
                String finalMsgTitle = msgTitle;
                String constant;
                if ("1".equals(dailyReport.getProjectClassification())) {
                    // 钻井
                    constant = PmsConstants.RY_DAILY_REPORT;
                } else {
                    // 修井
                    constant = PmsConstants.RY_XJ_DAILY_REPORT;
                }
                // 没有手机号也可以发送站内信消息
                if (StrUtil.isNotBlank(finalMsgTitle) && StrUtil.isNotBlank(creator)) {
                    pmsThreadPoolTaskExecutor.execute(() -> {
                        pmsMessage.sendMessage(dailyReport.getId(), finalMsgTitle, constant, Long.valueOf(creator), mobile);
                    });
                }
            }
        }
        // 更新瑞恒日报审核状态
        iotRyDailyReportMapper.updateById(dailyReport);
    }

    @Override
    public PageResult<IotRyDailyReportDO> teamReports(IotRyDailyReportPageReqVO pageReqVO) {
        // 查询选择部门下面所有子部门
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        // 检查contractName不为空但projectIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        // 检查taskName不为空但taskIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        IPage<IotRyDailyReportDO> page = iotRyDailyReportMapper.ryWellNameDailyReports(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public List<IotRyDailyReportDO> ryDeptDailyReportsGroupIds(IotRyDailyReportPageReqVO pageReqVO) {
        // 查询选择部门下面所有子部门
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        List<IotRyDailyReportDO> groupIds = iotRyDailyReportMapper.ryDeptDailyReportsGroupIds(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
        return groupIds;
    }

    @Override
    public List<IotRyDailyReportDO> ryWellNameDailyReportsGroupIds(IotRyDailyReportPageReqVO pageReqVO) {
        // 查询选择部门下面所有子部门
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        List<IotRyDailyReportDO> groupIds = iotRyDailyReportMapper.ryWellNameDailyReportsGroupIds(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
        return groupIds;
    }

    @Override
    public PageResult<IotRyDailyReportDO> wellReports(IotRyDailyReportPageReqVO pageReqVO) {
        // 查询选择部门下面所有子部门
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        // 检查contractName不为空但projectIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        // 检查taskName不为空但taskIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
            return new PageResult<>(Collections.emptyList(), 0L);
        }
        IPage<IotRyDailyReportDO> page = iotRyDailyReportMapper.ryDeptDailyReports(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);

        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override
    public void repairHistoryProdStatus() {
        // 修复历史生产动态数据 生产动态拆分明细后 需要把  productionStatus 值赋值到 明细表 rq_iot_ry_daily_report_detail
        // 查询所有 日报数据 筛选出 production_status 有值的记录
        IotRyDailyReportPageReqVO reqVO = new IotRyDailyReportPageReqVO();
        List<IotRyDailyReportDO> reports = iotRyDailyReportMapper.dailyReports(reqVO);
        List<IotRyDailyReportDetailDO> reportDetails = new ArrayList<>();
        if (CollUtil.isNotEmpty(reports)) {
            reports.forEach(report -> {
                if (StrUtil.isNotBlank(report.getProductionStatus())) {
                    IotRyDailyReportDetailDO reportDetail = new IotRyDailyReportDetailDO();
                    reportDetail.setDeptId(report.getDeptId());
                    reportDetail.setReportId(report.getId());
                    reportDetail.setTaskId(report.getTaskId());
                    reportDetail.setReportDate(report.getCreateTime());
                    reportDetail.setStartTime(LocalTime.MIN);
                    reportDetail.setEndTime(LocalTime.MAX);
                    // 计算2个时间之前间隔的小时数
                    reportDetail.setDuration(LocalTimeUtils.calculateDurationHours(LocalTime.MIN, LocalTime.MAX));
                    reportDetail.setConstructionDetail(report.getProductionStatus());
                    reportDetails.add(reportDetail);
                }
            });
            if (CollUtil.isNotEmpty(reportDetails)) {
                iotRyDailyReportDetailMapper.insertBatch(reportDetails);
            }
        }
    }

    @Override
    public List<IotRyDailyReportNptStatisticsRespVO> nptStatistics(IotRyDailyReportPageReqVO pageReqVO) {
        List<IotRyDailyReportNptStatisticsRespVO> result = new ArrayList<>();
        // 不分页统计所有数据
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            // 找到所有子部门对象集合
            ids.add(pageReqVO.getDeptId());
            pageReqVO.setDeptIds(ids);
        }
        // 检查contractName不为空但projectIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getContractName()) && (CollUtil.isEmpty(pageReqVO.getProjectIds()))) {
            return new ArrayList<>();
        }
        // 检查taskName不为空但taskIds为空的情况
        if (StrUtil.isNotBlank(pageReqVO.getTaskName()) && (CollUtil.isEmpty(pageReqVO.getTaskIds()))) {
            return new ArrayList<>();
        }
        PageResult<IotRyDailyReportDO> page = iotRyDailyReportMapper.selectPage(pageReqVO);
        List<IotRyDailyReportDO> dailyReports = page.getList();

        // 默认显示所有项目部的汇总数据 点击项目部 显示 下属队伍的数据
        // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认查询所有项目部数据
        if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
            result = nptStatisticsByProjectDept(pageReqVO, dailyReports, 158L);
        } else {
            // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
            DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
            if ("1".equals(selectedDept.getType())) {
                // 以项目部为维度汇总数据
                result = nptStatisticsByProjectDept(pageReqVO, dailyReports, pageReqVO.getDeptId());
            } else if ("2".equals(selectedDept.getType())) {
                // 以队伍为维度汇总数据
                result = nptStatisticsByProjectDepartment(pageReqVO, dailyReports);
            } else if ("3".equals(selectedDept.getType())) {
                // 显示单个队伍的汇总数据
                result = nptStatisticsByProjectDepartment(pageReqVO, dailyReports);
            } else {
                // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
                // 以项目部为维度汇总数据
                result = nptStatisticsByProjectDept(pageReqVO, dailyReports, pageReqVO.getDeptId());
            }
        }
        // 根据result集合内对象的 sort 属性正序排列 sort 类型为 integer 类型
        if (CollUtil.isNotEmpty(result)) {
            result.sort(Comparator.comparing(
                    IotRyDailyReportNptStatisticsRespVO::getSort,
                    Comparator.nullsLast(Comparator.naturalOrder())
            ));
        }
        return result;
    }

    @Override
    public List<IotRyDailyReportDO> productionBriefs(IotRyDailyReportPageReqVO pageReqVO) {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        PageResult<IotRyDailyReportDO> pageResult = iotRyDailyReportMapper.selectPage(pageReqVO);
        if (ObjUtil.isNotEmpty(pageResult)) {
            List<IotRyDailyReportDO> reports = pageResult.getList();
            return reports;
        }
        return Collections.emptyList();
    }

    private List<IotDeviceDO> devices() {
        // 查询 瑞鹰158l 所有存在设备的队伍
        // 查询 瑞鹰 下所有部门
        Set<Long> ids = new HashSet<>();
        ids = deptService.getChildDeptIdListFromCache(158l);
        ids.add(158l);
        // 查询ids下包含的所有设备 设备对应的部门就是 小队全集
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        List<IotDeviceDO> devices = iotDeviceMapper.selectSimpleList(deviceReqVO, ids);
        return devices;
    }

    /**
     * 按项目部维度统计数据
     * @param pageReqVO 日报查询对象
     * @param dailyReports 日报数据列表
     * @param rootDeptId 根部门ID（如158L为 瑞鹰 根部门，或其他公司级部门ID）
     * @return 项目部维度统计结果列表  钻井 修井
     */
    private List<IotRyDailyReportStatisticsRespVO> statisticsByProjectDept(IotRyDailyReportPageReqVO pageReqVO,
                                                                           List<IotRyDailyReportDO> dailyReports, Long rootDeptId) {
        List<IotRyDailyReportStatisticsRespVO> result = new ArrayList<>();

        Set<Long> projectDeptIds = new HashSet<>();
        // key项目部id    value项目部名称
        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
        // key部门id   value部门parentId
        Map<Long, Long> teamProjectIdPair = new HashMap<>();

        // key队伍id/项目部id   value累计进尺
        Map<Long, BigDecimal> cumulativeFootagePair = new HashMap<>();
        // key队伍id/项目部id   value累计用电
        Map<Long, BigDecimal> cumulativePowerConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value累计油耗
        Map<Long, BigDecimal> cumulativeFuelConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value对应项目部的施工井数
        Map<Long, Integer> cumulativeConstructWellsPair = new HashMap<>();
        // key队伍id/项目部id   value对应项目部的完工井数
        Map<Long, Integer> cumulativeCompletedWellsPair = new HashMap<>();
        // key队伍id/项目部id   value生产时间(H)
        Map<Long, BigDecimal> cumulativeProductTimePair = new HashMap<>();
        // key队伍id/项目部id   value额定生产时间(H)
        Map<Long, BigDecimal> cumulativeRatedTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计运行时效
        Map<Long, BigDecimal> cumulativeTransitTimePair = new HashMap<>();
        // key队伍id/项目部id   value非生产时间集合
        Map<Long, List<BigDecimal>> cumulativeNonProductionTimePair = new HashMap<>();
        // key队伍id/项目部id   value非生产时效
        Map<Long, BigDecimal> cumulativeNonProductionPair = new HashMap<>();
        // key队伍id/项目部id   value设备利用率
        Map<Long, BigDecimal> deviceUtilizationPair = new HashMap<>();

        // 钻井或修井部门 队伍
        List<Long> zjOrXjDeptIds = new ArrayList<>();
        // 1钻井  2修井
        String projectClassification = pageReqVO.getProjectClassification();
        // 查询钻井部门 修井 部门
        IotDeptTypePageReqVO deptTypeReqVO = new IotDeptTypePageReqVO();
        if ("1".equals(projectClassification)) {
            deptTypeReqVO.setType("zj");
        } else {
            deptTypeReqVO.setType("xj");
        }
        List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(deptTypeReqVO);
        if (CollUtil.isNotEmpty(deptTypes)) {
            deptTypes.forEach(dept -> {
                zjOrXjDeptIds.add(dept.getDeptId());
            });
        }

        // 以项目部为维度统计数据 找到所有项目部与队伍的对应关系 查询指定根部门下的所有子部门
        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(rootDeptId);
        DeptListReqVO reqVO = new DeptListReqVO();
        reqVO.setDeptIds(allRhChildDeptIds);
        List<DeptDO> depts = deptService.getDeptList(reqVO);

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            // 筛选出所有项目部
            if ("2".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // key项目部id   value项目部包含的钻井or修井队伍id集合
        Map<Long, Set<Long>> projectTeamPair = new HashMap<>();
        // 筛选项目部下包含的队伍
        depts.forEach(dept -> {
            Long deptId = dept.getId();
            Long parentId = dept.getParentId();
            if (projectDeptIds.contains(parentId)) {
                // 获得当前部门的上级项目部
                projectDeptIds.forEach(projectDeptId -> {
                    // 统计各钻井或修井项目部下队伍数量
                    if (projectDeptId.equals(parentId) && zjOrXjDeptIds.contains(deptId)) {
                        if (projectTeamPair.containsKey(projectDeptId)) {
                            Set<Long> tempTeamIds = projectTeamPair.get(projectDeptId);
                            tempTeamIds.add(deptId);
                            projectTeamPair.put(projectDeptId, tempTeamIds);
                        } else {
                            Set<Long> tempTeamIds = new HashSet<>();
                            tempTeamIds.add(deptId);
                            projectTeamPair.put(projectDeptId, tempTeamIds);
                        }
                    }
                });
            }
        });

        // key施工队伍id    value施工井数量
        Map<Long, Integer> totalTasksPair = new HashMap<>();
        // key施工队伍id    value完工井数量
        Map<Long, Integer> completedTasksPair = new HashMap<>();
        // key任务id   value额定生产时间
        Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();

        if ("2".equals(pageReqVO.getProjectClassification())) {
            // 查询修井 累计施工井数 累计完工井数
            if (ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
                List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportMapper.countRepairTasksByDept(pageReqVO);
                if (CollUtil.isNotEmpty(repairDeptTasks)) {
                    repairDeptTasks.forEach(task -> {
                        totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
                        completedTasksPair.put(task.getDeptId(), task.getCompletedTaskCount());
                    });
                }
            }
            // 计算 运行时效 累计生产时间/累计额定生产时间
            // 查询日报关联的任务信息
            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
            taskReqVO.setTaskIds(convertList(dailyReports, IotRyDailyReportDO::getTaskId));
            List<IotProjectTaskDO> tasks = iotProjectTaskMapper.selectList(taskReqVO);
            if (CollUtil.isNotEmpty(tasks)) {
                tasks.forEach(task -> {
                    if (CollUtil.isNotEmpty(task.getExtProperty())) {
                        List<IotTaskAttrModelProperty> taskAttrs = task.getExtProperty();
                        if (CollUtil.isNotEmpty(taskAttrs)) {
                            // 找到 额定生产时间 属性 对应的值
                            taskAttrs.forEach(attr -> {
                                if ("额定生产时间".equals(attr.getName()) && StrUtil.isNotBlank(attr.getActualValue())) {
                                    taskRatedProductionTimePair.put(task.getId(), new BigDecimal(attr.getActualValue()));
                                }
                            });
                        }
                    }
                });
            }
        }

        // 统计各项目部的设备利用率
        // key项目部id     value项目部包含的队伍指定时间区域内日报数量
        Map<Long, Integer> projectReportPair = new HashMap<>();

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                // 统计各项目部的日报数量
                if (CollUtil.isNotEmpty(projectTeamPair)) {
                    projectTeamPair.forEach((projectDeptId, teamDeptIds) -> {
                        if (teamDeptIds.contains(report.getDeptId())) {
                            // 项目部日报数量
                            if (projectReportPair.containsKey(projectDeptId)) {
                                Integer tempCount = projectReportPair.get(projectDeptId);
                                projectReportPair.put(projectDeptId, ++tempCount);
                            } else {
                                projectReportPair.put(projectDeptId, 1);
                            }
                        }
                    });
                }

                if (ObjUtil.isNotEmpty(report.getDeptId()) && teamProjectIdPair.containsKey(report.getDeptId())) {
                    Long projectDeptId = teamProjectIdPair.get(report.getDeptId());
                    if (ObjUtil.isNotEmpty(projectDeptId) && projectDeptPair.containsKey(projectDeptId)) {
                        // 累计进尺
                        cumulativeFootagePair.merge(projectDeptId, report.getDailyFootage(), BigDecimal::add);
                        // 累计用电量
                        cumulativePowerConsumptionPair.merge(projectDeptId, report.getDailyPowerUsage(), BigDecimal::add);
                        // 累计油耗
                        cumulativeFuelConsumptionPair.merge(projectDeptId, report.getDailyFuel(), BigDecimal::add);
                        // 统计各项目部的 累计施工井数 累计完工井数 取每个井任务的最大值 而不是累加
                        /* if (totalTasksPair.containsKey(report.getDeptId())) {
                            Integer tempCount = totalTasksPair.get(report.getDeptId());
                            cumulativeConstructWellsPair.merge(projectDeptId, tempCount, Integer::sum);
                        }
                        if (completedTasksPair.containsKey(report.getDeptId())) {
                            Integer tempCompleteCount = completedTasksPair.get(report.getDeptId());
                            cumulativeCompletedWellsPair.merge(projectDeptId, tempCompleteCount, Integer::sum);
                        } */
                        // 额定生产时间
                        if (taskRatedProductionTimePair.containsKey(report.getTaskId())) {
                            BigDecimal ratedTime = taskRatedProductionTimePair.get(report.getTaskId());
                            cumulativeRatedTimePair.merge(projectDeptId, ratedTime, BigDecimal::add);
                        }
                        // 生产时间
                        cumulativeProductTimePair.merge(projectDeptId, report.getProductionTime(), BigDecimal::add);
                    }

                    // 修井 非生产时间 用于计算非生产时效
                    // NPT 归类 设备故障repair_time 工程质量accident_time 技术受限complexity_time 生产组织rectification_time 不可抗力waiting_stop_time
                    // 甲方设计partya_design 甲方准备partya_prepare 甲方资源partya_resource 其他非生产时间other_npt_time
                    // 钻井 非生产时间 事故 修理 自停 复杂 搬迁 整改 等停 冬休
                    BigDecimal nonProductionTimeSum = Stream.of(
                                    report.getAccidentTime(),
                                    report.getRepairTime(),
                                    report.getComplexityTime(),
                                    report.getRectificationTime(),
                                    report.getWaitingStopTime(),
                                    report.getPartyaDesign(),
                                    report.getPartyaPrepare(),
                                    report.getPartyaResource(),
                                    report.getOtherNptTime()
                            )
                            .map(time -> ObjUtil.defaultIfNull(time, BigDecimal.ZERO))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    if ("2".equals(pageReqVO.getProjectClassification())) {
                        // BigDecimal nonProductionTime = report.getNonProductionTime();
                        if (nonProductionTimeSum.compareTo(BigDecimal.ZERO) > 0) {
                            if (cumulativeNonProductionTimePair.containsKey(projectDeptId)) {
                                List<BigDecimal> tempNonProductionTimes = cumulativeNonProductionTimePair.get(projectDeptId);
                                tempNonProductionTimes.add(nonProductionTimeSum);
                                cumulativeNonProductionTimePair.put(projectDeptId, tempNonProductionTimes);
                            } else {
                                List<BigDecimal> tempNonProductionTimes = new ArrayList<>();
                                tempNonProductionTimes.add(nonProductionTimeSum);
                                cumulativeNonProductionTimePair.put(projectDeptId, tempNonProductionTimes);
                            }
                        }
                    } else {
                        // 钻井 非生产时间 事故 修理 自停 复杂 搬迁 整改 等停 冬休
                        if (nonProductionTimeSum.compareTo(BigDecimal.ZERO) > 0) {
                            if (cumulativeNonProductionTimePair.containsKey(projectDeptId)) {
                                List<BigDecimal> tempNonProductionTimes = cumulativeNonProductionTimePair.get(projectDeptId);
                                tempNonProductionTimes.add(nonProductionTimeSum);
                                cumulativeNonProductionTimePair.put(projectDeptId, tempNonProductionTimes);
                            } else {
                                List<BigDecimal> tempNonProductionTimes = new ArrayList<>();
                                tempNonProductionTimes.add(nonProductionTimeSum);
                                cumulativeNonProductionTimePair.put(projectDeptId, tempNonProductionTimes);
                            }
                        }
                    }
                }
            });
            // 筛选每个队伍对应的项目部 设置每个项目部的 累计施工井数 累计完工井数 totalTasksPair   completedTasksPair
            if (CollUtil.isNotEmpty(totalTasksPair)) {
                totalTasksPair.forEach((teamDeptId, taskCount) -> {
                    if (teamProjectIdPair.containsKey(teamDeptId)) {
                        // 项目部id
                        Long projectDeptId = teamProjectIdPair.get(teamDeptId);
                        cumulativeConstructWellsPair.merge(projectDeptId, taskCount, Integer::sum);
                    }
                });
            }
            if (CollUtil.isNotEmpty(completedTasksPair)) {
                completedTasksPair.forEach((teamDeptId, taskCount) -> {
                    if (teamProjectIdPair.containsKey(teamDeptId)) {
                        // 项目部id
                        Long projectDeptId = teamProjectIdPair.get(teamDeptId);
                        cumulativeCompletedWellsPair.merge(projectDeptId, taskCount, Integer::sum);
                    }
                });
            }

            // 计算项目部对应的 运行时效
            if (CollUtil.isNotEmpty(cumulativeProductTimePair) && CollUtil.isNotEmpty(cumulativeRatedTimePair)) {
                cumulativeProductTimePair.forEach((projectDeptId, productionTime) -> {
                    if (cumulativeRatedTimePair.containsKey(projectDeptId)) {
                        BigDecimal tempRatedTime = cumulativeRatedTimePair.get(projectDeptId);
                        if (tempRatedTime.compareTo(BigDecimal.ZERO) > 0) {
                            // 指定项目部的 累计额定生产时间
                            BigDecimal tempTransitTime = productionTime.divide(tempRatedTime, 4, RoundingMode.HALF_UP);
                            cumulativeTransitTimePair.put(projectDeptId, tempTransitTime);
                        } else {
                            cumulativeTransitTimePair.put(projectDeptId, BigDecimal.ZERO);
                        }
                    }
                });
            }
        }

        Long days;
        if (ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
            LocalDateTime[] createTimes = pageReqVO.getCreateTime();
            // 获取开始时间和结束时间
            LocalDateTime startTime = createTimes[0];
            LocalDateTime endTime = createTimes[1];
            // 截断到日期（忽略时分秒）
            LocalDate startDate = startTime.toLocalDate();
            LocalDate endDate = endTime.toLocalDate();
            // 计算天数：日期差 + 1（包含首尾两天）
            days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
        } else {
            days = 0l;
        }

        if (CollUtil.isNotEmpty(cumulativeNonProductionTimePair)) {
            // 计算各项目部的非生产时效 分母为查询时间区间的总天数
            cumulativeNonProductionTimePair.forEach((projectDeptId, nonProductTimes) -> {
                // nonProductTimes 集合中元素的数量就是 分母中应该计算非生产时效的天数
                BigDecimal totalNonProductionTime = nonProductTimes.stream()
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                if (days > 0 && projectTeamPair.containsKey(projectDeptId)) {
                    Set<Long> tempTeamIds = projectTeamPair.get(projectDeptId);
                    BigDecimal denominator = new BigDecimal(days * 24 * tempTeamIds.size());
                    BigDecimal nonProductionEfficiency = totalNonProductionTime
                            .divide(denominator, 4, RoundingMode.HALF_UP);
                    cumulativeNonProductionPair.put(projectDeptId, nonProductionEfficiency);
                }
            });
        }

        // 计算各项目部的平均设备利用率
        if (CollUtil.isNotEmpty(projectTeamPair)) {
            projectTeamPair.forEach((projectDeptId, resultTeamIds) -> {
                double rate = 0.0;
                Integer currentTeamNum = resultTeamIds.size();
                if (projectReportPair.containsKey(projectDeptId)) {
                    Integer reportCount = projectReportPair.getOrDefault(projectDeptId, 0);
                    // 当前项目部 设备利用率 公式 reportCount/(currentTeamNum * daysCount)
                    // 计算设备利用率（处理除数为0的情况）
                    if (currentTeamNum > 0 && days > 0) {
                        rate = new BigDecimal((double) reportCount / (currentTeamNum * days))
                                .setScale(4, RoundingMode.HALF_UP)  // 保留4位小数，四舍五入
                                .doubleValue();
                        deviceUtilizationPair.put(projectDeptId, BigDecimal.valueOf(rate));
                    }
                }
            });
        }

        // 生成返回的数据列表集合
        projectDeptPair.forEach((deptId, dept) -> {
            IotRyDailyReportStatisticsRespVO statistics = new IotRyDailyReportStatisticsRespVO();
            statistics.setProjectDeptId(deptId);
            statistics.setProjectDeptName(dept.getName());
            statistics.setSort(dept.getSort());
            statistics.setType("2");
            statistics.setUtilizationRate(deviceUtilizationPair.get(deptId));
            statistics.setCumulativeFootage(cumulativeFootagePair.get(deptId));
            statistics.setCumulativeConstructWells(cumulativeConstructWellsPair.get(deptId));
            statistics.setCumulativeCompletedWells(cumulativeCompletedWellsPair.get(deptId));
            statistics.setCumulativePowerConsumption(cumulativePowerConsumptionPair.get(deptId));
            // 累计油耗
            BigDecimal cumulativeFuelConsumption = cumulativeFuelConsumptionPair.get(deptId);
            statistics.setCumulativeFuelConsumption(cumulativeFuelConsumption);
            // 平均油耗
            if (ObjUtil.isNotEmpty(cumulativeFuelConsumption) && ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
                statistics.setAverageFuelConsumption(cumulativeFuelConsumption.divide(new BigDecimal(days), 2, RoundingMode.HALF_UP));
            }
            statistics.setTransitTime(cumulativeTransitTimePair.get(deptId));
            statistics.setNonProductiveTime(cumulativeNonProductionPair.get(deptId));
            result.add(statistics);
        });

        return result;
    }

    /**
     * 按项目部维度统计 非生产时效
     * @param pageReqVO 日报查询对象
     * @param dailyReports 日报数据列表
     * @param rootDeptId 根部门ID（如158L为 瑞鹰 根部门，或其他公司级部门ID）
     * @return 项目部维度统计 非生产时效 钻井 修井
     */
    private List<IotRyDailyReportNptStatisticsRespVO> nptStatisticsByProjectDept(IotRyDailyReportPageReqVO pageReqVO,
                                                                           List<IotRyDailyReportDO> dailyReports, Long rootDeptId) {
        List<IotRyDailyReportNptStatisticsRespVO> result = new ArrayList<>();

        Set<Long> projectDeptIds = new HashSet<>();
        // key项目部id    value项目部名称
        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
        // key部门id   value部门parentId
        Map<Long, Long> teamProjectIdPair = new HashMap<>();
        // key队伍id    value队伍部门
        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
        // 队伍id 集合
        Set<Long> teamIds = new HashSet<>();

        // key队伍id/项目部id   value累计 工程质量npt
        Map<Long, BigDecimal> subtotalAccidentTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 设备故障npt
        Map<Long, BigDecimal> subtotalRepairTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 设备保养npt
        Map<Long, BigDecimal> subtotalSelfStopTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 技术受限npt
        Map<Long, BigDecimal> subtotalComplexityTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 生产配合npt
        Map<Long, BigDecimal> subtotalRelocationTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 生产组织npt
        Map<Long, BigDecimal> subtotalRectificationTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 不可抗力npt
        Map<Long, BigDecimal> subtotalWaitingStopTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 待命npt
        Map<Long, BigDecimal> subtotalWinterBreakTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 甲方设计npt
        Map<Long, BigDecimal> subtotalPartyaDesignPair = new HashMap<>();
        // key队伍id/项目部id   value累计 甲方准备npt
        Map<Long, BigDecimal> subtotalPartyaPreparePair = new HashMap<>();
        // key队伍id/项目部id   value累计 甲方资源npt
        Map<Long, BigDecimal> subtotalPartyaResourcePair = new HashMap<>();
        // key队伍id/项目部id   value累计 其它非生产时间npt
        Map<Long, BigDecimal> subtotalOtherNptTimePair = new HashMap<>();

        // key队伍id/项目部id   value npt小计
        Map<Long, BigDecimal> subtotalNptTimePair = new HashMap<>();
        // key队伍id/项目部id   value npt时效%
        Map<Long, BigDecimal> subtotalNptRatePair = new HashMap<>();

        // 钻井或修井部门 队伍
        List<Long> zjOrXjDeptIds = new ArrayList<>();

        // 1钻井  2修井
        String projectClassification = pageReqVO.getProjectClassification();
        // 查询钻井部门 修井 部门
        IotDeptTypePageReqVO deptTypeReqVO = new IotDeptTypePageReqVO();
        if ("1".equals(projectClassification)) {
            deptTypeReqVO.setType("zj");
        } else {
            deptTypeReqVO.setType("xj");
        }
        List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(deptTypeReqVO);
        if (CollUtil.isNotEmpty(deptTypes)) {
            deptTypes.forEach(dept -> {
                zjOrXjDeptIds.add(dept.getDeptId());
            });
        }

        // 以项目部为维度统计数据 找到所有项目部与队伍的对应关系 查询指定根部门下的所有子部门
        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(rootDeptId);
        DeptListReqVO reqVO = new DeptListReqVO();
        reqVO.setDeptIds(allRhChildDeptIds);
        List<DeptDO> depts = deptService.getDeptList(reqVO);

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            // 筛选出所有项目部
            if ("2".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
            // 队伍
            if ("3".equals(dept.getType())) {
                teamIds.add(dept.getId());
                teamDeptPair.put(dept.getId(), dept);
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // key项目部id   value项目部包含的钻井or修井队伍id集合
        Map<Long, Set<Long>> projectTeamPair = new HashMap<>();
        // 筛选项目部下包含的队伍
        depts.forEach(dept -> {
            Long deptId = dept.getId();
            Long parentId = dept.getParentId();
            if (projectDeptIds.contains(parentId)) {
                // 获得当前部门的上级项目部
                projectDeptIds.forEach(projectDeptId -> {
                    // 统计各钻井或修井项目部下队伍数量
                    if (projectDeptId.equals(parentId) && zjOrXjDeptIds.contains(deptId)) {
                        if (projectTeamPair.containsKey(projectDeptId)) {
                            Set<Long> tempTeamIds = projectTeamPair.get(projectDeptId);
                            tempTeamIds.add(deptId);
                            projectTeamPair.put(projectDeptId, tempTeamIds);
                        } else {
                            Set<Long> tempTeamIds = new HashSet<>();
                            tempTeamIds.add(deptId);
                            projectTeamPair.put(projectDeptId, tempTeamIds);
                        }
                    }
                });
            }
        });

        // 计算日期查询区间有多少小时
        LocalDateTime[] createTimes = pageReqVO.getCreateTime();
        List<Long> totalHours = new ArrayList<>();
        if (ObjUtil.isNotEmpty(createTimes) && createTimes.length >= 2) {
            LocalDate startDate = createTimes[0].toLocalDate();
            LocalDate endDate = createTimes[1].toLocalDate();
            // 核心：包含起止两天 → 天数差 +1 再 ×24
            long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
            Long tempTotalHours = days * 24L;
            totalHours.add(tempTotalHours);
        }

        // 累计计算各项 非生产时间
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                if (ObjUtil.isNotEmpty(report.getDeptId()) && teamProjectIdPair.containsKey(report.getDeptId()) && zjOrXjDeptIds.contains(report.getDeptId())) {
                    // projectDeptId可能是项目部 也可能是项目的上级
                    Long projectDeptId = 0l;
                    if (teamDeptPair.containsKey(report.getDeptId())) {
                        // 日报deptId如果是队伍 获取队伍的上级项目部
                        projectDeptId = teamProjectIdPair.get(report.getDeptId());
                    }
                    if (projectDeptPair.containsKey(report.getDeptId())) {
                        // 日报deptId如果是项目部 使用当前项目部
                        projectDeptId = report.getDeptId();
                    }
                    if (ObjUtil.isNotEmpty(projectDeptId) && (projectDeptId > 0)) {
                        // 工程质量 npt
                        BigDecimal accidentTime = report.getAccidentTime();
                        if (ObjUtil.isNotEmpty(accidentTime)) {
                            if (subtotalAccidentTimePair.containsKey(projectDeptId)) {
                                BigDecimal existAccidentTime = subtotalAccidentTimePair.get(projectDeptId);
                                BigDecimal tempAccidentTime = existAccidentTime.add(accidentTime);
                                subtotalAccidentTimePair.put(projectDeptId, tempAccidentTime);
                            } else {
                                subtotalAccidentTimePair.put(projectDeptId, accidentTime);
                            }
                        }
                        // 设备故障 npt
                        BigDecimal repairTime = report.getRepairTime();
                        if (ObjUtil.isNotEmpty(repairTime)) {
                            if (subtotalRepairTimePair.containsKey(projectDeptId)) {
                                BigDecimal existRepairTime = subtotalRepairTimePair.get(projectDeptId);
                                BigDecimal tempRepairTime = existRepairTime.add(repairTime);
                                subtotalRepairTimePair.put(projectDeptId, tempRepairTime);
                            } else {
                                subtotalRepairTimePair.put(projectDeptId, repairTime);
                            }
                        }
                        // 设备保养 npt
                        BigDecimal selfStopTime = report.getSelfStopTime();
                        if (ObjUtil.isNotEmpty(selfStopTime)) {
                            if (subtotalSelfStopTimePair.containsKey(projectDeptId)) {
                                BigDecimal existSelfStopTime = subtotalSelfStopTimePair.get(projectDeptId);
                                BigDecimal tempSelfStopTime = existSelfStopTime.add(selfStopTime);
                                subtotalSelfStopTimePair.put(projectDeptId, tempSelfStopTime);
                            } else {
                                subtotalSelfStopTimePair.put(projectDeptId, selfStopTime);
                            }
                        }
                        // 技术受限 npt
                        BigDecimal complexityTime = report.getComplexityTime();
                        if (ObjUtil.isNotEmpty(complexityTime)) {
                            if (subtotalComplexityTimePair.containsKey(projectDeptId)) {
                                BigDecimal existComplexityTime = subtotalComplexityTimePair.get(projectDeptId);
                                BigDecimal tempComplexityTime = existComplexityTime.add(complexityTime);
                                subtotalComplexityTimePair.put(projectDeptId, tempComplexityTime);
                            } else {
                                subtotalComplexityTimePair.put(projectDeptId, complexityTime);
                            }
                        }
                        // 生产配合 npt
                        BigDecimal relocationTime = report.getRelocationTime();
                        if (ObjUtil.isNotEmpty(relocationTime)) {
                            if (subtotalRelocationTimePair.containsKey(projectDeptId)) {
                                BigDecimal existRelocationTime = subtotalRelocationTimePair.get(projectDeptId);
                                BigDecimal tempRelocationTime = existRelocationTime.add(relocationTime);
                                subtotalRelocationTimePair.put(projectDeptId, tempRelocationTime);
                            } else {
                                subtotalRelocationTimePair.put(projectDeptId, relocationTime);
                            }
                        }
                        // 生产组织 npt
                        BigDecimal rectificationTime = report.getRectificationTime();
                        if (ObjUtil.isNotEmpty(rectificationTime)) {
                            if (subtotalRectificationTimePair.containsKey(projectDeptId)) {
                                BigDecimal existRectificationTime = subtotalRectificationTimePair.get(projectDeptId);
                                BigDecimal tempRectificationTime = existRectificationTime.add(rectificationTime);
                                subtotalRectificationTimePair.put(projectDeptId, tempRectificationTime);
                            } else {
                                subtotalRectificationTimePair.put(projectDeptId, rectificationTime);
                            }
                        }
                        // 不可抗力 npt
                        BigDecimal waitingStopTime = report.getWaitingStopTime();
                        if (ObjUtil.isNotEmpty(waitingStopTime)) {
                            if (subtotalWaitingStopTimePair.containsKey(projectDeptId)) {
                                BigDecimal existWaitingStopTime = subtotalWaitingStopTimePair.get(projectDeptId);
                                BigDecimal tempWaitingStopTime = existWaitingStopTime.add(waitingStopTime);
                                subtotalWaitingStopTimePair.put(projectDeptId, tempWaitingStopTime);
                            } else {
                                subtotalWaitingStopTimePair.put(projectDeptId, waitingStopTime);
                            }
                        }
                        // 待命 npt
                        BigDecimal winterBreakTime = report.getWinterBreakTime();
                        if (ObjUtil.isNotEmpty(winterBreakTime)) {
                            if (subtotalWinterBreakTimePair.containsKey(projectDeptId)) {
                                BigDecimal existWinterBreakTime = subtotalWinterBreakTimePair.get(projectDeptId);
                                BigDecimal tempWinterBreakTime = existWinterBreakTime.add(winterBreakTime);
                                subtotalWinterBreakTimePair.put(projectDeptId, tempWinterBreakTime);
                            } else {
                                subtotalWinterBreakTimePair.put(projectDeptId, winterBreakTime);
                            }
                        }
                        // 甲方设计 npt
                        BigDecimal partyaDesign = report.getPartyaDesign();
                        if (ObjUtil.isNotEmpty(partyaDesign)) {
                            if (subtotalPartyaDesignPair.containsKey(projectDeptId)) {
                                BigDecimal existPartyaDesign = subtotalPartyaDesignPair.get(projectDeptId);
                                BigDecimal tempPartyaDesign = existPartyaDesign.add(partyaDesign);
                                subtotalPartyaDesignPair.put(projectDeptId, tempPartyaDesign);
                            } else {
                                subtotalPartyaDesignPair.put(projectDeptId, partyaDesign);
                            }
                        }
                        // 甲方准备 npt
                        BigDecimal partyaPrepare = report.getPartyaPrepare();
                        if (ObjUtil.isNotEmpty(partyaPrepare)) {
                            if (subtotalPartyaPreparePair.containsKey(projectDeptId)) {
                                BigDecimal existPartyaPrepare = subtotalPartyaPreparePair.get(projectDeptId);
                                BigDecimal tempPartyaPrepare = existPartyaPrepare.add(partyaPrepare);
                                subtotalPartyaPreparePair.put(projectDeptId, tempPartyaPrepare);
                            } else {
                                subtotalPartyaPreparePair.put(projectDeptId, partyaPrepare);
                            }
                        }
                        // 甲方资源 npt
                        BigDecimal partyaResource = report.getPartyaResource();
                        if (ObjUtil.isNotEmpty(partyaResource)) {
                            if (subtotalPartyaResourcePair.containsKey(projectDeptId)) {
                                BigDecimal existPartyaResource = subtotalPartyaResourcePair.get(projectDeptId);
                                BigDecimal tempPartyaResource = existPartyaResource.add(partyaResource);
                                subtotalPartyaResourcePair.put(projectDeptId, tempPartyaResource);
                            } else {
                                subtotalPartyaResourcePair.put(projectDeptId, partyaResource);
                            }
                        }
                        // 其它非生产时间 npt
                        BigDecimal otherNptTime = report.getOtherNptTime();
                        if (ObjUtil.isNotEmpty(otherNptTime)) {
                            if (subtotalOtherNptTimePair.containsKey(projectDeptId)) {
                                BigDecimal existOtherNptTime = subtotalOtherNptTimePair.get(projectDeptId);
                                BigDecimal tempOtherNptTime = existOtherNptTime.add(otherNptTime);
                                subtotalOtherNptTimePair.put(projectDeptId, tempOtherNptTime);
                            } else {
                                subtotalOtherNptTimePair.put(projectDeptId, otherNptTime);
                            }
                        }
                    }
                }
            });

            // 计算每个项目部的 npt小计 npt时效
            if (CollUtil.isNotEmpty(projectDeptPair)) {
                projectDeptPair.forEach((projectDeptId, dept) -> {
                    // 统计当前项目部所有 npt 总和、时效
                    BigDecimal tempSubtotalNpt = BigDecimal.ZERO;
                    // 计入 npt时效 的非生产时间小计
                    BigDecimal tempNptSum = BigDecimal.ZERO;
                    if (subtotalAccidentTimePair.containsKey(projectDeptId)) {
                        BigDecimal accidentTime = subtotalAccidentTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(accidentTime);
                        tempNptSum = tempNptSum.add(accidentTime);
                    }
                    if (subtotalRepairTimePair.containsKey(projectDeptId)) {
                        BigDecimal repairTime = subtotalRepairTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(repairTime);
                        tempNptSum = tempNptSum.add(repairTime);
                    }
                    if (subtotalSelfStopTimePair.containsKey(projectDeptId)) {
                        BigDecimal selfStopTime = subtotalSelfStopTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(selfStopTime);
                    }
                    if (subtotalComplexityTimePair.containsKey(projectDeptId)) {
                        BigDecimal complexityTime = subtotalComplexityTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(complexityTime);
                        tempNptSum = tempNptSum.add(complexityTime);
                    }
                    if (subtotalRelocationTimePair.containsKey(projectDeptId)) {
                        BigDecimal relocationTime = subtotalRelocationTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(relocationTime);
                    }
                    if (subtotalRectificationTimePair.containsKey(projectDeptId)) {
                        BigDecimal rectificationTime = subtotalRectificationTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(rectificationTime);
                        tempNptSum = tempNptSum.add(rectificationTime);
                    }
                    if (subtotalWaitingStopTimePair.containsKey(projectDeptId)) {
                        BigDecimal waitingStopTime = subtotalWaitingStopTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(waitingStopTime);
                        tempNptSum = tempNptSum.add(waitingStopTime);
                    }
                    if (subtotalWinterBreakTimePair.containsKey(projectDeptId)) {
                        BigDecimal winterBreakTime = subtotalWinterBreakTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(winterBreakTime);
                    }
                    if (subtotalPartyaDesignPair.containsKey(projectDeptId)) {
                        BigDecimal partyaDesign = subtotalPartyaDesignPair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(partyaDesign);
                        tempNptSum = tempNptSum.add(partyaDesign);
                    }
                    if (subtotalPartyaPreparePair.containsKey(projectDeptId)) {
                        BigDecimal partyaPrepare = subtotalPartyaPreparePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(partyaPrepare);
                        tempNptSum = tempNptSum.add(partyaPrepare);
                    }
                    if (subtotalPartyaResourcePair.containsKey(projectDeptId)) {
                        BigDecimal partyaResource = subtotalPartyaResourcePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(partyaResource);
                        tempNptSum = tempNptSum.add(partyaResource);
                    }
                    if (subtotalOtherNptTimePair.containsKey(projectDeptId)) {
                        BigDecimal otherNptTime = subtotalOtherNptTimePair.get(projectDeptId);
                        tempSubtotalNpt = tempSubtotalNpt.add(otherNptTime);
                        tempNptSum = tempNptSum.add(otherNptTime);
                    }
                    // 项目部 npt 小计
                    subtotalNptTimePair.put(projectDeptId, tempNptSum);
                    // 项目部 npt 时效 以下非生产时间计入非生产时效
                    // 设备故障repair_time
                    // 工程质量accident_time
                    // 技术受限complexity_time
                    // 生产组织rectification_time
                    // 不可抗力waiting_stop_time
                    // 甲方设计partya_design
                    // 甲方准备partya_prepare
                    // 甲方资源partya_resource
                    // 其他非生产时间other_npt_time
                    if (CollUtil.isNotEmpty(totalHours)) {
                        Long totalHour = totalHours.get(0);
                        if (ObjUtil.isNotEmpty(totalHour) && totalHour > 0) {
                            // 查询每个项目部下的队伍数量
                            if (projectTeamPair.containsKey(projectDeptId)) {
                                Set<Long> projectTeamIds = projectTeamPair.get(projectDeptId);
                                BigDecimal nptRate = tempNptSum.divide(new BigDecimal(totalHour * projectTeamIds.size()), 4, RoundingMode.HALF_UP);
                                subtotalNptRatePair.put(projectDeptId, nptRate);
                            }
                        }
                    }
                });
            }
        }

        // 生成返回的数据列表集合
        projectDeptPair.forEach((deptId, dept) -> {
            IotRyDailyReportNptStatisticsRespVO statistics = new IotRyDailyReportNptStatisticsRespVO();
            statistics.setProjectDeptId(deptId);
            statistics.setProjectDeptName(dept.getName());
            statistics.setSort(dept.getSort());
            statistics.setType("2");
            statistics.setAccidentTime(subtotalAccidentTimePair.get(deptId));
            statistics.setRepairTime(subtotalRepairTimePair.get(deptId));
            statistics.setSelfStopTime(subtotalSelfStopTimePair.get(deptId));
            statistics.setComplexityTime(subtotalComplexityTimePair.get(deptId));
            statistics.setRelocationTime(subtotalRelocationTimePair.get(deptId));
            statistics.setRectificationTime(subtotalRectificationTimePair.get(deptId));
            statistics.setWaitingStopTime(subtotalWaitingStopTimePair.get(deptId));
            statistics.setWinterBreakTime(subtotalWinterBreakTimePair.get(deptId));
            statistics.setPartyaDesign(subtotalPartyaDesignPair.get(deptId));
            statistics.setPartyaPrepare(subtotalPartyaPreparePair.get(deptId));
            statistics.setPartyaResource(subtotalPartyaResourcePair.get(deptId));
            statistics.setOtherNptTime(subtotalOtherNptTimePair.get(deptId));
            statistics.setNptTotal(subtotalNptTimePair.get(deptId));
            statistics.setNptRate(subtotalNptRatePair.get(deptId));
            if (CollUtil.isNotEmpty(totalHours)) {
                Long totalHour = totalHours.get(0);
                // 自然时间 考虑进 项目部下的队伍数量
                if (projectTeamPair.containsKey(deptId)) {
                    Set<Long> tempTeamIds = projectTeamPair.get(deptId);
                    statistics.setCalendarTime(new BigDecimal(totalHour * tempTeamIds.size()));
                }
            }
            result.add(statistics);
        });

        return result;
    }

    /**
     * 按项目部维度统计数据 折线图
     * @param pageReqVO 日报查询对象
     * @param dailyReports 日报数据列表
     * @param rootDeptId 根部门ID（如158L为 瑞鹰 根部门，或其他公司级部门ID）
     * @return 项目部维度统计结果折线图  钻井 修井
     */
    private List<IotRyDailyReportPolylineVO> polylineStatisticsByProjectDept(IotRyDailyReportPageReqVO pageReqVO,
                                                                           List<IotRyDailyReportDO> dailyReports, Long rootDeptId, LocalDateTime[] createTimes) {
        List<IotRyDailyReportPolylineVO> result = new ArrayList<>();

        Set<Long> projectDeptIds = new HashSet<>();
        // key项目部id    value项目部名称
        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
        // key部门id   value部门parentId
        Map<Long, Long> teamProjectIdPair = new HashMap<>();

        // 按照日期维度统计各工作量数据
        // key日期yyyy-MM-dd   value累计进尺
        Map<String, BigDecimal> dateFootagePair = new HashMap<>();
        // key日期yyy-MM-dd    value去重后的施工任务集合
        Map<String, Set<Long>> dateConstructTaskPair = new HashMap<>();
        // key日期yyy-MM-dd    value去重后的完工任务集合
        Map<String, Set<Long>> dateFinishTaskPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计用电量
        Map<String, BigDecimal> datePowerConsumptionPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计油耗
        Map<String, BigDecimal> dateFuelConsumptionPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计运行时效   累计注气量/累计产能
        Map<String, BigDecimal> dateTransitTimePair = new HashMap<>();
        // key日期yyyy-MM-dd   value生产时间(H)
        Map<String, BigDecimal> dateProductTimePair = new HashMap<>();
        // key日期yyyy-MM-dd   value额定生产时间(H)
        Map<String, BigDecimal> dateRatedTimePair = new HashMap<>();

        // key部门id-任务id    value施工井对应的日期
        Map<String, String> deptTaskConstructPair = new HashMap<>();
        // key部门id-任务id    value完工井对应的日期
        Map<String, String> deptTaskFinishPair = new HashMap<>();

        // 以项目部为维度统计数据
        // 找到所有项目部与队伍的对应关系
        // 查询指定根部门下的所有子部门
        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(rootDeptId);
        DeptListReqVO reqVO = new DeptListReqVO();
        reqVO.setDeptIds(allRhChildDeptIds);
        List<DeptDO> depts = deptService.getDeptList(reqVO);

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            // 筛选出所有项目部
            if ("2".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // key施工队伍id    value施工井数量
        Map<Long, Integer> totalTasksPair = new HashMap<>();
        // key施工队伍id    value完工井数量
        Map<Long, Integer> completedTasksPair = new HashMap<>();
        // key任务id   value额定生产时间
        Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
        if ("2".equals(pageReqVO.getProjectClassification())) {
            // 计算累计施工井数 累计完工井数 时 过滤掉 taskId 为空的数据
            dailyReports.forEach(report -> {
                if (ObjUtil.isNotEmpty(report.getTaskId()) && allRhChildDeptIds.contains(report.getDeptId())) {
                    String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
                    String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
                    deptTaskConstructPair.put(uniqueKey, dateStr);
                    deptTaskFinishPair.put(uniqueKey, dateStr);
                }
            });
            // 查询 指定时间范围内的 修井 累计施工井数 累计完工井数
            // 每天的任务数量 taskId 去重后的数量
            // 每天完工任务数量 deptId+taskId 去重后 状态为 wg 的数量
            dailyReports.forEach(report -> {
                String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
                String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
                if (deptTaskConstructPair.containsKey(uniqueKey)) {
                    String tempDateStr = deptTaskFinishPair.get(uniqueKey);

                    if (dateConstructTaskPair.containsKey(tempDateStr)) {
                        Set<Long> tempUniqueTaskIds = dateConstructTaskPair.get(tempDateStr);
                        tempUniqueTaskIds.add(report.getTaskId());
                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
                    } else {
                        Set<Long> tempUniqueTaskIds = new HashSet<>();
                        tempUniqueTaskIds.add(report.getTaskId());
                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
                    }
                }
                // 组装完工任务集合
                if ("wg".equals(report.getRepairStatus())) {
                    if (deptTaskFinishPair.containsKey(uniqueKey)) {
                        String tempDateStr = deptTaskFinishPair.get(uniqueKey);
                        if (dateFinishTaskPair.containsKey(tempDateStr)) {
                            Set<Long> tempUniqueTaskIds = dateFinishTaskPair.get(tempDateStr);
                            tempUniqueTaskIds.add(report.getTaskId());
                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
                        } else {
                            Set<Long> tempUniqueTaskIds = new HashSet<>();
                            tempUniqueTaskIds.add(report.getTaskId());
                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
                        }
                    }
                }
            });

            // 计算 运行时效 累计生产时间/累计额定生产时间
            // 查询日报关联的任务信息
            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
            taskReqVO.setTaskIds(convertList(dailyReports, IotRyDailyReportDO::getTaskId));
            List<IotProjectTaskDO> tasks = iotProjectTaskMapper.selectList(taskReqVO);
            if (CollUtil.isNotEmpty(tasks)) {
                tasks.forEach(task -> {
                    if (CollUtil.isNotEmpty(task.getExtProperty())) {
                        List<IotTaskAttrModelProperty> taskAttrs = task.getExtProperty();
                        if (CollUtil.isNotEmpty(taskAttrs)) {
                            // 找到 额定生产时间 属性 对应的值
                            taskAttrs.forEach(attr -> {
                                if ("额定生产时间".equals(attr.getName()) && StrUtil.isNotBlank(attr.getActualValue())) {
                                    taskRatedProductionTimePair.put(task.getId(), new BigDecimal(attr.getActualValue()));
                                }
                            });
                        }
                    }
                });
            }
        }

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
                LocalDateTime reportLocalDate = report.getCreateTime();
                // 将日期格式转换成 字符串
                String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
                // 累计进尺
                dateFootagePair.merge(reportDateStr, report.getDailyFootage(), BigDecimal::add);
                // 累计用电量
                datePowerConsumptionPair.merge(reportDateStr, report.getDailyPowerUsage(), BigDecimal::add);
                // 累计油耗
                dateFuelConsumptionPair.merge(reportDateStr, report.getDailyFuel(), BigDecimal::add);
                // 生产时间
                dateProductTimePair.merge(reportDateStr, report.getProductionTime(), BigDecimal::add);
                // 额定生产时间
                if (taskRatedProductionTimePair.containsKey(report.getTaskId())) {
                    BigDecimal ratedTime = taskRatedProductionTimePair.get(report.getTaskId());
                    dateRatedTimePair.merge(reportDateStr, ratedTime, BigDecimal::add);
                }
            });

            // 根据 生产时间 额定生产时间 计算指定日期范围的 平均运行时效
            if (CollUtil.isNotEmpty(dateProductTimePair) && CollUtil.isNotEmpty(dateRatedTimePair)) {
                dateProductTimePair.forEach((reportDateStr, productTime) -> {
                    if (dateRatedTimePair.containsKey(reportDateStr)) {
                        BigDecimal ratedTime = dateRatedTimePair.get(reportDateStr);
                        if (ratedTime.compareTo(BigDecimal.ZERO) > 0) {
                            // 指日期范围的累计运行时效
                            BigDecimal tempTransitTime = productTime.divide(ratedTime, 4, RoundingMode.HALF_UP);
                            dateTransitTimePair.put(reportDateStr, tempTransitTime);
                        } else {
                            dateTransitTimePair.put(reportDateStr, BigDecimal.ZERO);
                        }
                    }
                });
            }
        }

        // 日期字符串集合
        List<String> dateRangeList = new ArrayList<>();

        if (createTimes.length >= 2) {
            LocalDate startDate = createTimes[0].toLocalDate();
            LocalDate endDate = createTimes[1].toLocalDate();
            // 生成从起始日期到结束日期的所有日期
            for (LocalDate date = startDate;
                 !date.isAfter(endDate);  // 使用 isAfter 而不是 <= 判断
                 date = date.plusDays(1)) {
                dateRangeList.add(date.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
            }
        }

        if (CollUtil.isNotEmpty(dateRangeList)) {
            dateRangeList.forEach(date -> {
                IotRyDailyReportPolylineVO statistics = new IotRyDailyReportPolylineVO();
                statistics.setReportDate(date);
                statistics.setCumulativeFootage(dateFootagePair.get(date));
                statistics.setCumulativeConstructWells(dateConstructTaskPair.containsKey(date) ? dateConstructTaskPair.get(date).size() : 0);
                statistics.setCumulativeCompletedWells(dateFinishTaskPair.containsKey(date) ? dateFinishTaskPair.get(date).size() : 0);
                statistics.setCumulativePowerConsumption(datePowerConsumptionPair.get(date));
                statistics.setCumulativeFuelConsumption(dateFuelConsumptionPair.get(date));
                statistics.setTransitTime(dateTransitTimePair.get(date));
                result.add(statistics);
            });
        }

        return result;
    }

    /**
     * 按 队伍 维度统计数据
     * @param pageReqVO 日报数据请求对象
     * @param dailyReports 日报数据列表
     * @param pageReqVO 项目部ID 或 队伍id（塔河项目部 HY-A1）
     * @return 队伍 维度统计结果列表
     */
    private List<IotRyDailyReportStatisticsRespVO> statisticsByProjectDepartment(IotRyDailyReportPageReqVO pageReqVO,
                                                                                 List<IotRyDailyReportDO> dailyReports) {
        List<IotRyDailyReportStatisticsRespVO> result = new ArrayList<>();

        Set<Long> projectDeptIds = new HashSet<>();
        // key项目部id    value项目部名称
        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
        // key队伍id    value队伍名称
        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
        // key部门id   value部门parentId
        Map<Long, Long> teamProjectIdPair = new HashMap<>();

        // key队伍id/项目部id   value累计进尺
        Map<Long, BigDecimal> cumulativeFootagePair = new HashMap<>();
        // key队伍id   value累计用电
        Map<Long, BigDecimal> cumulativePowerConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value累计油耗
        Map<Long, BigDecimal> cumulativeFuelConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value对应项目部的施工井数
        Map<Long, Integer> cumulativeConstructWellsPair = new HashMap<>();
        // key队伍id/项目部id   value对应项目部的完工井数
        Map<Long, Integer> cumulativeCompletedWellsPair = new HashMap<>();
        // key队伍id/项目部id   value生产时间(H)
        Map<Long, BigDecimal> cumulativeProductTimePair = new HashMap<>();
        // key队伍id/项目部id   value额定生产时间(H)
        Map<Long, BigDecimal> cumulativeRatedTimePair = new HashMap<>();
        // key队伍id   value累计运行时效
        Map<Long, BigDecimal> cumulativeTransitTimePair = new HashMap<>();
        // key队伍id/项目部id   value非生产时间集合
        Map<Long, List<BigDecimal>> cumulativeNonProductionTimePair = new HashMap<>();
        // key队伍id/项目部id   value非生产时效
        Map<Long, BigDecimal> cumulativeNonProductionPair = new HashMap<>();
        // key队伍id/项目部id   value设备利用率
        Map<Long, BigDecimal> deviceUtilizationPair = new HashMap<>();

        // 钻井或修井部门 队伍
        List<Long> zjOrXjDeptIds = new ArrayList<>();
        // 1钻井  2修井
        String projectClassification = pageReqVO.getProjectClassification();
        // 查询钻井部门 修井 部门
        IotDeptTypePageReqVO deptTypeReqVO = new IotDeptTypePageReqVO();
        if ("1".equals(projectClassification)) {
            deptTypeReqVO.setType("zj");
        } else {
            deptTypeReqVO.setType("xj");
        }
        List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(deptTypeReqVO);
        if (CollUtil.isNotEmpty(deptTypes)) {
            deptTypes.forEach(dept -> {
                zjOrXjDeptIds.add(dept.getDeptId());
            });
        }

        // 以 队伍 为维度统计数据
        // 找到所有项目部与队伍的对应关系
        // 查询指定根部门下的所有子部门
        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
        DeptListReqVO reqVO = new DeptListReqVO();
        allRhChildDeptIds.add(pageReqVO.getDeptId());  // 查询某支队伍
        reqVO.setDeptIds(allRhChildDeptIds);
        List<DeptDO> depts = deptService.getDeptList(reqVO);

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            if (0 == dept.getStatus()) {
                if ("3".equals(dept.getType())) {
                    teamDeptPair.put(dept.getId(), dept);
                }
                teamProjectIdPair.put(dept.getId(), dept.getParentId());
            }
        });

        // key施工队伍id    value施工井数量
        Map<Long, Integer> totalTasksPair = new HashMap<>();
        // key施工队伍id    value完工井数量
        Map<Long, Integer> completedTasksPair = new HashMap<>();
        // key任务id   value额定生产时间
        Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
        if ("2".equals(pageReqVO.getProjectClassification())) {
            // 查询修井 累计施工井数 累计完工井数
            List<IotRyDailyReportTaskCountVO> repairDeptTasks = iotRyDailyReportMapper.countRepairTasksByDept(pageReqVO);
            if (CollUtil.isNotEmpty(repairDeptTasks)) {
                repairDeptTasks.forEach(task -> {
                    totalTasksPair.put(task.getDeptId(), task.getTotalTaskCount());
                    completedTasksPair.put(task.getDeptId(), task.getCompletedTaskCount());
                });

            }
            // 计算 运行时效 累计生产时间/累计额定生产时间
            // 查询日报关联的任务信息
            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
            taskReqVO.setTaskIds(convertList(dailyReports, IotRyDailyReportDO::getTaskId));
            List<IotProjectTaskDO> tasks = iotProjectTaskMapper.selectList(taskReqVO);
            if (CollUtil.isNotEmpty(tasks)) {
                tasks.forEach(task -> {
                    if (CollUtil.isNotEmpty(task.getExtProperty())) {
                        List<IotTaskAttrModelProperty> taskAttrs = task.getExtProperty();
                        if (CollUtil.isNotEmpty(taskAttrs)) {
                            // 找到 额定生产时间 属性 对应的值
                            taskAttrs.forEach(attr -> {
                                if ("额定生产时间".equals(attr.getName()) && StrUtil.isNotBlank(attr.getActualValue())) {
                                    taskRatedProductionTimePair.put(task.getId(), new BigDecimal(attr.getActualValue()));
                                }
                            });
                        }
                    }
                });
            }
        }

        // 统计各队伍的设备利用率
        // key队伍id     value队伍指定时间区域内日报数量
        Map<Long, Integer> teamReportPair = new HashMap<>();

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                if (ObjUtil.isNotEmpty(report.getDeptId()) && zjOrXjDeptIds.contains(report.getDeptId())) {
                    // 统计各个队伍的日报数量
                    if (teamReportPair.containsKey(report.getDeptId())) {
                        Integer tempCount = teamReportPair.get(report.getDeptId());
                        teamReportPair.put(report.getDeptId(), ++tempCount);
                    } else {
                        teamReportPair.put(report.getDeptId(), 1);
                    }

                    // 累计进尺
                    cumulativeFootagePair.merge(report.getDeptId(), report.getDailyFootage(), BigDecimal::add);
                    // 累计油耗
                    cumulativeFuelConsumptionPair.merge(report.getDeptId(), report.getDailyFuel(), BigDecimal::add);
                    // 累计用电量
                    cumulativePowerConsumptionPair.merge(report.getDeptId(), report.getDailyPowerUsage(), BigDecimal::add);
                    // 统计各项目部的 累计施工井数 累计完工井数
                    /* if (totalTasksPair.containsKey(report.getDeptId())) {
                        Integer tempCount = totalTasksPair.get(report.getDeptId());
                        cumulativeConstructWellsPair.put(report.getDeptId(), tempCount);
                    }
                    if (completedTasksPair.containsKey(report.getDeptId())) {
                        Integer tempCompleteCount = completedTasksPair.get(report.getDeptId());
                        cumulativeCompletedWellsPair.put(report.getDeptId(), tempCompleteCount);
                    } */
                    // 额定生产时间
                    if (taskRatedProductionTimePair.containsKey(report.getTaskId())) {
                        BigDecimal ratedTime = taskRatedProductionTimePair.get(report.getTaskId());
                        cumulativeRatedTimePair.merge(report.getDeptId(), ratedTime, BigDecimal::add);
                    }
                    // 生产时间
                    cumulativeProductTimePair.merge(report.getDeptId(), report.getProductionTime(), BigDecimal::add);
                    // NPT 归类 设备故障repair_time 工程质量accident_time 技术受限complexity_time 生产组织rectification_time 不可抗力waiting_stop_time
                    // 甲方设计partya_design 甲方准备partya_prepare 甲方资源partya_resource 其他非生产时间other_npt_time
                    // BigDecimal nonProductionTime = report.getNonProductionTime();
                    BigDecimal nonProductionTimeSum = Stream.of(
                                    report.getAccidentTime(),
                                    report.getRepairTime(),
                                    report.getComplexityTime(),
                                    report.getRectificationTime(),
                                    report.getWaitingStopTime(),
                                    report.getPartyaDesign(),
                                    report.getPartyaPrepare(),
                                    report.getPartyaResource(),
                                    report.getOtherNptTime()
                            )
                            .map(time -> ObjUtil.defaultIfNull(time, BigDecimal.ZERO))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    if (nonProductionTimeSum.compareTo(BigDecimal.ZERO) > 0) {
                        if (cumulativeNonProductionTimePair.containsKey(report.getDeptId())) {
                            List<BigDecimal> tempNonProductionTimes = cumulativeNonProductionTimePair.get(report.getDeptId());
                            tempNonProductionTimes.add(nonProductionTimeSum);
                            cumulativeNonProductionTimePair.put(report.getDeptId(), tempNonProductionTimes);
                        } else {
                            List<BigDecimal> tempNonProductionTimes = new ArrayList<>();
                            tempNonProductionTimes.add(nonProductionTimeSum);
                            cumulativeNonProductionTimePair.put(report.getDeptId(), tempNonProductionTimes);
                        }
                    }
                }
            });
            // 根据 计算指定队伍下的平均产能
            if (CollUtil.isNotEmpty(cumulativeProductTimePair) && CollUtil.isNotEmpty(cumulativeRatedTimePair)) {
                cumulativeProductTimePair.forEach((teamDeptId, productionTime) -> {
                    if (cumulativeRatedTimePair.containsKey(teamDeptId)) {
                        BigDecimal tempRatedTime = cumulativeRatedTimePair.get(teamDeptId);
                        if (tempRatedTime.compareTo(BigDecimal.ZERO) > 0) {
                            // 指定队伍的累计运行时效
                            BigDecimal tempTransitTime = productionTime.divide(tempRatedTime, 4, RoundingMode.HALF_UP);
                            cumulativeTransitTimePair.put(teamDeptId, tempTransitTime);
                        }
                    }
                });
            }
        }

        Long days;
        if (ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
            LocalDateTime[] createTimes = pageReqVO.getCreateTime();
            // 获取开始时间和结束时间
            LocalDateTime startTime = createTimes[0];
            LocalDateTime endTime = createTimes[1];
            // 截断到日期（忽略时分秒）
            LocalDate startDate = startTime.toLocalDate();
            LocalDate endDate = endTime.toLocalDate();
            // 计算天数：日期差 + 1（包含首尾两天）
            days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
        } else {
            days = 0l;
        }

        if (CollUtil.isNotEmpty(cumulativeNonProductionTimePair)) {
            // 计算各队伍的 非生产时效
            cumulativeNonProductionTimePair.forEach((teamId, nonProductTimes) -> {
                // nonProductTimes 集合中元素的数量就是 分母中应该计算非生产时效的天数
                BigDecimal totalNonProductionTime = nonProductTimes.stream()
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                if (days > 0) {
                    BigDecimal denominator = new BigDecimal(days * 24);
                    BigDecimal nonProductionEfficiency = totalNonProductionTime
                            .divide(denominator, 4, RoundingMode.HALF_UP);
                    cumulativeNonProductionPair.put(teamId, nonProductionEfficiency);
                }
            });
        }

        // 计算各队伍的平均设备利用率
        if (CollUtil.isNotEmpty(teamReportPair)) {
            teamReportPair.forEach((teamDeptId, reportCount) -> {
                double rate = 0.0;
                Integer currentTeamNum = 1;
                // 当前项目部 设备利用率 公式 reportCount/(currentTeamNum * daysCount)
                // 计算设备利用率（处理除数为0的情况）
                if (currentTeamNum > 0 && days > 0) {
                    rate = new BigDecimal((double) reportCount / (currentTeamNum * days))
                            .setScale(4, RoundingMode.HALF_UP)  // 保留4位小数，四舍五入
                            .doubleValue();
                    deviceUtilizationPair.put(teamDeptId, BigDecimal.valueOf(rate));
                }
            });
        }

        // 生成返回的数据列表集合
        teamDeptPair.forEach((teamDeptId, dept) -> {
            IotRyDailyReportStatisticsRespVO statistics = new IotRyDailyReportStatisticsRespVO();
            statistics.setTeamId(teamDeptId);
            statistics.setTeamName(dept.getName());
            statistics.setSort(dept.getSort());
            statistics.setType("3");
            statistics.setNonProductiveTime(cumulativeNonProductionPair.get(teamDeptId));
            statistics.setUtilizationRate(deviceUtilizationPair.get(teamDeptId));
            statistics.setCumulativeFootage(cumulativeFootagePair.get(teamDeptId));
            statistics.setCumulativeConstructWells(totalTasksPair.get(teamDeptId));
            statistics.setCumulativeCompletedWells(completedTasksPair.get(teamDeptId));
            statistics.setCumulativePowerConsumption(cumulativePowerConsumptionPair.get(teamDeptId));
            // 累计油耗
            BigDecimal cumulativeFuelConsumption = cumulativeFuelConsumptionPair.get(teamDeptId);
            statistics.setCumulativeFuelConsumption(cumulativeFuelConsumption);
            // 平均油耗
            if (ObjUtil.isNotEmpty(cumulativeFuelConsumption) && ObjUtil.isNotEmpty(pageReqVO.getCreateTime())) {
                statistics.setAverageFuelConsumption(cumulativeFuelConsumption.divide(new BigDecimal(days), 2, RoundingMode.HALF_UP));
            }
            statistics.setTransitTime(cumulativeTransitTimePair.get(teamDeptId));
            result.add(statistics);
        });

        return result;
    }

    /**
     * 按 队伍 维度统计 非生产时效
     * @param pageReqVO 日报数据请求对象
     * @param dailyReports 日报数据列表
     * @param pageReqVO 项目部ID 或 队伍id（塔河项目部 HY-A1）
     * @return 队伍 维度统计 非生产时效
     */
    private List<IotRyDailyReportNptStatisticsRespVO> nptStatisticsByProjectDepartment(IotRyDailyReportPageReqVO pageReqVO,
                                                                                 List<IotRyDailyReportDO> dailyReports) {
        List<IotRyDailyReportNptStatisticsRespVO> result = new ArrayList<>();

        Set<Long> projectDeptIds = new HashSet<>();
        // key项目部id    value项目部名称
        Map<Long, DeptDO> projectDeptPair = new HashMap<>();
        // key队伍id    value队伍名称
        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
        // key部门id   value部门parentId
        Map<Long, Long> teamProjectIdPair = new HashMap<>();

        // key队伍id/项目部id   value累计 工程质量npt
        Map<Long, BigDecimal> subtotalAccidentTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 设备故障npt
        Map<Long, BigDecimal> subtotalRepairTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 设备保养npt
        Map<Long, BigDecimal> subtotalSelfStopTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 技术受限npt
        Map<Long, BigDecimal> subtotalComplexityTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 生产配合npt
        Map<Long, BigDecimal> subtotalRelocationTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 生产组织npt
        Map<Long, BigDecimal> subtotalRectificationTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 不可抗力npt
        Map<Long, BigDecimal> subtotalWaitingStopTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 待命npt
        Map<Long, BigDecimal> subtotalWinterBreakTimePair = new HashMap<>();
        // key队伍id/项目部id   value累计 甲方设计npt
        Map<Long, BigDecimal> subtotalPartyaDesignPair = new HashMap<>();
        // key队伍id/项目部id   value累计 甲方准备npt
        Map<Long, BigDecimal> subtotalPartyaPreparePair = new HashMap<>();
        // key队伍id/项目部id   value累计 甲方资源npt
        Map<Long, BigDecimal> subtotalPartyaResourcePair = new HashMap<>();
        // key队伍id/项目部id   value累计 其它非生产时间npt
        Map<Long, BigDecimal> subtotalOtherNptTimePair = new HashMap<>();

        // key队伍id   value npt小计
        Map<Long, BigDecimal> subtotalNptTimePair = new HashMap<>();
        // key队伍id   value npt时效%
        Map<Long, BigDecimal> subtotalNptRatePair = new HashMap<>();

        // 钻井或修井部门 队伍
        List<Long> zjOrXjDeptIds = new ArrayList<>();
        // 1钻井  2修井
        String projectClassification = pageReqVO.getProjectClassification();
        // 查询钻井部门 修井 部门
        IotDeptTypePageReqVO deptTypeReqVO = new IotDeptTypePageReqVO();
        if ("1".equals(projectClassification)) {
            deptTypeReqVO.setType("zj");
        } else {
            deptTypeReqVO.setType("xj");
        }
        List<IotDeptTypeDO> deptTypes = iotDeptTypeMapper.selectList(deptTypeReqVO);
        if (CollUtil.isNotEmpty(deptTypes)) {
            deptTypes.forEach(dept -> {
                zjOrXjDeptIds.add(dept.getDeptId());
            });
        }

        // 以 队伍 为维度统计数据
        // 找到所有项目部与队伍的对应关系
        // 查询指定根部门下的所有子部门
        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
        DeptListReqVO reqVO = new DeptListReqVO();
        allRhChildDeptIds.add(pageReqVO.getDeptId());  // 查询某支队伍
        reqVO.setDeptIds(allRhChildDeptIds);
        List<DeptDO> depts = deptService.getDeptList(reqVO);

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            if ("3".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                teamDeptPair.put(dept.getId(), dept);
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // 计算日期查询区间有多少小时
        LocalDateTime[] createTimes = pageReqVO.getCreateTime();
        List<Long> totalHours = new ArrayList<>();
        if (ObjUtil.isNotEmpty(createTimes) && createTimes.length >= 2) {
            LocalDate startDate = createTimes[0].toLocalDate();
            LocalDate endDate = createTimes[1].toLocalDate();
            // 核心：包含起止两天 → 天数差 +1 再 ×24
            long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
            Long tempTotalHours = days * 24L;
            totalHours.add(tempTotalHours);
        }

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                // 统计日报 每个队伍的非生产时间集合
                Long reportDeptId = report.getDeptId();
                if (ObjUtil.isNotEmpty(reportDeptId) && teamDeptPair.containsKey(reportDeptId) && zjOrXjDeptIds.contains(reportDeptId)) {
                    // 工程质量 npt
                    BigDecimal accidentTime = report.getAccidentTime();
                    if (ObjUtil.isNotEmpty(accidentTime)) {
                        if (subtotalAccidentTimePair.containsKey(reportDeptId)) {
                            BigDecimal existAccidentTime = subtotalAccidentTimePair.get(reportDeptId);
                            BigDecimal tempAccidentTime = existAccidentTime.add(accidentTime);
                            subtotalAccidentTimePair.put(reportDeptId, tempAccidentTime);
                        } else {
                            subtotalAccidentTimePair.put(reportDeptId, accidentTime);
                        }
                    }

                    // 设备故障 npt
                    BigDecimal repairTime = report.getRepairTime();
                    if (ObjUtil.isNotEmpty(repairTime)) {
                        if (subtotalRepairTimePair.containsKey(reportDeptId)) {
                            BigDecimal existRepairTime = subtotalRepairTimePair.get(reportDeptId);
                            BigDecimal tempRepairTime = existRepairTime.add(repairTime);
                            subtotalRepairTimePair.put(reportDeptId, tempRepairTime);
                        } else {
                            subtotalRepairTimePair.put(reportDeptId, repairTime);
                        }
                    }
                    // 设备保养 npt
                    BigDecimal selfStopTime = report.getSelfStopTime();
                    if (ObjUtil.isNotEmpty(selfStopTime)) {
                        if (subtotalSelfStopTimePair.containsKey(reportDeptId)) {
                            BigDecimal existSelfStopTime = subtotalSelfStopTimePair.get(reportDeptId);
                            BigDecimal tempSelfStopTime = existSelfStopTime.add(selfStopTime);
                            subtotalSelfStopTimePair.put(reportDeptId, tempSelfStopTime);
                        } else {
                            subtotalSelfStopTimePair.put(reportDeptId, selfStopTime);
                        }
                    }
                    // 技术受限 npt
                    BigDecimal complexityTime = report.getComplexityTime();
                    if (ObjUtil.isNotEmpty(complexityTime)) {
                        if (subtotalComplexityTimePair.containsKey(reportDeptId)) {
                            BigDecimal existComplexityTime = subtotalComplexityTimePair.get(reportDeptId);
                            BigDecimal tempComplexityTime = existComplexityTime.add(complexityTime);
                            subtotalComplexityTimePair.put(reportDeptId, tempComplexityTime);
                        } else {
                            subtotalComplexityTimePair.put(reportDeptId, complexityTime);
                        }
                    }
                    // 生产配合 npt
                    BigDecimal relocationTime = report.getRelocationTime();
                    if (ObjUtil.isNotEmpty(relocationTime)) {
                        if (subtotalRelocationTimePair.containsKey(reportDeptId)) {
                            BigDecimal existRelocationTime = subtotalRelocationTimePair.get(reportDeptId);
                            BigDecimal tempRelocationTime = existRelocationTime.add(relocationTime);
                            subtotalRelocationTimePair.put(reportDeptId, tempRelocationTime);
                        } else {
                            subtotalRelocationTimePair.put(reportDeptId, relocationTime);
                        }
                    }
                    // 生产组织 npt
                    BigDecimal rectificationTime = report.getRectificationTime();
                    if (ObjUtil.isNotEmpty(rectificationTime)) {
                        if (subtotalRectificationTimePair.containsKey(reportDeptId)) {
                            BigDecimal existRectificationTime = subtotalRectificationTimePair.get(reportDeptId);
                            BigDecimal tempRectificationTime = existRectificationTime.add(rectificationTime);
                            subtotalRectificationTimePair.put(reportDeptId, tempRectificationTime);
                        } else {
                            subtotalRectificationTimePair.put(reportDeptId, rectificationTime);
                        }
                    }
                    // 不可抗力 npt
                    BigDecimal waitingStopTime = report.getWaitingStopTime();
                    if (ObjUtil.isNotEmpty(waitingStopTime)) {
                        if (subtotalWaitingStopTimePair.containsKey(reportDeptId)) {
                            BigDecimal existWaitingStopTime = subtotalWaitingStopTimePair.get(reportDeptId);
                            BigDecimal tempWaitingStopTime = existWaitingStopTime.add(waitingStopTime);
                            subtotalWaitingStopTimePair.put(reportDeptId, tempWaitingStopTime);
                        } else {
                            subtotalWaitingStopTimePair.put(reportDeptId, waitingStopTime);
                        }
                    }
                    // 待命 npt
                    BigDecimal winterBreakTime = report.getWinterBreakTime();
                    if (ObjUtil.isNotEmpty(winterBreakTime)) {
                        if (subtotalWinterBreakTimePair.containsKey(reportDeptId)) {
                            BigDecimal existWinterBreakTime = subtotalWinterBreakTimePair.get(reportDeptId);
                            BigDecimal tempWinterBreakTime = existWinterBreakTime.add(winterBreakTime);
                            subtotalWinterBreakTimePair.put(reportDeptId, tempWinterBreakTime);
                        } else {
                            subtotalWinterBreakTimePair.put(reportDeptId, winterBreakTime);
                        }
                    }
                    // 甲方设计 npt
                    BigDecimal partyaDesign = report.getPartyaDesign();
                    if (ObjUtil.isNotEmpty(partyaDesign)) {
                        if (subtotalPartyaDesignPair.containsKey(reportDeptId)) {
                            BigDecimal existPartyaDesign = subtotalPartyaDesignPair.get(reportDeptId);
                            BigDecimal tempPartyaDesign = existPartyaDesign.add(partyaDesign);
                            subtotalPartyaDesignPair.put(reportDeptId, tempPartyaDesign);
                        } else {
                            subtotalPartyaDesignPair.put(reportDeptId, partyaDesign);
                        }
                    }
                    // 甲方准备 npt
                    BigDecimal partyaPrepare = report.getPartyaPrepare();
                    if (ObjUtil.isNotEmpty(partyaPrepare)) {
                        if (subtotalPartyaPreparePair.containsKey(reportDeptId)) {
                            BigDecimal existPartyaPrepare = subtotalPartyaPreparePair.get(reportDeptId);
                            BigDecimal tempPartyaPrepare = existPartyaPrepare.add(partyaPrepare);
                            subtotalPartyaPreparePair.put(reportDeptId, tempPartyaPrepare);
                        } else {
                            subtotalPartyaPreparePair.put(reportDeptId, partyaPrepare);
                        }
                    }
                    // 甲方资源 npt
                    BigDecimal partyaResource = report.getPartyaResource();
                    if (ObjUtil.isNotEmpty(partyaResource)) {
                        if (subtotalPartyaResourcePair.containsKey(reportDeptId)) {
                            BigDecimal existPartyaResource = subtotalPartyaResourcePair.get(reportDeptId);
                            BigDecimal tempPartyaResource = existPartyaResource.add(partyaResource);
                            subtotalPartyaResourcePair.put(reportDeptId, tempPartyaResource);
                        } else {
                            subtotalPartyaResourcePair.put(reportDeptId, partyaResource);
                        }
                    }
                    // 其它非生产时间 npt
                    BigDecimal otherNptTime = report.getOtherNptTime();
                    if (ObjUtil.isNotEmpty(otherNptTime)) {
                        if (subtotalOtherNptTimePair.containsKey(reportDeptId)) {
                            BigDecimal existOtherNptTime = subtotalOtherNptTimePair.get(reportDeptId);
                            BigDecimal tempOtherNptTime = existOtherNptTime.add(otherNptTime);
                            subtotalOtherNptTimePair.put(reportDeptId, tempOtherNptTime);
                        } else {
                            subtotalOtherNptTimePair.put(reportDeptId, otherNptTime);
                        }
                    }
                }
            });
            // 计算每个 施工队伍 的 npt小计 npt时效
            if (CollUtil.isNotEmpty(teamDeptPair)) {
                teamDeptPair.forEach((teamDeptId, dept) -> {
                    if (zjOrXjDeptIds.contains(teamDeptId)) {
                        // 统计当前 施工队伍 所有 npt总和 npt时效
                        BigDecimal tempSubtotalNpt = BigDecimal.ZERO;
                        // 计入 npt时效 的非生产时间小计
                        BigDecimal tempNptSum = BigDecimal.ZERO;
                        if (subtotalAccidentTimePair.containsKey(teamDeptId)) {
                            BigDecimal accidentTime = subtotalAccidentTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(accidentTime);
                            tempNptSum = tempNptSum.add(accidentTime);
                        }
                        if (subtotalRepairTimePair.containsKey(teamDeptId)) {
                            BigDecimal repairTime = subtotalRepairTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(repairTime);
                            tempNptSum = tempNptSum.add(repairTime);
                        }
                        // 设备保养 不计入 非生产时效
                        if (subtotalSelfStopTimePair.containsKey(teamDeptId)) {
                            BigDecimal selfStopTime = subtotalSelfStopTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(selfStopTime);
                        }
                        if (subtotalComplexityTimePair.containsKey(teamDeptId)) {
                            BigDecimal complexityTime = subtotalComplexityTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(complexityTime);
                            tempNptSum = tempNptSum.add(complexityTime);
                        }
                        // 生产配合 不计入 非生产时效
                        if (subtotalRelocationTimePair.containsKey(teamDeptId)) {
                            BigDecimal relocationTime = subtotalRelocationTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(relocationTime);
                        }
                        if (subtotalRectificationTimePair.containsKey(teamDeptId)) {
                            BigDecimal rectificationTime = subtotalRectificationTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(rectificationTime);
                            tempNptSum = tempNptSum.add(rectificationTime);
                        }
                        if (subtotalWaitingStopTimePair.containsKey(teamDeptId)) {
                            BigDecimal waitingStopTime = subtotalWaitingStopTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(waitingStopTime);
                            tempNptSum = tempNptSum.add(waitingStopTime);
                        }
                        // 待命 不计入 非生产时效
                        if (subtotalWinterBreakTimePair.containsKey(teamDeptId)) {
                            BigDecimal winterBreakTime = subtotalWinterBreakTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(winterBreakTime);
                        }
                        if (subtotalPartyaDesignPair.containsKey(teamDeptId)) {
                            BigDecimal partyaDesign = subtotalPartyaDesignPair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(partyaDesign);
                            tempNptSum = tempNptSum.add(partyaDesign);
                        }
                        if (subtotalPartyaPreparePair.containsKey(teamDeptId)) {
                            BigDecimal partyaPrepare = subtotalPartyaPreparePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(partyaPrepare);
                            tempNptSum = tempNptSum.add(partyaPrepare);
                        }
                        if (subtotalPartyaResourcePair.containsKey(teamDeptId)) {
                            BigDecimal partyaResource = subtotalPartyaResourcePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(partyaResource);
                            tempNptSum = tempNptSum.add(partyaResource);
                        }
                        if (subtotalOtherNptTimePair.containsKey(teamDeptId)) {
                            BigDecimal otherNptTime = subtotalOtherNptTimePair.get(teamDeptId);
                            tempSubtotalNpt = tempSubtotalNpt.add(otherNptTime);
                            tempNptSum = tempNptSum.add(otherNptTime);
                        }
                        // 施工队伍 npt 小计
                        subtotalNptTimePair.put(teamDeptId, tempNptSum);
                        // 施工队伍 npt 时效 以下非生产时间计入非生产时效
                        // 设备故障repair_time
                        // 工程质量accident_time
                        // 技术受限complexity_time
                        // 生产组织rectification_time
                        // 不可抗力waiting_stop_time
                        // 甲方设计partya_design
                        // 甲方准备partya_prepare
                        // 甲方资源partya_resource
                        // 其他非生产时间other_npt_time
                        if (CollUtil.isNotEmpty(totalHours)) {
                            Long totalHour = totalHours.get(0);
                            if (ObjUtil.isNotEmpty(totalHour) && totalHour > 0) {
                                BigDecimal nptRate = tempNptSum.divide(new BigDecimal(totalHour), 4, RoundingMode.HALF_UP);
                                subtotalNptRatePair.put(teamDeptId, nptRate);
                            }
                        }
                    }
                });
            }
        }

        // 生成返回的数据列表集合
        teamDeptPair.forEach((teamDeptId, dept) -> {
            IotRyDailyReportNptStatisticsRespVO statistics = new IotRyDailyReportNptStatisticsRespVO();
            statistics.setTeamId(teamDeptId);
            statistics.setTeamName(dept.getName());
            statistics.setSort(dept.getSort());
            statistics.setType("3");
            statistics.setAccidentTime(subtotalAccidentTimePair.get(teamDeptId));
            statistics.setRepairTime(subtotalRepairTimePair.get(teamDeptId));
            statistics.setSelfStopTime(subtotalSelfStopTimePair.get(teamDeptId));
            statistics.setComplexityTime(subtotalComplexityTimePair.get(teamDeptId));
            statistics.setRelocationTime(subtotalRelocationTimePair.get(teamDeptId));
            statistics.setRectificationTime(subtotalRectificationTimePair.get(teamDeptId));
            statistics.setWaitingStopTime(subtotalWaitingStopTimePair.get(teamDeptId));
            statistics.setWinterBreakTime(subtotalWinterBreakTimePair.get(teamDeptId));
            statistics.setPartyaDesign(subtotalPartyaDesignPair.get(teamDeptId));
            statistics.setPartyaPrepare(subtotalPartyaPreparePair.get(teamDeptId));
            statistics.setPartyaResource(subtotalPartyaResourcePair.get(teamDeptId));
            statistics.setOtherNptTime(subtotalOtherNptTimePair.get(teamDeptId));
            statistics.setNptTotal(subtotalNptTimePair.get(teamDeptId));
            statistics.setNptRate(subtotalNptRatePair.get(teamDeptId));
            if (CollUtil.isNotEmpty(totalHours)) {
                Long totalHour = totalHours.get(0);
                statistics.setCalendarTime(new BigDecimal(totalHour));
            }
            result.add(statistics);
        });

        return result;
    }

    /**
     * 按 队伍 维度统计数据 折线图
     * @param pageReqVO 日报数据请求对象
     * @param dailyReports 日报数据列表
     * @param deptId 项目部ID 或 队伍id（新疆项目部 7009队）
     * @return 队伍 维度统计结果 折线图
     */
    private List<IotRyDailyReportPolylineVO> polylineStatisticsByProjectDepartment(IotRyDailyReportPageReqVO pageReqVO,
                                                                                 List<IotRyDailyReportDO> dailyReports, Long deptId, LocalDateTime[] createTimes) {
        List<IotRyDailyReportPolylineVO> result = new ArrayList<>();

        Set<Long> projectDeptIds = new HashSet<>();
        // key队伍id    value队伍名称
        Map<Long, DeptDO> teamDeptPair = new HashMap<>();
        // key部门id   value部门parentId
        Map<Long, Long> teamProjectIdPair = new HashMap<>();

        // 按照日期维度统计各工作量数据
        // key日期yyyy-MM-dd   value累计进尺
        Map<String, BigDecimal> dateFootagePair = new HashMap<>();
        // key日期yyy-MM-dd    value去重后的施工任务集合
        Map<String, Set<Long>> dateConstructTaskPair = new HashMap<>();
        // key日期yyy-MM-dd    value去重后的完工任务集合
        Map<String, Set<Long>> dateFinishTaskPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计用电量
        Map<String, BigDecimal> datePowerConsumptionPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计油耗
        Map<String, BigDecimal> dateFuelConsumptionPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计运行时效   累计注气量/累计产能
        Map<String, BigDecimal> dateTransitTimePair = new HashMap<>();
        // key日期yyyy-MM-dd   value生产时间(H)
        Map<String, BigDecimal> dateProductTimePair = new HashMap<>();
        // key日期yyyy-MM-dd   value额定生产时间(H)
        Map<String, BigDecimal> dateRatedTimePair = new HashMap<>();

        // key部门id-任务id    value施工井对应的日期
        Map<String, String> deptTaskConstructPair = new HashMap<>();
        // key部门id-任务id    value完工井对应的日期
        Map<String, String> deptTaskFinishPair = new HashMap<>();

        // 以 队伍 为维度统计数据
        // 找到所有项目部与队伍的对应关系
        // 查询指定根部门下的所有子部门
        Set<Long> allRhChildDeptIds = deptService.getChildDeptIdListFromCache(deptId);
        DeptListReqVO reqVO = new DeptListReqVO();
        allRhChildDeptIds.add(deptId);  // 查询某支队伍
        reqVO.setDeptIds(allRhChildDeptIds);
        List<DeptDO> depts = deptService.getDeptList(reqVO);

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            if ("3".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                teamDeptPair.put(dept.getId(), dept);
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // key施工队伍id    value施工井数量
        Map<Long, Integer> totalTasksPair = new HashMap<>();
        // key施工队伍id    value完工井数量
        Map<Long, Integer> completedTasksPair = new HashMap<>();
        // key任务id   value额定生产时间
        Map<Long, BigDecimal> taskRatedProductionTimePair = new HashMap<>();
        if ("2".equals(pageReqVO.getProjectClassification())) {

            // 1. 先校验时间区间数组有效性
            boolean isCreateTimesValid = createTimes != null && createTimes.length >= 2
                    && createTimes[0] != null && createTimes[1] != null;

            // 计算累计施工井数 累计完工井数 时 过滤掉 taskId 为空的数据
            dailyReports.forEach(report -> {
                // 2. 获取日报创建时间并校验非空
                LocalDateTime reportCreateTime = report.getCreateTime();
                if (ObjUtil.isNotEmpty(report.getTaskId()) && allRhChildDeptIds.contains(report.getDeptId())
                        && ObjUtil.isNotEmpty(reportCreateTime) && isCreateTimesValid
                        && !reportCreateTime.isBefore(createTimes[0]) && !reportCreateTime.isAfter(createTimes[1])) {
                    String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
                    String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
                    deptTaskConstructPair.put(uniqueKey, dateStr);
                    deptTaskFinishPair.put(uniqueKey, dateStr);
                }
            });

            // 查询 指定时间范围内的 修井 累计施工井数 累计完工井数
            // 每天的任务数量 taskId 去重后的数量
            // 每天完工任务数量 taskId 去重后 状态为 wg 的数量
            dailyReports.forEach(report -> {
                String uniqueKey = StrUtil.join("-", report.getDeptId(), report.getTaskId());
                String dateStr = LocalDateTimeUtil.format(report.getCreateTime(), DatePattern.NORM_DATE_PATTERN);
                if (deptTaskConstructPair.containsKey(uniqueKey)) {
                    String tempDateStr = deptTaskFinishPair.get(uniqueKey);

                    if (dateConstructTaskPair.containsKey(tempDateStr)) {
                        Set<Long> tempUniqueTaskIds = dateConstructTaskPair.get(tempDateStr);
                        tempUniqueTaskIds.add(report.getTaskId());
                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
                    } else {
                        Set<Long> tempUniqueTaskIds = new HashSet<>();
                        tempUniqueTaskIds.add(report.getTaskId());
                        dateConstructTaskPair.put(tempDateStr, tempUniqueTaskIds);
                    }
                }
                // 组装完工任务集合
                if ("wg".equals(report.getRepairStatus())) {
                    if (deptTaskFinishPair.containsKey(uniqueKey)) {
                        String tempDateStr = deptTaskFinishPair.get(uniqueKey);

                        if (dateFinishTaskPair.containsKey(tempDateStr)) {
                            Set<Long> tempUniqueTaskIds = dateFinishTaskPair.get(tempDateStr);
                            tempUniqueTaskIds.add(report.getTaskId());
                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
                        } else {
                            Set<Long> tempUniqueTaskIds = new HashSet<>();
                            tempUniqueTaskIds.add(report.getTaskId());
                            dateFinishTaskPair.put(tempDateStr, tempUniqueTaskIds);
                        }
                    }
                }
            });

            // 计算 运行时效 累计生产时间/累计额定生产时间
            // 查询日报关联的任务信息
            IotProjectTaskPageReqVO taskReqVO = new IotProjectTaskPageReqVO();
            taskReqVO.setTaskIds(convertList(dailyReports, IotRyDailyReportDO::getTaskId));
            List<IotProjectTaskDO> tasks = iotProjectTaskMapper.selectList(taskReqVO);
            if (CollUtil.isNotEmpty(tasks)) {
                tasks.forEach(task -> {
                    if (CollUtil.isNotEmpty(task.getExtProperty())) {
                        List<IotTaskAttrModelProperty> taskAttrs = task.getExtProperty();
                        if (CollUtil.isNotEmpty(taskAttrs)) {
                            // 找到 额定生产时间 属性 对应的值
                            taskAttrs.forEach(attr -> {
                                if ("额定生产时间".equals(attr.getName()) && StrUtil.isNotBlank(attr.getActualValue())) {
                                    taskRatedProductionTimePair.put(task.getId(), new BigDecimal(attr.getActualValue()));
                                }
                            });
                        }
                    }
                });
            }
        }

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                if (ObjUtil.isNotEmpty(report.getCreateTime())) {
                    // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
                    LocalDateTime reportLocalDate = report.getCreateTime();
                    // 将日期格式转换成 字符串
                    String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
                    // 累计进尺
                    dateFootagePair.merge(reportDateStr, report.getDailyFootage(), BigDecimal::add);
                    // 累计用电量
                    datePowerConsumptionPair.merge(reportDateStr, report.getDailyPowerUsage(), BigDecimal::add);
                    // 累计油耗
                    dateFuelConsumptionPair.merge(reportDateStr, report.getDailyFuel(), BigDecimal::add);
                    // 生产时间
                    dateProductTimePair.merge(reportDateStr, report.getProductionTime(), BigDecimal::add);
                    // 额定生产时间
                    if (taskRatedProductionTimePair.containsKey(report.getTaskId())) {
                        BigDecimal ratedTime = taskRatedProductionTimePair.get(report.getTaskId());
                        dateRatedTimePair.merge(reportDateStr, ratedTime, BigDecimal::add);
                    }
                }
            });
            // 根据 生产时间 额定生产时间 计算指定日期范围的 平均运行时效
            if (CollUtil.isNotEmpty(dateProductTimePair) && CollUtil.isNotEmpty(dateRatedTimePair)) {
                dateProductTimePair.forEach((reportDateStr, productTime) -> {
                    if (dateRatedTimePair.containsKey(reportDateStr)) {
                        BigDecimal ratedTime = dateRatedTimePair.get(reportDateStr);
                        if (ratedTime.compareTo(BigDecimal.ZERO) > 0) {
                            // 指日期范围的累计运行时效
                            BigDecimal tempTransitTime = productTime.divide(ratedTime, 4, RoundingMode.HALF_UP);
                            dateTransitTimePair.put(reportDateStr, tempTransitTime);
                        } else {
                            dateTransitTimePair.put(reportDateStr, BigDecimal.ZERO);
                        }
                    }
                });
            }
        }

        // 日期字符串集合
        List<String> dateRangeList = new ArrayList<>();

        if (createTimes.length >= 2) {
            LocalDate startDate = createTimes[0].toLocalDate();
            LocalDate endDate = createTimes[1].toLocalDate();
            // 生成从起始日期到结束日期的所有日期
            for (LocalDate date = startDate;
                 !date.isAfter(endDate);  // 使用 isAfter 而不是 <= 判断
                 date = date.plusDays(1)) {
                dateRangeList.add(date.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
            }
        }

        if (CollUtil.isNotEmpty(dateRangeList)) {
            dateRangeList.forEach(date -> {
                IotRyDailyReportPolylineVO statistics = new IotRyDailyReportPolylineVO();
                statistics.setReportDate(date);
                statistics.setCumulativeFootage(dateFootagePair.get(date));
                statistics.setCumulativeConstructWells(dateConstructTaskPair.containsKey(date) ? dateConstructTaskPair.get(date).size() : 0);
                statistics.setCumulativeCompletedWells(dateFinishTaskPair.containsKey(date) ? dateFinishTaskPair.get(date).size() : 0);
                statistics.setCumulativePowerConsumption(datePowerConsumptionPair.get(date));
                statistics.setCumulativeFuelConsumption(dateFuelConsumptionPair.get(date));
                statistics.setTransitTime(dateTransitTimePair.get(date));
                result.add(statistics);
            });
        }

        return result;
    }
}