供需平衡分析

master
yangzhe123 2025-12-03 16:02:03 +08:00
parent 75162d9e33
commit b278261480
4 changed files with 113 additions and 16 deletions

View File

@ -48,7 +48,7 @@ public class RiceSupportBalanceController {
return R.ok(true); return R.ok(true);
} }
@Operation(summary = "来水预测-分页查询,供需平衡") @Operation(summary = "来水预测-分页查询,供需平衡")
@PostMapping("/icpage") @PostMapping("/icpage")
public R<Page<IcWaterForecast>> icPage(@RequestBody RiceSupportBalanceCaculatePageSo pageSo){ public R<Page<IcWaterForecast>> icPage(@RequestBody RiceSupportBalanceCaculatePageSo pageSo){
Page<IcWaterForecast> page = riceSupportBalanceService.icPage(pageSo); Page<IcWaterForecast> page = riceSupportBalanceService.icPage(pageSo);

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.entity.dto; package com.gunshi.project.hsz.entity.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -13,8 +14,10 @@ public class RiceSupportBalanceCaculateDto {
private String planName;//方案名称 private String planName;//方案名称
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime startTime;//开始时间 private LocalDateTime startTime;//开始时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime endTime;//结束时间 private LocalDateTime endTime;//结束时间
private Long icId;//来水方案Id private Long icId;//来水方案Id

View File

@ -73,7 +73,7 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
List<StZvarlB> list = stZvarlBService.lambdaQuery().orderByAsc(StZvarlB::getRz).list(); List<StZvarlB> list = stZvarlBService.lambdaQuery().orderByAsc(StZvarlB::getRz).list();
BigDecimal w = stZvarlBService.getWByZvarl(list, stRsvrRReal.getRz());//获取库容 BigDecimal w = stZvarlBService.getWByZvarl(list, stRsvrRReal.getRz());//获取库容
BigDecimal deadW = stZvarlBService.getWByZvarl(list, deadLev);//死水位库容 BigDecimal deadW = stZvarlBService.getWByZvarl(list, deadLev);//死水位库容
Integer year = icWaterForecast.getYear();//获取相似年 Integer year = riceRqWater.getRiceGrowConfig().getYear();//获取相似年
if(dto.getStartTime().isAfter(today)){ if(dto.getStartTime().isAfter(today)){
// 总来水量 = 当前~开始时间这一段时间的来水量 + 来回方案来水 // 总来水量 = 当前~开始时间这一段时间的来水量 + 来回方案来水
//方案来水量的时间范围 今天1号开始时间4号需要计算1-3号共3天 //方案来水量的时间范围 今天1号开始时间4号需要计算1-3号共3天
@ -118,13 +118,13 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
break; break;
} }
} }
// 总来水量 = 当前到开始时间的降雨来水量 + 方案来水 // 总来水量 = 当前到开始时间的降雨来水量 + 方案来水(长期预测为万m³,短期预测为m³ 所以如果为短期则需要进行÷10000
BigDecimal currentToStartWater = totalRainfallWater; // 这里假设totalRainfallWater就是需要的来水量 BigDecimal currentToStartWater = totalRainfallWater; // 这里假设totalRainfallWater就是需要的来水量
totalIcWater = totalIcWater.add(currentToStartWater).add(icWaterForecast.getForecastWater()); // 将当前到开始时间的来水量加入总来水量 totalIcWater = totalIcWater.add(currentToStartWater).add(icWaterForecast.getType() == 0? icWaterForecast.getForecastWater(): icWaterForecast.getForecastWater().divide(new BigDecimal("10000"))); // 将当前到开始时间的来水量加入总来水量
}else{ }else{
// 总来水量 = 当前蓄水量 + 来水方案中的来水 // 总来水量 = 当前蓄水量 + 来水方案中的来水
BigDecimal forecastWater = icWaterForecast.getForecastWater(); BigDecimal forecastWater = icWaterForecast.getType() == 0? icWaterForecast.getForecastWater(): icWaterForecast.getForecastWater().divide(new BigDecimal("10000"));
totalIcWater = w.add(forecastWater); totalIcWater = w.add(forecastWater);
} }
BigDecimal totalNeedWater = BigDecimal.ZERO; BigDecimal totalNeedWater = BigDecimal.ZERO;
@ -181,7 +181,7 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
// 计算灌溉用水的缩放比例 // 计算灌溉用水的缩放比例
BigDecimal irrigationRatio; BigDecimal irrigationRatio;
if (totalIrrigationNeed.compareTo(BigDecimal.ZERO) > 0) { if (totalIrrigationNeed.compareTo(BigDecimal.ZERO) > 0) {
irrigationRatio = totalWaterForIrrigation.divide(totalIrrigationNeed, 4, BigDecimal.ROUND_HALF_UP); irrigationRatio = totalIcWater.divide(totalNeedWater, 4, BigDecimal.ROUND_HALF_UP);
} else { } else {
irrigationRatio = BigDecimal.ZERO; irrigationRatio = BigDecimal.ZERO;
} }
@ -193,10 +193,11 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
riceSupportBalance.setEndTime(dto.getEndTime()); riceSupportBalance.setEndTime(dto.getEndTime());
riceSupportBalance.setCreateTime(LocalDateTime.now()); riceSupportBalance.setCreateTime(LocalDateTime.now());
riceSupportBalance.setTotalSupport(totalPlan); riceSupportBalance.setTotalSupport(totalPlan);
riceSupportBalance.setTotalCost(totalIrrigationNeed); riceSupportBalance.setTotalCost(totalNeedWater);
riceSupportBalance.setCreateName(dto.getCreateName()); riceSupportBalance.setCreateName(dto.getCreateName());
riceSupportBalance.setStatus(0); riceSupportBalance.setStatus(0);
this.save(riceSupportBalance); riceSupportBalance.setPlanName(dto.getPlanName());
boolean save = this.save(riceSupportBalance);
// 创建final或effectively final的局部变量副本 // 创建final或effectively final的局部变量副本
final Long mainId = riceSupportBalance.getId(); final Long mainId = riceSupportBalance.getId();
final BigDecimal finalDailyEcoWaterUse = dailyEcoWaterUse; final BigDecimal finalDailyEcoWaterUse = dailyEcoWaterUse;
@ -205,10 +206,10 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
final List<RiceSupportMidCaculate> finalRiceSupportMidCaculates = new ArrayList<>(riceSupportMidCaculates); final List<RiceSupportMidCaculate> finalRiceSupportMidCaculates = new ArrayList<>(riceSupportMidCaculates);
// 在新线程中执行计算和保存 // 在新线程中执行计算和保存
//TODO 这样做会有事务问题(如果明细数据计算失败,那么会导致 只有主表数据,没有明细数据(当然也可以保持同步计算逻辑)
new Thread(() -> { new Thread(() -> {
try { try {
List<RiceSupportBalanceDetail> saveDetails = new ArrayList<>(); List<RiceSupportBalanceDetail> saveDetails = new ArrayList<>();
for (LocalDateTime localDateTime : finalAllDays) { for (LocalDateTime localDateTime : finalAllDays) {
RiceSupportBalanceDetail entity = new RiceSupportBalanceDetail(); RiceSupportBalanceDetail entity = new RiceSupportBalanceDetail();
entity.setTm(localDateTime); entity.setTm(localDateTime);
@ -216,11 +217,38 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
// 查找当前日期属于哪个生长周期,计算灌溉需水量 // 查找当前日期属于哪个生长周期,计算灌溉需水量
BigDecimal dailyIrrigationNeed = BigDecimal.ZERO; // 灌溉需水量 BigDecimal dailyIrrigationNeed = BigDecimal.ZERO; // 灌溉需水量
for (RiceSupportMidCaculate caculate : finalRiceSupportMidCaculates) { for (RiceSupportMidCaculate caculate : finalRiceSupportMidCaculates) {
if (!localDateTime.isBefore(caculate.getStartTime()) && // 提取月份和日,忽略年份
!localDateTime.isAfter(caculate.getEndTime())) { int currentMonth = localDateTime.getMonthValue();
int currentDay = localDateTime.getDayOfMonth();
int startMonth = caculate.getStartTime().getMonthValue();
int startDay = caculate.getStartTime().getDayOfMonth();
int endMonth = caculate.getEndTime().getMonthValue();
int endDay = caculate.getEndTime().getDayOfMonth();
// 判断日期是否在周期内(只比较月日)
boolean isInCycle = false;
if (startMonth < endMonth || (startMonth == endMonth && startDay <= endDay)) {
// 正常情况:开始月日 <= 结束月日(不跨年)
if ((currentMonth > startMonth || (currentMonth == startMonth && currentDay >= startDay)) &&
(currentMonth < endMonth || (currentMonth == endMonth && currentDay <= endDay))) {
isInCycle = true;
}
} else {
// 跨年情况:开始月日 > 结束月日如11月到次年2月
if ((currentMonth > startMonth || (currentMonth == startMonth && currentDay >= startDay)) ||
(currentMonth < endMonth || (currentMonth == endMonth && currentDay <= endDay))) {
isInCycle = true;
}
}
if (isInCycle) {
// 计算该生长周期的天数 // 计算该生长周期的天数
int daysInCycle = LocalDateTimeUtils.getTotalDayByRangeDate( int daysInCycle = LocalDateTimeUtils.calculateDaysIgnoringYear(
caculate.getStartTime(), caculate.getEndTime() caculate.getStartTime(),
caculate.getEndTime()
); );
if (daysInCycle > 0 && caculate.getIrrigationUse() != null) { if (daysInCycle > 0 && caculate.getIrrigationUse() != null) {
@ -259,14 +287,14 @@ public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMap
updateById(riceSupportBalance); updateById(riceSupportBalance);
} catch (Exception e) { } catch (Exception e) {
log.error("保存水稻平衡供水明细失败", e); log.error("保存水稻平衡供水明细失败", e);
// 这里可以添加异常处理,比如记录日志、发送通知等
} }
}).start(); }).start();
// 主线程立即返回,不等待明细计算完成
// 主线程立即返回,不等待明细计算完成
log.info("水稻平衡供水主表已保存,明细计算正在异步执行"); log.info("水稻平衡供水主表已保存,明细计算正在异步执行");
} }
public Page<IcWaterForecast> icPage(RiceSupportBalanceCaculatePageSo pageSo) { public Page<IcWaterForecast> icPage(RiceSupportBalanceCaculatePageSo pageSo) {
LambdaQueryWrapper<IcWaterForecast> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<IcWaterForecast> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.le(IcWaterForecast::getStartTime,pageSo.getStartTime()); queryWrapper.le(IcWaterForecast::getStartTime,pageSo.getStartTime());

View File

@ -190,6 +190,72 @@ public class LocalDateTimeUtils {
return (int) days; return (int) days;
} }
/**
*
* 1115315
*
* @param startTime
* @param endTime
* @return
*/
public static int calculateDaysIgnoringYear(LocalDateTime startTime, LocalDateTime endTime) {
if (startTime == null || endTime == null) {
return 0;
}
// 将开始和结束时间调整为同一年比如都调整为2020年
int baseYear = 2020; // 选择一个基准年
LocalDateTime adjustedStart = startTime.withYear(baseYear);
LocalDateTime adjustedEnd = endTime.withYear(baseYear);
// 如果调整后开始时间在结束时间之后,说明是跨年周期
// 如11月15日2020年到3月15日2020年实际上应该是11月15日到次年3月15日
if (adjustedStart.isAfter(adjustedEnd)) {
adjustedEnd = adjustedEnd.plusYears(1); // 结束时间加一年
}
// 计算天数
return getTotalDayByRangeDate(adjustedStart, adjustedEnd);
}
/**
*
*
* @param checkDate
* @param startTime
* @param endTime
* @return
*/
public static boolean isDateInCycleIgnoringYear(LocalDateTime checkDate,
LocalDateTime startTime,
LocalDateTime endTime) {
if (checkDate == null || startTime == null || endTime == null) {
return false;
}
// 提取月日
int checkMonth = checkDate.getMonthValue();
int checkDay = checkDate.getDayOfMonth();
int startMonth = startTime.getMonthValue();
int startDay = startTime.getDayOfMonth();
int endMonth = endTime.getMonthValue();
int endDay = endTime.getDayOfMonth();
// 判断日期是否在周期内
if (startMonth < endMonth || (startMonth == endMonth && startDay <= endDay)) {
// 不跨年情况
return (checkMonth > startMonth || (checkMonth == startMonth && checkDay >= startDay)) &&
(checkMonth < endMonth || (checkMonth == endMonth && checkDay <= endDay));
} else {
// 跨年情况
return (checkMonth > startMonth || (checkMonth == startMonth && checkDay >= startDay)) ||
(checkMonth < endMonth || (checkMonth == endMonth && checkDay <= endDay));
}
}
} }