|
|
@@ -127,6 +127,7 @@ import java.time.format.DateTimeFormatter;
|
|
|
import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
+import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
|
|
|
@@ -859,6 +860,120 @@ public class IotStaticController {
|
|
|
return success(ImmutableMap.of("xAxis", xAxis, "series", outData));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 最近6个月的运维成本 维修费用 保养费用
|
|
|
+ * @param dept
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @GetMapping("/rh/month-ywcb/{dept}")
|
|
|
+ @PermitAll
|
|
|
+ public CommonResult<Map<String, Object>> getMonthYwcbStat(@PathVariable("dept") String dept) {
|
|
|
+ Set<Long> ids = getDeptIds(dept);
|
|
|
+
|
|
|
+ // 最近6个自然月,包含当前月:2026-09 => 2026-04 ~ 2026-09
|
|
|
+ LocalDateTime[] range = lastSixMonthsRange();
|
|
|
+
|
|
|
+ // 定义月份格式化器
|
|
|
+ DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
|
+
|
|
|
+ // 查询维修成本
|
|
|
+ IotMaintainPageReqVO maintainPageReqVO = new IotMaintainPageReqVO();
|
|
|
+ maintainPageReqVO.setDeptIds(ids);
|
|
|
+ maintainPageReqVO.setCreateTime(range);
|
|
|
+ maintainPageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
|
|
+ List<IotMaintainDO> repairOrders = iotMaintainService.getIotMaintainPage(maintainPageReqVO).getList();
|
|
|
+ // 计算每个月的维修费用
|
|
|
+ // 2. 计算每个月的维修费用 key: 2026-04
|
|
|
+ LinkedHashMap<String, BigDecimal> repairMonthMap =
|
|
|
+ sumByMonth(repairOrders, IotMaintainDO::getCreateTime, IotMaintainDO::getMaintainFee);
|
|
|
+
|
|
|
+ // 查询保养成本
|
|
|
+ IotMainWorkOrderPageReqVO workOrderReqVO = new IotMainWorkOrderPageReqVO();
|
|
|
+ workOrderReqVO.setDeptIds(ids);
|
|
|
+ workOrderReqVO.setCreateTime(range);
|
|
|
+ List<IotMainWorkOrderDO> workOrders = iotMainWorkOrderService.workOrders(workOrderReqVO);
|
|
|
+ // 计算每个月的保养费用
|
|
|
+ // 4. 计算每个月的保养费用 key: 2026-04
|
|
|
+ LinkedHashMap<String, BigDecimal> maintainMonthMap =
|
|
|
+ sumByMonth(workOrders, IotMainWorkOrderDO::getCreateTime, IotMainWorkOrderDO::getCost);
|
|
|
+
|
|
|
+ // 按月份分组汇总保养费用
|
|
|
+ Map<String, BigDecimal> monthlyFeeMap = workOrders.stream()
|
|
|
+ .filter(Objects::nonNull) // 过滤掉 null 工单(可选)
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ order -> order.getCreateTime().format(monthFormatter), // 分组键:yyyy-MM
|
|
|
+ TreeMap::new, // 使用 TreeMap 保证月份有序(可选)
|
|
|
+ Collectors.reducing(
|
|
|
+ BigDecimal.ZERO, // 初始值
|
|
|
+ order -> Optional.ofNullable(order.getCost()).orElse(BigDecimal.ZERO), // 处理 null
|
|
|
+ BigDecimal::add // 累加
|
|
|
+ )
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 维修费用 + 保养费用,按月份合并
|
|
|
+ LinkedHashMap<String, BigDecimal> totalMap = new LinkedHashMap<>();
|
|
|
+ YearMonth now = YearMonth.now();
|
|
|
+ for (int i = 5; i >= 0; i--) {
|
|
|
+ totalMap.put(now.minusMonths(i).toString(), BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ repairMonthMap.forEach((month, cost) -> totalMap.merge(month, cost, BigDecimal::add));
|
|
|
+ maintainMonthMap.forEach((month, cost) -> totalMap.merge(month, cost, BigDecimal::add));
|
|
|
+
|
|
|
+ LinkedList<Object> xAxis = new LinkedList<>(totalMap.keySet());
|
|
|
+ LinkedList<Object> outData = new LinkedList<>(totalMap.values());
|
|
|
+
|
|
|
+ return success(ImmutableMap.of("xAxis", xAxis, "series", outData));
|
|
|
+ }
|
|
|
+
|
|
|
+ private <T> LinkedHashMap<String, BigDecimal> sumByMonth(List<T> list,
|
|
|
+ Function<T, LocalDateTime> timeGetter,
|
|
|
+ Function<T, BigDecimal> amountGetter) {
|
|
|
+ return list.stream()
|
|
|
+ .filter(o -> timeGetter.apply(o) != null)
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ o -> YearMonth.from(timeGetter.apply(o)).toString(),
|
|
|
+ LinkedHashMap::new,
|
|
|
+ Collectors.reducing(BigDecimal.ZERO,
|
|
|
+ o -> Optional.ofNullable(amountGetter.apply(o)).orElse(BigDecimal.ZERO),
|
|
|
+ BigDecimal::add)));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按月份统计成本,包含当前月。
|
|
|
+ */
|
|
|
+ private <T> LinkedHashMap<String, BigDecimal> countCostByMonth(
|
|
|
+ List<T> records,
|
|
|
+ Function<T, LocalDateTime> timeGetter,
|
|
|
+ Function<T, BigDecimal> amountGetter,
|
|
|
+ int months) {
|
|
|
+
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
|
+
|
|
|
+ YearMonth endMonth = YearMonth.now();
|
|
|
+ YearMonth startMonth = endMonth.minusMonths(months - 1L);
|
|
|
+
|
|
|
+ Map<String, BigDecimal> amountMap = records.stream()
|
|
|
+ .filter(r -> timeGetter.apply(r) != null)
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ r -> timeGetter.apply(r).format(formatter),
|
|
|
+ Collectors.reducing(
|
|
|
+ BigDecimal.ZERO,
|
|
|
+ r -> {
|
|
|
+ BigDecimal amount = amountGetter.apply(r);
|
|
|
+ return amount == null ? BigDecimal.ZERO : amount;
|
|
|
+ },
|
|
|
+ BigDecimal::add
|
|
|
+ )
|
|
|
+ ));
|
|
|
+
|
|
|
+ LinkedHashMap<String, BigDecimal> result = new LinkedHashMap<>();
|
|
|
+ for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
|
|
|
+ String key = month.format(formatter);
|
|
|
+ result.put(key, amountMap.getOrDefault(key, BigDecimal.ZERO));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
@GetMapping("/rh/order/{dept}")
|
|
|
@PermitAll
|
|
|
public CommonResult<Map<String, Object>> getOrderNumberStat(@PathVariable("dept") String dept) {
|