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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
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.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.pms.constant.PmsConstants;
import cn.iocoder.yudao.module.pms.controller.admin.iotcarzhbd.vo.IotCarZhbdPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicecategorytemplateattrs.vo.IotDeviceProperty;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogPageReqVO;
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.iotrddailyreport.vo.IotRdDailyReportSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotrhdailyreport.vo.*;
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.iotcarzhbd.IotCarZhbdDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdailyreportfuel.IotDailyReportFuelDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicerunlog.IotDeviceRunLogDO;
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.iotrhdailyreport.IotRhDailyReportDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotcarzhbd.IotCarZhbdMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdailyreportfuel.IotDailyReportFuelMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicerunlog.IotDeviceRunLogMapper;
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.iotrhdailyreport.IotRhDailyReportMapper;
import cn.iocoder.yudao.module.pms.enums.common.FailureAuditStatusEnum;
import cn.iocoder.yudao.module.pms.job.IotDeviceCarFuelVO;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.util.ZHBDUtil;
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.DictDataDO;
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.dept.DeptMapper;
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.DictDataService;
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.gson.Gson;
import com.google.gson.reflect.TypeToken;
import lombok.extern.log4j.Log4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
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.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
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.module.pms.enums.ErrorCodeConstant.*;
import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;

/**
 * 瑞恒日报 Service 实现类
 *
 * @author ruiqi
 */
