gunshi-project-ss/src/main/java/com/gunshi/project/hsz/service/RiceRqWaterService.java

658 lines
29 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.gunshi.project.hsz.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.project.hsz.entity.dto.RiceWaterCaculateDto;
import com.gunshi.project.hsz.entity.so.RiceRqWaterPageSo;
import com.gunshi.project.hsz.entity.vo.RiceRqWaterCaculateVo;
import com.gunshi.project.hsz.entity.vo.TyYearRainfallVo;
import com.gunshi.project.hsz.mapper.RiceRqWaterMapper;
import com.gunshi.project.hsz.model.*;
import com.gunshi.project.hsz.util.LocalDateTimeUtils;
import com.ruoyi.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Collectors;
/**
* 描述: 水稻需水主表
* author: xusan
* date: 2024-09-04 13:42:40
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RiceRqWaterService extends ServiceImpl<RiceRqWaterMapper, RiceRqWater> {
@Autowired
private RiceGrowConfigService riceGrowConfigService;
@Autowired
private RiceIrrigationUseService riceIrrigationUseService;
@Autowired
private RiceWaterForecastCycleService riceWaterForecastCycleService;
@Autowired
private RiceWaterForecastMonthService riceWaterForecastMonthService;
@Autowired
private RiceWaterKiService riceWaterKiService;
public Page<RiceRqWater> pageQuery(RiceRqWaterPageSo page) {
LambdaQueryWrapper<RiceRqWater> queryWrapper = new LambdaQueryWrapper<>();
if(page.getYear() != null){
queryWrapper.eq(RiceRqWater::getYear,page.getYear());
}
if(!StringUtils.isBlank(page.getPlanName())){
queryWrapper.like(RiceRqWater::getPlanName,page.getPlanName());
}
queryWrapper.orderByDesc(RiceRqWater::getCreateTime);
Page<RiceRqWater> riceRqWaterPage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper);
List<RiceRqWater> records = riceRqWaterPage.getRecords();
for (RiceRqWater record : records) {
//灌水定额配置
record.setRiceWaterKis(riceWaterKiService.selectByRiceWaterId(record.getId()));
//水稻生长系数配置
record.setRiceGrowConfig(riceGrowConfigService.selectByRiceWaterId(record.getId()));
//按月份
record.setRiceWaterForecastMonths(riceWaterForecastMonthService.selectByRiceWaterId(record.getId()));
//按生长周期
record.setRiceWaterForecastCycles(riceWaterForecastCycleService.selectByRiceWaterId(record.getId()));
}
return riceRqWaterPage;
}
public RiceRqWater queryById(Long id) {
RiceRqWater riceRqWater = this.baseMapper.selectById(id);
if(riceRqWater == null){
return riceRqWater;
}
riceRqWater.setRiceWaterKis(riceWaterKiService.selectByRiceWaterId(riceRqWater.getId()));
//水稻生长系数配置
riceRqWater.setRiceGrowConfig(riceGrowConfigService.selectByRiceWaterId(riceRqWater.getId()));
//按月份
riceRqWater.setRiceWaterForecastMonths(riceWaterForecastMonthService.selectByRiceWaterId(riceRqWater.getId()));
//按生长周期
riceRqWater.setRiceWaterForecastCycles(riceWaterForecastCycleService.selectByRiceWaterId(riceRqWater.getId()));
return riceRqWater;
}
public RiceRqWater saveData(RiceRqWater dto) {
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis();
List<RiceWaterForecastCycle> riceWaterForecastCycles = dto.getRiceWaterForecastCycles();
List<RiceWaterForecastMonth> riceWaterForecastMonths = dto.getRiceWaterForecastMonths();
dto.setReqWater(riceGrowConfig.getIrrigationUse());
dto.setCreateTime(LocalDateTime.now());
save(dto);
riceGrowConfig.setRiceWaterId(dto.getId());
riceWaterKis.stream().forEach(o ->{
o.setRiceWaterId(dto.getId());
});
riceWaterForecastCycles.stream().forEach(o ->{
o.setRiceWaterId(dto.getId());
});
riceWaterForecastMonths.stream().forEach(o ->{
o.setRiceWaterId(dto.getId());
});
riceWaterKiService.saveBatch(riceWaterKis);
riceGrowConfigService.save(riceGrowConfig);
riceWaterForecastCycleService.saveBatch(riceWaterForecastCycles);
riceWaterForecastMonthService.saveBatch(riceWaterForecastMonths);
return dto;
}
public RiceRqWater updateData(RiceRqWater dto) {
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis();
List<RiceWaterForecastCycle> riceWaterForecastCycles = dto.getRiceWaterForecastCycles();
List<RiceWaterForecastMonth> riceWaterForecastMonths = dto.getRiceWaterForecastMonths();
dto.setReqWater(riceGrowConfig.getIrrigationUse());
dto.setCreateTime(LocalDateTime.now());
updateById(dto);
riceWaterKiService.removeByRiceWaterId(dto.getId());
riceGrowConfigService.removeByRiceWaterId(dto.getId());
riceIrrigationUseService.removeByRiceWaterId(dto.getId());
riceWaterForecastCycleService.removeByRiceWaterId(dto.getId());
riceWaterForecastMonthService.removeByRiceWaterId(dto.getId());
riceWaterKis.stream().forEach(o ->{
o.setRiceWaterId(dto.getId());
});
riceWaterForecastCycles.stream().forEach(o ->{
o.setRiceWaterId(dto.getId());
});
riceWaterForecastMonths.stream().forEach(o ->{
o.setRiceWaterId(dto.getId());
});
riceGrowConfig.setRiceWaterId(dto.getId());
riceWaterKiService.saveBatch(riceWaterKis);
riceGrowConfigService.save(riceGrowConfig);
riceWaterForecastCycleService.saveBatch(riceWaterForecastCycles);
riceWaterForecastMonthService.saveBatch(riceWaterForecastMonths);
return dto;
}
public Boolean delData(Long id) {
removeById(id);
riceWaterKiService.removeByRiceWaterId(id);
riceGrowConfigService.removeByRiceWaterId(id);
riceIrrigationUseService.removeByRiceWaterId(id);
riceWaterForecastCycleService.removeByRiceWaterId(id);
riceWaterForecastMonthService.removeByRiceWaterId(id);
return true;
}
public List<RiceWaterKi> stageCaculate(RiceWaterCaculateDto dto) {
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis();
orderByStartTimeAsc(riceWaterKis);
// 早稻需水系数
BigDecimal α1 = riceGrowConfig.getΑ1();
if(α1 == null){
throw new IllegalArgumentException("早稻需水系数不能为空");
}
// 渗漏强度
BigDecimal lkIntensity = riceGrowConfig.getLkIntensity();
if(lkIntensity == null){
throw new IllegalArgumentException("渗漏强度不能为空");
}
// 生长期水面蒸发量mm
BigDecimal ed1 = riceGrowConfig.getEd1();
if(ed1 == null){
throw new IllegalArgumentException("生长期水面蒸发量不能为空");
}
for (RiceWaterKi riceWaterKi : riceWaterKis) {
// 计算阶段耗水量
if(riceWaterKi.getRiceGrowStage().contains("泡田")){
riceWaterKi.setKi(riceGrowConfig.getΑ1());//需水系数
riceWaterKi.setWaterRqStage(riceGrowConfig.getKaQuota());//泡田定额
continue;
}
BigDecimal waterRqStage = calculateWaterRqStage(riceWaterKi, α1, ed1, lkIntensity);
riceWaterKi.setWaterRqStage(waterRqStage.setScale(1,RoundingMode.UP));
}
return riceWaterKis;
}
/**
* 计算阶段耗水量
* 公式ki * α1 * ed1 + days * lkIntensity
*/
private BigDecimal calculateWaterRqStage(RiceWaterKi riceWaterKi, BigDecimal α1,
BigDecimal ed1, BigDecimal lkIntensity) {
// 获取需水模系数
BigDecimal ki = riceWaterKi.getKi();
if(ki == null){
throw new IllegalArgumentException("需水模型系数不能为空");
}
// 计算天数如果days为空则根据开始结束日期计算
Integer days = riceWaterKi.getDays();
if (days == null && riceWaterKi.getStartTime() != null && riceWaterKi.getEndTime() != null) {
days = calculateDaysBetween(riceWaterKi.getStartTime(), riceWaterKi.getEndTime());
riceWaterKi.setDays(days); // 同时设置回实体中
}
if (days == null) {
days = 0;
}
// 计算公式ki * α1 * ed1 + days * lkIntensity
BigDecimal part1 = ki.multiply(α1).multiply(ed1);
BigDecimal part2 = new BigDecimal(days).multiply(lkIntensity);
return part1.add(part2);
}
/**
* 计算两个LocalDateTime之间的天数包含开始和结束日期
* 例如2025-04-26 ~ 2025-05-06 = 11天
*/
private Integer calculateDaysBetween(LocalDateTime startTime, LocalDateTime endTime) {
if (startTime == null || endTime == null) {
return 0;
}
// 使用LocalDate来计算天数忽略时间部分
long days = java.time.temporal.ChronoUnit.DAYS.between(
startTime.toLocalDate(),
endTime.toLocalDate()
);
// 因为包含开始和结束日期,所以需要+1
return (int) days + 1;
}
@Autowired
private TyYearRainfallService tyYearRainfallService;
public List<RiceIrrigationUse> irrigationCaculate(RiceWaterCaculateDto dto) {
List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis();
List<RiceIrrigationUse> res = new ArrayList<>();
orderByStartTimeAsc(riceWaterKis);
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
riceGrowConfig.setCycle(LocalDateTimeUtils.getTotalDayByRangeDate(riceWaterKis.getFirst().getStartTime(),riceWaterKis.getLast().getEndTime()));
Integer year = riceGrowConfig.getYear();//相似年
List<TyYearRainfallVo> tyYearRainfallVos = tyYearRainfallService.queryList();
List<TyYearRainfallVo> collect = tyYearRainfallVos.stream().filter(o -> {
return o.getYear().equals(year);
}).collect(Collectors.toList());
if(collect == null || collect.isEmpty()){
throw new IllegalArgumentException("对不起,没有该年份的降雨资料");
}
TyYearRainfallVo tyYearRainfallVo = collect.get(0);
List<TyYearRainfall> list = tyYearRainfallVo.getList();//获取月份的降雨资料
//泡田定额
BigDecimal kaQuota = riceGrowConfig.getKaQuota();
// 泡田期是第一个元素
RiceWaterKi kaPeriod = riceWaterKis.get(0);
LocalDateTime kaStartTime = kaPeriod.getStartTime();
LocalDateTime kaEndTime = kaPeriod.getEndTime();
int totalKaDays = calculateTotalKaDays(kaStartTime, kaEndTime);
// 生育期数据(排除泡田期)
List<RiceWaterKi> growPeriods = riceWaterKis.subList(1, riceWaterKis.size());
// 用于存储去重后的月份1-12
Set<Integer> monthSet = new HashSet<>();
// 添加泡田期的月份
monthSet.add(kaStartTime.getMonthValue());
monthSet.add(kaEndTime.getMonthValue());
// 遍历集合,提取每个元素的 startTime 和 endTime 对应的月份
for (RiceWaterKi riceWaterKi : riceWaterKis) {
LocalDateTime start = riceWaterKi.getStartTime();
LocalDateTime end = riceWaterKi.getEndTime();
if (start != null) {
monthSet.add(start.getMonthValue());
}
if (end != null) {
monthSet.add(end.getMonthValue());
}
}
// 将去重后的月份转为列表并按从小到大排序
List<Integer> sortedMonths = monthSet.stream()
.sorted()
.collect(Collectors.toList());
//boolean isFirst = true;
for (Integer sortedMonth : sortedMonths) {
RiceIrrigationUse riceIrrigationUse = new RiceIrrigationUse();
riceIrrigationUse.setMonth(sortedMonth);
BigDecimal irrigationVolume = BigDecimal.ZERO;
// 计算泡田期在当前月份的耗水量
/**
* 由于这个方法是按照月份进行计算的,所以当后面的生长期有属于泡田期的月份时,那么也要把泡田期的算上
* 比如 泡田期3.30~4.25
* 返青期4·26~5·6
* 属于四月份的有泡田期和返青期,那么计算的时候就要把泡田期在四月份的灌溉用水量和返青期在四月份的灌溉用水量计算上
*/
if (isMonthInKaPeriod(sortedMonth, kaStartTime, kaEndTime)) {
int kaDaysInMonth = calculateKaDaysInMonth(kaStartTime, kaEndTime, sortedMonth);
BigDecimal kaConsumption = kaQuota.divide(BigDecimal.valueOf(totalKaDays), 2, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(kaDaysInMonth));
irrigationVolume = irrigationVolume.add(kaConsumption);
}
// 修正计算生育期在当前月份的总耗水量按Excel逻辑
BigDecimal growConsumption = calculateGrowConsumptionForMonth(sortedMonth, growPeriods);
irrigationVolume = irrigationVolume.add(growConsumption);
// 计算该月份所有生育阶段的总有效降雨量
// if(isMonthInKaPeriod(sortedMonth, kaStartTime, kaEndTime) && !isFirst){
// growPeriods.addFirst(kaPeriod);
// }
BigDecimal monthlyRainfall = calculateTotalEffectiveRainfallForMonth(sortedMonth, growPeriods, list);
// if(isMonthInKaPeriod(sortedMonth, kaStartTime, kaEndTime) && !isFirst){
// growPeriods.removeFirst();
// }
irrigationVolume = irrigationVolume.subtract(monthlyRainfall);
// // 如果计算结果是负数则设为0
// if (irrigationVolume.compareTo(BigDecimal.ZERO) < 0) {
// irrigationVolume = BigDecimal.ZERO;
// }
// 保留2位小数
irrigationVolume = irrigationVolume.setScale(2,RoundingMode.UP);
riceIrrigationUse.setIrrigationUse(irrigationVolume);
res.add(riceIrrigationUse);
// isFirst = false;
}
return res;
}
/**
* 计算指定月份生育期的总耗水量按Excel逻辑
*/
private BigDecimal calculateGrowConsumptionForMonth(int month, List<RiceWaterKi> growPeriods) {
BigDecimal totalConsumption = BigDecimal.ZERO;
for (RiceWaterKi growPeriod : growPeriods) {
LocalDateTime startTime = growPeriod.getStartTime();
LocalDateTime endTime = growPeriod.getEndTime();
// 检查该阶段是否包含这个月份
if (LocalDateTimeUtils.isMonthInPeriod(month, startTime, endTime)) {
// 获取阶段在该月份的天数
int daysInMonth = LocalDateTimeUtils.calculateDaysInMonthForPeriod(startTime, endTime, month);
if (daysInMonth > 0) {
// 判断阶段是否跨月份
List<Integer> monthsInStage = LocalDateTimeUtils.getMonthsInPeriod(startTime, endTime);
if (monthsInStage.size() == 1) {
// 不跨月份:直接使用完整耗水量
totalConsumption = totalConsumption.add(growPeriod.getWaterRqStage());
} else {
// 跨月份:按天数比例分配耗水量
//当前月份对应阶段的耗水量/当前阶段的全天数
/**
* 比如
* 泡田期 3.30~4.25
* 返青期 4·26~5·6 这里就跨月份了
* 同时month为4 表示4月份
* 那么计算公式为 返青期耗水量/返青期天数11天*返青期四月份天数(ps 泡田期在四月份的耗水量已经计算完了)
*/
BigDecimal dailyConsumption = growPeriod.getWaterRqStage()
.divide(BigDecimal.valueOf(growPeriod.getDays()), 2, RoundingMode.HALF_UP);
//再去乘当前阶段在当前月份的天数
BigDecimal monthlyConsumption = dailyConsumption.multiply(BigDecimal.valueOf(daysInMonth));
totalConsumption = totalConsumption.add(monthlyConsumption);
}
}
}
}
return totalConsumption;
}
/**
* 计算指定月份所有生育阶段的总有效降雨量
*/
private BigDecimal calculateTotalEffectiveRainfallForMonth(int month, List<RiceWaterKi> growPeriods,
List<TyYearRainfall> rainfallList) {
BigDecimal totalRainfall = BigDecimal.ZERO;
for (RiceWaterKi growPeriod : growPeriods) {
LocalDateTime startTime = growPeriod.getStartTime();
LocalDateTime endTime = growPeriod.getEndTime();
// 检查该阶段是否包含这个月份
if (LocalDateTimeUtils.isMonthInPeriod(month, startTime, endTime)) {
// 使用getMonthlyRainfall方法计算该阶段在该月份的有效降雨量
BigDecimal stageRainfall = getMonthlyRainfall(rainfallList, month, startTime, endTime);
totalRainfall = totalRainfall.add(stageRainfall);
}
}
return totalRainfall.setScale(1, RoundingMode.HALF_UP);
}
/**
* 判断月份是否在泡田期内
*/
private boolean isMonthInKaPeriod(int month, LocalDateTime kaStart, LocalDateTime kaEnd) {
int startMonth = kaStart.getMonthValue();
int endMonth = kaEnd.getMonthValue();
return month >= startMonth && month <= endMonth;
}
/**
* 计算泡田期在当前月份的天数
*/
private int calculateKaDaysInMonth(LocalDateTime kaStart, LocalDateTime kaEnd, int targetMonth) {
int startMonth = kaStart.getMonthValue();
int endMonth = kaEnd.getMonthValue();
// 如果整个泡田期都在目标月份内
if (startMonth == targetMonth && endMonth == targetMonth) {
return (int) java.time.temporal.ChronoUnit.DAYS.between(kaStart.toLocalDate(), kaEnd.toLocalDate()) + 1;
}
// 如果泡田期开始时间在目标月份,结束时间在下个月
if (startMonth == targetMonth && endMonth > targetMonth) {
LocalDate lastDayOfMonth = kaStart.toLocalDate().withDayOfMonth(kaStart.toLocalDate().lengthOfMonth());
return (int) java.time.temporal.ChronoUnit.DAYS.between(kaStart.toLocalDate(), lastDayOfMonth) + 1;
}
// 如果泡田期结束时间在目标月份,开始时间在上个月
if (endMonth == targetMonth && startMonth < targetMonth) {
LocalDate firstDayOfMonth = kaEnd.toLocalDate().withDayOfMonth(1);
return (int) java.time.temporal.ChronoUnit.DAYS.between(firstDayOfMonth, kaEnd.toLocalDate()) + 1;
}
return 0;
}
/**
* 计算泡田期总天数
*/
private int calculateTotalKaDays(LocalDateTime kaStart, LocalDateTime kaEnd) {
return (int) java.time.temporal.ChronoUnit.DAYS.between(kaStart.toLocalDate(), kaEnd.toLocalDate()) + 1;
}
/**
* 将ki的数据按照月份从小到大排序
*/
private void orderByStartTimeAsc(List<RiceWaterKi> riceWaterKis) {
Collections.sort(riceWaterKis, (ki1, ki2) -> {
LocalDateTime time1 = ki1.getStartTime();
LocalDateTime time2 = ki2.getStartTime();
if (time1 == null) return -1;
if (time2 == null) return 1;
return time1.compareTo(time2);
});
}
public List<RiceWaterForecastMonth> irrigationComprehensiveCaculateMonth(RiceWaterCaculateDto dto) {
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
List<RiceIrrigationUse> riceIrrigationUses = irrigationCaculate(dto);//获取灌区水稻用水量
BigDecimal totalWaterUse = BigDecimal.ZERO;
for (RiceIrrigationUse riceIrrigationUs : riceIrrigationUses) {
totalWaterUse = totalWaterUse.add(riceIrrigationUs.getIrrigationUse());
}
riceGrowConfig.setWaterUse(totalWaterUse);
List<RiceWaterForecastMonth> res = new ArrayList<>();
//灌溉区面积(亩)
BigDecimal sArea = riceGrowConfig.getArea();
sArea = sArea.multiply(new BigDecimal("10000"));
for (RiceIrrigationUse riceIrrigationUse : riceIrrigationUses) {
RiceWaterForecastMonth entity = new RiceWaterForecastMonth();
entity.setMonth(riceIrrigationUse.getMonth());
BigDecimal irrigationUse = riceIrrigationUse.getIrrigationUse();
if(irrigationUse.compareTo(BigDecimal.ZERO) <= 0){
entity.setIrrigationUse(BigDecimal.ZERO);
}else{
// 计算公式2/3 * irrigationUse * sArea / 10000
BigDecimal value = new BigDecimal("2")
.divide(new BigDecimal("3"), 20, RoundingMode.HALF_UP) // 2/3保留10位小数
.multiply(irrigationUse)
.multiply(sArea)
.divide(new BigDecimal("10000")); // 除以10000保留2位小数
entity.setIrrigationUse(value);
}
res.add(entity);
}
return res;
}
public List<RiceWaterForecastCycle> irrigationComprehensiveCaculateCycle(RiceWaterCaculateDto dto) {
List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis();
orderByStartTimeAsc(riceWaterKis);
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
BigDecimal kaQuota = riceGrowConfig.getKaQuota();//泡田定额
Integer year = riceGrowConfig.getYear();//相似年
BigDecimal sArea = riceGrowConfig.getArea();
List<TyYearRainfallVo> tyYearRainfallVos = tyYearRainfallService.queryList();
List<TyYearRainfallVo> collect = tyYearRainfallVos.stream().filter(o -> {
return o.getYear().equals(year);
}).collect(Collectors.toList());
if(collect == null || collect.isEmpty()){
throw new IllegalArgumentException("对不起,没有该年份的降雨资料");
}
TyYearRainfallVo tyYearRainfallVo = collect.get(0);
List<TyYearRainfall> rainfallList = tyYearRainfallVo.getList();//获取月份的降雨资料
List<RiceWaterForecastCycle> res = new ArrayList<>();
for (int i = 0; i < riceWaterKis.size(); i++) {
RiceWaterKi riceWaterKi = riceWaterKis.get(i);
RiceWaterForecastCycle data = new RiceWaterForecastCycle();
data.setRiceGrowStage(riceWaterKi.getRiceGrowStage());
data.setOrder(i + 1);
//泡田期为定值,泡田定额
if(riceWaterKi.getRiceGrowStage().contains("泡田")){
data.setIrrigationUse(kaQuota);
data.setRiceGrowStage("泡田期");
res.add(data);
} else {
LocalDateTime startTime = riceWaterKi.getStartTime();
LocalDateTime endTime = riceWaterKi.getEndTime();
BigDecimal irrigationUse = calculateIrrigationUse(riceWaterKi, rainfallList, startTime, endTime);
data.setIrrigationUse(irrigationUse.setScale(2,RoundingMode.HALF_UP));
res.add(data);
}
}
sArea = sArea.multiply(new BigDecimal("10000"));
for (RiceWaterForecastCycle re : res) {
BigDecimal irrigationUse = re.getIrrigationUse();
if(irrigationUse.compareTo(BigDecimal.ZERO) <=0){
re.setIrrigationUse(BigDecimal.ZERO);
}else{
BigDecimal value = new BigDecimal("2")
.divide(new BigDecimal("3"), 20, RoundingMode.HALF_UP) // 2/3保留10位小数
.multiply(irrigationUse)
.multiply(sArea)
.divide(new BigDecimal("10000")); // 除以10000保留2位小数
re.setIrrigationUse(value);
}
}
return res;
}
/**
* 计算非泡田期的灌溉用水量
*/
private BigDecimal calculateIrrigationUse(RiceWaterKi riceWaterKi, List<TyYearRainfall> rainfallList,
LocalDateTime startTime, LocalDateTime endTime) {
// 阶段用水量从waterRqStage获取
BigDecimal stageWaterUse = riceWaterKi.getWaterRqStage();
if (stageWaterUse == null) {
stageWaterUse = BigDecimal.ZERO;
}
// 计算有效降雨量
BigDecimal effectiveRainfall = calculateEffectiveRainfall(rainfallList, startTime, endTime);
// 灌溉用水量 = 阶段用水量 - 有效降雨量
BigDecimal irrigationUse = stageWaterUse.subtract(effectiveRainfall);
// 确保不会出现负值
return irrigationUse;
}
/**
* 计算阶段内的有效降雨量
*/
private BigDecimal calculateEffectiveRainfall(List<TyYearRainfall> rainfallList,
LocalDateTime stageStartTime, LocalDateTime stageEndTime) {
BigDecimal totalEffectiveRainfall = BigDecimal.ZERO;
// 获取阶段跨越的月份
Set<Integer> months = LocalDateTimeUtils.getMonthsInPeriodSet(stageStartTime, stageEndTime);
for (Integer month : months) {
BigDecimal monthlyRainfall = getMonthlyRainfall(rainfallList, month, stageStartTime, stageEndTime);
totalEffectiveRainfall = totalEffectiveRainfall.add(monthlyRainfall);
}
return totalEffectiveRainfall;
}
/**
* 从降雨资料中获取指定月份的降雨量,并根据阶段实际使用天数进行调整
*/
private BigDecimal getMonthlyRainfall(List<TyYearRainfall> rainfallList, int month,
LocalDateTime stageStartTime, LocalDateTime stageEndTime) {
if (rainfallList == null || stageStartTime == null || stageEndTime == null) {
return BigDecimal.ZERO;
}
// 获取原始月降雨量
BigDecimal originalRainfall = rainfallList.stream()
.filter(rainfall -> rainfall.getMonth() != null && rainfall.getMonth() == month)
.findFirst()
.map(TyYearRainfall::getDrp)
.orElse(BigDecimal.ZERO);
// 计算阶段在该月份的实际使用天数
int daysInMonth = LocalDateTimeUtils.calculateDaysInMonthForPeriod(stageStartTime, stageEndTime, month);
int totalDaysInMonth = LocalDateTimeUtils.getTotalDaysInMonth(stageStartTime.getYear(), month);
if (daysInMonth > 0 && totalDaysInMonth > 0) {
// 按实际使用天数比例计算有效降雨量
return originalRainfall
.multiply(BigDecimal.valueOf(daysInMonth))
.divide(BigDecimal.valueOf(totalDaysInMonth), 2, RoundingMode.HALF_UP);
}
return BigDecimal.ZERO;
}
public RiceRqWaterCaculateVo caculate(RiceWaterCaculateDto dto) {
//先计算阶段耗水量
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
RiceRqWaterCaculateVo vo = new RiceRqWaterCaculateVo();
List<RiceWaterKi> riceWaterKis = stageCaculate(dto);
dto.setRiceWaterKis(riceWaterKis);
//计算灌区水稻用水量-按月份
List<RiceWaterForecastMonth> riceWaterForecastMonths = irrigationComprehensiveCaculateMonth(dto);
BigDecimal monthTotal = BigDecimal.ZERO;
for (RiceWaterForecastMonth riceWaterForecastMonth : riceWaterForecastMonths) {
monthTotal = monthTotal.add(riceWaterForecastMonth.getIrrigationUse());
// riceWaterForecastMonth.setIrrigationUse(riceWaterForecastMonth.getIrrigationUse().setScale(2,RoundingMode.HALF_UP));
}
riceGrowConfig.setIrrigationUse(monthTotal);
//计算灌区水稻用水量-按周期
List<RiceWaterForecastCycle> riceWaterForecastCycles = irrigationComprehensiveCaculateCycle(dto);
BigDecimal cycleTotal = BigDecimal.ZERO;
for (RiceWaterForecastCycle riceWaterForecastCycle : riceWaterForecastCycles) {
cycleTotal = cycleTotal.add(riceWaterForecastCycle.getIrrigationUse());
// riceWaterForecastCycle.setIrrigationUse(riceWaterForecastCycle.getIrrigationUse().setScale(2,RoundingMode.HALF_UP));
}
monthTotal = cycleTotal;
vo.setIrrigationMonthTotalUse(monthTotal.setScale(2,RoundingMode.HALF_UP));
vo.setIrrigationCycleTotalUse(cycleTotal.setScale(2,RoundingMode.HALF_UP));
vo.setRiceWaterKis(riceWaterKis);
vo.setRiceWaterForecastMonths(riceWaterForecastMonths);
vo.setRiceWaterForecastCycles(riceWaterForecastCycles);
vo.setRiceGrowConfig(riceGrowConfig);
return vo;
}
}