|
|
@@ -77,6 +77,7 @@ import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
+import java.time.YearMonth;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.time.format.DateTimeParseException;
|
|
|
import java.time.temporal.ChronoUnit;
|
|
|
@@ -2120,6 +2121,93 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public List<IotRhDailyReportPolylineVO> monthPolylineStatistics(IotRhDailyReportPageReqVO pageReqVO) {
|
|
|
+ // 以 月为维度 统计工作量 非整月 上个月26日-本月25日
|
|
|
+ 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<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 时间查询区间内如果包含 未发生的时间段(今年 本季度) 则设置 结束时间为 当前日期
|
|
|
+ // 调整 查询时间 因为 非整月查询 比如 查询时间是 2026-04-01 到 2026-05-31 则查询统计 2026年4月(3.26-4.25)、5月(4.26-5.25)的数据
|
|
|
+ // createTime[0]: 2026-09-01 00:00:00
|
|
|
+ // createTime[1]: 2026-09-07 23:59:59
|
|
|
+ adjustMonthStatisticsTime(pageReqVO);
|
|
|
+
|
|
|
+ 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 = monthPolylineStatisticsByProjectDept(dailyReports, 157L, pageReqVO.getCreateTime());
|
|
|
+ } else {
|
|
|
+ // 判断点击的组织树中的部门类型 类型(公司级1 项目部2 队伍3)
|
|
|
+ DeptDO selectedDept = deptService.getDept(pageReqVO.getDeptId());
|
|
|
+ if ("1".equals(selectedDept.getType())) {
|
|
|
+ // 以项目部为维度汇总数据
|
|
|
+ result = monthPolylineStatisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
|
|
|
+ } else if ("2".equals(selectedDept.getType())) {
|
|
|
+ // 以队伍为维度汇总数据
|
|
|
+ result = monthPolylineStatisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
|
|
|
+ } else if ("3".equals(selectedDept.getType())) {
|
|
|
+ // 显示单个队伍的汇总数据
|
|
|
+ result = monthPolylineStatisticsByProjectDepartment(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
|
|
|
+ } else {
|
|
|
+ // 点击的部门没有类型 判断部门下的是否包含 项目部类型部门 新疆分公司
|
|
|
+ // 以项目部为维度汇总数据
|
|
|
+ result = monthPolylineStatisticsByProjectDept(dailyReports, pageReqVO.getDeptId(), pageReqVO.getCreateTime());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void adjustMonthStatisticsTime(IotRhDailyReportPageReqVO pageReqVO) {
|
|
|
+ LocalDateTime[] times = pageReqVO.getCreateTime();
|
|
|
+ if (times == null || times.length < 2 || times[0] == null || times[1] == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始时间:开始时间所在月份的上个月26号 00:00:00
|
|
|
+ times[0] = times[0].minusMonths(1).withDayOfMonth(26).toLocalDate().atStartOfDay();
|
|
|
+
|
|
|
+ // 截止时间规则处理
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+ LocalDate bDate = times[1].toLocalDate();
|
|
|
+ LocalDate month25Date = bDate.withDayOfMonth(25);
|
|
|
+
|
|
|
+ LocalDate endDate;
|
|
|
+ if (!month25Date.isAfter(today)) {
|
|
|
+ // 该月25号已经过去或就是今天,截止时间取该月25号
|
|
|
+ endDate = month25Date;
|
|
|
+ } else {
|
|
|
+ // 该月25号还没到,截止时间取 min(B, 今天)
|
|
|
+ endDate = bDate.isAfter(today) ? today : bDate;
|
|
|
+ }
|
|
|
+
|
|
|
+ times[1] = endDate.atTime(23, 59, 59);
|
|
|
+ pageReqVO.setCreateTime(times);
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void updateIotRhDailyReport(IotRhDailyReportSaveReqVO updateReqVO) {
|
|
|
// 校验存在
|
|
|
@@ -3364,6 +3452,270 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 按项目部 日期 维度统计 月度 折线 数据
|
|
|
+ * @param dailyReports 日报数据列表
|
|
|
+ * @param rootDeptId 根部门ID(如157L为瑞恒根部门,或其他公司级部门ID)
|
|
|
+ * @return 项目部 月度 维度统计结果列表
|
|
|
+ */
|
|
|
+ private List<IotRhDailyReportPolylineVO> monthPolylineStatisticsByProjectDept(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<>();
|
|
|
+
|
|
|
+ // 20260915 修改设备利用率计算逻辑 修改分母为 日报总数
|
|
|
+
|
|
|
+ // 构建项目部映射和父子部门关系
|
|
|
+ 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日报id集合
|
|
|
+ Map<String, Set<Long>> dateUtilizationDeptPair = new HashMap<>();
|
|
|
+
|
|
|
+ // key日期yyyy-MM-dd value日期对应的日报总数量
|
|
|
+ Map<String, Integer> dateTotalReportPair = new HashMap<>();
|
|
|
+
|
|
|
+ // 累计计算各项指标
|
|
|
+ if (CollUtil.isNotEmpty(dailyReports)) {
|
|
|
+ dailyReports.forEach(report -> {
|
|
|
+ Long reportId = report.getId();
|
|
|
+ Long deptId = report.getDeptId();
|
|
|
+ // 按照日期维度统计各 工作量数据 累计用电量 累计油耗 累计注气量 累计注水量
|
|
|
+ LocalDateTime reportLocalDate = report.getCreateTime();
|
|
|
+ String reportMonth = getReportMonthGroup(reportLocalDate);
|
|
|
+ // 将日期格式转换成 字符串
|
|
|
+ String reportDateStr = LocalDateTimeUtil.format(reportLocalDate, DatePattern.NORM_DATE_PATTERN);
|
|
|
+ // 累计注气量
|
|
|
+ dateGasInjectionPair.merge(reportMonth, report.getDailyGasInjection(), BigDecimal::add);
|
|
|
+ // 累计注水量
|
|
|
+ dateWaterInjectionPair.merge(reportMonth, report.getDailyWaterInjection(), BigDecimal::add);
|
|
|
+ // 累计用电量
|
|
|
+ datePowerConsumptionPair.merge(reportMonth, report.getDailyPowerUsage(), BigDecimal::add);
|
|
|
+ // 累计油耗
|
|
|
+ dateFuelConsumptionPair.merge(reportMonth, report.getDailyOilUsage(), BigDecimal::add);
|
|
|
+ // 累计产能
|
|
|
+ if (teamCapacityPair.containsKey(deptId)) {
|
|
|
+ BigDecimal tempCapacity = teamCapacityPair.get(deptId);
|
|
|
+ dateCapacityPair.merge(reportMonth, 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(reportMonth)) {
|
|
|
+ Set<Long> tempDeptIds = dateUtilizationDeptPair.get(reportMonth);
|
|
|
+ tempDeptIds.add(reportId);
|
|
|
+ dateUtilizationDeptPair.put(reportMonth, tempDeptIds);
|
|
|
+ } else {
|
|
|
+ Set<Long> tempDeptIds = new HashSet<>();
|
|
|
+ tempDeptIds.add(reportId);
|
|
|
+ dateUtilizationDeptPair.put(reportMonth, tempDeptIds);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 统计当前日期下所有日报总数量
|
|
|
+ if (dateTotalReportPair.containsKey(reportMonth)) {
|
|
|
+ Integer tempCount = dateTotalReportPair.get(reportMonth);
|
|
|
+ dateTotalReportPair.put(reportMonth, ++tempCount);
|
|
|
+ } else {
|
|
|
+ dateTotalReportPair.put(reportMonth, 1);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 根据 累计注气量 累计产能 计算指定日期范围的平均产能
|
|
|
+ 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 = getMonthRangeList(createTimes);
|
|
|
+
|
|
|
+ /* 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();
|
|
|
+ // 20260915 修改设备利用率 计算逻辑 分母修改为日报总数量
|
|
|
+ BigDecimal rate = BigDecimal.ZERO;
|
|
|
+ if (dateTotalReportPair.containsKey(date)) {
|
|
|
+ Integer totalReportNum = dateTotalReportPair.get(date);
|
|
|
+ BigDecimal total = new BigDecimal(totalReportNum);
|
|
|
+ BigDecimal current = new BigDecimal(dateDeptIdCount);
|
|
|
+ rate = current.divide(total, 4, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+ statistics.setUtilizationRate(rate);
|
|
|
+ }
|
|
|
+ result.add(statistics);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据日报日期获取统计月份分组,格式:yyyy-MM
|
|
|
+ * 规则:上月26日 ~ 本月25日 算作本月
|
|
|
+ *
|
|
|
+ * 例如:
|
|
|
+ * 2026-04-26 ~ 2026-05-25 -> 2026-05
|
|
|
+ * 2026-05-26 ~ 2026-06-25 -> 2026-06
|
|
|
+ * 2026-09-20 -> 2026-09
|
|
|
+ *
|
|
|
+ * @param reportTime 日报创建时间
|
|
|
+ * @return 统计月份,格式 yyyy-MM
|
|
|
+ */
|
|
|
+ private String getReportMonthGroup(LocalDateTime reportTime) {
|
|
|
+ if (reportTime == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDate reportDate = reportTime.toLocalDate();
|
|
|
+ YearMonth yearMonth = YearMonth.from(reportDate);
|
|
|
+
|
|
|
+ // 26号及以后,归属下个月
|
|
|
+ if (reportDate.getDayOfMonth() >= 26) {
|
|
|
+ yearMonth = yearMonth.plusMonths(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // YearMonth.toString() 默认就是 yyyy-MM
|
|
|
+ return yearMonth.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据时间筛选区间获取所包含的统计月份列表(升序)
|
|
|
+ * 统计月规则:上月26日 ~ 本月25日 算作本月
|
|
|
+ * 例如:2026-04-26 ~ 2026-05-25 -> 2026-05
|
|
|
+ *
|
|
|
+ * @param createTimes 时间筛选区间,[开始时间, 结束时间]
|
|
|
+ * @return 月份字符串列表,格式:yyyy-MM,例如 ["2026-05", "2026-06"]
|
|
|
+ */
|
|
|
+ public List<String> getMonthRangeList(LocalDateTime[] createTimes) {
|
|
|
+ List<String> monthRangeList = new ArrayList<>();
|
|
|
+ if (createTimes == null || createTimes.length < 2
|
|
|
+ || createTimes[0] == null || createTimes[1] == null) {
|
|
|
+ return monthRangeList;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算起始和结束的统计月
|
|
|
+ YearMonth startMonth = getStatisticsMonth(createTimes[0].toLocalDate());
|
|
|
+ YearMonth endMonth = getStatisticsMonth(createTimes[1].toLocalDate());
|
|
|
+
|
|
|
+ // 按月份升序生成
|
|
|
+ for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
|
|
|
+ monthRangeList.add(month.toString()); // YearMonth.toString() 返回 yyyy-MM
|
|
|
+ }
|
|
|
+ return monthRangeList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取日期所属的统计月
|
|
|
+ * 规则:day >= 26 归属下个月,day <= 25 归属当前月
|
|
|
+ */
|
|
|
+ private YearMonth getStatisticsMonth(LocalDate date) {
|
|
|
+ return date.getDayOfMonth() >= 26
|
|
|
+ ? YearMonth.from(date).plusMonths(1)
|
|
|
+ : YearMonth.from(date);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 按 队伍 维度统计数据
|
|
|
* @param dailyReports 日报数据列表
|
|
|
@@ -4201,6 +4553,189 @@ public class IotRhDailyReportServiceImpl implements IotRhDailyReportService {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 按 队伍 月度 维度统计数据
|
|
|
+ * @param dailyReports 日报数据列表
|
|
|
+ * @param deptId 项目部ID 或 队伍id(塔河项目部 HY-A1)
|
|
|
+ * @return 队伍 月份 维度统计结果列表
|
|
|
+ */
|
|
|
+ private List<IotRhDailyReportPolylineVO> monthPolylineStatisticsByProjectDepartment(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) {
|