农业需水

供需平衡分析
master
yangzhe123 2025-12-03 13:52:10 +08:00
parent f9765f11ac
commit 75162d9e33
21 changed files with 752 additions and 10 deletions

View File

@ -0,0 +1,65 @@
package com.gunshi.project.hsz.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gunshi.core.result.R;
import com.gunshi.project.hsz.entity.dto.RiceSupportBalanceCaculateDto;
import com.gunshi.project.hsz.entity.dto.RiceWaterCaculateDto;
import com.gunshi.project.hsz.entity.so.RiceSupportBalanceCaculatePageSo;
import com.gunshi.project.hsz.entity.vo.RiceRqWaterCaculateVo;
import com.gunshi.project.hsz.model.IcWaterForecast;
import com.gunshi.project.hsz.model.RiceRqWater;
import com.gunshi.project.hsz.model.RiceSupportBalance;
import com.gunshi.project.hsz.service.IcWaterForecastService;
import com.gunshi.project.hsz.service.RiceRqWaterService;
import com.gunshi.project.hsz.service.RiceSupportBalanceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Tag(name = "供需平衡分析")
@RestController
@RequestMapping(value="/riceSupportBalance")
public class RiceSupportBalanceController {
@Autowired
private RiceSupportBalanceService riceSupportBalanceService;
@Operation(summary = "分页")
@PostMapping("/page")
public R<Page<RiceSupportBalance>> page(@RequestBody RiceSupportBalanceCaculatePageSo page){
Page<RiceSupportBalance> res = riceSupportBalanceService.queryPage(page);
return R.ok(res);
}
@Operation(summary = "删除")
@PostMapping("/del/{id}")
public R<Boolean> del(@Schema(name = "id") @PathVariable("id") Long id){
boolean flag = riceSupportBalanceService.delData(id);
return R.ok(flag);
}
@Operation(summary = "计算")
@PostMapping("/caculate")
public R<Boolean> caculate(@RequestBody RiceSupportBalanceCaculateDto dto){
riceSupportBalanceService.caculateAndSave(dto);
return R.ok(true);
}
@Operation(summary = "来水预测-分页查询,供需平衡板")
@PostMapping("/icpage")
public R<Page<IcWaterForecast>> icPage(@RequestBody RiceSupportBalanceCaculatePageSo pageSo){
Page<IcWaterForecast> page = riceSupportBalanceService.icPage(pageSo);
return R.ok(page);
}
@Operation(summary = "农业需水-分页查询,供需平衡版")
@PostMapping("/rcpage")
public R<Page<RiceRqWater>> rcPage(@RequestBody RiceSupportBalanceCaculatePageSo pageSo){
Page<RiceRqWater> page = riceSupportBalanceService.rcPage(pageSo);
return R.ok(page);
}
}

View File

@ -0,0 +1,21 @@
package com.gunshi.project.hsz.entity;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
*
*/
@Data
public class RiceSupportMidCaculate {
private String name;//灌溉生长周期
private LocalDateTime startTime;// 开始时间
private LocalDateTime endTime;//结束时间
private BigDecimal irrigationUse;//灌溉用水万m³
}

View File

@ -0,0 +1,28 @@
package com.gunshi.project.hsz.entity.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class RiceSupportBalanceCaculateDto {
private String planName;//方案名称
private LocalDateTime startTime;//开始时间
private LocalDateTime endTime;//结束时间
private Long icId;//来水方案Id
private Long rqId;//需水方案Id
private BigDecimal ecoQ;//生态最小径流(单位m³/s)
private String createName;//创建人
}

View File

@ -0,0 +1,21 @@
package com.gunshi.project.hsz.entity.so;
import com.gunshi.db.dto.PageSo;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class RiceSupportBalanceCaculatePageSo {
private PageSo pageSo;
private LocalDateTime startTime; // 开始时间
private LocalDateTime endTime; // 结束时间
private String planName; // 计划名称
private Integer type; // 类型 0 长期 1短期
}

View File

@ -0,0 +1,10 @@
package com.gunshi.project.hsz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gunshi.project.hsz.model.RiceSupportBalanceDetail;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RiceSupportBalanceDetailMapper extends BaseMapper<RiceSupportBalanceDetail> {
}