@Service
@Validated
@Log4j
public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {

    @Resource
    private IotRhDailyReportMapper iotRhDailyReportMapper;
    @Resource
    private IotProjectTaskMapper iotProjectTaskMapper;
    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private ZHBDUtil zhbdUtil;
    @Resource
    private DictTypeService dictTypeService;
    @Resource
    private IotOpeationFillMapper iotOpeationFillMapper;
    @Resource
    private IotDeviceRunLogMapper iotDeviceRunLogMapper;
    @Resource
    private DeptService deptService;
    @Resource
    private IotCarZhbdMapper iotCarZhbdMapper;
    @Resource
    private AdminUserService adminUserService;
    @Resource
    private IotDailyReportFuelMapper iotDailyReportFuelMapper;
    @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 DictDataService dictDataService;
    @Resource
    private DeptMapper deptMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createIotRhDailyReport(IotRhDailyReportSaveReqVO createReqVO) {
        System.out.println("新增日报方法开始：");
        // 插入
        IotRhDailyReportDO iotRhDailyReport = BeanUtils.toBean(createReqVO, IotRhDailyReportDO.class);

        LocalDateTime reportDate = createReqVO.getFillOrderCreateTime();
        if (ObjUtil.isEmpty(reportDate)) {
            throw exception(IOT_RH_DAILY_REPORT_NO_DATE);
        }
        Long deptId = createReqVO.getDeptId();
        if (ObjUtil.isEmpty(deptId)) {
            throw exception(IOT_RH_DAILY_REPORT_NO_DEPT);
        }
        // 过滤掉数据权限 运行记录 中 没有使用 yudao 的数据权限
        final DeptDO[] currentDept = new DeptDO[1];
        DataPermissionUtils.executeIgnore(() -> {
            currentDept[0] = deptMapper.selectById(deptId);
        });
        if (ObjUtil.isEmpty(currentDept[0])) {
            System.out.println("查询到的部门是NULL：" + deptId);
            System.out.println("当前租户：" + TenantContextHolder.getTenantId());
            throw exception(IOT_RH_DAILY_REPORT_NO_DEPT);
        }
        // 队伍下设备非施工状态，新增时需要向填报人发送 消息提醒
        // 查询当前队伍下的设备的施工状态 如果是非施工，就需要向 日报 创建人发送钉钉消息
        List<DeptDO> teams = new ArrayList<>();
        teams.add(currentDept[0]);
        // 查询增压机状态为非施工的小队
        List<IotDeviceDO> teamStatusL = iotOpeationFillMapper.selectDevStatusBatch(teams);
        // System.out.println("无施工设备的队伍：" + currentDept.getName());

        // 设置 日报填写状态 审核状态
        iotRhDailyReport.setStatus(1);
        // 设置 日报审批状态为 审批中 auditStatus = 10
        iotRhDailyReport.setAuditStatus(10);

        // 根据日报的 施工队伍 deptId 查询队伍所在的 项目 任务
        // 根据日报的施工状态 更新 对应任务的 状态
        Long taskId = Long.MIN_VALUE;
        Set<Long> deviceIds = new HashSet<>();
        IotProjectTaskPageReqVO reqVO = new IotProjectTaskPageReqVO();
        reqVO.setDeptId(createReqVO.getDeptId());
        // 只筛选未施工完成的任务
        reqVO.setJobFlag("Y");
        // 查询包含当前日报施工队伍的任务
        List<IotProjectTaskDO> tasks = iotProjectTaskMapper.selectList(reqVO);
        // 日报对应的任务中的设备列表
        Set<String> carDeviceCodes = new HashSet<>();
        // 生成 carId 与 IotDeviceDO 的对应关系Map
        Map<String, IotDeviceDO> carIdDevicePair = new HashMap<>();
        // 中航北斗车辆id集合
        Set<String> zhbdCarIds = new HashSet<>();
        // 井号
        String wellName;
        if (CollUtil.isNotEmpty(tasks)) {
            // 只查询 未施工完成 的任务 随机获取1个 最好是保持 1个施工队伍只存在于1个任务中
            IotProjectTaskDO task = tasks.get(0);
            // 暂时只考虑1个施工队伍只属于1个任务
            iotRhDailyReport.setProjectId(task.getProjectId());
            iotRhDailyReport.setTaskId(task.getId());
            taskId = task.getId();
            wellName = task.getWellName();
            // 根据日报状态 查询 日报所属任务的状态
            if (ObjUtil.isNotEmpty(createReqVO.getConstructionStatus())) {
                task.setStatus(createReqVO.getConstructionStatus());
                // 更新任务状态
                iotProjectTaskMapper.updateById(task);
            }
            // 查询任务的设备列表
            deviceIds = task.getDeviceIds();
            IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
            deviceReqVO.setDeviceIds(new ArrayList<>(deviceIds));
            List<IotDeviceDO> carDevices = iotDeviceMapper.selectListAlone(deviceReqVO);
            // key设备编码   value设备对象
            Map<String, IotDeviceDO> devicePair = new HashMap<>();
            // key中航北斗carId   value设备编码
            Map<String, String> carIdDeviceCodePair = new HashMap<>();

            if (CollUtil.isNotEmpty(carDevices)) {
                carDevices.forEach(device -> {
                    carDeviceCodes.add(device.getDeviceCode());
                    if (ObjUtil.isNotEmpty(device.getCarId())) {
                        zhbdCarIds.add(String.valueOf(device.getCarId()));
                        carIdDeviceCodePair.put(String.valueOf(device.getCarId()), device.getDeviceCode());
                    }
                    devicePair.put(device.getDeviceCode(), device);
                });
                // 查询中航北斗表中的设备车辆
                IotCarZhbdPageReqVO customDeviceReqVO = new IotCarZhbdPageReqVO();
                // 设备表中存在的设备编码
                customDeviceReqVO.setDeviceCodes(carDeviceCodes);
                List<IotCarZhbdDO> deviceCars = iotCarZhbdMapper.selectList(customDeviceReqVO);
                if (CollUtil.isNotEmpty(deviceCars)) {
                    deviceCars.forEach(car -> {
                        zhbdCarIds.add(car.getCarId());
                        carIdDeviceCodePair.put(car.getCarId(), car.getDeviceCode());
                    });
                }
                // 额外匹配的 RA 与 设备表对应的编码
                customDeviceReqVO.setDeviceCodes(null);
                customDeviceReqVO.setCustomDeviceCodes(carDeviceCodes);
                List<IotCarZhbdDO> raCars = iotCarZhbdMapper.selectList(customDeviceReqVO);
                if (CollUtil.isNotEmpty(raCars)) {
                    raCars.forEach(car -> {
                        zhbdCarIds.add(car.getCarId());
                        carIdDeviceCodePair.put(car.getCarId(), car.getUserName());
                    });
                }
                // 生成 carId 与 IotDeviceDO 的对应关系Map
                carIdDevicePair = carIdDeviceCodePair.entrySet().stream()
                        .filter(entry -> devicePair.containsKey(entry.getValue()))
                        .collect(Collectors.toMap(
                                Map.Entry::getKey,
                                entry -> devicePair.get(entry.getValue())
                        ));
            }
        } else {
            wellName = StrUtil.EMPTY;
            // 当前队伍没有关联任务 不生成日报
            // throw exception(IOT_PROJECT_TASK_NOT_RELATED);
        }

        // 查询当前队伍的运行记录 找到注水量 注水时间 赋值到日报的 注水时间
        Set<Long> deviceTypeIds = new HashSet<>();
        List<DictDataDO> deviceTypeDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_water_injection_device_type");
        if (CollUtil.isNotEmpty(deviceTypeDictData)) {
            deviceTypeDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    deviceTypeIds.add(longValue);
                }
            });
        }
        // 查询 注水泵 类别 下包含的设备
        if (CollUtil.isNotEmpty(deviceTypeIds)) {
            // 查询当前任务下关联的 注水泵 设备 查询这些设备在运行记录中填写的 注水时间
            IotDevicePageReqVO deptDeviceReqVO = new IotDevicePageReqVO();
            deptDeviceReqVO.setDeptId(createReqVO.getDeptId());
            deptDeviceReqVO.setAssetClasses(new ArrayList<>(deviceTypeIds));
            List<IotDeviceDO> deptDevices = iotDeviceMapper.selectList(deptDeviceReqVO);
            Set<Long> pumpDeviceIds = new HashSet<>();
            if (CollUtil.isNotEmpty(deptDevices)) {
                deptDevices.forEach(device -> {
                    pumpDeviceIds.add(device.getId());
                });
            }

            DataPermissionUtils.executeIgnore(() -> {
                if (CollUtil.isNotEmpty(pumpDeviceIds)) {
                    BigDecimal maxWaterInjectionTime = BigDecimal.ZERO;
                    // 过滤数据权限 查询 运行记录 日志
                    // 根据 当前日期 deptId pumpDeviceIds 查询运行记录工单关联的 deviceId
                    String reportDateStr = LocalDateTimeUtil.format(reportDate, DatePattern.NORM_DATE_PATTERN);
                    IotOpeationFillPageReqVO fillReqVO = new IotOpeationFillPageReqVO();
                    fillReqVO.setCreateTimeStr(reportDateStr);
                    fillReqVO.setDeptId(deptId);
                    fillReqVO.setDeviceIds(pumpDeviceIds);
                    List<IotOpeationFillDO> fills = iotOpeationFillMapper.selectList(fillReqVO);
                    Set<Long> fillPumpDeviceIds = new HashSet<>();
                    if (CollUtil.isNotEmpty(fills)) {
                        fills.forEach(fill -> {
                            fillPumpDeviceIds.add(fill.getDeviceId());
                        });
                    }
                    // 根据 device_id createTime is_sum=0 在表 rq_iot_device_run_log 中查询 "当日运转时间H" 的值  fill_content
                    // 如果有多个注水泵的 运转时间 取 较大值
                    if (CollUtil.isNotEmpty(fillPumpDeviceIds)) {
                        IotDeviceRunLogPageReqVO runLogReqVO = new IotDeviceRunLogPageReqVO();
                        runLogReqVO.setCreateTimeStr(reportDateStr);
                        runLogReqVO.setDeviceIds(new ArrayList<>(fillPumpDeviceIds));
                        runLogReqVO.setIsSum(0);
                        List<IotDeviceRunLogDO> runLogs = iotDeviceRunLogMapper.selectList(runLogReqVO);
                        if (CollUtil.isNotEmpty(runLogs)) {
                            // 查询 注水泵 当日注水时间 参数名称
                            DictTypeDO pointNameDict = dictTypeService.getDictType("rq_iot_rh_water_point_name");
                            if (ObjUtil.isNotEmpty(pointNameDict) && StrUtil.isNotBlank(pointNameDict.getRemark())) {
                                String pointName = pointNameDict.getRemark();
                                // 当日填报的 注水泵 的运行时间 即 注水时间
                                maxWaterInjectionTime = runLogs.stream()
                                        .filter(log -> pointName.equals(log.getPointName()))
                                        .map(IotDeviceRunLogDO::getFillContent)
                                        .filter(StrUtil::isNotBlank)
                                        .filter(NumberUtil::isNumber)
                                        .map(BigDecimal::new)
                                        .max(BigDecimal::compareTo)
                                        .orElse(BigDecimal.ZERO);
                                iotRhDailyReport.setDailyInjectWaterTime(maxWaterInjectionTime);
                            }
                        }
                    }
                }
            });
        }

        /* if (CollUtil.isNotEmpty(deptDevices)) {
            deptDevices.forEach(device -> {
                deviceCodes.add(device.getDeviceCode());
            });
            // 查询当前小队在运行记录填报结果表中 生产日报虚拟设备id 查询当年的日报
            // 然后根据 虚拟设备id 在 rq_iot_device_run_log 表中查询 日报中填写的 当日注气量
             List<IotOpeationFillDO> reports = iotOpeationFillMapper.selectReportsByYear(createReqVO.getDeptId(), LocalDateTime.now().getYear());
            Set<Long> reportDeviceIds = new HashSet<>();
            if (CollUtil.isNotEmpty(reports)) {
                reports.forEach(report -> {
                    reportDeviceIds.add(report.getDeviceId());
                });
                // 累计注气量
                BigDecimal currentYearFillContentSum = iotDeviceRunLogMapper.selectCurrentYearFillContentSum(createReqVO.getDeptId(), reportDeviceIds);
                iotRhDailyReport.setTotalGasInjection(currentYearFillContentSum);
            }
        } */

        BigDecimal capacity = queryCapacity(createReqVO.getDeptId());
        // 计算运行时效 当日注气量/产能
        if (ObjUtil.isNotEmpty(createReqVO.getDailyGasInjection()) && (capacity.compareTo(BigDecimal.ZERO)>0)) {
            // 将当日注气量单位 换算成 万方
            // 将当日注气量单位由"方"换算成"万方"
            iotRhDailyReport.setTransitTime(createReqVO.getDailyGasInjection().divide(capacity, 4, RoundingMode.HALF_UP));
        }

        // 当天如果已经有此小队的记录 新增 当天如果没有此小队的日报记录 修改
        // deptId - taskId - createTime(yyyy-MM-dd) 确定唯一一条记录 不能使用 LocalDateTime.now() 来查询，应该使用 运行记录工单的创建日期查询
        IotRhDailyReportDO existReport = iotRhDailyReportMapper.selectExistReport(createReqVO.getDeptId(), null, reportDate);
        // 查询日报相关的任务关联的设备油耗
        // 获得昨天的日期
        String yesterdayDateStr = StrUtil.EMPTY;
        LocalDateTime yesterday = reportDate.minusDays(1);
        yesterdayDateStr = LocalDateTimeUtil.format(yesterday, DatePattern.NORM_DATE_PATTERN);

        // 标识是否是设备无施工状态的设备队伍
        AtomicBoolean noDeviceTeam = new AtomicBoolean(false);

        if (ObjUtil.isEmpty(existReport)) {
            // 新增日报记录 如果是 无施工设备的队伍 status auditStatus 需要单独处理
            if (CollUtil.isNotEmpty(teamStatusL)) {
                // 自动生成的日报 设置 填报完成 审批通过
                iotRhDailyReport.setStatus(1);
                iotRhDailyReport.setAuditStatus(20);
                // 如果是自动生成的日报 需要根据规则设备 非生产时间
                // 设备状态为 "动迁" 时，系统生成的日报里面，非生产时间内的 "生产配合"（relocation_time） 时间为24小时；
                // 设备状态为 "完工" 时，系统生成的日报里面，非生产时间内的 "待命"(winter_break_time) 时间为24小时
                Set<String> dqStatuses = new HashSet<>();
                Set<String> wgStatuses = new HashSet<>();
                teamStatusL.forEach(status -> {
                    String deviceStatus = status.getDeviceStatus();
                    if ("dq".equals(deviceStatus)) {
                        dqStatuses.add(deviceStatus);
                    } else if ("wg".equals(deviceStatus)) {
                        wgStatuses.add(deviceStatus);
                    }
                });
                if (CollUtil.isNotEmpty(dqStatuses)) {
                    iotRhDailyReport.setRelocationTime(BigDecimal.valueOf(24));
                    iotRhDailyReport.setProductionStatus("动迁24小时");
                }
                if (CollUtil.isNotEmpty(wgStatuses)) {
                    iotRhDailyReport.setWinterBreakTime(BigDecimal.valueOf(24));
                    iotRhDailyReport.setProductionStatus("待命24小时");
                }
            }

            // 今天下午4点
            LocalDateTime today4pm = reportDate.withHour(16).withMinute(0).withSecond(0).withNano(0);
            // 昨天下午4点
            LocalDateTime yesterday4pm = today4pm.minusDays(1);

            iotRhDailyReport.setConstructionStartDate(yesterday4pm);
            iotRhDailyReport.setConstructionEndDate(today4pm);
            iotRhDailyReport.setCreateTime(reportDate);
            iotRhDailyReport.setUpdateTime(reportDate);
            iotRhDailyReportMapper.insert(iotRhDailyReport);
            BigDecimal totalOilUsage = BigDecimal.ZERO;
            // 生成日报时 查询当前日报关联的任务中的车辆 查询中航北斗指定日报区间范围内的油耗数据 子表 主表
            List<IotDailyReportFuelDO> reportFuels = new ArrayList<>();
            if (CollUtil.isNotEmpty(zhbdCarIds)) {
                if (StrUtil.isNotBlank(yesterdayDateStr)) {
                    try {
                        Map<Integer, IotDeviceCarFuelVO> carFuels = zhbdUtil.carFuels(StrUtil.join(",", zhbdCarIds),
                                StrUtil.join(" ", yesterdayDateStr, "00:00:00"), StrUtil.join(" ", yesterdayDateStr, "23:59:59"));
                        System.out.println("请求参数：" + zhbdCarIds.size() + " -开始时间： "
                                + StrUtil.join(" ", yesterdayDateStr, "00:00:00") + " -开始时间： "
                                + StrUtil.join(" ", yesterdayDateStr, "23:59:59"));
                        if (CollUtil.isNotEmpty(carFuels)) {
                            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                            Map<String, IotDeviceDO> finalCarIdDevicePair = carIdDevicePair;
                            for (Map.Entry<Integer, IotDeviceCarFuelVO> carFuelEntry : carFuels.entrySet()) {
                                Integer carId = carFuelEntry.getKey();
                                IotDeviceCarFuelVO carFuel = carFuelEntry.getValue();
                                // carId中航北斗车辆id   value车辆油耗
                                IotDailyReportFuelDO reportFuel = new IotDailyReportFuelDO();
                                reportFuel.setType("RH");
                                reportFuel.setReportId(iotRhDailyReport.getId());
                                reportFuel.setCarId(String.valueOf(carId));
                                // 使用 carIdDeviceMap 获取对应的设备对象并设置deviceId
                                IotDeviceDO device = finalCarIdDevicePair.get(String.valueOf(carId));
                                reportFuel.setDeviceId(device.getId());
                                reportFuel.setDeviceCode(device.getDeviceCode());
                                reportFuel.setDeviceName(device.getDeviceName());
                                BigDecimal tempOil = new BigDecimal(carFuel.getOil());
                                totalOilUsage = totalOilUsage.add(tempOil);
                                reportFuel.setZhbdFuel(tempOil);
                                // 将字符串转换为LocalDateTime
                                try {
                                    LocalDateTime queryDate = LocalDate.parse(yesterdayDateStr, formatter).atStartOfDay();;
                                    reportFuel.setQueryDate(queryDate);
                                } catch (DateTimeParseException e) {
                                    log.error("瑞恒日报-中航北斗油耗-日期格式解析失败: {}", e);
                                    // 根据业务需求设置默认值或抛出异常
                                    reportFuel.setQueryDate(null);
                                }
                                reportFuels.add(reportFuel);
                            }
                        }
                    } catch (Exception e) {
                        log.info("获取油耗数据失败！");
                    }
                    if (CollUtil.isNotEmpty(reportFuels)) {
                        // 生成瑞恒日报时 同步新增日报关联的任务车辆油耗
                        iotDailyReportFuelMapper.insertBatch(reportFuels);
                    }
                }
            }
            // 先插入记录再更新 因为需要获取日报id
            iotRhDailyReport.setDailyOilUsage(totalOilUsage);
            // 根据日报关联任务车辆油耗 计算总油耗 后保存日报
            iotRhDailyReportMapper.updateById(iotRhDailyReport);

            if (CollUtil.isNotEmpty(teamStatusL)) {
                // 添加空白日报时 只需要发送填报提醒 不需要发送审批提醒
                noDeviceTeam.set(true);
                // 说明队伍下的设备类别为非施工状态，需要向 日报填报人发送 消息提醒
                Set<Long> targetUserIds = new HashSet<>();
                targetUserIds.add(Long.valueOf(iotRhDailyReport.getCreator()));
                System.out.println("日报创建人：" + iotRhDailyReport.getCreator());
                Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(targetUserIds);
                // 给多个用户发送 相同 的 提醒消息
                if (CollUtil.isNotEmpty(users)) {
                    // 生成消息提醒标题 部门名称-井号
                    String msgTitle = currentDept[0].getName();
                    if (StrUtil.isNotBlank(wellName)) {
                        msgTitle = StrUtil.join("-", msgTitle, wellName);
                    }
                    CountDownLatch latch = new CountDownLatch(users.size());
                    String finalMsgTitle = msgTitle;
                    users.forEach((userId, user) -> {
                        pmsThreadPoolTaskExecutor.execute(() -> {
                            try {
                                String mobile = user.getMobile();
                                // 没有手机号也发送站内信消息
                                if (StrUtil.isNotBlank(finalMsgTitle)) {
                                    System.out.println("向日报创建人发送消息");
                                    pmsMessage.sendMessage(iotRhDailyReport.getId(), finalMsgTitle, PmsConstants.RH_DAILY_REPORT,
                                            userId, mobile);
                                }
                            } finally {
                                latch.countDown();
                            }
                        });
                    });
                }
            }

        } else {
            // 修改现有记录
            iotRhDailyReport.setId(existReport.getId());
            iotRhDailyReport.setCreator(existReport.getCreator());
            iotRhDailyReportMapper.updateById(iotRhDailyReport);
        }
        // 只要保存了记录就要发送审批提醒到 提交人对应的项目经理 角色 项目部日报审批RH
        // 根据日报的 deptId 查询上级项目部经理 角色的审批人 发送站内信 钉钉提醒
        // 此时需要判断下当前队伍下有无增压机，如果 ‘当前队伍下无增压机’ 或 ‘增压机的状态不是施工’ 需要新增空白记录 向填报人推送消息。
        // 暂时添加判断条件 创建人 是 null 的话 不发送 站内信及钉钉消息 如果已经发送了填报日报的提醒 不需要再发送审批的提醒
        if (StrUtil.isNotBlank(iotRhDailyReport.getCreator()) && !noDeviceTeam.get()) {
            Long parentId = currentDept[0].getParentId();
            if (ObjUtil.isNotEmpty(parentId)) {
                AtomicReference<DeptDO> projectDept = new AtomicReference<>();
                DataPermissionUtils.executeIgnore(() -> {
                    projectDept.set(deptService.getDept(parentId));
                    if (ObjUtil.isNotEmpty(projectDept) && "2".equals(projectDept.get().getType())) {
                        // 查询项目部下具有 项目部日报审批RH 角色的人员
                        Set<Long> projectIds = new HashSet<>();
                        projectIds.add(projectDept.get().getId());
                        List<AdminUserDO> receivedMsgUsers = adminUserService.getUserListByDeptIds(projectIds);
                        if (CollUtil.isNotEmpty(receivedMsgUsers)) {
                            Set<Long> userIds = new HashSet<>();
                            receivedMsgUsers.forEach(user -> {
                                userIds.add(user.getId());
                            });
                            RoleDO role = roleService.getRoleByCode("项目部日报审批RH");
                            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 = currentDept[0].getName();
                                            if (StrUtil.isNotBlank(wellName)) {
                                                msgTitle = StrUtil.join("-", msgTitle, wellName);
                                            }
                                            CountDownLatch latch = new CountDownLatch(users.size());
                                            String finalMsgTitle = msgTitle;
                                            users.forEach((userId, user) -> {
                                                pmsThreadPoolTaskExecutor.execute(() -> {
                                                    try {
                                                        String mobile = user.getMobile();
                                                        // 没有手机号也发送站内信消息
                                                        if (StrUtil.isNotBlank(finalMsgTitle)) {
                                                            pmsMessage.sendMessage(iotRhDailyReport.getId(), finalMsgTitle, PmsConstants.RH_DAILY_REPORT_APPROVAL,
                                                                    userId, mobile);
                                                        }
                                                    } finally {
                                                        latch.countDown();
                                                    }
                                                });
                                            });
                                        }
                                    }
                                }
                            }
                        }
                    }
                });
            }
        }
        System.out.println("新增日报方法结束：");
        return iotRhDailyReport.getId();
    }

    /***
     * 计算指定队伍下包含的 增压机设备的产能
     */
    public BigDecimal queryCapacity(Long deptId) {
        // 找到当前小队下的 电驱增压机 分类下设备的产能 计算 运行时效
        DictTypeDO dictType = dictTypeService.getDictType("rq_iot_charger_device_category");
        AtomicReference<BigDecimal> capacity = new AtomicReference<>(BigDecimal.ZERO);
        if (ObjUtil.isNotEmpty(dictType)) {
            if (StrUtil.isNotBlank(dictType.getRemark())) {
                IotDevicePageReqVO capacityReqVO = new IotDevicePageReqVO();
                capacityReqVO.setDeptId(deptId);
                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(new BigDecimal(property.getValue()));
                                    }
                                });
                            }
                        }
                    });
                }
            }
        }
        return capacity.get();
    }

    /* @Override
    public Map<Long, BigDecimal> queryCapacities(List<Long> deptIds) {
        Map<Long, BigDecimal> capacityPair = new HashMap<>();
        // 找到当前小队下的 电驱增压机 分类下设备的产能 计算 运行时效
        DictTypeDO dictType = dictTypeService.getDictType("rq_iot_charger_device_category");
        if (ObjUtil.isNotEmpty(dictType)) {
            if (StrUtil.isNotBlank(dictType.getRemark())) {
                // 可能统计多个设备的产能 remark 是逗号分隔的数据
                List<Long> deviceCategoryIdLongs = Arrays.stream(dictType.getRemark().split(","))
                        .map(String::trim)
                        .filter(s -> s.matches("\\d+")) // 过滤出纯数字字符串
                        .map(Long::valueOf)
                        .collect(Collectors.toList());
                // 查询队伍下维护了产能的已知类别的设备 累加所有产能
                IotDevicePageReqVO capacityReqVO = new IotDevicePageReqVO();
                capacityReqVO.setDeptIds(deptIds);
                // capacityReqVO.setAssetClass(Long.valueOf(dictType.getRemark()));
                capacityReqVO.setAssetClasses(deviceCategoryIdLongs);
                List<IotDeviceDO> capacityDevices = iotDeviceMapper.selectList(capacityReqVO);
                if (CollUtil.isNotEmpty(capacityDevices)) {
                    // 解析每个设备的 扩展属性 找出 已经设置 了产能的设备并提取值
                    capacityDevices.forEach(device -> {
                        AtomicReference<BigDecimal> capacity = new AtomicReference<>(BigDecimal.ZERO);
                        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(new BigDecimal(property.getValue()));
                                    }
                                    capacityPair.put(device.getDeptId(), capacity.get());
                                });
                            }
                        }
                        // 如果相同的部门下有多个设备维护过产能 累加所有设备的产能

                    });
                }
            }
        }
        return capacityPair;
    } */

    /**
     * 查询队伍下设备产能
     * @param deptIds
     * @return
     */
    @Override
    public Map<Long, BigDecimal> queryCapacities(List<Long> deptIds) {
        Map<Long, BigDecimal> capacityPair = new HashMap<>();

        // 找到当前小队下的 电驱增压机 分类下设备的产能 计算 运行时效
        DictTypeDO dictType = dictTypeService.getDictType("rq_iot_charger_device_category");
        if (ObjUtil.isNotEmpty(dictType) && StrUtil.isNotBlank(dictType.getRemark())) {
            // 可能统计多个设备的产能 remark 是逗号分隔的数据
            List<Long> deviceCategoryIdLongs = Arrays.stream(dictType.getRemark().split(","))
                    .map(String::trim)
                    .filter(s -> s.matches("\\d+")) // 过滤出纯数字字符串
                    .map(Long::valueOf)
                    .collect(Collectors.toList());

            // 查询队伍下维护了产能的已知类别的设备
            IotDevicePageReqVO capacityReqVO = new IotDevicePageReqVO();
            capacityReqVO.setDeptIds(deptIds);
            // 查询队伍下所有维护了产能的设备的产能和
            capacityReqVO.setAssetClasses(deviceCategoryIdLongs);

            List<IotDeviceDO> capacityDevices = iotDeviceMapper.selectList(capacityReqVO);

            if (CollUtil.isNotEmpty(capacityDevices)) {
                // 使用Map按部门分组累加产能
                Map<Long, List<IotDeviceDO>> devicesByDept = capacityDevices.stream()
                        .collect(Collectors.groupingBy(IotDeviceDO::getDeptId));

                // 遍历每个部门的设备列表
                for (Map.Entry<Long, List<IotDeviceDO>> entry : devicesByDept.entrySet()) {
                    Long deptId = entry.getKey();
                    List<IotDeviceDO> deptDevices = entry.getValue();

                    // 累加当前部门下所有设备的产能
                    BigDecimal deptTotalCapacity = BigDecimal.ZERO;

                    for (IotDeviceDO device : deptDevices) {
                        BigDecimal deviceCapacity = extractCapacityFromDevice(device);
                        deptTotalCapacity = deptTotalCapacity.add(deviceCapacity);
                    }

                    // 将部门总产能放入结果Map
                    capacityPair.put(deptId, deptTotalCapacity);
                }
            }
        }

        return capacityPair;
    }

    /**
     * 从设备中提取产能值
     */
    private BigDecimal extractCapacityFromDevice(IotDeviceDO device) {
        if (StrUtil.isBlank(device.getTemplateJson())) {
            return BigDecimal.ZERO;
        }

        try {
            Gson gson = new Gson();
            Type listType = new TypeToken<List<IotDeviceProperty>>(){}.getType();
            List<IotDeviceProperty> deviceProperties = gson.fromJson(device.getTemplateJson(), listType);

            if (CollUtil.isEmpty(deviceProperties)) {
                return BigDecimal.ZERO;
            }

            // 查找产能属性并返回其值
            return deviceProperties.stream()
                    .filter(property -> "产能".equals(property.getName()))
                    .filter(property -> StrUtil.isNotBlank(property.getValue()))
                    .findFirst() // 假设每个设备只有一个产能属性，如果有多个可以改为求和
                    .map(property -> new BigDecimal(property.getValue()))
                    .orElse(BigDecimal.ZERO);

        } catch (Exception e) {
            // 解析JSON失败时返回0
            System.out.println("{} 解析设备模板JSON失败，设备ID: {}" + e.getMessage());
            return BigDecimal.ZERO;
        }
    }

    @Override
    public PageResult<IotRhDailyReportDO> dailyReportSummary(IotRhDailyReportPageReqVO pageReqVO) {
        // 查询 瑞恒兴域 下所有项目部级别的部门
        // 组装成 map key项目部id     value项目部下包含的部门集合
        Set<Long> projectDeptIds = new HashSet<>();
        Map<Long, Set<Long>> projectSubDeptPair = new HashMap<>();
        Map<Long, String> deptMap = new HashMap<>();
        Set<Long> rhChildDeptIds = deptService.getChildDeptIdListFromCache(157l);
        List<DeptDO> depts =deptService.getDeptList(rhChildDeptIds);
        // 找出名称中包含 项目部 的部门
        if (CollUtil.isNotEmpty(depts)) {
            depts.forEach(dept -> {
                if (dept.getName().contains("项目部")) {
                    projectDeptIds.add(dept.getId());
                }
                deptMap.put(dept.getId(), dept.getName());
            });
            // 查询每个项目部下所有子部门 小队
            if (CollUtil.isNotEmpty(projectDeptIds)) {
                projectDeptIds.forEach(deptId -> {
                    Set<Long> tempDeptIds = deptService.getChildDeptIdListFromCache(deptId);
                    tempDeptIds.add(deptId);
                    projectSubDeptPair.put(deptId, tempDeptIds);
                });
            }
            // 查询所有瑞恒日报数据

        }
        return null;
    }

    @Override
    public List<IotRhDailyReportPolylineVO> polylineStatistics(IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportPolylineVO> 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<>();
        }
        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhReportStatistics(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
        List<IotRhDailyReportDO> dailyReports = page.getRecords();
        if (CollUtil.isNotEmpty(dailyReports)) {
            // 默认显示所有项目部的汇总数据(新疆分公司也展示 下属各项目部的数据)
            // 点击项目部 显示 下属队伍的数据
            // 首先判断点击的部门是属于 公司 还是 队伍 如果没有点击任何部门 默认查询所有项目部数据
            if (ObjUtil.isEmpty(pageReqVO.getDeptId())) {
                result = polylineStatisticsByProjectDept(dailyReports, 157L, pageReqVO.getCreateTime());
            } else {
                // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
                DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
                if ("1".equals(selectedDept.getType())) {
                    // 以项目部为维度汇总数据
                    result = polylineStatisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
                } else if ("2".equals(selectedDept.getType())) {
                    // 以队伍为维度汇总数据
                    result = polylineStatisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
                } else if ("3".equals(selectedDept.getType())) {
                    // 显示单个队伍的汇总数据
                    result = polylineStatisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
                } else {
                    // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
                    // 以项目部为维度汇总数据
                    result = polylineStatisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
                }
            }
        }
        return result;
    }

    @Override
    public void approvalRhDailyReport(IotRdDailyReportSaveReqVO updateReqVO) {
        // 审核瑞恒日报
        // 如果审批拒绝 修改日报 填报状态 status = 0 填写中  审批状态 auditStatus = 30
        // 审批通过 设置 日报审批状态 auditStatus = 20
        IotRhDailyReportDO dailyReport = validateIotRhDailyReportExists(updateReqVO.getId());
        dailyReport.setAuditStatus(updateReqVO.getAuditStatus());
        dailyReport.setOpinion(updateReqVO.getOpinion());
        if (SupplierAuditStatusEnum.REJECT.getStatus().equals(updateReqVO.getAuditStatus())) {
            dailyReport.setStatus(0);
            // 审批拒绝后需要向 日报填报人 发送消息提醒 每个队伍暂时只有1人 随机取1人
            Long deptId = dailyReport.getDeptId();
            Long taskId = dailyReport.getTaskId();
            DeptDO dept = deptService.getDept(deptId);
            // 消息标题
            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;
                if (StrUtil.isNotBlank(finalMsgTitle)) {
                    pmsThreadPoolTaskExecutor.execute(() -> {
                        pmsMessage.sendMessage(dailyReport.getId(), finalMsgTitle, PmsConstants.RH_DAILY_REPORT, user.getId(), mobile);
                    });
                }
            }
        }
        // 更新瑞恒日报审核状态
        iotRhDailyReportMapper.updateById(dailyReport);
    }

    @Override
    public List<IotRhDailyReportNptStatisticsRespVO> nptStatistics(IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportNptStatisticsRespVO> 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<>();
        }
        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhReportStatistics(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
        List<IotRhDailyReportDO> dailyReports = page.getRecords();

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

    @Override
    public void updateIotRhDailyReport(IotRhDailyReportSaveReqVO updateReqVO) {
        // 校验存在
        validateIotRhDailyReportExists(updateReqVO.getId());
        // 更新
        IotRhDailyReportDO updateObj = BeanUtils.toBean(updateReqVO, IotRhDailyReportDO.class);
        // 编辑后 直接设置 已经 审核通过
        updateObj.setAuditStatus(FailureAuditStatusEnum.APPROVE.getStatus());
        iotRhDailyReportMapper.updateById(updateObj);
    }

    @Override
    public void deleteIotRhDailyReport(Long id) {
        // 校验存在
        validateIotRhDailyReportExists(id);
        // 删除
        iotRhDailyReportMapper.deleteById(id);
    }

    private IotRhDailyReportDO validateIotRhDailyReportExists(Long id) {
        IotRhDailyReportDO dailyReport = iotRhDailyReportMapper.selectById(id);
        if (ObjUtil.isEmpty(dailyReport)) {
            throw exception(IOT_RH_DAILY_REPORT_NOT_EXISTS);
        }
        return dailyReport;
    }

    @Override
    public IotRhDailyReportDO getIotRhDailyReport(Long id) {
        return iotRhDailyReportMapper.selectById(id);
    }

    @Override
    public PageResult<IotRhDailyReportDO> getIotRhDailyReportPage(IotRhDailyReportPageReqVO 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);
            }
        }

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

        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhDailyReports(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);

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

    @Override
    public PageResult<IotRhDailyReportDO> teamReports(IotRhDailyReportPageReqVO 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<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhWellNameDailyReports(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);

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

    @Override
    public PageResult<IotRhDailyReportDO> wellReports(IotRhDailyReportPageReqVO 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<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhDeptDailyReports(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);

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

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

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

    @Override
    public List<IotRhDailyReportStatisticsRespVO> statistics(IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportStatisticsRespVO> 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());

        IPage<IotRhDailyReportDO> page = iotRhDailyReportMapper.rhReportStatistics(
                new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), pageReqVO,
                pageReqVO.getTaskIds(), pageReqVO.getProjectIds(), ids);
        List<IotRhDailyReportDO> dailyReports = page.getRecords();

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

    /**
     * 按项目部维度统计数据
     * @param dailyReports 日报数据列表
     * @param rootDeptId 根部门ID（如157L为瑞恒根部门，或其他公司级部门ID）
     * @return 项目部维度统计结果列表
     */
    private List<IotRhDailyReportStatisticsRespVO> statisticsByProjectDept(List<IotRhDailyReportDO> dailyReports,
                                                                           Long rootDeptId, IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportStatisticsRespVO> 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> cumulativeGasInjectionPair = new HashMap<>();
        // key队伍id/项目部id   value累计注水量
        Map<Long, BigDecimal> cumulativeWaterInjectionPair = new HashMap<>();
        // key队伍id/项目部id   value累计用电
        Map<Long, BigDecimal> cumulativePowerConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value累计油耗
        Map<Long, BigDecimal> cumulativeOilConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value对应项目部的总产能
        Map<Long, BigDecimal> cumulativeCapacityPair = new HashMap<>();
        // key队伍id/项目部id   value累计运行时效   累计注气量/累计产能
        Map<Long, BigDecimal> cumulativeTransitTimePair = new HashMap<>();
        // key项目部id   value项目部下包含的队伍总数
        Map<Long, Integer> teamCountPair = new HashMap<>();
        // key项目部id   value项目部下包含的 施工 队伍数量
        Map<Long, Integer> sgTeamCountPair = new HashMap<>();
        // key项目部id   value项目部下包含的 施工准备 队伍数量
        Map<Long, Integer> zbTeamCountPair = new HashMap<>();
        // key项目部id   value项目部下包含的 驻地待命 队伍数量
        Map<Long, Integer> zddmTeamCountPair = new HashMap<>();
        // 队伍id 集合
        Set<Long> teamIds = new HashSet<>();
        // 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<>();
        // key队伍id/项目部id   value设备利用率(按小时统计)
        Map<Long, BigDecimal> hourDeviceUtilizationPair = new HashMap<>();

        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
        Set<Long> mainDeviceCategoryIds = new HashSet<>();
        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
            constructionStatusDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    mainDeviceCategoryIds.add(longValue);
                }
            });
        }

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

        // 包含设备的部门id集合
        Set<Long> haveDeviceDeptIds = new HashSet<>();
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        if (CollUtil.isNotEmpty(devices)) {
            // 筛选出包含设备的队伍部门集合
            devices.forEach(device -> {
                // 20260605 筛选包含主设备的队伍
                if (mainDeviceCategoryIds.contains(device.getAssetClass())) {
                    haveDeviceDeptIds.add(device.getDeptId());
                }
            });
        }

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            // 暂时过滤掉 欧洲项目部 克拉玛依项目部
            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
                // 状态为LY的项目部 才统计设备利用率
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
            if ("3".equals(dept.getType())) {
                // 队伍
                teamIds.add(dept.getId());
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });
        // key项目部id   value项目部包含的队伍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) && haveDeviceDeptIds.contains(deptId) && teamIds.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[] createTime = pageReqVO.getCreateTime();
        List<Long> daysCounts = new ArrayList<>();
        // 如果 createTime 包含的时间是 1天则查询 这1天时间内的 队伍总数 施工队伍数量 施工准备队伍数量 驻地待命队伍数量
        if (ObjUtil.isNotEmpty(createTime)) {
            LocalDateTime startTime = createTime[0];
            LocalDateTime endTime = createTime[1];
            if (ObjUtil.isNotEmpty(startTime) && ObjUtil.isNotEmpty(endTime) && !endTime.isBefore(startTime)) {
                // 查询时间区间包含的天数
                // 使用ChronoUnit.DAYS.between计算天数差，并+1包含首尾两天
                long daysCount = ChronoUnit.DAYS.between(
                        startTime.toLocalDate(),
                        endTime.toLocalDate()
                ) + 1;
                daysCounts.add(daysCount);

                LocalDate startLocalDate = startTime.toLocalDate();
                LocalDate endLocalDate = endTime.toLocalDate();
                if (startLocalDate.isEqual(endLocalDate)) {
                    // 查询日期区间是 同一天
                    // 设置每个项目部下的队伍数量 只筛选 包含设备的队伍数量
                    Set<Long> deviceDeptIds = new HashSet<>();
                    if (CollUtil.isNotEmpty(devices)) {
                        devices.forEach(device -> {
                            if (haveDeviceDeptIds.contains(device.getDeptId())) {
                                deviceDeptIds.add(device.getDeptId());
                            }
                        });
                    }
                    projectDeptPair.forEach((projectDeptId, projectDept) -> {
                        // 找到每个项目部下的队伍 只筛选 包含设备的队伍
                        teamProjectIdPair.forEach((deptId, parentDeptId) -> {
                            if (parentDeptId.equals(projectDeptId) && deviceDeptIds.contains(deptId) && teamIds.contains(deptId)) {
                                if (teamCountPair.containsKey(projectDeptId)) {
                                    Integer tempCount = teamCountPair.get(projectDeptId);
                                    teamCountPair.put(projectDeptId, ++tempCount);
                                } else {
                                    teamCountPair.put(projectDeptId, 1);
                                }
                            }
                        });
                    });
                    // 找出日报列表中 状态为 施工 施工准备 驻地待命的 记录
                    // 待命队伍 = 队伍总数 - 施工队伍 -  准备队伍
                    if (CollUtil.isNotEmpty(dailyReports)) {
                        dailyReports.forEach(report -> {
                            if (teamProjectIdPair.containsKey(report.getDeptId()) && deviceDeptIds.contains(report.getDeptId())) {
                                // 找到队伍所属的上级项目部
                                Long projectDeptId = teamProjectIdPair.get(report.getDeptId());
                                // 动迁 准备 完工 都算作 准备
                                // 施工sg  观察使用gcsy 待维修dwx 待保养dby
                                // 20260624 修改为 注水 或 注气量 >0 的日报队伍数量
                                BigDecimal tempGasInjection = report.getDailyGasInjection();
                                BigDecimal tempWaterInjection = report.getDailyWaterInjection();
                                if (tempGasInjection.compareTo(BigDecimal.ZERO) > 0 || tempWaterInjection.compareTo(BigDecimal.ZERO) > 0) {
                                    if (sgTeamCountPair.containsKey(projectDeptId)) {
                                        Integer tempCount = sgTeamCountPair.get(projectDeptId);
                                        sgTeamCountPair.put(projectDeptId, ++tempCount);
                                    } else {
                                        sgTeamCountPair.put(projectDeptId, 1);
                                    }
                                }
                                // 准备
                                if ("zb".equals(report.getConstructionStatus()) || "dq".equals(report.getConstructionStatus()) || "wg".equals(report.getConstructionStatus())) {
                                    if (zbTeamCountPair.containsKey(projectDeptId)) {
                                        Integer tempCount = zbTeamCountPair.get(projectDeptId);
                                        zbTeamCountPair.put(projectDeptId, ++tempCount);
                                    } else {
                                        zbTeamCountPair.put(projectDeptId, 1);
                                    }
                                }
                                // 待命 = 队伍总数 - 施工队伍 -  准备队伍
                                if ("zddm".equals(report.getConstructionStatus()) || "xcdm".equals(report.getConstructionStatus())
                                        || "dm".equals(report.getConstructionStatus()) || "wxz".equals(report.getConstructionStatus())  || "xz".equals(report.getConstructionStatus())) {
                                    if (zddmTeamCountPair.containsKey(projectDeptId)) {
                                        Integer tempCount = zddmTeamCountPair.get(projectDeptId);
                                        zddmTeamCountPair.put(projectDeptId, ++tempCount);
                                    } else {
                                        zddmTeamCountPair.put(projectDeptId, 1);
                                    }
                                }
                            }
                        });
                    }
                }
            }
        }

        // 统计各项目部的设备利用率
        // key项目部id     value项目部包含的队伍指定时间区域内日报数量
        Map<Long, Integer> projectReportPair = new HashMap<>();
        // 查询指定部门下相关设备的产能
        // key队伍id   value队伍下相关设备产能
        Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));

        // key项目部id     value项目部下包含设备的队伍注气时间或注水时间总和
        Map<Long, BigDecimal> projectWorkTimePair = new HashMap<>();

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                Long deptId = report.getDeptId();
                // 统计各项目部的日报数量 注气量 或 注水量 >0 的日报数量
                if (CollUtil.isNotEmpty(projectTeamPair)) {
                    if (report.getDailyGasInjection().compareTo(BigDecimal.ZERO)>0 || report.getDailyWaterInjection().compareTo(BigDecimal.ZERO)>0) {
                        projectTeamPair.forEach((projectDeptId, teamDeptIds) -> {
                            if (teamDeptIds.contains(deptId)) {
                                // 项目部日报数量
                                if (projectReportPair.containsKey(projectDeptId)) {
                                    Integer tempCount = projectReportPair.get(projectDeptId);
                                    projectReportPair.put(projectDeptId, ++tempCount);
                                } else {
                                    projectReportPair.put(projectDeptId, 1);
                                }
                            }
                        });
                    }

                    // 按小时数 统计设备利用率
                    BigDecimal gasInjectionTime = ObjUtil.defaultIfNull(report.getDailyInjectGasTime(), BigDecimal.ZERO);
                    BigDecimal waterInjectionTime = ObjUtil.defaultIfNull(report.getDailyInjectWaterTime(), BigDecimal.ZERO);
                    BigDecimal workTime = gasInjectionTime.compareTo(BigDecimal.ZERO) > 0
                            ? gasInjectionTime
                            : waterInjectionTime.compareTo(BigDecimal.ZERO) > 0
                            ? waterInjectionTime
                            : BigDecimal.ZERO;
                    if (workTime.compareTo(BigDecimal.ZERO) > 0) {
                        // 取 注气时间 注水时间 的较大者
                        // 直接获取队伍对应的项目部ID
                        Long projectDeptId = teamProjectIdPair.get(deptId);
                        // 校验：项目部ID不为空 + 该项目部存在有效队伍
                        if (ObjUtil.isNotEmpty(projectDeptId) && projectTeamPair.containsKey(projectDeptId)) {
                            // 存在则累加，不存在则赋值
                            projectWorkTimePair.merge(projectDeptId, workTime, BigDecimal::add);
                        }
                    }
                }

                if (ObjUtil.isNotEmpty(deptId) && teamProjectIdPair.containsKey(deptId)) {
                    Long projectDeptId = teamProjectIdPair.get(deptId);
                    if (ObjUtil.isNotEmpty(projectDeptId) && projectDeptPair.containsKey(projectDeptId)) {
                        // 累计注气量
                        cumulativeGasInjectionPair.merge(projectDeptId, report.getDailyGasInjection(), BigDecimal::add);
                        // 累计注水量
                        cumulativeWaterInjectionPair.merge(projectDeptId, report.getDailyWaterInjection(), BigDecimal::add);
                        // 累计用电量
                        cumulativePowerConsumptionPair.merge(projectDeptId, report.getDailyPowerUsage(), BigDecimal::add);
                        // 累计油耗
                        cumulativeOilConsumptionPair.merge(projectDeptId, report.getDailyOilUsage(), BigDecimal::add);
                        if (teamCapacityPair.containsKey(deptId)) {
                            BigDecimal tempCapacity = teamCapacityPair.get(deptId);
                            cumulativeCapacityPair.merge(projectDeptId, tempCapacity, 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);
                        // 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);
                            }
                        }
                    }
                }
            });
            // 根据 累计注气量 累计产能 计算指定项目部下的平均产能
            if (CollUtil.isNotEmpty(cumulativeGasInjectionPair) && CollUtil.isNotEmpty(cumulativeCapacityPair)) {
                cumulativeGasInjectionPair.forEach((projectDeptId, cumulativeGasInjection) -> {
                    if (cumulativeCapacityPair.containsKey(projectDeptId)) {
                        BigDecimal tempCapacity = cumulativeCapacityPair.get(projectDeptId);
                        if (tempCapacity.compareTo(BigDecimal.ZERO) > 0) {
                            // 指定项目部的累计运行时效
                            BigDecimal tempTransitTime = cumulativeGasInjection.divide(tempCapacity, 4, RoundingMode.HALF_UP);
                            cumulativeTransitTimePair.put(projectDeptId, tempTransitTime);
                        } else {
                            cumulativeTransitTimePair.put(projectDeptId, BigDecimal.ZERO);
                        }
                    }
                });
            }
        }

        // 计算各项目部的平均设备利用率
        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 && CollUtil.isNotEmpty(daysCounts)) {
                        long daysCount = daysCounts.get(0);
                        rate = new BigDecimal((double) reportCount / (currentTeamNum * daysCount))
                                .setScale(4, RoundingMode.HALF_UP)  // 保留4位小数，四舍五入
                                .doubleValue();
                        deviceUtilizationPair.put(projectDeptId, BigDecimal.valueOf(rate));
                    }
                }
            });

            // 计算各项目部的平均设备利用率(按照小时统计)
            projectTeamPair.forEach((projectDeptId, resultTeamIds) -> {
                Integer currentTeamNum = resultTeamIds.size();
                if (projectWorkTimePair.containsKey(projectDeptId)) {
                    BigDecimal reportWorkTime = projectWorkTimePair.getOrDefault(projectDeptId, BigDecimal.ZERO);
                    // 当前项目部 设备利用率 公式 reportCount/(currentTeamNum * daysCount)
                    // 计算设备利用率（处理除数为0的情况）
                    if (currentTeamNum > 0 && CollUtil.isNotEmpty(daysCounts)) {
                        long daysCount = daysCounts.get(0);
                        // 分母 = 队伍数 * 天数 * 24小时
                        BigDecimal denominator = new BigDecimal(currentTeamNum * daysCount * 24);
                        // 安全计算，避免除0
                        BigDecimal utilization = BigDecimal.ZERO;
                        if (denominator.compareTo(BigDecimal.ZERO) > 0) {
                            utilization = reportWorkTime.divide(denominator, 4, RoundingMode.HALF_UP);
                        }
                        hourDeviceUtilizationPair.put(projectDeptId, utilization);
                    }
                }
            });
        }

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

        // 生成返回的数据列表集合
        projectDeptPair.forEach((deptId, dept) -> {
            IotRhDailyReportStatisticsRespVO statistics = new IotRhDailyReportStatisticsRespVO();
            statistics.setProjectDeptId(deptId);
            statistics.setProjectDeptName(dept.getName());
            statistics.setSort(dept.getSort());
            statistics.setType("2");
            statistics.setUtilizationRate(deviceUtilizationPair.get(deptId));
            // 按小时统计 设备利用率
            statistics.setHourUtilizationRate(hourDeviceUtilizationPair.get(deptId));
            statistics.setCumulativeGasInjection(cumulativeGasInjectionPair.get(deptId));
            statistics.setCumulativeWaterInjection(cumulativeWaterInjectionPair.get(deptId));
            statistics.setCumulativePowerConsumption(cumulativePowerConsumptionPair.get(deptId));
            statistics.setCumulativeFuelConsumption(cumulativeOilConsumptionPair.get(deptId));
            statistics.setTransitTime(cumulativeTransitTimePair.get(deptId));
            statistics.setNonProductiveTime(cumulativeNonProductionPair.get(deptId));
            // 队伍数量
            Integer teamCount = teamCountPair.getOrDefault(deptId, 0);
            // 施工队伍数量
            Integer sgTeamCount = sgTeamCountPair.getOrDefault(deptId, 0);
            // 施工准备队伍数量
            Integer zbTeamCount = zbTeamCountPair.getOrDefault(deptId, 0);

            statistics.setTeamCount(teamCount);
            statistics.setSgTeamCount(sgTeamCount);
            statistics.setZbTeamCount(zbTeamCount);

            // 驻地待命 队伍数量 = 队伍总数 - 施工队伍 -  准备队伍
            Integer dmTeamCount = Math.max(teamCount - sgTeamCount - zbTeamCount, 0);
            statistics.setZddmTeamCount(dmTeamCount);
            result.add(statistics);
        });
        return result;
    }

    /**
     * 按项目部维度统计 非生产时效
     * @param dailyReports 日报数据列表
     * @param rootDeptId 根部门ID（如157L为瑞恒根部门，或其他公司级部门ID）
     * @return 项目部维度统计 非生产时效
     */
    private List<IotRhDailyReportNptStatisticsRespVO> nptStatisticsByProjectDept(List<IotRhDailyReportDO> dailyReports,
                                                                           Long rootDeptId, IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportNptStatisticsRespVO> 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<>();
        // 队伍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<>();

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

        // 包含设备的部门id集合
        Set<Long> haveDeviceDeptIds = new HashSet<>();
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        if (CollUtil.isNotEmpty(devices)) {
            // 筛选出包含设备的队伍部门集合
            devices.forEach(device -> {
                haveDeviceDeptIds.add(device.getDeptId());
            });
        }

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            // 暂时过滤掉 欧洲项目部 克拉玛依项目部
            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
                // 状态为LY的项目部 才统计设备利用率
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
            if ("3".equals(dept.getType())) {
                // 队伍
                teamIds.add(dept.getId());
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // 筛选出每个项目部下有多少支队伍 自然日时间 = 队伍数量*24
        // key项目部id   value项目部包含的队伍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) && haveDeviceDeptIds.contains(deptId) && teamIds.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())) {
                    // projectDeptId可能是项目部 也可能是项目的上级
                    Long projectDeptId = 0l;
                    if (teamIds.contains(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) -> {
            IotRhDailyReportNptStatisticsRespVO statistics = new IotRhDailyReportNptStatisticsRespVO();
            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 dailyReports 日报数据列表
     * @param rootDeptId 根部门ID（如157L为瑞恒根部门，或其他公司级部门ID）
     * @return 项目部维度统计结果列表
     */
    private List<IotRhDailyReportPolylineVO> polylineStatisticsByProjectDept(List<IotRhDailyReportDO> dailyReports, Long rootDeptId, LocalDateTime[] createTimes) {
        List<IotRhDailyReportPolylineVO> 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> dateGasInjectionPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计注水量
        Map<String, BigDecimal> dateWaterInjectionPair = 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对应日报部门的总产能
        Map<String, BigDecimal> dateCapacityPair = new HashMap<>();

        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
        Set<Long> mainDeviceCategoryIds = new HashSet<>();
        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
            constructionStatusDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    mainDeviceCategoryIds.add(longValue);
                }
            });
        }

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

        // 包含瑞恒主设备的 部门id 集合
        Set<Long> haveDeviceDeptIds = new HashSet<>();
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        if (CollUtil.isNotEmpty(devices)) {
            // 筛选出包含设备的队伍部门集合
            devices.forEach(device -> {
                // 20260605 筛选包含主设备的队伍
                if (mainDeviceCategoryIds.contains(device.getAssetClass())) {
                    haveDeviceDeptIds.add(device.getDeptId());
                }
            });
        }

        // 当前已经选择的部门下 包含瑞恒主设备的 队伍id 集合
        Set<Long> currentDeviceDeptIds = new HashSet<>();
        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            if ("2".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
            // 筛选出当前选择的组织部门下包含瑞恒主设备的 队伍id 列表
            if ("3".equals(dept.getType()) && haveDeviceDeptIds.contains(dept.getId())) {
                currentDeviceDeptIds.add(dept.getId());
            }
        });

        // 查询指定部门下相关设备的产能
        // key队伍id   value队伍下相关设备产能
        Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));

        // key日期yyyy-MM-dd   value累计注气量
        Map<String, Set<Long>> dateUtilizationDeptPair = new HashMap<>();

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                Long deptId = report.getDeptId();
                // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
                LocalDateTime reportLocalDate = report.getCreateTime();
                // 将日期格式转换成 字符串
                String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
                // 累计注气量
                dateGasInjectionPair.merge(reportDateStr, report.getDailyGasInjection(), BigDecimal::add);
                // 累计注水量
                dateWaterInjectionPair.merge(reportDateStr, report.getDailyWaterInjection(), BigDecimal::add);
                // 累计用电量
                datePowerConsumptionPair.merge(reportDateStr, report.getDailyPowerUsage(), BigDecimal::add);
                // 累计油耗
                dateFuelConsumptionPair.merge(reportDateStr, report.getDailyOilUsage(), BigDecimal::add);
                // 累计产能
                if (teamCapacityPair.containsKey(deptId)) {
                    BigDecimal tempCapacity = teamCapacityPair.get(deptId);
                    dateCapacityPair.merge(reportDateStr, tempCapacity, BigDecimal::add);
                }
                // 统计各日期的设备利用率 注气量 或 注水量 >0 的日报数量
                BigDecimal dailyGasInjection = report.getDailyGasInjection();
                BigDecimal dailyWaterInjection = report.getDailyWaterInjection();
                if (haveDeviceDeptIds.contains(deptId) && (dailyGasInjection.compareTo(BigDecimal.ZERO)>0 || dailyWaterInjection.compareTo(BigDecimal.ZERO)>0)) {
                    if (dateUtilizationDeptPair.containsKey(reportDateStr)) {
                        Set<Long> tempDeptIds = dateUtilizationDeptPair.get(reportDateStr);
                        tempDeptIds.add(deptId);
                        dateUtilizationDeptPair.put(reportDateStr, tempDeptIds);
                    } else {
                        Set<Long> tempDeptIds = new HashSet<>();
                        tempDeptIds.add(deptId);
                        dateUtilizationDeptPair.put(reportDateStr, tempDeptIds);
                    }
                }

            });
            // 根据 累计注气量 累计产能 计算指定日期范围的平均产能
            if (CollUtil.isNotEmpty(dateGasInjectionPair) && CollUtil.isNotEmpty(dateCapacityPair)) {
                dateGasInjectionPair.forEach((reportDateStr, dateGasInjection) -> {
                    if (dateCapacityPair.containsKey(reportDateStr)) {
                        BigDecimal tempCapacity = dateCapacityPair.get(reportDateStr);
                        if (tempCapacity.compareTo(BigDecimal.ZERO) > 0) {
                            // 指日期范围的累计运行时效
                            BigDecimal tempTransitTime = dateGasInjection.divide(tempCapacity, 4, RoundingMode.HALF_UP);
                            dateTransitTimePair.put(reportDateStr, tempTransitTime);
                        } else {
                            dateTransitTimePair.put(reportDateStr, BigDecimal.ZERO);
                        }
                    }
                });
            }
        }

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

        if (ObjUtil.isNotEmpty(createTimes) && 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 -> {
                IotRhDailyReportPolylineVO statistics = new IotRhDailyReportPolylineVO();
                statistics.setReportDate(date);
                statistics.setCumulativeGasInjection(dateGasInjectionPair.get(date));
                statistics.setCumulativeWaterInjection(dateWaterInjectionPair.get(date));
                statistics.setCumulativePowerConsumption(datePowerConsumptionPair.get(date));
                statistics.setCumulativeFuelConsumption(dateFuelConsumptionPair.get(date));
                statistics.setTransitTime(dateTransitTimePair.get(date));
                // 设置每个日期的设备利用率
                if (dateUtilizationDeptPair.containsKey(date)) {
                    Set<Long> dateDeptIds = dateUtilizationDeptPair.get(date);
                    Integer dateDeptIdCount = dateDeptIds.size();
                    Integer mainDeviceIdCount = currentDeviceDeptIds.size();
                    BigDecimal rate = BigDecimal.ZERO;
                    if (mainDeviceIdCount > 0) {
                        BigDecimal total = new BigDecimal(mainDeviceIdCount);
                        BigDecimal current = new BigDecimal(dateDeptIdCount);
                        rate = current.divide(total, 4, RoundingMode.HALF_UP);
                    }
                    statistics.setUtilizationRate(rate);
                }
                result.add(statistics);
            });
        }
        return result;
    }

    /**
     * 按 队伍 维度统计数据
     * @param dailyReports 日报数据列表
     * @param pageReqVO  查询条件 项目 或 任务井号 or deptId
     * @return 队伍 维度统计 日报汇总 工作量
     */
    private List<IotRhDailyReportStatisticsRespVO> statisticsByProjectDepartment(List<IotRhDailyReportDO> dailyReports,
                                                                                 IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportStatisticsRespVO> 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   value累计注气量
        Map<Long, BigDecimal> cumulativeGasInjectionPair = new HashMap<>();
        // key队伍id   value累计注水量
        Map<Long, BigDecimal> cumulativeWaterInjectionPair = new HashMap<>();
        // key队伍id   value累计用电
        Map<Long, BigDecimal> cumulativePowerConsumptionPair = new HashMap<>();
        // key队伍id   value累计油耗
        Map<Long, BigDecimal> cumulativeOilConsumptionPair = new HashMap<>();
        // key队伍id/项目部id   value对应项目部的总产能
        Map<Long, BigDecimal> cumulativeCapacityPair = 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<>();
        // key队伍id/项目部id   value设备利用率(按小时统计)
        Map<Long, BigDecimal> hourDeviceUtilizationPair = new HashMap<>();

        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
        Set<Long> mainDeviceCategoryIds = new HashSet<>();
        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
            constructionStatusDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    mainDeviceCategoryIds.add(longValue);
                }
            });
        }

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

        // 筛选出状态为 LY 的项目部
        depts.forEach(dept -> {
            // 暂时过滤掉 欧洲项目部 克拉玛依项目部
            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
                // 状态为LY的项目部 才统计设备利用率
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
        });

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

        // 包含设备的部门id集合
        Set<Long> haveDeviceDeptIds = new HashSet<>();
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        if (CollUtil.isNotEmpty(devices)) {
            // 筛选出包含设备的队伍部门集合
            devices.forEach(device -> {
                // 20260605 筛选包含主设备的队伍
                if (mainDeviceCategoryIds.contains(device.getAssetClass())) {
                    device.getAssetClass();
                    haveDeviceDeptIds.add(device.getDeptId());
                }
            });
        }

        LocalDateTime[] createTime = pageReqVO.getCreateTime();
        List<Long> daysCounts = new ArrayList<>();
        // 如果 createTime 包含的时间是 1天则查询 这1天时间内的 队伍总数 施工队伍数量 施工准备队伍数量 驻地待命队伍数量
        if (ObjUtil.isNotEmpty(createTime)) {
            LocalDateTime startTime = createTime[0];
            LocalDateTime endTime = createTime[1];
            if (ObjUtil.isNotEmpty(startTime) && ObjUtil.isNotEmpty(endTime) && !endTime.isBefore(startTime)) {
                // 查询时间区间包含的天数
                // 使用ChronoUnit.DAYS.between计算天数差，并+1包含首尾两天
                long daysCount = ChronoUnit.DAYS.between(
                        startTime.toLocalDate(),
                        endTime.toLocalDate()
                ) + 1;
                daysCounts.add(daysCount);
            }
        }

        // 查询指定部门下相关设备的产能
        // key队伍id   value队伍下相关设备产能
        Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));
        // 统计各队伍的设备利用率
        // key队伍id     value队伍指定时间区域内日报数量
        Map<Long, Integer> teamReportPair = new HashMap<>();
        // key队伍id     value包含设备的队伍注气时间或注水时间总和
        Map<Long, BigDecimal> teamWorkTimePair = new HashMap<>();

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                Long deptId = report.getDeptId();
                if (ObjUtil.isNotEmpty(deptId)) {
                    if (haveDeviceDeptIds.contains(deptId)) {
                        // 统计各个队伍的日报数量 筛选 注气量 或 注水量 >0 的日报
                        if (report.getDailyGasInjection().compareTo(BigDecimal.ZERO)>0 || report.getDailyWaterInjection().compareTo(BigDecimal.ZERO)>0) {
                            if (teamReportPair.containsKey(deptId)) {
                                Integer tempCount = teamReportPair.get(deptId);
                                teamReportPair.put(deptId, ++tempCount);
                            } else {
                                teamReportPair.put(deptId, 1);
                            }
                        }
                        // 按照时间H统计设备利用率
                        BigDecimal gasInjectionTime = ObjUtil.defaultIfNull(report.getDailyInjectGasTime(), BigDecimal.ZERO);
                        BigDecimal waterInjectionTime = ObjUtil.defaultIfNull(report.getDailyInjectWaterTime(), BigDecimal.ZERO);
                        BigDecimal workTime = gasInjectionTime.compareTo(BigDecimal.ZERO) > 0
                                ? gasInjectionTime
                                : waterInjectionTime.compareTo(BigDecimal.ZERO) > 0
                                ? waterInjectionTime
                                : BigDecimal.ZERO;
                        if (workTime.compareTo(BigDecimal.ZERO) > 0) {
                            // 取 注气时间 注水时间 的较大者
                            // 校验：项目部ID不为空 + 该项目部存在有效队伍
                            // 存在则累加，不存在则赋值
                            teamWorkTimePair.merge(deptId, workTime, BigDecimal::add);
                        }
                    }

                    // 累计注气量
                    cumulativeGasInjectionPair.merge(deptId, report.getDailyGasInjection(), BigDecimal::add);
                    // 累计注水量
                    cumulativeWaterInjectionPair.merge(deptId, report.getDailyWaterInjection(), BigDecimal::add);
                    // 累计用电量
                    cumulativePowerConsumptionPair.merge(deptId, report.getDailyPowerUsage(), BigDecimal::add);
                    // 累计油耗
                    cumulativeOilConsumptionPair.merge(deptId, report.getDailyOilUsage(), BigDecimal::add);
                    if (teamCapacityPair.containsKey(deptId)) {
                        BigDecimal tempCapacity = teamCapacityPair.get(deptId);
                        cumulativeCapacityPair.merge(deptId, tempCapacity, 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(deptId)) {
                            List<BigDecimal> tempNonProductionTimes = cumulativeNonProductionTimePair.get(deptId);
                            tempNonProductionTimes.add(nonProductionTimeSum);
                            cumulativeNonProductionTimePair.put(deptId, tempNonProductionTimes);
                        } else {
                            List<BigDecimal> tempNonProductionTimes = new ArrayList<>();
                            tempNonProductionTimes.add(nonProductionTimeSum);
                            cumulativeNonProductionTimePair.put(deptId, tempNonProductionTimes);
                        }
                    }
                }
            });
            // 根据 累计注气量 累计产能 计算指定队伍下的平均产能
            if (CollUtil.isNotEmpty(cumulativeGasInjectionPair) && CollUtil.isNotEmpty(cumulativeCapacityPair)) {
                cumulativeGasInjectionPair.forEach((teamDeptId, cumulativeGasInjection) -> {
                    if (cumulativeCapacityPair.containsKey(teamDeptId)) {
                        BigDecimal tempCapacity = cumulativeCapacityPair.get(teamDeptId);
                        if (tempCapacity.compareTo(BigDecimal.ZERO) > 0) {
                            // 指定队伍的累计运行时效
                            BigDecimal tempTransitTime = cumulativeGasInjection.divide(tempCapacity, 4, RoundingMode.HALF_UP);
                            cumulativeTransitTimePair.put(teamDeptId, tempTransitTime);
                        }
                    }
                });
            }
            if (CollUtil.isNotEmpty(cumulativeNonProductionTimePair)) {
                // 计算各队伍的 非生产时效
                cumulativeNonProductionTimePair.forEach((teamId, nonProductTimes) -> {
                    // nonProductTimes 集合中元素的数量就是 分母中应该计算非生产时效的天数
                    BigDecimal totalNonProductionTime = nonProductTimes.stream()
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    if (CollUtil.isNotEmpty(daysCounts)) {
                        BigDecimal denominator = new BigDecimal(daysCounts.get(0) * 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 && CollUtil.isNotEmpty(daysCounts)) {
                            long daysCount = daysCounts.get(0);
                            rate = new BigDecimal((double) reportCount / (currentTeamNum * daysCount))
                                    .setScale(4, RoundingMode.HALF_UP)  // 保留4位小数，四舍五入
                                    .doubleValue();
                            deviceUtilizationPair.put(teamDeptId, BigDecimal.valueOf(rate));
                        }
                });
            }

            // 计算各队伍的平均设备利用率 按照小时H统计
            if (CollUtil.isNotEmpty(teamWorkTimePair)) {
                teamWorkTimePair.forEach((teamDeptId, workTime) -> {
                    BigDecimal reportWorkTime = teamWorkTimePair.getOrDefault(teamDeptId, BigDecimal.ZERO);
                    Integer currentTeamNum = 1;
                    // 当前项目部 设备利用率 公式 reportCount/(currentTeamNum * daysCount)
                    // 计算设备利用率（处理除数为0的情况）
                    if (currentTeamNum > 0 && CollUtil.isNotEmpty(daysCounts)) {
                        long daysCount = daysCounts.get(0);
                        // 分母 = 队伍数 * 天数 * 24小时
                        BigDecimal denominator = new BigDecimal(currentTeamNum * daysCount * 24);
                        // 安全计算，避免除0
                        BigDecimal utilization = BigDecimal.ZERO;
                        if (denominator.compareTo(BigDecimal.ZERO) > 0) {
                            utilization = reportWorkTime.divide(denominator, 4, RoundingMode.HALF_UP);
                        }
                        hourDeviceUtilizationPair.put(teamDeptId, utilization);
                    }
                });
            }
        }

        // 生成返回的数据列表集合
        teamDeptPair.forEach((teamDeptId, dept) -> {
            IotRhDailyReportStatisticsRespVO statistics = new IotRhDailyReportStatisticsRespVO();
            statistics.setTeamId(teamDeptId);
            statistics.setTeamName(dept.getName());
            statistics.setSort(dept.getSort());
            statistics.setType("3");
            // 按天统计的设备利用率
            statistics.setUtilizationRate(deviceUtilizationPair.get(teamDeptId));
            // 按小时统计的设备利用率
            statistics.setHourUtilizationRate(hourDeviceUtilizationPair.get(teamDeptId));
            statistics.setCumulativeGasInjection(cumulativeGasInjectionPair.get(teamDeptId));
            statistics.setCumulativeWaterInjection(cumulativeWaterInjectionPair.get(teamDeptId));
            statistics.setCumulativePowerConsumption(cumulativePowerConsumptionPair.get(teamDeptId));
            statistics.setCumulativeFuelConsumption(cumulativeOilConsumptionPair.get(teamDeptId));
            statistics.setTransitTime(cumulativeTransitTimePair.get(teamDeptId));
            statistics.setNonProductiveTime(cumulativeNonProductionPair.get(teamDeptId));
            result.add(statistics);
        });

        return result;
    }

    /**
     * 按 队伍 维度统计 非生产时效
     * @param dailyReports 日报数据列表
     * @param pageReqVO  查询条件 项目 或 任务井号 or deptId
     * @return 队伍 维度统计 非生产时效
     */
    private List<IotRhDailyReportNptStatisticsRespVO> nptStatisticsByProjectDepartment(List<IotRhDailyReportDO> dailyReports,
                                                                                 IotRhDailyReportPageReqVO pageReqVO) {
        List<IotRhDailyReportNptStatisticsRespVO> 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<>();

        // 以 队伍 为维度统计数据 找到所有项目部与队伍的对应关系
        // 查询指定根部门下的所有子部门
        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 ("2".equals(dept.getType())) {
                // 组装项目部id集合
                projectDeptIds.add(dept.getId());
                projectDeptPair.put(dept.getId(), dept);
            }
        });

        // 构建项目部映射和父子部门关系
        depts.forEach(dept -> {
            if ("3".equals(dept.getType())) {
                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)) {
                    // 工程质量 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) -> {
                    // 统计当前 施工队伍 所有 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) -> {
            IotRhDailyReportNptStatisticsRespVO statistics = new IotRhDailyReportNptStatisticsRespVO();
            statistics.setTeamId(teamDeptId);
            statistics.setTeamName(dept.getName());
            statistics.setSort(dept.getSort());
            if (teamDeptPair.containsKey(teamDeptId)) {
                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 dailyReports 日报数据列表
     * @param deptId 项目部ID 或 队伍id（塔河项目部 HY-A1）
     * @return 队伍 维度统计结果列表
     */
    private List<IotRhDailyReportPolylineVO> polylineStatisticsByProjectDepartment(List<IotRhDailyReportDO> dailyReports, Long deptId, LocalDateTime[] createTimes) {
        List<IotRhDailyReportPolylineVO> 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日期yyyy-MM-dd   value累计注气量
        Map<String, BigDecimal> dateGasInjectionPair = new HashMap<>();
        // key日期yyyy-MM-dd   value累计注水量
        Map<String, BigDecimal> dateWaterInjectionPair = 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对应日报部门的总产能
        Map<String, BigDecimal> dateCapacityPair = new HashMap<>();

        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
        Set<Long> mainDeviceCategoryIds = new HashSet<>();
        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
            constructionStatusDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    mainDeviceCategoryIds.add(longValue);
                }
            });
        }

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

        // 包含瑞恒主设备的 部门id 集合
        Set<Long> haveDeviceDeptIds = new HashSet<>();
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(allRhChildDeptIds));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        if (CollUtil.isNotEmpty(devices)) {
            // 筛选出包含设备的队伍部门集合
            devices.forEach(device -> {
                // 20260605 筛选包含主设备的队伍
                if (mainDeviceCategoryIds.contains(device.getAssetClass())) {
                    haveDeviceDeptIds.add(device.getDeptId());
                }
            });
        }

        // 构建项目部映射和父子部门关系
        // 当前已经选择的部门下 包含瑞恒主设备的 队伍id 集合
        Set<Long> currentDeviceDeptIds = new HashSet<>();
        depts.forEach(dept -> {
            if ("3".equals(dept.getType())) {
                projectDeptIds.add(dept.getId());
                teamDeptPair.put(dept.getId(), dept);
                // 筛选出当前选择的组织部门下包含瑞恒主设备的 队伍id 列表
                if (haveDeviceDeptIds.contains(dept.getId())) {
                    currentDeviceDeptIds.add(dept.getId());
                }
            }
            teamProjectIdPair.put(dept.getId(), dept.getParentId());
        });

        // 查询指定部门下相关设备的产能
        // key队伍id   value队伍下相关设备产能
        Map<Long, BigDecimal> teamCapacityPair = queryCapacities(new ArrayList<>(allRhChildDeptIds));

        // key日期yyyy-MM-dd   value指定日期内包含主设备队伍id集合
        Map<String, Set<Long>> dateUtilizationDeptPair = new HashMap<>();

        // 累计计算各项指标
        if (CollUtil.isNotEmpty(dailyReports)) {
            dailyReports.forEach(report -> {
                Long currentDeptId = report.getDeptId();
                // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
                LocalDateTime reportLocalDate = report.getCreateTime();
                // 将日期格式转换成 字符串
                String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
                // 累计注气量
                dateGasInjectionPair.merge(reportDateStr, report.getDailyGasInjection(), BigDecimal::add);
                // 累计注水量
                dateWaterInjectionPair.merge(reportDateStr, report.getDailyWaterInjection(), BigDecimal::add);
                // 累计用电量
                datePowerConsumptionPair.merge(reportDateStr, report.getDailyPowerUsage(), BigDecimal::add);
                // 累计油耗
                dateFuelConsumptionPair.merge(reportDateStr, report.getDailyOilUsage(), BigDecimal::add);
                // 累计产能
                if (teamCapacityPair.containsKey(currentDeptId)) {
                    BigDecimal tempCapacity = teamCapacityPair.get(currentDeptId);
                    dateCapacityPair.merge(reportDateStr, tempCapacity, BigDecimal::add);
                }
                // 统计各日期的设备利用率 注气量 或 注水量 >0 的日报数量
                BigDecimal dailyGasInjection = report.getDailyGasInjection();
                BigDecimal dailyWaterInjection = report.getDailyWaterInjection();
                if (haveDeviceDeptIds.contains(currentDeptId) && (dailyGasInjection.compareTo(BigDecimal.ZERO)>0 || dailyWaterInjection.compareTo(BigDecimal.ZERO)>0)) {
                    if (dateUtilizationDeptPair.containsKey(reportDateStr)) {
                        Set<Long> tempDeptIds = dateUtilizationDeptPair.get(reportDateStr);
                        tempDeptIds.add(currentDeptId);
                        dateUtilizationDeptPair.put(reportDateStr, tempDeptIds);
                    } else {
                        Set<Long> tempDeptIds = new HashSet<>();
                        tempDeptIds.add(currentDeptId);
                        dateUtilizationDeptPair.put(reportDateStr, tempDeptIds);
                    }
                }
            });
            // 根据 累计注气量 累计产能 计算指定队伍下的平均产能
            if (CollUtil.isNotEmpty(dateGasInjectionPair) && CollUtil.isNotEmpty(dateCapacityPair)) {
                dateGasInjectionPair.forEach((teamDeptId, dateGasInjection) -> {
                    if (dateCapacityPair.containsKey(teamDeptId)) {
                        BigDecimal tempCapacity = dateCapacityPair.get(teamDeptId);
                        if (tempCapacity.compareTo(BigDecimal.ZERO) > 0) {
                            // 指定队伍的累计运行时效
                            BigDecimal tempTransitTime = dateGasInjection.divide(tempCapacity, 4, RoundingMode.HALF_UP);
                            dateTransitTimePair.put(teamDeptId, tempTransitTime);
                        }
                    }
                });
            }
        }

        // 新增：日期字符串集合
        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 -> {
                IotRhDailyReportPolylineVO statistics = new IotRhDailyReportPolylineVO();
                statistics.setReportDate(date);
                statistics.setCumulativeGasInjection(dateGasInjectionPair.get(date));
                statistics.setCumulativeWaterInjection(dateWaterInjectionPair.get(date));
                statistics.setCumulativePowerConsumption(datePowerConsumptionPair.get(date));
                statistics.setCumulativeFuelConsumption(dateFuelConsumptionPair.get(date));
                statistics.setTransitTime(dateTransitTimePair.get(date));
                // 设置每个日期的设备利用率
                if (dateUtilizationDeptPair.containsKey(date)) {
                    Set<Long> dateDeptIds = dateUtilizationDeptPair.get(date);
                    Integer dateDeptIdCount = dateDeptIds.size();
                    Integer mainDeviceIdCount = currentDeviceDeptIds.size();
                    BigDecimal rate = BigDecimal.ZERO;
                    if (mainDeviceIdCount > 0) {
                        BigDecimal total = new BigDecimal(mainDeviceIdCount);
                        BigDecimal current = new BigDecimal(dateDeptIdCount);
                        rate = current.divide(total, 4, RoundingMode.HALF_UP);
                    }
                    statistics.setUtilizationRate(rate);
                }
                result.add(statistics);
            });
        }

        return result;
    }

    @Override
    public List<IotRhDailyReportStatisticsVO> rhDailyReportStatistics(IotRhDailyReportPageReqVO reqVO) {
        if (reqVO.getCreateTime().length == 0) {
            // 必须传递时间区间参数
            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
        }
        List<IotRhDailyReportStatisticsVO> results = new ArrayList<>();
        // 查询 瑞恒 157l 所有存在设备的队伍
        // 所有需要填报日报的 瑞恒 队伍集合
        Set<Long> deptIds = new HashSet<>();

        Set<Long> ids = new HashSet<>();
        ids = deptService.getChildDeptIdListFromCache(157l);
        ids.add(157l);

        DeptListReqVO deptReqVO = new DeptListReqVO();
        deptReqVO.setDeptIds(ids);
        List<DeptDO> depts = deptService.getDeptList(deptReqVO);
        // 项目部类型的部门id集合
        Set<Long> projectDeptIds = new HashSet<>();
        // 队伍类型的部门id集合
        Set<Long> teamDeptIds = new HashSet<>();
        depts.forEach(dept -> {
            // 查找需要统计的项目部
            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
                projectDeptIds.add(dept.getId());
            }
        });
        depts.forEach(dept -> {
            // 队伍类型的部门id集合
            if ("3".equals(dept.getType()) && projectDeptIds.contains(dept.getParentId())) {
                teamDeptIds.add(dept.getId());
            }
        });

        // 20260605 筛选包含瑞恒主设备的队伍
        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
        Set<Long> mainDeviceCategoryIds = new HashSet<>();
        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
            constructionStatusDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    mainDeviceCategoryIds.add(longValue);
                }
            });
        }

        // 筛选有设备的队伍部门
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(ids));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        // 包含设备的部门id集合
        Set<Long> deviceTeamIds = new HashSet<>();
        if (CollUtil.isNotEmpty(devices)) {
            devices.forEach(device -> {
                if (teamDeptIds.contains(device.getDeptId()) && mainDeviceCategoryIds.contains(device.getAssetClass())) {
                    deviceTeamIds.add(device.getDeptId());
                }
            });
        }

        // 瑞恒日报总数
        long rhTotalCount = 0;

        // 瑞恒已填报完成日报总数
        AtomicReference<Integer> rhFinishedCount = new AtomicReference<>(0);
        // 瑞恒未填报完成日报总数
        AtomicReference<Integer> rhUnfinishedCount = new AtomicReference<>(0);

        // 根据指定的时间区间 计算出天数
        LocalDateTime[] createTimes = reqVO.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;
        // 队伍总数 = 天数*符合要求的队伍数量

        if (CollUtil.isNotEmpty(deviceTeamIds)) {
            long teamCount =deviceTeamIds.size();
            long totalCount = teamCount * days;

            rhTotalCount = totalCount;

            // 查询指定时间区间内 符合条件的队伍的日报
            reqVO.setDeptIds(deviceTeamIds);
            List<IotRhDailyReportDO> reports = iotRhDailyReportMapper.dailyReports(reqVO);
            // 未生成日报的队伍id集合
            Set<Long> unCreatedDeptIds = new HashSet<>();
            // 已生成日报的队伍id集合
            Set<Long> createdDeptIds = new HashSet<>();
            if (CollUtil.isNotEmpty(reports)) {
                reports.forEach(report -> {
                    if (deviceTeamIds.contains(report.getDeptId())) {
                        createdDeptIds.add(report.getDeptId());
                        // status = 0未填报    status = 1已填报
                        if (report.getStatus() == 1) {
                            rhFinishedCount.set(rhFinishedCount.get() + 1);
                        }
                        if (report.getStatus() == 0) {
                            rhUnfinishedCount.set(rhUnfinishedCount.get() + 1);
                        }
                    }
                });
            }
            // rhUnfinishedCount 还要统计没有生成日报的队伍数量
            unCreatedDeptIds = deviceTeamIds.stream()
                    .filter(deptId -> !createdDeptIds.contains(deptId))
                    .collect(Collectors.toSet());
            long unCreatedCount = unCreatedDeptIds.size() * days;
            rhUnfinishedCount.set(rhUnfinishedCount.get() + (int) unCreatedCount);
        }
        // 先查询未填报 的队伍数量  已填报数量=总数-未填报
        rhFinishedCount.set((int)rhTotalCount - rhUnfinishedCount.get());

        IotRhDailyReportStatisticsVO allReports = new IotRhDailyReportStatisticsVO();
        allReports.setGroupName("总数");
        allReports.setCount(rhTotalCount);
        IotRhDailyReportStatisticsVO haveReported = new IotRhDailyReportStatisticsVO();
        haveReported.setGroupName("已填报");
        haveReported.setCount(rhFinishedCount.get());
        IotRhDailyReportStatisticsVO notReported = new IotRhDailyReportStatisticsVO();
        notReported.setGroupName("未填报");
        notReported.setCount(rhUnfinishedCount.get());
        results.add(allReports);
        results.add(haveReported);
        results.add(notReported);
        return results;
    }

    @Override
    public List<IotRhDailyReportStatisticsVO> rhUnReportedDetails(IotRhDailyReportPageReqVO reqVO) {
        // 查询所有未填报日报的队伍名称 HY-A1,HY-A2...
        // 首先必须传递了日期范围
        if (reqVO.getCreateTime().length == 0) {
            // 必须传递时间区间参数
            throw exception(IOT_DAILY_REPORT_TIME_NOT_EXISTS);
        }
        List<IotRhDailyReportStatisticsVO> results = new ArrayList<>();
        // 所有需要填报日报的 瑞恒 队伍集合
        Set<Long> deptIds = new HashSet<>();
        List<String> reportDates = new ArrayList<>();

        Set<Long> ids = new HashSet<>();
        ids = deptService.getChildDeptIdListFromCache(157l);
        ids.add(157l);

        DeptListReqVO deptReqVO = new DeptListReqVO();
        deptReqVO.setDeptIds(ids);
        List<DeptDO> depts = deptService.getDeptList(deptReqVO);

        // 项目部类型的部门id集合
        Set<Long> projectDeptIds = new HashSet<>();
        // 队伍类型的部门id集合
        Set<Long> teamDeptIds = new HashSet<>();

        depts.forEach(dept -> {
            // 查找需要统计的项目部
            if ("2".equals(dept.getType()) && "LY".equals(dept.getEmail())) {
                projectDeptIds.add(dept.getId());
            }
        });
        depts.forEach(dept -> {
            // 队伍类型的部门id集合
            if ("3".equals(dept.getType()) && projectDeptIds.contains(dept.getParentId())) {
                teamDeptIds.add(dept.getId());
            }
        });

        // 筛选瑞恒 主设备 rq_iot_rh_main_device_category
        Set<Long> mainDeviceCategoryIds = new HashSet<>();
        List<DictDataDO> constructionStatusDictData = dictDataService.getDictDataListByDictType("rq_iot_rh_main_device_category");
        if (CollUtil.isNotEmpty(constructionStatusDictData)) {
            constructionStatusDictData.forEach(data -> {
                String value = data.getValue();
                if (NumberUtil.isNumber(value)) {
                    Long longValue = Long.valueOf(value);
                    mainDeviceCategoryIds.add(longValue);
                }
            });
        }

        // 筛选有设备的队伍部门 20260605 修改成 查询包含瑞恒主设备的队伍
        IotDevicePageReqVO deviceReqVO = new IotDevicePageReqVO();
        deviceReqVO.setDeptIds(new ArrayList<>(ids));
        List<IotDeviceDO> devices = iotDeviceMapper.selectListAlone(deviceReqVO);
        // 包含设备的部门id集合
        Set<Long> deviceTeamIds = new HashSet<>();
        if (CollUtil.isNotEmpty(devices)) {
            devices.forEach(device -> {
                if (teamDeptIds.contains(device.getDeptId()) && mainDeviceCategoryIds.contains(device.getAssetClass())) {
                    deviceTeamIds.add(device.getDeptId());
                }
            });
        }

        // 根据指定的时间区间 计算出天数
        LocalDateTime[] createTimes = reqVO.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天

        // 生成 deptId-createTime 全集A allDeptIdReportDates
        List<String> allDeptIdReportDates = new ArrayList<>();
        if (CollUtil.isNotEmpty(reportDates) && CollUtil.isNotEmpty(deviceTeamIds)) {
            // 笛卡尔积：每个队伍ID匹配每个日期，生成 "teamId-reportDate" 格式的字符串
            List<String> finalReportDates = reportDates;
            allDeptIdReportDates = deviceTeamIds.stream()
                    // 对每个队伍ID，关联所有日期
                    .flatMap(teamId -> finalReportDates.stream()
                            // 拼接成 "teamId-reportDate" 格式
                            .map(date -> teamId + "~" + date))
                    // 收集到List中（如需去重可加 .distinct()，根据实际场景决定）
                    .collect(Collectors.toList());
        }

        // 根据符合要求的队伍查询相关的日报列表
        if (CollUtil.isNotEmpty(deviceTeamIds)) {
            reqVO.setDeptIds(deviceTeamIds);
            // 查询出指定时间区间内 已经填写的日报数量
            List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.dailyReports(reqVO);
            // 未生成日报的队伍id集合
            Set<Long> unCreatedDeptIds = new HashSet<>();
            // 已生成日报的队伍id集合
            Set<Long> createdDeptIds = new HashSet<>();
            if (CollUtil.isNotEmpty(dailyReports)) {
                dailyReports.forEach(report -> {
                    createdDeptIds.add(report.getDeptId());
                });
            }
            // 统计没有生成日报的队伍id集合
            unCreatedDeptIds = deviceTeamIds.stream()
                    .filter(deptId -> !createdDeptIds.contains(deptId))
                    .collect(Collectors.toSet());

            // 已经填报的队伍名称集合
            Map<String, List<String>> reportedDeptNames = new HashMap<>();
            // 未填报的队伍名称集合
            Map<String, List<String>> unReportedDeptNames = new HashMap<>();
            // 查询所有部门信息
            Map<Long, DeptDO> allDepts = deptService.getDeptMap(ids);
            // 过滤后的所有部门信息
            Map<Long, DeptDO> filteredDepts = new HashMap<>();
            // 队伍集合
            if (CollUtil.isNotEmpty(allDepts)) {
                allDepts.forEach((deptId, dept) -> {
                    if ("3".equals(dept.getType()) && deviceTeamIds.contains(deptId)) {
                        filteredDepts.put(deptId, dept);
                    }
                });
            }
            // 日报相关的 deptId-createTime 集合
            List<String> reportDeptDates = new ArrayList<>();
            if (CollUtil.isNotEmpty(dailyReports)) {
                // 组装每天填写的日报集合 从而统计出每天未填写日报的队伍
                dailyReports.forEach(report -> {
                    // status=1 日报已经填报
                    LocalDateTime createTime = report.getCreateTime();
                    LocalDate tempDate = createTime.toLocalDate();
                    String tempReportDate = tempDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                    // 生成每个队伍日报的 deptId-createTime 集合
                    reportDeptDates.add(StrUtil.join("~", report.getDeptId(), tempReportDate));
                    // 已经生成了日报 但是没有填报
                    if (0 == report.getStatus()) {
                        Long tempDeptId = report.getDeptId();
                        if (filteredDepts.containsKey(tempDeptId)) {
                            String deptName = filteredDepts.get(tempDeptId).getName();
                            if (unReportedDeptNames.containsKey(tempReportDate)) {
                                List<String> tempDeptNames = unReportedDeptNames.get(tempReportDate);
                                tempDeptNames.add(deptName);
                                unReportedDeptNames.put(tempReportDate, tempDeptNames);
                            } else {
                                List<String> tempDeptNames = new ArrayList<>();
                                tempDeptNames.add(deptName);
                                unReportedDeptNames.put(tempReportDate, tempDeptNames);
                            }
                        }
                    }
                });
            }

            // 还需要统计未生成日报的队伍id集合
            // 首先生成 deptId-createTime 全集allDeptIdReportDates 然后根据生成的日报组装日报相关的deptId-createTime集合 reportDeptDates
            // allDeptIdReportDates-reportDeptDates 就是没有生成日报的队伍
            List<String> unCreatedDeptDates = new ArrayList<>();
            if (CollUtil.isNotEmpty(allDeptIdReportDates)) {
                // 将已填报的 reportDeptDates 转换为 Set，提升查找效率（O(1)）
                Set<String> reportedSet = new HashSet<>(reportDeptDates);

                // 过滤出 allDeptIdReportDates 中不在 reportedSet 中的元素，即是未生成日报的记录
                unCreatedDeptDates = allDeptIdReportDates.stream()
                        .filter(item -> !reportedSet.contains(item)) // 核心：排除已填报的记录
                        .distinct() // 可选：去重（根据业务场景决定是否需要）
                        .collect(Collectors.toList());
            }

            if (CollUtil.isNotEmpty(unCreatedDeptDates)) {
                unCreatedDeptDates.forEach(deptDate -> {
                    // deptId-createDate
                    String[] deptDateArr = deptDate.split("~");
                    if (deptDateArr.length > 0) {
                        String tempDeptName = StrUtil.EMPTY;
                        String deptIdStr = deptDateArr[0];
                        // 根据deptId获得部门名称
                        if (StrUtil.isNotBlank(deptIdStr) && !"null".equals(deptIdStr)) {
                            Long deptId = Long.valueOf(deptIdStr);
                            if (filteredDepts.containsKey(deptId)) {
                                DeptDO dept = filteredDepts.get(deptId);
                                tempDeptName = dept.getName();
                            }
                        }
                        String createTimeStr = deptDateArr[1];
                        if (StrUtil.isNotBlank(createTimeStr) && !"null".equals(createTimeStr)) {
                            if (StrUtil.isNotBlank(tempDeptName)) {
                                if (unReportedDeptNames.containsKey(createTimeStr)) {
                                    List<String> tempDeptNames = unReportedDeptNames.get(createTimeStr);
                                    tempDeptNames.add(tempDeptName);
                                    unReportedDeptNames.put(createTimeStr, tempDeptNames);
                                } else {
                                    List<String> tempDeptNames = new ArrayList<>();
                                    tempDeptNames.add(tempDeptName);
                                    unReportedDeptNames.put(createTimeStr, tempDeptNames);
                                }
                            }
                        }
                    }
                });
            }

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

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

    @Override
    public List<IotRhDailyReportDO> taskActualProgress(IotRhDailyReportPageReqVO reqVO) {
        if (ObjUtil.isEmpty(reqVO.getTaskId())) {
            throw exception(IOT_PROJECT_TASK_NOT_EXISTS);
        }
        // 根据 taskId 任务提取日报中的施工状态进度节点信息
        IotRhDailyReportPageReqVO reportReqVO = new IotRhDailyReportPageReqVO();
        reportReqVO.setTaskId(reqVO.getTaskId());
        List<IotRhDailyReportDO> dailyReports = iotRhDailyReportMapper.selectListGrouped(reportReqVO);
        return dailyReports;
    }

    @Override
    public List<IotRhDailyReportDO> relocationDays(IotRhDailyReportPageReqVO reqVO) {
        return iotRhDailyReportMapper.relocationDays(reqVO);
    }

}