413 lines
18 KiB
Java
413 lines
18 KiB
Java
package com.gunshi.project.ss.service;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||
import com.gunshi.project.ss.entity.so.GateHisPageSo;
|
||
import com.gunshi.project.ss.entity.vo.AttResBaseVo;
|
||
import com.gunshi.project.ss.entity.vo.GateStautsVo;
|
||
import com.gunshi.project.ss.entity.vo.GateValveOplogVo;
|
||
import com.gunshi.project.ss.mapper.GateValveRealMapper;
|
||
import com.gunshi.project.ss.mapper.StWaterRRealMapper;
|
||
import com.gunshi.project.ss.mapper.TyYearRainfallMapper;
|
||
import com.gunshi.project.ss.model.*;
|
||
import com.gunshi.project.ss.util.DataHandleUtil;
|
||
import com.gunshi.project.ss.util.DateUtil;
|
||
import com.gunshi.project.ss.util.ExcelUtil;
|
||
import jakarta.annotation.Resource;
|
||
import jakarta.servlet.http.HttpServletResponse;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.apache.commons.lang3.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.math.RoundingMode;
|
||
import java.time.LocalDate;
|
||
import java.util.*;
|
||
import java.util.stream.Collectors;
|
||
|
||
/**
|
||
* 描述: 闸阀开关表
|
||
* author: xusan
|
||
* date: 2024-07-08 17:30:37
|
||
*/
|
||
@Service
|
||
@Slf4j
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public class GateValveRealService extends ServiceImpl<GateValveRealMapper, GateValveReal>
|
||
{
|
||
@Resource
|
||
private com.gunshi.project.ss.model.GateValveKeyAutoDao gateValveKeyAutoDao;
|
||
|
||
@Resource
|
||
private com.gunshi.project.ss.model.GateValveOplogAutoDao gateValveOplogAutoDao;
|
||
|
||
@Resource
|
||
private ReservoirWaterService reservoirWaterService;
|
||
|
||
@Resource
|
||
private StWaterRRealMapper stWaterRRealMapper;
|
||
|
||
@Resource
|
||
private TyYearRainfallMapper tyYearRainfallMapper;
|
||
|
||
public List<GateStautsVo> gateStatusList() {
|
||
List<GateStautsVo> list = baseMapper.gateStatusList();
|
||
for(GateStautsVo vo : list){
|
||
if(vo.getTm() != null && DateUtil.hoursBetweenDate(vo.getTm(), new Date()) > 2){
|
||
vo.setFlag(1);
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
|
||
public BigDecimal realQ(String valveCode) {
|
||
return baseMapper.realQ(valveCode);
|
||
}
|
||
|
||
public String control(GateValveKey gateValveKey) {
|
||
//先判断密码是否正确
|
||
String valveCode = gateValveKey.getValveCode();
|
||
String key = gateValveKey.getKey();
|
||
GateValveKey valveKey = gateValveKeyAutoDao.getById(valveCode);
|
||
if(valveKey == null || !key.equals(valveKey.getKey())){
|
||
throw new IllegalArgumentException("密码不正确");
|
||
}
|
||
//生成闸阀操作日志
|
||
GateValveOplog oplog = new GateValveOplog();
|
||
oplog.setId(IdWorker.getId());
|
||
oplog.setStatus(gateValveKey.getStatus());
|
||
oplog.setOpContent("设置闸阀开度为"+gateValveKey.getStatus());
|
||
oplog.setValveCode(valveCode);
|
||
oplog.setTm(new Date());
|
||
oplog.setOpUserId(1L);
|
||
oplog.setOpUserName("胡兵");
|
||
|
||
GateValveReal valveReal = this.getOne(new QueryWrapper<GateValveReal>().eq("valve_code", valveCode));
|
||
oplog.setBeforeStatus(valveReal == null ? "-" : valveReal.getStatus());
|
||
gateValveOplogAutoDao.save(oplog);
|
||
//todo 给闸阀下发调节指令
|
||
// GateValveR gateValveR = new GateValveR();
|
||
// BeanUtils.copyProperties(gateValveKey,gateValveR);
|
||
// gateValveR.setTm(new Date());
|
||
// gateValveRMapper.insert(gateValveR);
|
||
//
|
||
// GateValveReal real = new GateValveReal();
|
||
// BeanUtils.copyProperties(gateValveKey,real);
|
||
// real.setTm(new Date());
|
||
// this.remove(new QueryWrapper<GateValveReal>().eq("valve_code",valveCode));
|
||
// this.save(real);
|
||
return "调节闸阀成功";
|
||
}
|
||
|
||
public Page<GateValveOplogVo> logPage(GateHisPageSo so) {
|
||
return baseMapper.logPage(so.getPageSo().toPage(),so);
|
||
}
|
||
|
||
public GateValveOplog loginfo(String code) {
|
||
if(StringUtils.isBlank(code)){
|
||
return null;
|
||
}
|
||
LambdaQueryWrapper<GateValveOplog> qw = new LambdaQueryWrapper();
|
||
qw.eq(GateValveOplog::getValveCode,code);
|
||
qw.orderByDesc(GateValveOplog::getTm).last("LIMIT 1");
|
||
List<GateValveOplog> list = gateValveOplogAutoDao.list(qw);
|
||
return list.isEmpty() ? null : list.get(0);
|
||
}
|
||
|
||
public void logExport(GateHisPageSo so, HttpServletResponse response) {
|
||
List<GateValveOplogVo> logList = baseMapper.logList(so);
|
||
ExcelUtil.exportExcel(logList,"闸阀操作日志",GateValveOplogVo.class,response,"闸阀操作日志");
|
||
}
|
||
|
||
@Autowired
|
||
private StEvpoService stEvpoService;
|
||
|
||
@Autowired
|
||
private StFlowRService stFlowRService;
|
||
|
||
@Autowired
|
||
private StWaterRRealService stWaterRRealService;
|
||
|
||
public Map<BigDecimal, String> supplyTime(Integer year, Integer month) {
|
||
Map<BigDecimal, String> result = new HashMap<>();
|
||
|
||
// 获取所有月份的日蒸发量数据
|
||
List<StEvpo> allEvaporationData = stEvpoService.lambdaQuery().list();
|
||
Map<Integer, BigDecimal> evaporationMap = allEvaporationData.stream()
|
||
.collect(Collectors.toMap(StEvpo::getMonth, StEvpo::getEvaporation));
|
||
|
||
// 获取水库基础数据
|
||
List<AttResBaseVo> reservoirList = reservoirWaterService.list();
|
||
if (CollectionUtils.isEmpty(reservoirList)) {
|
||
return result;
|
||
}
|
||
AttResBaseVo reservoir = reservoirList.get(0);
|
||
|
||
// 初始可供水量 = 实时库容 - 死库容 (万m³)
|
||
BigDecimal nowCap = reservoir.getNowCap() == null ? BigDecimal.ZERO : reservoir.getNowCap();
|
||
BigDecimal deadCap = reservoir.getDeadCap() == null ? BigDecimal.ZERO : reservoir.getDeadCap();
|
||
BigDecimal availableWater = nowCap.subtract(deadCap);
|
||
|
||
Date tm = reservoir.getTm();
|
||
Calendar now = Calendar.getInstance();
|
||
now.set(Calendar.MINUTE, 0);
|
||
now.set(Calendar.SECOND, 0);
|
||
now.set(Calendar.MILLISECOND, 0);
|
||
Date currentHour = now.getTime();
|
||
if(tm.before(currentHour)){
|
||
result.put(BigDecimal.ZERO,"当前时间无最新水位数据");
|
||
return result;
|
||
}
|
||
|
||
// 如果初始可供水量就为0或负数,直接返回
|
||
if (availableWater.compareTo(BigDecimal.ZERO) <= 0) {
|
||
result.put(BigDecimal.ZERO, "当前无可供水量");
|
||
return result;
|
||
}
|
||
|
||
// 获取当前流量数据
|
||
List<StWaterRReal> waterFlowList = stWaterRRealService.listNewData();
|
||
BigDecimal totalFlow = waterFlowList.stream()
|
||
.map(StWaterRReal::getQ)
|
||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
// 计算日供水量 (m³/d) 并转换为万m³/d
|
||
BigDecimal dailySupply = totalFlow.multiply(new BigDecimal(3600 * 24));
|
||
BigDecimal dailySupplyInTenThousand = dailySupply.divide(new BigDecimal(10000), 10, RoundingMode.HALF_UP);
|
||
|
||
// 从当前时间开始计算
|
||
Calendar calendar = Calendar.getInstance();
|
||
int currentYear = calendar.get(Calendar.YEAR);
|
||
int currentMonth = calendar.get(Calendar.MONTH) + 1;
|
||
|
||
// 计算当前月份剩余天数
|
||
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||
int daysInCurrentMonth = calendar.get(Calendar.DAY_OF_MONTH);
|
||
int currentDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
|
||
int remainingDaysInMonth = daysInCurrentMonth - currentDay + 1;
|
||
|
||
BigDecimal totalSupplyDays = BigDecimal.ZERO;
|
||
BigDecimal remainingWater = availableWater;
|
||
|
||
// 判断是否计算预测水量
|
||
boolean calculatePredictWater = (year != null && month != null);
|
||
|
||
// 逐月计算,直到可供水量耗尽
|
||
int calcYear = currentYear;
|
||
int calcMonth = currentMonth;
|
||
boolean waterExhausted = false;
|
||
|
||
while (remainingWater.compareTo(BigDecimal.ZERO) > 0 && !waterExhausted) {
|
||
// 获取当前计算月份的蒸发量
|
||
String monthKey = String.valueOf(calcMonth);
|
||
BigDecimal monthlyEvaporation = evaporationMap.getOrDefault(Integer.valueOf(monthKey), BigDecimal.ZERO);
|
||
|
||
// 计算当前月份的预测来水量(只有当传入年份和月份不为空,且当前月份在预测范围内时才计算)
|
||
BigDecimal monthlyPredictWater = BigDecimal.ZERO;
|
||
if (calculatePredictWater && isMonthInPredictRange(calcMonth, currentMonth, month)) {
|
||
monthlyPredictWater = calcMonthlyPredictV(year, calcMonth, reservoir.getWatShedArea());
|
||
}
|
||
|
||
// 当前月份总可用水量 = 剩余水量 + 预测来水量
|
||
BigDecimal monthlyTotalWater = remainingWater.add(monthlyPredictWater);
|
||
|
||
// 当前月份日消耗量 = 日供水量 + 日蒸发量 (万m³/d)
|
||
BigDecimal dailyConsumption = dailySupplyInTenThousand.add(monthlyEvaporation);
|
||
|
||
if (dailyConsumption.compareTo(BigDecimal.ZERO) <= 0) {
|
||
// 如果日消耗量为0或负数,说明可以无限供水
|
||
totalSupplyDays = new BigDecimal("9999"); // 表示无限期
|
||
break;
|
||
}
|
||
|
||
// 计算当前月份可供水天数
|
||
int daysInMonth = getDaysInMonth(calcYear, calcMonth);
|
||
int daysToCalculate = (calcYear == currentYear && calcMonth == currentMonth) ?
|
||
remainingDaysInMonth : daysInMonth;
|
||
|
||
// 当前月份最大可供水量 = 日消耗量 * 当月剩余天数
|
||
BigDecimal monthlyMaxConsumption = dailyConsumption.multiply(new BigDecimal(daysToCalculate));
|
||
|
||
if (monthlyTotalWater.compareTo(monthlyMaxConsumption) >= 0) {
|
||
// 当前月份水量充足,可以支撑整个月
|
||
totalSupplyDays = totalSupplyDays.add(new BigDecimal(daysToCalculate));
|
||
remainingWater = monthlyTotalWater.subtract(monthlyMaxConsumption);
|
||
|
||
// 移动到下个月
|
||
calcMonth++;
|
||
if (calcMonth > 12) {
|
||
calcMonth = 1;
|
||
calcYear++;
|
||
}
|
||
} else {
|
||
// 当前月份水量不足,计算具体天数
|
||
BigDecimal remainingDays = monthlyTotalWater.divide(dailyConsumption, 1, RoundingMode.HALF_UP);
|
||
totalSupplyDays = totalSupplyDays.add(remainingDays);
|
||
waterExhausted = true;
|
||
}
|
||
}
|
||
|
||
// 计算结束日期
|
||
long totalDays = DataHandleUtil.BigDecimalIntegerPart(totalSupplyDays);
|
||
|
||
String endDate = DateUtil.getPlusDate(new Date(), totalDays);
|
||
|
||
result.put(totalSupplyDays, endDate);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 判断当前计算月份是否在预测范围内
|
||
* 预测范围:从当前月份到传入的截至月份
|
||
*/
|
||
private boolean isMonthInPredictRange(int calcMonth, int currentMonth, int endMonth) {
|
||
if (endMonth >= currentMonth) {
|
||
// 不跨年情况:当前月份 <= 计算月份 <= 截至月份
|
||
return calcMonth >= currentMonth && calcMonth <= endMonth;
|
||
} else {
|
||
// 跨年情况:计算月份 >= 当前月份 或者 计算月份 <= 截至月份
|
||
return calcMonth >= currentMonth || calcMonth <= endMonth;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取指定年份月份的天数
|
||
*/
|
||
private int getDaysInMonth(int year, int month) {
|
||
Calendar calendar = Calendar.getInstance();
|
||
calendar.set(Calendar.YEAR, year);
|
||
calendar.set(Calendar.MONTH, month - 1);
|
||
return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
|
||
}
|
||
|
||
|
||
|
||
// public Map<BigDecimal, String> supplyTime(Integer year, Integer month) {
|
||
// StEvpo stEvpo = stEvpoService.lambdaQuery().eq(StEvpo::getMonth, month.toString()).list().get(0);
|
||
// BigDecimal evpo = BigDecimal.ZERO; //蒸发量 (万m³
|
||
// if(stEvpo != null){
|
||
// evpo = stEvpo.getEvaporation();
|
||
// }
|
||
// Map<BigDecimal, String> map = new HashMap<>();
|
||
// /**
|
||
// * 可供水量= 实时库容 - 死库容
|
||
// * 小时水量= (输水管流量 + 放水管流量)*3600 ->改为 (输水管流量 + 放水管流量)*3600 + 蒸发量
|
||
// * 可供水小时数 = 可供水量 * 10000/ 小时水量 ->改为 (可供水量 + 预测水量如果有) * 10000 / 小时水量
|
||
// * 可供水天数 = 可供水小时数换算为天数
|
||
// */
|
||
// List<AttResBaseVo> list = reservoirWaterService.list();
|
||
// if(CollectionUtils.isEmpty(list)){
|
||
// return map;
|
||
// }
|
||
// AttResBaseVo attResBaseVo = list.get(0);
|
||
// BigDecimal nowCap = attResBaseVo.getNowCap() == null ? new BigDecimal(0) : attResBaseVo.getNowCap();
|
||
// BigDecimal deadCap = attResBaseVo.getDeadCap() == null ? new BigDecimal(0) : attResBaseVo.getDeadCap();
|
||
//
|
||
// BigDecimal supplyV = nowCap.subtract(deadCap);
|
||
// if(year != null){
|
||
// //计算预测来水量
|
||
// BigDecimal predictV = calcPredictV(year,month,attResBaseVo.getWatShedArea());
|
||
// supplyV = supplyV.add(predictV);
|
||
// }
|
||
// List<StWaterRReal> water = stWaterRRealMapper.listRelated();
|
||
// //小时水量
|
||
// BigDecimal hourQ = water.stream().map(StWaterRReal::getQ).reduce(BigDecimal.ZERO, BigDecimal::add).multiply(new BigDecimal(3600));
|
||
// BigDecimal day = supplyV.multiply(new BigDecimal(10000)).divide(hourQ.multiply(new BigDecimal(24)),1, RoundingMode.HALF_UP);
|
||
// long l = DataHandleUtil.BigDecimalIntegerPart(day);
|
||
// String date = DateUtil.getPlusDate(new Date(), l);
|
||
// map.put(day,date);
|
||
// return map;
|
||
// }
|
||
|
||
/**
|
||
* 新增方法:计算指定月份的预测来水量(独立月份计算)
|
||
* 例子:10.14-10.30预测水量为40,11.01-11.30预测水量为60
|
||
*/
|
||
private BigDecimal calcMonthlyPredictV(Integer year, Integer month, BigDecimal watShedArea) {
|
||
LocalDate now = LocalDate.now();
|
||
Integer nowMonth = now.getMonthValue();
|
||
|
||
// 查询指定月份的降雨量数据
|
||
LambdaQueryWrapper<TyYearRainfall> queryWrapper = Wrappers.lambdaQuery();
|
||
queryWrapper.eq(TyYearRainfall::getYear, year)
|
||
.eq(TyYearRainfall::getMonth, month)
|
||
.eq(TyYearRainfall::getType, 2);
|
||
|
||
TyYearRainfall rainfall = tyYearRainfallMapper.selectOne(queryWrapper);
|
||
|
||
if (rainfall == null || rainfall.getDrp() == null) {
|
||
return BigDecimal.ZERO;
|
||
}
|
||
|
||
BigDecimal monthlyRainfall = rainfall.getDrp();
|
||
|
||
// 如果是当前月份,需要按剩余天数比例计算
|
||
if (month.equals(nowMonth)) {
|
||
int dayOfMonth = now.getDayOfMonth();
|
||
int totalDaysInMonth = now.lengthOfMonth();
|
||
int remainingDays = totalDaysInMonth - dayOfMonth + 1;
|
||
|
||
// 按剩余天数比例计算当月有效降雨量
|
||
monthlyRainfall = new BigDecimal(remainingDays)
|
||
.multiply(monthlyRainfall)
|
||
.divide(new BigDecimal(totalDaysInMonth), 2, RoundingMode.HALF_UP);
|
||
}
|
||
// 如果不是当前月份,则使用整月的降雨量(不需要按比例计算)
|
||
|
||
// 预测来水量 = 月降雨量 * 水库坝址控制流域面积 / 1000
|
||
BigDecimal sum = monthlyRainfall.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
|
||
return sum.multiply(watShedArea);
|
||
}
|
||
|
||
|
||
private BigDecimal calcPredictV(Integer year, Integer month,BigDecimal watShedArea) {
|
||
LocalDate now = LocalDate.now();
|
||
Integer nowMonth = now.getMonthValue();
|
||
|
||
LambdaQueryWrapper<TyYearRainfall> queryWrapper = Wrappers.lambdaQuery();
|
||
queryWrapper.eq(TyYearRainfall::getYear,year)
|
||
.eq(TyYearRainfall::getType,2)
|
||
.ge(TyYearRainfall::getMonth,nowMonth)
|
||
.le(TyYearRainfall::getMonth,month);
|
||
List<TyYearRainfall> list = tyYearRainfallMapper.selectList(queryWrapper);
|
||
|
||
//和当前月份相同的降雨量
|
||
Optional<TyYearRainfall> first = list.stream().filter(o -> nowMonth == o.getMonth()).findFirst();
|
||
BigDecimal drp = first.isPresent() ? first.get().getDrp() : new BigDecimal(0);
|
||
int dayOfMonth = now.getDayOfMonth();
|
||
int total = now.lengthOfMonth();
|
||
BigDecimal nowMonthDrp = new BigDecimal((total - dayOfMonth + 1)).multiply(drp).divide(new BigDecimal(total), 2, RoundingMode.HALF_UP);
|
||
|
||
//当前月到预测月份的降雨量
|
||
BigDecimal value = list.stream().filter(o -> nowMonth != o.getMonth()).map(TyYearRainfall::getDrp).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||
|
||
//预测来水量 = 月降雨量和 * 水库坝址控制流域面积
|
||
BigDecimal sum = nowMonthDrp.add(value).divide(new BigDecimal(1000),2,RoundingMode.HALF_UP);
|
||
return sum.multiply(watShedArea);
|
||
}
|
||
|
||
public BigDecimal predictWater(Integer year, Integer month) {
|
||
List<AttResBaseVo> list = reservoirWaterService.list();
|
||
if(CollectionUtils.isEmpty(list)){
|
||
return new BigDecimal(0);
|
||
}
|
||
return calcPredictV(year,month,list.get(0).getWatShedArea());
|
||
}
|
||
|
||
public BigDecimal predictWaterMonth(Integer year, Integer month) {
|
||
List<AttResBaseVo> list = reservoirWaterService.list();
|
||
if(CollectionUtils.isEmpty(list)){
|
||
return new BigDecimal(0);
|
||
}
|
||
return calcMonthlyPredictV(year,month,list.get(0).getWatShedArea());
|
||
}
|
||
}
|
||
|
||
|