|
@@ -0,0 +1,1579 @@
|
|
|
+package org.jeecg.modules.productionConsume.service.impl;
|
|
|
+
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.jeecg.common.util.oConvertUtils;
|
|
|
+import org.jeecg.modules.deviceLesm.mapper.DeviceInformationMapper;
|
|
|
+import org.jeecg.modules.deviceLesm.mapper.DeviceRegionMapper;
|
|
|
+import org.jeecg.modules.fpgLeanModel.entity.ElectricityControlReport;
|
|
|
+import org.jeecg.modules.fpgLeanModel.entity.ExportQueryDTO;
|
|
|
+import org.jeecg.modules.productionConsume.entity.AggregatedData;
|
|
|
+import org.jeecg.modules.productionConsume.entity.ProductionConsume;
|
|
|
+import org.jeecg.modules.productionConsume.entity.ProductionConsumeReport;
|
|
|
+import org.jeecg.modules.productionConsume.mapper.ProductionConsumeMapper;
|
|
|
+import org.jeecg.modules.productionConsume.service.IProductionConsumeService;
|
|
|
+import org.jeecg.modules.systemConfig.peaksAndValleysTimeConfig.entity.PeaksAndValleysTimeConfig;
|
|
|
+import org.jeecg.modules.systemConfig.peaksAndValleysTimeConfig.service.IPeaksAndValleysTimeConfigService;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.text.ParseException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class ProductionConsumeServiceImpl extends ServiceImpl<ProductionConsumeMapper, ProductionConsume> implements IProductionConsumeService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DeviceInformationMapper deviceInformationMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DeviceRegionMapper deviceRegionMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IPeaksAndValleysTimeConfigService peaksAndValleysTimeConfigService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public JSONObject productionConsumeDay(ExportQueryDTO queryDTO) {
|
|
|
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+ JSONObject result = new JSONObject();
|
|
|
+
|
|
|
+ List<ProductionConsumeReport> finalResult = new ArrayList<>();
|
|
|
+
|
|
|
+ // 设置日期范围
|
|
|
+ LocalDate startDate, endDate;
|
|
|
+ String month = queryDTO.getMonth();
|
|
|
+ if (month == null || month.isEmpty()) {
|
|
|
+ LocalDate currentDate = LocalDate.now();
|
|
|
+ startDate = currentDate.withDayOfMonth(1);
|
|
|
+ endDate = startDate.plusMonths(1);
|
|
|
+ } else {
|
|
|
+ startDate = LocalDate.parse(month + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
|
+ endDate = startDate.plusMonths(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<ProductionConsume> consumeQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ consumeQueryWrapper.between(ProductionConsume::getCreateTime, startDate, endDate);
|
|
|
+ List<ProductionConsume> productionConsumeList = baseMapper.selectList(consumeQueryWrapper);
|
|
|
+
|
|
|
+ if (oConvertUtils.listIsEmpty(productionConsumeList)) {
|
|
|
+ log.info("数据库生产消耗数据查询为空,峰平谷报表导出失败!");
|
|
|
+ result.put("data", new JSONArray());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取尖峰平谷时段配置
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksAndValleysTimeConfiglist = peaksAndValleysTimeConfigService.list();
|
|
|
+ List<PeaksAndValleysTimeConfig> topsTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "tops".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "peaks".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> flatTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "flat".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> valleysTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "valleys".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ JSONArray jsonResult = new JSONArray();
|
|
|
+
|
|
|
+ // 按 deviceTitle 和 regionTitle 同时分组
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDeviceAndRegion = productionConsumeList.stream()
|
|
|
+ .collect(Collectors.groupingBy(productionConsume ->
|
|
|
+ productionConsume.getRegionTitle() + "_" + productionConsume.getDeviceTitle()
|
|
|
+ ));
|
|
|
+
|
|
|
+ List<String> uniqueDeviceRegionKeys = groupedByDeviceAndRegion.keySet().stream()
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+
|
|
|
+ for (String device : uniqueDeviceRegionKeys) {
|
|
|
+ String[] parts = device.split("_"); // 分割键
|
|
|
+ String regionTitle = parts[0];
|
|
|
+ String deviceTitle = parts[1];
|
|
|
+ List<ProductionConsume> filteredList = productionConsumeList.stream()
|
|
|
+ .filter(p -> deviceTitle.equals(p.getDeviceTitle()) && regionTitle.equals(p.getRegionTitle()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDate = filteredList.stream()
|
|
|
+ .collect(Collectors.groupingBy(p -> dateFormat.format(p.getCreateTime())));
|
|
|
+
|
|
|
+ // 对每个日期的记录处理
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ topsTimeConfigs.forEach(config -> {
|
|
|
+
|
|
|
+ BigDecimal totalActivePowerDiff = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ String startTimeStr = date + " " + config.getStartTime(); // 拼接开始时间
|
|
|
+ String endTimeStr = date + " " + config.getEndTime(); // 拼接结束时间
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime)) // 按 createTime 排序
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("尖");
|
|
|
+ productionConsumeReport.setOrderIndex(1);
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff = totalActivePowerDiff.add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ totalActivePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (totalActivePowerDiff.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ peaksTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("峰");
|
|
|
+ productionConsumeReport.setOrderIndex(2);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ flatTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("平");
|
|
|
+ productionConsumeReport.setOrderIndex(3);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ final BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 累加差值
|
|
|
+
|
|
|
+
|
|
|
+ // 处理 valleysTimeConfigs 特殊时段
|
|
|
+ valleysTimeConfigs.forEach(config -> {
|
|
|
+ try {
|
|
|
+ // 第一部分:date + 00:00:00 到 date + 06:59:59
|
|
|
+ Date startTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 00:00:00");
|
|
|
+ Date endTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getEndTime());
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems1 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime1) && !item.getCreateTime().after(endTime1))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems1.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems1.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems1.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems1.get(rangeItems1.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二部分:date + 23:00:00 到 date + 23:59:59
|
|
|
+ Date startTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getStartTime());
|
|
|
+ Date endTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 23:59:59");
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems2 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime2) && !item.getCreateTime().after(endTime2))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems2.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems2.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems2.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems2.get(rangeItems2.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("谷");
|
|
|
+ productionConsumeReport.setOrderIndex(4);
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Map<String, Map<String, List<ProductionConsumeReport>>>> groupedByRegionDeviceAndDate = finalResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(ProductionConsumeReport::getRegionTitle,
|
|
|
+ Collectors.groupingBy(ProductionConsumeReport::getDeviceTitle,
|
|
|
+ Collectors.groupingBy(ProductionConsumeReport::getCreateTime))));
|
|
|
+
|
|
|
+ // 遍历每个区域、设备和日期组合
|
|
|
+ groupedByRegionDeviceAndDate.forEach((regionTitle, deviceMap) -> {
|
|
|
+ deviceMap.forEach((deviceTitle, dateMap) -> {
|
|
|
+ dateMap.forEach((date, reports) -> {
|
|
|
+ // 计算当天总值
|
|
|
+ BigDecimal totalValue = reports.stream()
|
|
|
+ .map(ProductionConsumeReport::getValue)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ // 如果总值为 0,则所有占比设为 0
|
|
|
+ if (totalValue.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ // 计算每条记录的占比
|
|
|
+ reports.forEach(report -> {
|
|
|
+ BigDecimal proportion = report.getValue().divide(totalValue, 4, RoundingMode.HALF_UP); // 保留4位小数
|
|
|
+ report.setProportion(proportion);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 设置占比为 0
|
|
|
+ reports.forEach(report -> report.setProportion(BigDecimal.ZERO));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ jsonResult = JSON.parseArray(JSON.toJSONString(finalResult));
|
|
|
+ log.info("积木报表导出总数:{}", jsonResult.size());
|
|
|
+ result.put("data", jsonResult);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public JSONObject productionConsumeMonth(ExportQueryDTO queryDTO) {
|
|
|
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+
|
|
|
+ List<ProductionConsumeReport> finalResult = new ArrayList<>();
|
|
|
+
|
|
|
+ // 定义日期格式
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+ JSONObject result = new JSONObject();
|
|
|
+
|
|
|
+ // 获取 queryDTO 中的 year 字段
|
|
|
+ String year = queryDTO.getYear();
|
|
|
+ LocalDate startDate, endDate;
|
|
|
+
|
|
|
+ // 判断是否传入了 year 参数
|
|
|
+ if (year == null || year.isEmpty()) {
|
|
|
+ // 如果 year 为空,默认查询当前年的数据
|
|
|
+ LocalDate currentDate = LocalDate.now();
|
|
|
+ startDate = currentDate.withDayOfYear(1); // 当前年的第一天
|
|
|
+ endDate = startDate.plusYears(1); // 下一年的第一天
|
|
|
+ } else {
|
|
|
+ // 如果 year 不为空,解析 year 为年范围
|
|
|
+ startDate = LocalDate.parse(year + "-01-01", formatter); // 年份的第一天
|
|
|
+ endDate = startDate.plusYears(1); // 下一年的第一天
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<ProductionConsume> consumeQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ consumeQueryWrapper.between(ProductionConsume::getCreateTime, startDate, endDate);
|
|
|
+ List<ProductionConsume> productionConsumeList = baseMapper.selectList(consumeQueryWrapper);
|
|
|
+
|
|
|
+ if (oConvertUtils.listIsEmpty(productionConsumeList)) {
|
|
|
+ log.info("数据库生产消耗数据查询为空,峰平谷报表导出失败!");
|
|
|
+ result.put("data", new JSONArray());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取尖峰平谷时段配置
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksAndValleysTimeConfiglist = peaksAndValleysTimeConfigService.list();
|
|
|
+ List<PeaksAndValleysTimeConfig> topsTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "tops".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "peaks".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> flatTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "flat".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> valleysTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "valleys".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ JSONArray jsonResult = new JSONArray();
|
|
|
+
|
|
|
+ // 按 deviceTitle 和 regionTitle 同时分组
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDeviceAndRegion = productionConsumeList.stream()
|
|
|
+ .collect(Collectors.groupingBy(productionConsume ->
|
|
|
+ productionConsume.getRegionTitle() + "_" + productionConsume.getDeviceTitle()
|
|
|
+ ));
|
|
|
+
|
|
|
+ List<String> uniqueDeviceRegionKeys = groupedByDeviceAndRegion.keySet().stream()
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ for (String device : uniqueDeviceRegionKeys) {
|
|
|
+ String[] parts = device.split("_"); // 分割键
|
|
|
+ String regionTitle = parts[0];
|
|
|
+ String deviceTitle = parts[1];
|
|
|
+ List<ProductionConsume> filteredList = productionConsumeList.stream()
|
|
|
+ .filter(p -> deviceTitle.equals(p.getDeviceTitle()) && regionTitle.equals(p.getRegionTitle()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDate = filteredList.stream()
|
|
|
+ .collect(Collectors.groupingBy(p -> dateFormat.format(p.getCreateTime())));
|
|
|
+
|
|
|
+ // 对每个日期的记录处理
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ topsTimeConfigs.forEach(config -> {
|
|
|
+
|
|
|
+ BigDecimal totalActivePowerDiff = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ String startTimeStr = date + " " + config.getStartTime(); // 拼接开始时间
|
|
|
+ String endTimeStr = date + " " + config.getEndTime(); // 拼接结束时间
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime)) // 按 createTime 排序
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("尖");
|
|
|
+ productionConsumeReport.setOrderIndex(1);
|
|
|
+
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff = totalActivePowerDiff.add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ totalActivePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (totalActivePowerDiff.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ peaksTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("峰");
|
|
|
+ productionConsumeReport.setOrderIndex(2);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ flatTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("平");
|
|
|
+ productionConsumeReport.setOrderIndex(3);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ final BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 累加差值
|
|
|
+
|
|
|
+
|
|
|
+ // 处理 valleysTimeConfigs 特殊时段
|
|
|
+ valleysTimeConfigs.forEach(config -> {
|
|
|
+ try {
|
|
|
+ // 第一部分:date + 00:00:00 到 date + 06:59:59
|
|
|
+ Date startTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 00:00:00");
|
|
|
+ Date endTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getEndTime());
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems1 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime1) && !item.getCreateTime().after(endTime1))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems1.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems1.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems1.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems1.get(rangeItems1.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二部分:date + 23:00:00 到 date + 23:59:59
|
|
|
+ Date startTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getStartTime());
|
|
|
+ Date endTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 23:59:59");
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems2 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime2) && !item.getCreateTime().after(endTime2))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems2.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems2.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems2.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems2.get(rangeItems2.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("谷");
|
|
|
+ productionConsumeReport.setOrderIndex(4);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 按月份、deviceTitle、regionTitle 和 key1 分组并累加 value,同时保留 orderIndex
|
|
|
+ Map<String, Map<String, Map<String, Map<String, AggregatedData>>>> groupedResult = finalResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ report -> report.getCreateTime().substring(0, 7), // 按 yyyy-MM 分组
|
|
|
+ Collectors.groupingBy(
|
|
|
+ ProductionConsumeReport::getDeviceTitle, // 按 deviceTitle 分组
|
|
|
+ Collectors.groupingBy(
|
|
|
+ ProductionConsumeReport::getRegionTitle, // 按 regionTitle 分组
|
|
|
+ Collectors.groupingBy(
|
|
|
+ ProductionConsumeReport::getKey1, // 按 key1 分组
|
|
|
+ Collectors.collectingAndThen(
|
|
|
+ Collectors.toList(),
|
|
|
+ list -> {
|
|
|
+ // 获取 total value 的累加值
|
|
|
+ BigDecimal totalValue = list.stream()
|
|
|
+ .map(ProductionConsumeReport::getValue)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ // 获取 orderIndex 的第一个值 (每个组内 orderIndex 相同)
|
|
|
+ int orderIndex = list.get(0).getOrderIndex();
|
|
|
+
|
|
|
+ return new AggregatedData(totalValue, orderIndex);
|
|
|
+ }
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ ));
|
|
|
+
|
|
|
+
|
|
|
+ // 将结果转化为新的集合
|
|
|
+ List<ProductionConsumeReport> monthlyAggregatedResult = new ArrayList<>();
|
|
|
+ groupedResult.forEach((month, deviceMap) -> {
|
|
|
+ deviceMap.forEach((deviceTitle, regionMap) -> {
|
|
|
+ regionMap.forEach((regionTitle, key1Map) -> {
|
|
|
+ key1Map.forEach((key1, aggregatedData) -> {
|
|
|
+ // 获取累加后的 value 和 orderIndex
|
|
|
+ BigDecimal totalValue = aggregatedData.getTotalValue();
|
|
|
+ int orderIndex = aggregatedData.getOrderIndex();
|
|
|
+
|
|
|
+ // 创建一个新的 ProductionConsumeReport 对象
|
|
|
+ ProductionConsumeReport aggregatedReport = new ProductionConsumeReport();
|
|
|
+ aggregatedReport.setCreateTime(month);
|
|
|
+ aggregatedReport.setYear(month.substring(0, 4) + "年");
|
|
|
+ aggregatedReport.setDeviceTitle(deviceTitle);
|
|
|
+ aggregatedReport.setRegionTitle(regionTitle);
|
|
|
+ aggregatedReport.setKey1(key1);
|
|
|
+ aggregatedReport.setValue(totalValue);
|
|
|
+ aggregatedReport.setOrderIndex(orderIndex);
|
|
|
+
|
|
|
+ // 添加到结果集合
|
|
|
+ monthlyAggregatedResult.add(aggregatedReport);
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 按设备和日期分组
|
|
|
+ Map<String, Map<String, List<ProductionConsumeReport>>> groupedByDeviceAndDate = monthlyAggregatedResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(ProductionConsumeReport::getDeviceTitle,
|
|
|
+ Collectors.groupingBy(ProductionConsumeReport::getCreateTime)));
|
|
|
+
|
|
|
+ // 遍历每个设备和日期组合
|
|
|
+ groupedByDeviceAndDate.forEach((deviceTitle, dateMap) -> {
|
|
|
+ dateMap.forEach((date, reports) -> {
|
|
|
+ // 计算当天总值
|
|
|
+ BigDecimal totalValue = reports.stream()
|
|
|
+ .map(ProductionConsumeReport::getValue)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ // 如果总值为 0,则所有占比设为 0
|
|
|
+ if (totalValue.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ // 计算每条记录的占比
|
|
|
+ reports.forEach(report -> {
|
|
|
+ BigDecimal proportion = report.getValue().divide(totalValue, 4, RoundingMode.HALF_UP); // 保留4位小数
|
|
|
+ report.setProportion(proportion);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 设置占比为 0
|
|
|
+ reports.forEach(report -> report.setProportion(BigDecimal.ZERO));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ jsonResult = JSON.parseArray(JSON.toJSONString(monthlyAggregatedResult));
|
|
|
+ log.info("积木报表导出总数:{}", jsonResult.size());
|
|
|
+ result.put("data", jsonResult);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public JSONObject productionConsumeRegionDay(ExportQueryDTO queryDTO) {
|
|
|
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+ // 定义日期格式
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ JSONObject result = new JSONObject();
|
|
|
+
|
|
|
+ List<ProductionConsumeReport> finalResult = new ArrayList<>();
|
|
|
+
|
|
|
+ // 设置日期范围
|
|
|
+ LocalDate startDate, endDate;
|
|
|
+ String month = queryDTO.getMonth();
|
|
|
+ if (month == null || month.isEmpty()) {
|
|
|
+ LocalDate currentDate = LocalDate.now();
|
|
|
+ startDate = currentDate.withDayOfMonth(1);
|
|
|
+ endDate = startDate.plusMonths(1);
|
|
|
+ } else {
|
|
|
+ startDate = LocalDate.parse(month + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
|
|
+ endDate = startDate.plusMonths(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<ProductionConsume> consumeQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ consumeQueryWrapper.between(ProductionConsume::getCreateTime, startDate, endDate);
|
|
|
+ List<ProductionConsume> productionConsumeList = baseMapper.selectList(consumeQueryWrapper);
|
|
|
+
|
|
|
+ if (oConvertUtils.listIsEmpty(productionConsumeList)) {
|
|
|
+ log.info("数据库生产消耗数据查询为空,峰平谷报表导出失败!");
|
|
|
+ result.put("data", new JSONArray());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取尖峰平谷时段配置
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksAndValleysTimeConfiglist = peaksAndValleysTimeConfigService.list();
|
|
|
+ List<PeaksAndValleysTimeConfig> topsTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "tops".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "peaks".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> flatTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "flat".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> valleysTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "valleys".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ JSONArray jsonResult = new JSONArray();
|
|
|
+
|
|
|
+ // 按 deviceTitle 和 regionTitle 同时分组
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDeviceAndRegion = productionConsumeList.stream()
|
|
|
+ .collect(Collectors.groupingBy(productionConsume ->
|
|
|
+ productionConsume.getRegionTitle() + "_" + productionConsume.getDeviceTitle()
|
|
|
+ ));
|
|
|
+
|
|
|
+ List<String> uniqueDeviceRegionKeys = groupedByDeviceAndRegion.keySet().stream()
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+
|
|
|
+ for (String device : uniqueDeviceRegionKeys) {
|
|
|
+ String[] parts = device.split("_"); // 分割键
|
|
|
+ String regionTitle = parts[0];
|
|
|
+ String deviceTitle = parts[1];
|
|
|
+ List<ProductionConsume> filteredList = productionConsumeList.stream()
|
|
|
+ .filter(p -> deviceTitle.equals(p.getDeviceTitle()) && regionTitle.equals(p.getRegionTitle()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDate = filteredList.stream()
|
|
|
+ .collect(Collectors.groupingBy(p -> dateFormat.format(p.getCreateTime())));
|
|
|
+
|
|
|
+ // 对每个日期的记录处理
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ topsTimeConfigs.forEach(config -> {
|
|
|
+
|
|
|
+ BigDecimal totalActivePowerDiff = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ String startTimeStr = date + " " + config.getStartTime(); // 拼接开始时间
|
|
|
+ String endTimeStr = date + " " + config.getEndTime(); // 拼接结束时间
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime)) // 按 createTime 排序
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("尖");
|
|
|
+ productionConsumeReport.setOrderIndex(1);
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff = totalActivePowerDiff.add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ totalActivePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (totalActivePowerDiff.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ peaksTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("峰");
|
|
|
+ productionConsumeReport.setOrderIndex(2);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ flatTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("平");
|
|
|
+ productionConsumeReport.setOrderIndex(3);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ final BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 累加差值
|
|
|
+
|
|
|
+
|
|
|
+ // 处理 valleysTimeConfigs 特殊时段
|
|
|
+ valleysTimeConfigs.forEach(config -> {
|
|
|
+ try {
|
|
|
+ // 第一部分:date + 00:00:00 到 date + 06:59:59
|
|
|
+ Date startTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 00:00:00");
|
|
|
+ Date endTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getEndTime());
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems1 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime1) && !item.getCreateTime().after(endTime1))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems1.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems1.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems1.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems1.get(rangeItems1.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二部分:date + 23:00:00 到 date + 23:59:59
|
|
|
+ Date startTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getStartTime());
|
|
|
+ Date endTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 23:59:59");
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems2 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime2) && !item.getCreateTime().after(endTime2))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems2.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems2.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems2.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems2.get(rangeItems2.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setMonth(date.substring(0, 7));
|
|
|
+ productionConsumeReport.setKey1("谷");
|
|
|
+ productionConsumeReport.setOrderIndex(4);
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, BigDecimal> dailyTotals = finalResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(report -> report.getCreateTime() + "_" + report.getRegionTitle(),
|
|
|
+ Collectors.mapping(ProductionConsumeReport::getValue,
|
|
|
+ Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
|
|
|
+
|
|
|
+ // 按 createTime 和 regionTitle 分组
|
|
|
+ Map<String, Map<String, List<ProductionConsumeReport>>> groupedData = finalResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ ProductionConsumeReport::getCreateTime, // 按 createTime 分组
|
|
|
+ Collectors.groupingBy(ProductionConsumeReport::getRegionTitle) // 按 CompanyName 分组
|
|
|
+ ));
|
|
|
+
|
|
|
+ JSONArray resultArray = new JSONArray();
|
|
|
+
|
|
|
+ groupedData.forEach((createTime, companyGroup) -> companyGroup.forEach((regionTitle, reports) -> {
|
|
|
+ LocalDate date = LocalDate.parse(createTime, formatter);
|
|
|
+ String formattedDate = date.getYear() + "年" + date.getMonthValue() + "月";
|
|
|
+ String yearFormattedDate = date.getYear() + "年";
|
|
|
+
|
|
|
+ BigDecimal dailyTotal = dailyTotals.get(createTime + "_" + regionTitle); // 获取当天总值
|
|
|
+
|
|
|
+ Map<String, BigDecimal> keyTotals = reports.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ ProductionConsumeReport::getKey1,
|
|
|
+ Collectors.mapping(ProductionConsumeReport::getValue,
|
|
|
+ Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))
|
|
|
+ ));
|
|
|
+
|
|
|
+ keyTotals.forEach((key, totalValue) -> {
|
|
|
+ ProductionConsumeReport summaryReport = new ProductionConsumeReport();
|
|
|
+ summaryReport.setCreateTime(createTime); // 设置日期
|
|
|
+ summaryReport.setMonth(formattedDate);
|
|
|
+ summaryReport.setYear(yearFormattedDate);
|
|
|
+ summaryReport.setRegionTitle(regionTitle);
|
|
|
+ summaryReport.setKey1(key);
|
|
|
+ summaryReport.setValue(totalValue);
|
|
|
+ summaryReport.setTotalNum(dailyTotal.stripTrailingZeros()); // 设置当天总值
|
|
|
+
|
|
|
+ // 设置 key1 对应的 orderIndex
|
|
|
+ int orderIndex;
|
|
|
+ switch (summaryReport.getKey1()) {
|
|
|
+ case "尖":
|
|
|
+ orderIndex = 1;
|
|
|
+ break;
|
|
|
+ case "峰":
|
|
|
+ orderIndex = 2;
|
|
|
+ break;
|
|
|
+ case "平":
|
|
|
+ orderIndex = 3;
|
|
|
+ break;
|
|
|
+ case "谷":
|
|
|
+ orderIndex = 4;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ orderIndex = 5; // 默认值,防止其他 key 情况
|
|
|
+ }
|
|
|
+ summaryReport.setOrderIndex(orderIndex);
|
|
|
+ // 计算占比
|
|
|
+ summaryReport.setProportion(totalValue.divide(dailyTotal, 6, RoundingMode.HALF_UP).stripTrailingZeros());
|
|
|
+ resultArray.add(summaryReport);
|
|
|
+ });
|
|
|
+ }));
|
|
|
+
|
|
|
+
|
|
|
+ jsonResult = JSON.parseArray(JSON.toJSONString(resultArray));
|
|
|
+ log.info("积木报表导出总数:{}", jsonResult.size());
|
|
|
+ result.put("data", jsonResult);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public JSONObject productionConsumeRegionMonth(ExportQueryDTO queryDTO) {
|
|
|
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
|
|
+
|
|
|
+ List<ProductionConsumeReport> finalResult = new ArrayList<>();
|
|
|
+
|
|
|
+ // 定义日期格式
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+ JSONObject result = new JSONObject();
|
|
|
+
|
|
|
+ // 获取 queryDTO 中的 year 字段
|
|
|
+ String year = queryDTO.getYear();
|
|
|
+ LocalDate startDate, endDate;
|
|
|
+
|
|
|
+ // 判断是否传入了 year 参数
|
|
|
+ if (year == null || year.isEmpty()) {
|
|
|
+ // 如果 year 为空,默认查询当前年的数据
|
|
|
+ LocalDate currentDate = LocalDate.now();
|
|
|
+ startDate = currentDate.withDayOfYear(1); // 当前年的第一天
|
|
|
+ endDate = startDate.plusYears(1); // 下一年的第一天
|
|
|
+ } else {
|
|
|
+ // 如果 year 不为空,解析 year 为年范围
|
|
|
+ startDate = LocalDate.parse(year + "-01-01", formatter); // 年份的第一天
|
|
|
+ endDate = startDate.plusYears(1); // 下一年的第一天
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<ProductionConsume> consumeQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ consumeQueryWrapper.between(ProductionConsume::getCreateTime, startDate, endDate);
|
|
|
+ List<ProductionConsume> productionConsumeList = baseMapper.selectList(consumeQueryWrapper);
|
|
|
+
|
|
|
+ if (oConvertUtils.listIsEmpty(productionConsumeList)) {
|
|
|
+ log.info("数据库生产消耗数据查询为空,峰平谷报表导出失败!");
|
|
|
+ result.put("data", new JSONArray());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取尖峰平谷时段配置
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksAndValleysTimeConfiglist = peaksAndValleysTimeConfigService.list();
|
|
|
+ List<PeaksAndValleysTimeConfig> topsTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "tops".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> peaksTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "peaks".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> flatTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "flat".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<PeaksAndValleysTimeConfig> valleysTimeConfigs = peaksAndValleysTimeConfiglist.stream()
|
|
|
+ .filter(config -> "valleys".equals(config.getType()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ JSONArray jsonResult = new JSONArray();
|
|
|
+
|
|
|
+ // 按 deviceTitle 和 regionTitle 同时分组
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDeviceAndRegion = productionConsumeList.stream()
|
|
|
+ .collect(Collectors.groupingBy(productionConsume ->
|
|
|
+ productionConsume.getRegionTitle() + "_" + productionConsume.getDeviceTitle()
|
|
|
+ ));
|
|
|
+
|
|
|
+ List<String> uniqueDeviceRegionKeys = groupedByDeviceAndRegion.keySet().stream()
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ for (String device : uniqueDeviceRegionKeys) {
|
|
|
+ String[] parts = device.split("_"); // 分割键
|
|
|
+ String regionTitle = parts[0];
|
|
|
+ String deviceTitle = parts[1];
|
|
|
+ List<ProductionConsume> filteredList = productionConsumeList.stream()
|
|
|
+ .filter(p -> deviceTitle.equals(p.getDeviceTitle()) && regionTitle.equals(p.getRegionTitle()))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ Map<String, List<ProductionConsume>> groupedByDate = filteredList.stream()
|
|
|
+ .collect(Collectors.groupingBy(p -> dateFormat.format(p.getCreateTime())));
|
|
|
+
|
|
|
+ // 对每个日期的记录处理
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ topsTimeConfigs.forEach(config -> {
|
|
|
+
|
|
|
+ BigDecimal totalActivePowerDiff = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ String startTimeStr = date + " " + config.getStartTime(); // 拼接开始时间
|
|
|
+ String endTimeStr = date + " " + config.getEndTime(); // 拼接结束时间
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime)) // 按 createTime 排序
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("尖");
|
|
|
+ productionConsumeReport.setOrderIndex(1);
|
|
|
+
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff = totalActivePowerDiff.add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ totalActivePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (totalActivePowerDiff.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ peaksTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("峰");
|
|
|
+ productionConsumeReport.setOrderIndex(2);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 使用数组作为可变容器
|
|
|
+
|
|
|
+ flatTimeConfigs.forEach(config -> {
|
|
|
+ String startTimeStr = date + " " + config.getStartTime();
|
|
|
+ String endTimeStr = date + " " + config.getEndTime();
|
|
|
+
|
|
|
+ try {
|
|
|
+ Date startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(startTimeStr);
|
|
|
+ Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr);
|
|
|
+
|
|
|
+ // 筛选 createTime 在 startTime 和 endTime 范围内的数据
|
|
|
+ List<ProductionConsume> rangeItems = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime) && !item.getCreateTime().after(endTime))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems.get(rangeItems.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("平");
|
|
|
+ productionConsumeReport.setOrderIndex(3);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ groupedByDate.forEach((date, items) -> {
|
|
|
+ final BigDecimal[] totalActivePowerDiff = {BigDecimal.ZERO}; // 累加差值
|
|
|
+
|
|
|
+
|
|
|
+ // 处理 valleysTimeConfigs 特殊时段
|
|
|
+ valleysTimeConfigs.forEach(config -> {
|
|
|
+ try {
|
|
|
+ // 第一部分:date + 00:00:00 到 date + 06:59:59
|
|
|
+ Date startTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 00:00:00");
|
|
|
+ Date endTime1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getEndTime());
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems1 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime1) && !item.getCreateTime().after(endTime1))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems1.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems1.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems1.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems1.get(rangeItems1.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第二部分:date + 23:00:00 到 date + 23:59:59
|
|
|
+ Date startTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " " + config.getStartTime());
|
|
|
+ Date endTime2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date + " 23:59:59");
|
|
|
+
|
|
|
+ List<ProductionConsume> rangeItems2 = items.stream()
|
|
|
+ .filter(item -> !item.getCreateTime().before(startTime2) && !item.getCreateTime().after(endTime2))
|
|
|
+ .sorted(Comparator.comparing(ProductionConsume::getCreateTime))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (!rangeItems2.isEmpty()) {
|
|
|
+ ProductionConsume first = rangeItems2.get(0); // 第一条数据
|
|
|
+
|
|
|
+ // 如果只有一条数据,那差值为0
|
|
|
+ if (rangeItems2.size() == 1) {
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(BigDecimal.ZERO);
|
|
|
+ } else {
|
|
|
+ ProductionConsume last = rangeItems2.get(rangeItems2.size() - 1); // 最后一条数据
|
|
|
+
|
|
|
+ BigDecimal activePowerDiff = last.getActivePower().subtract(first.getActivePower()); // 差值计算
|
|
|
+ totalActivePowerDiff[0] = totalActivePowerDiff[0].add(activePowerDiff); // 累加差值
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (ParseException e) {
|
|
|
+ log.error("日期解析错误", e);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 生成报表数据
|
|
|
+ ProductionConsumeReport productionConsumeReport = new ProductionConsumeReport();
|
|
|
+ productionConsumeReport.setRegionTitle(regionTitle);
|
|
|
+ productionConsumeReport.setDeviceTitle(deviceTitle);
|
|
|
+ productionConsumeReport.setCreateTime(date);
|
|
|
+ productionConsumeReport.setKey1("谷");
|
|
|
+ productionConsumeReport.setOrderIndex(4);
|
|
|
+
|
|
|
+ if (totalActivePowerDiff[0].compareTo(BigDecimal.ZERO) != 0) {
|
|
|
+ productionConsumeReport.setValue(totalActivePowerDiff[0]); // 设置累加的差值
|
|
|
+ } else {
|
|
|
+ productionConsumeReport.setValue(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ finalResult.add(productionConsumeReport);
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ Map<String, BigDecimal> dailyTotals = finalResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(report -> report.getCreateTime().substring(0, 7)+ "_" + report.getRegionTitle(),
|
|
|
+ Collectors.mapping(ProductionConsumeReport::getValue,
|
|
|
+ Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
|
|
|
+
|
|
|
+ // 按 createTime 和 regionTitle 分组
|
|
|
+ Map<String, Map<String, List<ProductionConsumeReport>>> groupedData = finalResult.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ report -> report.getCreateTime().substring(0, 7), // 按 CreateTime 的前7位 (年月) 分组
|
|
|
+ Collectors.groupingBy(ProductionConsumeReport::getRegionTitle) // 按 RegionTitle 分组
|
|
|
+ ));
|
|
|
+
|
|
|
+ JSONArray resultArray = new JSONArray();
|
|
|
+
|
|
|
+ groupedData.forEach((createTime, companyGroup) -> companyGroup.forEach((regionTitle, reports) -> {
|
|
|
+ LocalDate date = LocalDate.parse(createTime + "-01", formatter); // 补全为 yyyy-MM-dd
|
|
|
+ String formattedDate = date.getYear() + "年" + date.getMonthValue() + "月";
|
|
|
+ String yearFormattedDate = date.getYear() + "年";
|
|
|
+
|
|
|
+ BigDecimal dailyTotal = dailyTotals.get(createTime + "_" + regionTitle); // 获取当天总值
|
|
|
+
|
|
|
+ Map<String, BigDecimal> keyTotals = reports.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ ProductionConsumeReport::getKey1,
|
|
|
+ Collectors.mapping(ProductionConsumeReport::getValue,
|
|
|
+ Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))
|
|
|
+ ));
|
|
|
+
|
|
|
+ keyTotals.forEach((key, totalValue) -> {
|
|
|
+ ProductionConsumeReport summaryReport = new ProductionConsumeReport();
|
|
|
+ summaryReport.setCreateTime(createTime); // 设置日期
|
|
|
+ summaryReport.setMonth(formattedDate);
|
|
|
+ summaryReport.setYear(yearFormattedDate);
|
|
|
+ summaryReport.setRegionTitle(regionTitle);
|
|
|
+ summaryReport.setKey1(key);
|
|
|
+ summaryReport.setValue(totalValue);
|
|
|
+ summaryReport.setTotalNum(dailyTotal.stripTrailingZeros()); // 设置当天总值
|
|
|
+
|
|
|
+ // 设置 key1 对应的 orderIndex
|
|
|
+ int orderIndex;
|
|
|
+ switch (summaryReport.getKey1()) {
|
|
|
+ case "尖":
|
|
|
+ orderIndex = 1;
|
|
|
+ break;
|
|
|
+ case "峰":
|
|
|
+ orderIndex = 2;
|
|
|
+ break;
|
|
|
+ case "平":
|
|
|
+ orderIndex = 3;
|
|
|
+ break;
|
|
|
+ case "谷":
|
|
|
+ orderIndex = 4;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ orderIndex = 5; // 默认值,防止其他 key 情况
|
|
|
+ }
|
|
|
+ summaryReport.setOrderIndex(orderIndex);
|
|
|
+
|
|
|
+ // 计算占比
|
|
|
+ summaryReport.setProportion(totalValue.divide(dailyTotal, 6, RoundingMode.HALF_UP).stripTrailingZeros());
|
|
|
+ resultArray.add(summaryReport);
|
|
|
+ });
|
|
|
+ }));
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ jsonResult = JSON.parseArray(JSON.toJSONString(resultArray));
|
|
|
+ log.info("积木报表导出总数:{}", jsonResult.size());
|
|
|
+ result.put("data", jsonResult);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|