gunshi-project-ss/src/main/java/com/gunshi/project/ss/service/GateValveRealService.java

413 lines
18 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.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预测水量为4011.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());
}
}