View File

@ -0,0 +1,9 @@
package com.gunshi.project.hsz.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gunshi.project.hsz.model.RiceSupportBalance;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RiceSupportBalanceMapper extends BaseMapper<RiceSupportBalance> {
}

View File

@ -91,6 +91,11 @@ public class IcWaterForecast implements Serializable {
@Schema(description = "降雨相似年") @Schema(description = "降雨相似年")
private Integer year; private Integer year;
@TableField(value = "hours")
@Schema(description = "小时")
private Integer hours;
@TableField(exist = false) @TableField(exist = false)
private List<IcWaterForecastDetail> details; private List<IcWaterForecastDetail> details;
} }

View File

@ -28,12 +28,12 @@ public class IcWaterForecastDetail implements Serializable {
private Long icWaterId; private Long icWaterId;
@TableField(value = "start_time") @TableField(value = "start_time")
@Schema(description = "预测开始时间(长期)") @Schema(description = "预测开始时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime startTime; private LocalDateTime startTime;
@TableField(value = "end_time") @TableField(value = "end_time")
@Schema(description = "预测结束时间(长期)") @Schema(description = "预测结束时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime endTime; private LocalDateTime endTime;

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -29,7 +30,7 @@ public class RiceGrowConfig implements Serializable {
/** /**
* *
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键") @Schema(description = "主键")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -27,7 +28,7 @@ public class RiceIrrigationUse implements Serializable {
/** /**
* id * id
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键id") @Schema(description = "主键id")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -14,6 +15,7 @@ import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -30,7 +32,7 @@ public class RiceRqWater implements Serializable {
/** /**
* ID * ID
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键ID") @Schema(description = "主键ID")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -56,7 +58,7 @@ public class RiceRqWater implements Serializable {
@TableField(value = "create_time") @TableField(value = "create_time")
@Schema(description = "制定时间") @Schema(description = "制定时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime; private LocalDateTime createTime;
/** /**
* *

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -15,6 +16,7 @@ import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
@Data @Data
@TableName(value = "rice_support_balance") @TableName(value = "rice_support_balance")
@ -23,7 +25,7 @@ public class RiceSupportBalance implements Serializable {
/** /**
* ID * ID
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键ID") @Schema(description = "主键ID")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;
@ -101,4 +103,7 @@ public class RiceSupportBalance implements Serializable {
@TableField(value = "ic_water_id") @TableField(value = "ic_water_id")
@Schema(description = "来水预测主键") @Schema(description = "来水预测主键")
private Long icWaterId; private Long icWaterId;
@TableField(exist = false)
private List<RiceSupportBalanceDetail> details;
} }

View File

@ -0,0 +1,71 @@
package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName(value = "rice_support_balance_detail")
public class RiceSupportBalanceDetail implements Serializable {
/**
* ID
*/
@TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* ID
*/
@TableField(value = "rice_support_id")
@Schema(description = "水稻支持平衡主表ID")
private Long riceSupportId;
/**
*
*/
@TableField(value = "tm")
@Schema(description = "时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime tm;
/**
* (m³)-
*/
@TableField(value = "irrigation_use")
@Schema(description = "灌溉水量(万m³)-需水量")
private BigDecimal irrigationUse;
/**
* (m³)-
*/
@TableField(value = "irrigation_plan")
@Schema(description = "灌溉水量(万m³)-计划供水量")
private BigDecimal irrigationPlan;
/**
* (m³)-
*/
@TableField(value = "eco_use")
@Schema(description = "生态水量(万m³)-需水量")
private BigDecimal ecoUse;
/**
* (m³)-
*/
@TableField(value = "eco_plan")
@Schema(description = "生态水量(万m³)-计划供水量")
private BigDecimal ecoPlan;
}

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -27,7 +28,7 @@ public class RiceWaterForecastCycle implements Serializable {
/** /**
* id * id
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键id") @Schema(description = "主键id")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -27,7 +28,7 @@ public class RiceWaterForecastMonth implements Serializable {
/** /**
* id * id
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键id") @Schema(description = "主键id")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;

View File

@ -1,5 +1,6 @@
package com.gunshi.project.hsz.model; package com.gunshi.project.hsz.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
@ -30,7 +31,7 @@ public class RiceWaterKi implements Serializable {
/** /**
* *
*/ */
@TableId(value = "id") @TableId(value = "id",type = IdType.AUTO)
@Schema(description = "主键") @Schema(description = "主键")
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long id; private Long id;

View File

@ -56,6 +56,13 @@ public class IcWaterForecastService extends ServiceImpl<IcWaterForecastMapper, I
totalWater = totalWater.add(detail.getForecastWater() != null?detail.getForecastWater():BigDecimal.ZERO); totalWater = totalWater.add(detail.getForecastWater() != null?detail.getForecastWater():BigDecimal.ZERO);
} }
dto.setForecastWater(totalWater); dto.setForecastWater(totalWater);
if(dto.getType() == 1){
LocalDateTime now = LocalDateTime.now();
LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0);
LocalDateTime plusHours = nowHour.plusHours(dto.getHours());
dto.setStartTime(nowHour);
dto.setEndTime(plusHours);
}
save(dto); save(dto);
details.stream().forEach(item -> { details.stream().forEach(item -> {
item.setIcWaterId(dto.getId()); item.setIcWaterId(dto.getId());
@ -66,6 +73,16 @@ public class IcWaterForecastService extends ServiceImpl<IcWaterForecastMapper, I
} }
public IcWaterForecast queryById(Long id){
IcWaterForecast icWaterForecast = this.baseMapper.selectById(id);
if(icWaterForecast == null){
return icWaterForecast;
}
icWaterForecast.setDetails(icWaterForecastDetailService.listByForecastId(id));
return icWaterForecast;
}
public Page<IcWaterForecast> pageQuery(IcWaterForecastPageSo pageSo) { public Page<IcWaterForecast> pageQuery(IcWaterForecastPageSo pageSo) {
LambdaQueryWrapper<IcWaterForecast> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<IcWaterForecast> queryWrapper = new LambdaQueryWrapper<>();
if (pageSo.getType() != null) { if (pageSo.getType() != null) {
@ -99,6 +116,13 @@ public class IcWaterForecastService extends ServiceImpl<IcWaterForecastMapper, I
} }
dto.setForecastWater(totalWater); dto.setForecastWater(totalWater);
dto.setCreateTime(LocalDateTime.now()); dto.setCreateTime(LocalDateTime.now());
if(dto.getType() == 1){
LocalDateTime now = LocalDateTime.now();
LocalDateTime nowHour = now.withMinute(0).withSecond(0).withNano(0);
LocalDateTime plusHours = nowHour.plusHours(dto.getHours());
dto.setStartTime(nowHour);
dto.setEndTime(plusHours);
}
save(dto); save(dto);
dto.getDetails().stream().forEach(item -> { dto.getDetails().stream().forEach(item -> {
item.setIcWaterId(dto.getId()); item.setIcWaterId(dto.getId());

View File

@ -74,11 +74,28 @@ public class RiceRqWaterService extends ServiceImpl<RiceRqWaterMapper, RiceRqWat
return riceRqWaterPage; 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) { public RiceRqWater saveData(RiceRqWater dto) {
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig(); RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis(); List<RiceWaterKi> riceWaterKis = dto.getRiceWaterKis();
List<RiceWaterForecastCycle> riceWaterForecastCycles = dto.getRiceWaterForecastCycles(); List<RiceWaterForecastCycle> riceWaterForecastCycles = dto.getRiceWaterForecastCycles();
List<RiceWaterForecastMonth> riceWaterForecastMonths = dto.getRiceWaterForecastMonths(); List<RiceWaterForecastMonth> riceWaterForecastMonths = dto.getRiceWaterForecastMonths();
dto.setReqWater(riceGrowConfig.getIrrigationUse());
dto.setCreateTime(LocalDateTime.now());
save(dto); save(dto);
riceGrowConfig.setRiceWaterId(dto.getId()); riceGrowConfig.setRiceWaterId(dto.getId());
riceWaterKis.stream().forEach(o ->{ riceWaterKis.stream().forEach(o ->{
@ -209,6 +226,7 @@ public class RiceRqWaterService extends ServiceImpl<RiceRqWaterMapper, RiceRqWat
List<RiceIrrigationUse> res = new ArrayList<>(); List<RiceIrrigationUse> res = new ArrayList<>();
orderByStartTimeAsc(riceWaterKis); orderByStartTimeAsc(riceWaterKis);
RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig(); RiceGrowConfig riceGrowConfig = dto.getRiceGrowConfig();
riceGrowConfig.setCycle(LocalDateTimeUtils.getTotalDayByRangeDate(riceWaterKis.getFirst().getStartTime(),riceWaterKis.getLast().getEndTime()));
Integer year = riceGrowConfig.getYear();//相似年 Integer year = riceGrowConfig.getYear();//相似年
List<TyYearRainfallVo> tyYearRainfallVos = tyYearRainfallService.queryList(); List<TyYearRainfallVo> tyYearRainfallVos = tyYearRainfallService.queryList();
List<TyYearRainfallVo> collect = tyYearRainfallVos.stream().filter(o -> { List<TyYearRainfallVo> collect = tyYearRainfallVos.stream().filter(o -> {
@ -599,6 +617,7 @@ public class RiceRqWaterService extends ServiceImpl<RiceRqWaterMapper, RiceRqWat
vo.setRiceWaterKis(riceWaterKis); vo.setRiceWaterKis(riceWaterKis);
vo.setRiceWaterForecastMonths(riceWaterForecastMonths); vo.setRiceWaterForecastMonths(riceWaterForecastMonths);
vo.setRiceWaterForecastCycles(riceWaterForecastCycles); vo.setRiceWaterForecastCycles(riceWaterForecastCycles);
vo.setRiceGrowConfig(riceGrowConfig);
return vo; return vo;
} }

View File

@ -0,0 +1,28 @@
package com.gunshi.project.hsz.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.project.hsz.mapper.RiceSupportBalanceDetailMapper;
import com.gunshi.project.hsz.model.RiceSupportBalanceDetail;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RiceSupportBalanceDetailService extends ServiceImpl<RiceSupportBalanceDetailMapper, RiceSupportBalanceDetail> {
public List<RiceSupportBalanceDetail> selectByRCId(Long id) {
LambdaQueryWrapper<RiceSupportBalanceDetail> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RiceSupportBalanceDetail::getRiceSupportId,id);
return this.baseMapper.selectList(queryWrapper);
}
public void delByRcId(Long id) {
LambdaQueryWrapper<RiceSupportBalanceDetail> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(RiceSupportBalanceDetail::getRiceSupportId,id);
baseMapper.delete(queryWrapper);
}
}

View File

@ -0,0 +1,338 @@
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.common.model.StRsvrRReal;
import com.gunshi.project.hsz.entity.RiceSupportMidCaculate;
import com.gunshi.project.hsz.entity.dto.RiceSupportBalanceCaculateDto;
import com.gunshi.project.hsz.entity.so.RiceSupportBalanceCaculatePageSo;
import com.gunshi.project.hsz.entity.vo.TyYearRainfallVo;
import com.gunshi.project.hsz.mapper.RiceSupportBalanceMapper;
import com.gunshi.project.hsz.model.*;
import com.gunshi.project.hsz.util.LocalDateTimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.jodconverter.core.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RiceSupportBalanceService extends ServiceImpl<RiceSupportBalanceMapper, RiceSupportBalance> {
@Autowired
private RiceRqWaterService riceRqWaterService;
@Autowired
private RiceSupportBalanceDetailService riceSupportBalanceDetailService;
@Autowired
private IcWaterForecastService icWaterForecastService;
@Autowired
private AttResBaseService attResBaseService; //水库站点
@Autowired
private StZvarlBService stZvarlBService;//库容曲线
@Autowired
private StRsvrRRealService stRsvrRRealService;
@Autowired
private TyYearRainfallService tyYearRainfallService;//降雨相似年资料
public AttResBase getAttResBase(){
return attResBaseService.list().get(0);
}
public void caculateAndSave(RiceSupportBalanceCaculateDto dto) {
RiceRqWater riceRqWater = riceRqWaterService.queryById(dto.getRqId());
IcWaterForecast icWaterForecast = icWaterForecastService.queryById(dto.getIcId());
//获取生态每天生态需水量万m³
BigDecimal dailyEcoWaterUse;
dailyEcoWaterUse = dto.getEcoQ().multiply(new BigDecimal("3600").multiply(new BigDecimal("24")));
dailyEcoWaterUse = dailyEcoWaterUse.divide(new BigDecimal("10000"));//转为万m³
List<LocalDateTime> allDaysByStartAndEndTime = LocalDateTimeUtils.getAllDaysByStartAndEndTime(dto.getStartTime(), dto.getEndTime());
LocalDateTime today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
BigDecimal totalIcWater = BigDecimal.ZERO;//总来水量
AttResBase attResBase = getAttResBase();
String stcd = attResBase.getStcd();//获取站点编码
//获取死水位
BigDecimal deadLev = attResBase.getDeadLev();
StRsvrRReal stRsvrRReal = stRsvrRRealService.getBaseMapper().queryRzByStcd(stcd);
List<StZvarlB> list = stZvarlBService.lambdaQuery().orderByAsc(StZvarlB::getRz).list();
BigDecimal w = stZvarlBService.getWByZvarl(list, stRsvrRReal.getRz());//获取库容
BigDecimal deadW = stZvarlBService.getWByZvarl(list, deadLev);//死水位库容
Integer year = icWaterForecast.getYear();//获取相似年
if(dto.getStartTime().isAfter(today)){
// 总来水量 = 当前~开始时间这一段时间的来水量 + 来回方案来水
//方案来水量的时间范围 今天1号开始时间4号需要计算1-3号共3天
Integer gapDay = LocalDateTimeUtils.getTotalDayByRangeDate(today, dto.getStartTime().minusDays(1)); // 注意:这里应该是到开始时间前一天
//获取降雨相似年资料
BigDecimal totalRainfallWater = BigDecimal.ZERO;
for (TyYearRainfallVo tyYearRainfallVo : tyYearRainfallService.queryList()) {
if (tyYearRainfallVo.getYear().equals(year)) {
List<TyYearRainfall> monthData = tyYearRainfallVo.getList();
// 获取时间范围内的所有月份
List<Integer> months = LocalDateTimeUtils.getMonthsInPeriod(today, dto.getStartTime());
for (Integer month : months) {
// 计算该月份在时间范围内的天数
int daysInMonthForPeriod = LocalDateTimeUtils.calculateDaysInMonthForPeriod(
today, dto.getStartTime().minusDays(1), month
);
if (daysInMonthForPeriod > 0) {
// 找到该月份的降雨资料
for (TyYearRainfall monthDatum : monthData) {
if (monthDatum.getMonth().equals(month)) {
BigDecimal monthRainfall = monthDatum.getDrp();
if (monthRainfall != null) {
int totalDaysInMonth = LocalDateTimeUtils.getTotalDaysInMonth(
today.getYear(), month
);
// 该月份的平均日降雨量
BigDecimal avgDailyRainfall = monthRainfall.divide(
new BigDecimal(totalDaysInMonth), 4, BigDecimal.ROUND_HALF_UP
);
// 该月份在时间范围内的总降雨量
BigDecimal monthRainfallInPeriod = avgDailyRainfall.multiply(
new BigDecimal(daysInMonthForPeriod)
);
totalRainfallWater = totalRainfallWater.add(monthRainfallInPeriod);
}
break;
}
}
}
}
break;
}
}
// 总来水量 = 当前到开始时间的降雨来水量 + 方案来水
BigDecimal currentToStartWater = totalRainfallWater; // 这里假设totalRainfallWater就是需要的来水量
totalIcWater = totalIcWater.add(currentToStartWater).add(icWaterForecast.getForecastWater()); // 将当前到开始时间的来水量加入总来水量
}else{
// 总来水量 = 当前蓄水量 + 来水方案中的来水
BigDecimal forecastWater = icWaterForecast.getForecastWater();
totalIcWater = w.add(forecastWater);
}
BigDecimal totalNeedWater = BigDecimal.ZERO;
//获取总需水量(需水总量 + 每日生态用水量 * 天数)
totalNeedWater = riceRqWater.getReqWater().add(dailyEcoWaterUse.multiply(new BigDecimal(allDaysByStartAndEndTime.size())));
//总计划供水量
BigDecimal totalPlan;
if(totalIcWater.compareTo(totalNeedWater) > 0){
//如果来水量大于需水量
totalPlan = totalNeedWater;
}else{
//总计划供水量 = (当前蓄水量 + 来水) - 死水位对应库容
totalPlan = (w.add(totalIcWater)).subtract(deadW);
}
/**
*
*
* 80001007900 + = 7500
* 1007400(+)/
*/
//获取灌溉用水周期参数
List<RiceWaterForecastCycle> riceWaterForecastCycles = riceRqWater.getRiceWaterForecastCycles();
List<RiceSupportMidCaculate> riceSupportMidCaculates = fillData(riceWaterForecastCycles, riceRqWater.getRiceWaterKis());
// 先计算总灌溉需水量
BigDecimal totalIrrigationNeed = BigDecimal.ZERO;
for (RiceSupportMidCaculate caculate : riceSupportMidCaculates) {
if (caculate.getIrrigationUse() != null) {
totalIrrigationNeed = totalIrrigationNeed.add(caculate.getIrrigationUse());
}
}
// 计算可供灌溉的生态水量
BigDecimal totalWaterForIrrigation;
BigDecimal totalWaterForEco = dailyEcoWaterUse.multiply(new BigDecimal(allDaysByStartAndEndTime.size()));
// 如果来水量足够供应所有生态用水和灌溉用水
if (totalPlan.compareTo(totalNeedWater) >= 0) {
// 充足,完全满足
totalWaterForIrrigation = totalIrrigationNeed;
}else {
// 不足,优先保障生态用水,剩余给灌溉
if (totalPlan.compareTo(totalWaterForEco) >= 0) {
// 生态用水能完全满足,剩余给灌溉
totalWaterForIrrigation = totalPlan.subtract(totalWaterForEco);
} else {
// 连生态用水都不能完全满足
totalWaterForIrrigation = BigDecimal.ZERO;
totalWaterForEco = totalPlan; // 实际生态供水量调整为可用的总量
dailyEcoWaterUse = totalWaterForEco.divide(
new BigDecimal(allDaysByStartAndEndTime.size()), 4, BigDecimal.ROUND_HALF_UP
);
}
}
// 计算灌溉用水的缩放比例
BigDecimal irrigationRatio;
if (totalIrrigationNeed.compareTo(BigDecimal.ZERO) > 0) {
irrigationRatio = totalWaterForIrrigation.divide(totalIrrigationNeed, 4, BigDecimal.ROUND_HALF_UP);
} else {
irrigationRatio = BigDecimal.ZERO;
}
//首先保存主表信息
RiceSupportBalance riceSupportBalance = new RiceSupportBalance();
riceSupportBalance.setRiceWaterId(dto.getRqId());
riceSupportBalance.setIcWaterId(dto.getIcId());
riceSupportBalance.setStartTime(dto.getStartTime());
riceSupportBalance.setEndTime(dto.getEndTime());
riceSupportBalance.setCreateTime(LocalDateTime.now());
riceSupportBalance.setTotalSupport(totalPlan);
riceSupportBalance.setTotalCost(totalIrrigationNeed);
riceSupportBalance.setCreateName(dto.getCreateName());
riceSupportBalance.setStatus(0);
this.save(riceSupportBalance);
// 创建final或effectively final的局部变量副本
final Long mainId = riceSupportBalance.getId();
final BigDecimal finalDailyEcoWaterUse = dailyEcoWaterUse;
final BigDecimal finalIrrigationRatio = irrigationRatio;
final List<LocalDateTime> finalAllDays = new ArrayList<>(allDaysByStartAndEndTime);
final List<RiceSupportMidCaculate> finalRiceSupportMidCaculates = new ArrayList<>(riceSupportMidCaculates);
// 在新线程中执行计算和保存
new Thread(() -> {
try {
List<RiceSupportBalanceDetail> saveDetails = new ArrayList<>();
for (LocalDateTime localDateTime : finalAllDays) {
RiceSupportBalanceDetail entity = new RiceSupportBalanceDetail();
entity.setTm(localDateTime);
// 查找当前日期属于哪个生长周期,计算灌溉需水量
BigDecimal dailyIrrigationNeed = BigDecimal.ZERO; // 灌溉需水量
for (RiceSupportMidCaculate caculate : finalRiceSupportMidCaculates) {
if (!localDateTime.isBefore(caculate.getStartTime()) &&
!localDateTime.isAfter(caculate.getEndTime())) {
// 计算该生长周期的天数
int daysInCycle = LocalDateTimeUtils.getTotalDayByRangeDate(
caculate.getStartTime(), caculate.getEndTime()
);
if (daysInCycle > 0 && caculate.getIrrigationUse() != null) {
// 该生长周期每天的灌溉需水量
dailyIrrigationNeed = caculate.getIrrigationUse()
.divide(new BigDecimal(daysInCycle), 2, BigDecimal.ROUND_HALF_UP);
}
break;
}
}
// 设置灌溉需水量
entity.setIrrigationUse(dailyIrrigationNeed);
// 按比例计算灌溉计划供水量
BigDecimal dailyIrrigationPlan = dailyIrrigationNeed.multiply(finalIrrigationRatio);
entity.setIrrigationPlan(dailyIrrigationPlan);
// 每日生态需水量
entity.setEcoUse(finalDailyEcoWaterUse);
// 每日生态计划供水量
entity.setEcoPlan(finalDailyEcoWaterUse);
// 设置主表关联ID
entity.setRiceSupportId(mainId);
saveDetails.add(entity);
}
if(!saveDetails.isEmpty()){
riceSupportBalanceDetailService.saveBatch(saveDetails);
log.info("成功保存水稻平衡供水明细主表ID{},明细数量:{}",
mainId, saveDetails.size());
}
riceSupportBalance.setStatus(1);
updateById(riceSupportBalance);
} catch (Exception e) {
log.error("保存水稻平衡供水明细失败", e);
// 这里可以添加异常处理,比如记录日志、发送通知等
}
}).start();
// 主线程立即返回,不等待明细计算完成
log.info("水稻平衡供水主表已保存,明细计算正在异步执行");
}
public Page<IcWaterForecast> icPage(RiceSupportBalanceCaculatePageSo pageSo) {
LambdaQueryWrapper<IcWaterForecast> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.le(IcWaterForecast::getStartTime,pageSo.getStartTime());
queryWrapper.ge(IcWaterForecast::getEndTime,pageSo.getEndTime());
if(pageSo.getType() != null){
queryWrapper.eq(IcWaterForecast::getType, pageSo.getType());
}
if(!StringUtils.isBlank(pageSo.getPlanName())){
queryWrapper.like(IcWaterForecast::getPlanName, pageSo.getPlanName());
}
Page<IcWaterForecast> icWaterForecastPage = icWaterForecastService.getBaseMapper().selectPage(pageSo.getPageSo().toPage(), queryWrapper);
return icWaterForecastPage;
}
public Page<RiceRqWater> rcPage(RiceSupportBalanceCaculatePageSo pageSo) {
List<Integer> yearByRangeDate = LocalDateTimeUtils.getYearByRangeDate(pageSo.getStartTime(), pageSo.getEndTime());
LambdaQueryWrapper<RiceRqWater> queryWrapper = new LambdaQueryWrapper<>();
if(!StringUtils.isBlank(pageSo.getPlanName())){
queryWrapper.like(RiceRqWater::getPlanName, pageSo.getPlanName());
}
queryWrapper.in(RiceRqWater::getYear, yearByRangeDate);
Page<RiceRqWater> riceRqWaterPage = riceRqWaterService.getBaseMapper().selectPage(pageSo.getPageSo().toPage(), queryWrapper);
return riceRqWaterPage;
}
private List<RiceSupportMidCaculate> fillData(List<RiceWaterForecastCycle> riceWaterForecastCycles, List<RiceWaterKi> riceWaterKis){
List<RiceSupportMidCaculate> res = new ArrayList<>();
for (RiceWaterKi riceWaterKi : riceWaterKis) {
RiceSupportMidCaculate entity = new RiceSupportMidCaculate();
entity.setStartTime(riceWaterKi.getStartTime());
entity.setEndTime(riceWaterKi.getEndTime());
entity.setName(riceWaterKi.getRiceGrowStage());
// 修正:查找匹配的灌溉用水数据
Optional<RiceWaterForecastCycle> matchingCycle = riceWaterForecastCycles.stream()
.filter(cycle -> cycle.getRiceGrowStage().equals(riceWaterKi.getRiceGrowStage()))
.findFirst();
// 根据是否找到匹配设置灌溉用水
if (matchingCycle.isPresent()) {
// 假设RiceWaterForecastCycle中有getIrrigationUse方法
entity.setIrrigationUse(matchingCycle.get().getIrrigationUse());
} else {
// 如果没有匹配的设置默认值或null
entity.setIrrigationUse(BigDecimal.ZERO); // 或者BigDecimal.ZERO等默认值
}
res.add(entity);
}
return res;
}
public Page<RiceSupportBalance> queryPage(RiceSupportBalanceCaculatePageSo page) {
LambdaQueryWrapper<RiceSupportBalance> queryWrapper = new LambdaQueryWrapper<>();
if(!StringUtils.isBlank(page.getPlanName())){
queryWrapper.like(RiceSupportBalance::getPlanName, page.getPlanName());
}
Page<RiceSupportBalance> riceSupportBalancePage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper);
for (RiceSupportBalance record : riceSupportBalancePage.getRecords()) {
List<RiceSupportBalanceDetail> details = riceSupportBalanceDetailService.selectByRCId(record.getId());
record.setDetails(details);
}
return riceSupportBalancePage;
}
public boolean delData(Long id) {
riceSupportBalanceDetailService.delByRcId(id);
boolean flag = removeById(id);
return flag;
}
}

View File

@ -2,7 +2,10 @@ package com.gunshi.project.hsz.util;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class LocalDateTimeUtils { public class LocalDateTimeUtils {
@ -99,6 +102,94 @@ public class LocalDateTimeUtils {
return months; return months;
} }
/**
*
*
* @param startTime
* @param endTime
* @return
*/
public static List<LocalDateTime> getAllDaysByStartAndEndTime(LocalDateTime startTime, LocalDateTime endTime) {
// 1. 参数校验
if (startTime == null || endTime == null) {
throw new IllegalArgumentException("开始时间和结束时间不能为空");
}
if (startTime.isAfter(endTime)) {
throw new IllegalArgumentException("开始时间不能晚于结束时间");
}
List<LocalDateTime> result = new ArrayList<>();
// 2. 获取开始日期的0点
LocalDateTime currentDay = startTime.toLocalDate().atStartOfDay();
LocalDateTime endDay = endTime.toLocalDate().atStartOfDay();
// 3. 循环添加每一天
while (!currentDay.isAfter(endDay)) {
result.add(currentDay);
currentDay = currentDay.plusDays(1);
}
return result;
}
/**
*
* @param startTime
* @param endTime
* @return
*/
public static List<Integer> getYearByRangeDate(LocalDateTime startTime, LocalDateTime endTime) {
if (startTime == null || endTime == null) {
throw new IllegalArgumentException("开始时间和结束时间不能为空");
}
if (startTime.isAfter(endTime)) {
throw new IllegalArgumentException("开始时间不能晚于结束时间");
}
int startYear = startTime.getYear();
int endYear = endTime.getYear();
// 使用Stream生成年份列表
return IntStream.rangeClosed(startYear, endYear)
.boxed()
.collect(Collectors.toList());
}
/**
*
*
*
* @param startTime
* @param endTime
* @return
*/
public static Integer getTotalDayByRangeDate(LocalDateTime startTime, LocalDateTime endTime) {
if (startTime == null || endTime == null) {
throw new IllegalArgumentException("开始时间和结束时间不能为空");
}
if (startTime.isAfter(endTime)) {
throw new IllegalArgumentException("开始时间不能晚于结束时间");
}
// 转换为LocalDate忽略时间部分
LocalDate startDate = startTime.toLocalDate();
LocalDate endDate = endTime.toLocalDate();
// 使用ChronoUnit.DAYS.between计算天数差+1表示包含起止日
long days = ChronoUnit.DAYS.between(startDate, endDate) + 1;
// 转换为Integer注意数值范围检查
if (days > Integer.MAX_VALUE) {
throw new ArithmeticException("天数超出Integer范围");
}
return (int) days;
}
} }