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

451 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.hsz.service;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gunshi.project.hsz.entity.dto.StZqrlBDto;
import com.gunshi.project.hsz.entity.so.HomeStStbprpBSo;
import com.gunshi.project.hsz.entity.vo.*;
import com.gunshi.project.hsz.mapper.OsmoticPressRMapper;
import com.gunshi.project.hsz.mapper.OsmoticShiftRMapper;
import com.gunshi.project.hsz.mapper.StStbprpBMapper;
import com.gunshi.project.hsz.model.StRsvrR;
import com.gunshi.project.hsz.model.StStbprpB;
import com.gunshi.project.hsz.model.StZqrlB;
import com.gunshi.project.hsz.model.StZvarlB;
import com.gunshi.project.hsz.util.DateUtil;
import jakarta.annotation.Resource;
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.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 描述: sttp 以水利标准来
* author: xusan
* date: 2024-07-08 17:30:38
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class StStbprpBService extends ServiceImpl<StStbprpBMapper, StStbprpB> {
@Resource
private OsmoticPressRMapper pressRMapper;
@Resource
private OsmoticShiftRMapper shiftRMapper;
@Autowired
private StZqrlBService stZqrlBService;
@Autowired
private StZvarlBService stZvarlBService;
@Autowired
private StRsvrRService rsvrRService;
public List<HomeStStbprpBVo> rainfallStationDetailsList(HomeStStbprpBSo dto) {
return baseMapper.rainfallStationDetailsList(dto);
}
public List<HomeStStbprpBVo> reservoirStationDetailsList() {
return baseMapper.reservoirStationDetailsList();
}
public List<HomeStStbprpBVo> flowStationDetailsList() {
return baseMapper.flowStationDetailsList();
}
public StStatusListVo statusList() {
StStatusListVo res = new StStatusListVo();
//水雨情站超过2小时为离线渗压渗流位移暂定超过24小时为离线
List<StStatusVo> list = new ArrayList<>();
List<StStatusVo> onLineList = new ArrayList<>();
List<StStatusVo> offLineList = new ArrayList<>();
//雨量站
List<StStatusVo> rainList = baseMapper.realRainList();
//水位站
List<StStatusVo> rzList = baseMapper.rzList();
//图像站
List<StStatusVo> imgList = baseMapper.imgList();
rainList.addAll(rzList);
rainList.addAll(imgList);
rainList.stream().collect(Collectors.toMap(obj -> obj.getStcd(), obj -> obj, (obj1, obj2) ->
DateUtil.convertStringToDate(obj1.getTm()).after(DateUtil.convertStringToDate(obj2.getTm())) ? obj1 : obj2
)).values().stream().collect(Collectors.toList());
for (StStatusVo statusVo : rainList) {
String tm = statusVo.getTm();
if (StringUtils.isEmpty(tm) || DateUtil.hoursBetweenDate(DateUtil.convertStringToDate(tm), new Date()) > 2) {
offLineList.add(statusVo);
} else {
onLineList.add(statusVo);
}
}
//渗压
List<OsmoticPressVo> pressList = pressRMapper.listValue();
list.addAll(pressList.stream().map(o -> {
StStatusVo vo = new StStatusVo();
vo.setStnm(o.getStationCode());
vo.setTm(o.getTm());
return vo;
}).collect(Collectors.toList()));
//渗流
List<OsmoticPressVo> flowList = pressRMapper.flowListValue();
list.addAll(flowList.stream().map(o -> {
StStatusVo vo = new StStatusVo();
vo.setStnm(o.getStationCode());
vo.setTm(o.getTm());
return vo;
}).collect(Collectors.toList()));
//位移
List<OsmoticShiftListVo> shiftList = shiftRMapper.listValue();
list.addAll(shiftList.stream().map(o -> {
StStatusVo vo = new StStatusVo();
vo.setStnm(o.getStationCode());
vo.setTm(o.getTm());
return vo;
}).collect(Collectors.toList()));
for (StStatusVo vo : list) {
String tm = vo.getTm();
if (StringUtils.isEmpty(tm) || DateUtil.hoursBetweenDate(DateUtil.convertStringToDate(tm), new Date()) > 24) {
offLineList.add(vo);
} else {
onLineList.add(vo);
}
}
res.setOnline(onLineList.stream().sorted(Comparator.comparing(StStatusVo::getTm, Comparator.nullsFirst(String::compareTo)).reversed()).collect(Collectors.toList()));
res.setOffLine(offLineList.stream().sorted(Comparator.comparing(StStatusVo::getTm, Comparator.nullsFirst(String::compareTo)).reversed()).collect(Collectors.toList()));
return res;
}
public List<StStatusVo> rainList() {
return this.baseMapper.rainList();
}
public List<StZqrlBVo> flowList(StZqrlBDto obj) {
/*
* 查出时段内的水位列表,按时间升序排,根据水位查水位流量曲线表得到流量
* 第一条数据的累计溢洪量设为0第二条累计溢洪量=上一条累计溢洪量+本条溢洪流量*60分*60秒以此类推
*/
//TODO 这里得确定一下,这个新建的泄洪道水位站是不是从水库历史水位表中查
//获取水位历史数据
List<StRsvrR> rsvrList = rsvrRService.lambdaQuery()
.eq(StRsvrR::getStcd, obj.getStcd())
.between(StRsvrR::getTm, obj.getDateSo().getStart(), obj.getDateSo().getEnd())
.orderBy(true, true, StRsvrR::getTm)
.list();
//查询水位-流量关系
List<StZqrlB> zqrlList = stZqrlBService.list();
zqrlList.sort(Comparator.comparing(StZqrlB::getZ));
//获取水位-库容关系
List<StZvarlB> zvarlList = stZvarlBService.list();
zvarlList.sort(Comparator.comparing(StZvarlB::getRz));
List<StZqrlBVo> ret = new ArrayList<>();
for (int i = 0; i < rsvrList.size(); i++) {
StRsvrR rsvr = rsvrList.get(i);
BigDecimal rz = new BigDecimal(rsvr.getRz());
StZqrlBVo vo = new StZqrlBVo();
vo.setStcd(rsvr.getStcd());
vo.setTm(rsvr.getTm());
vo.setWaterLevel(rz);
//溢洪流量计算
//TODO 这里水位->流量 需要计算公式
BigDecimal q = stZqrlBService.getQByZqrl(zqrlList,rz);//根据水位计算流量
vo.setFlowNum(q);//计算溢洪量(非累加值)
BigDecimal w = stZvarlBService.getWByZvarl(zvarlList, rz);//根据水位计算库容
vo.setBoxNum(w);
if (i == 0) {
vo.setQtotal(BigDecimal.ZERO);
} else {
StZqrlBVo voPrev = ret.get(i - 1);
//累计溢洪量 = 上一条数据累计溢洪量 + 本条溢洪流量 * 2条数据之间的间隔
Instant curInstant = vo.getTm().toInstant();
Instant preInstant = voPrev.getTm().toInstant();
long timeDiffSeconds = Duration.between(curInstant, preInstant).getSeconds();
BigDecimal qTotal = voPrev.getQtotal().add(vo.getFlowNum().multiply(BigDecimal.valueOf(timeDiffSeconds)));
vo.setQtotal(qTotal);
}
ret.add(vo);
}
//倒序输出
ret.sort(Comparator.comparing(StZqrlBVo::getTm).reversed());
return ret;
}
public StZqrlBCountVo count(Serializable stcd) {
StZqrlBCountVo vo = new StZqrlBCountVo();
vo.setStcd(stcd.toString());
//取出当月的时间 20xx-xx-01 00:00:00
Calendar calendar = Calendar.getInstance();
Date now = calendar.getTime();
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date monthStart = calendar.getTime();
//取本年的时间 20xx-01-01 00:00:00
calendar.set(Calendar.MONTH,0);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date yearStart = calendar.getTime();
calendar.setTime(now);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date dayStart = calendar.getTime();
//查询当年水位数据
List<StRsvrR> rsvrList = rsvrRService.lambdaQuery()
.eq(StRsvrR::getStcd, stcd)
.between(StRsvrR::getTm, yearStart, now)
.orderByAsc(true, StRsvrR::getTm)
.list();
//获取水位流量关系
List<StZqrlB> zqrlList = stZqrlBService.list();
zqrlList.sort(Comparator.comparing(StZqrlB::getZ));
List<RsvrComplexVo> complexList = new ArrayList<>();
int idx = 0;
for (StRsvrR rsvr : rsvrList) {
RsvrComplexVo complex = new RsvrComplexVo();
BigDecimal rz = new BigDecimal(rsvr.getRz());
complex.setRz(rz);
complex.setTm(rsvr.getTm());
//TODO 这里需要重新计算水位-流量(溢洪量)对应数据
//BigDecimal q = stZqrlBService.getQFromZqrl(rz, zqrlList);
BigDecimal q = stZqrlBService.getQByZqrl(zqrlList,rz);
complex.setQ(q);
complex.setSv(complex.getQ());
// if (idx == 0) {
// complex.setSv(BigDecimal.ZERO);
// } else {
// //计算溢洪量
// RsvrComplexVo complexPrev = complexList.get(idx - 1);
// complex.setSv(complexPrev.getSv().add(complex.getQ().multiply(BigDecimal.valueOf(60 * 60))));
// }
complexList.add(complex);
idx++;
}
//当前流量
vo.setVal(complexList.getLast().getQ());
vo.setCreateTime(complexList.getLast().getTm());
// 今日累计溢洪量(基于时间间隔的积分)
List<RsvrComplexVo> complexDayList = complexList.stream().filter(complex -> complex.getTm().after(dayStart)).collect(Collectors.toList());
BigDecimal sumToday = stZqrlBService.getFlowQSum(complexDayList);
vo.setCurrDayValSum(sumToday);
// 当月累计溢洪量
List<RsvrComplexVo> complexMonthList = complexList.stream().filter(complex -> (complex.getTm().after(monthStart) || complex.getTm().equals(monthStart))
&& complex.getTm().before(now) || complex.getTm().equals(now)).collect(Collectors.toList());
BigDecimal sumMonth = stZqrlBService.getFlowQSum(complexMonthList);
vo.setCurrMonthSum(sumMonth);
// 当年累计溢洪量
BigDecimal sumYear = stZqrlBService.getFlowQSum(complexList);
vo.setCurrYearSum(sumYear);
// //今日sv的和
// BigDecimal sumToday = complexList.stream().filter(complex -> complex.getTm().after(dayStart))
// .map(RsvrComplexVo::getSv)
// .reduce(BigDecimal.ZERO, BigDecimal::add);
// vo.setCurrDayValSum(sumToday);
//
// // 当月溢洪量总和(筛选本月数据)
// BigDecimal sumMonth = complexList.stream()
// .filter(complex -> (complex.getTm().after(monthStart) || complex.getTm().equals(monthStart))
// && complex.getTm().before(now) || complex.getTm().equals(now))
// .map(RsvrComplexVo::getSv)
// .reduce(BigDecimal.ZERO, BigDecimal::add);
// vo.setCurrMonthSum(sumMonth);
//
// // 当年溢洪量总和(所有数据都是当年的,直接求和)
// BigDecimal sumYear = complexList.stream()
// .map(RsvrComplexVo::getSv)
// .reduce(BigDecimal.ZERO, BigDecimal::add);
// vo.setCurrYearSum(sumYear);
//计算溢洪次数
// 0 0 0 1 1 0 1 0 1
int overFlowCount = 0;
boolean isOverFlow = false;
//连续的sv > 0 才算一次 溢洪
for(int i =0;i<complexList.size();i++){
BigDecimal sv = complexList.get(i).getSv();
if(sv.compareTo(BigDecimal.ZERO) > 0){
if(!isOverFlow){
overFlowCount++;
isOverFlow = true;
}
}else{
isOverFlow = false;
}
}
vo.setCurrYearCount(Long.valueOf(overFlowCount));
// 本年单次最大溢洪量
Optional<RsvrComplexVo> maxOverflowComplex = complexList.stream()
.max(Comparator.comparing(RsvrComplexVo::getSv));
if (maxOverflowComplex.isPresent()) {
RsvrComplexVo maxComplex = maxOverflowComplex.get();
vo.setCurrYearMaxVal(maxComplex.getSv());
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss");
int maxIndex = complexList.indexOf(maxComplex);
if (maxIndex < complexList.size() - 1) {
// 可以取前后时间点作为时间段的参考
Date startTime = complexList.get(maxIndex).getTm();
Date endTime = complexList.get(maxIndex + 1).getTm();
String period = sdf.format(startTime) + " ~ " + sdf.format(endTime);
vo.setMaxOverflowPeriod(period);
}else{
Date startTime = complexList.get(maxIndex).getTm();
String period = sdf.format(startTime) + " ~ " + sdf.format(now);
vo.setMaxOverflowPeriod(period);
}
} else {
vo.setCurrYearMaxVal(BigDecimal.ZERO);
vo.setMaxOverflowPeriod("无溢洪记录");
}
return vo;
}
public StZqrlBCount24Vo count24(Serializable stcd) {
StZqrlBCount24Vo vo = new StZqrlBCount24Vo();
vo.setStcd(stcd.toString());
StRsvrR rsvrLatest = rsvrRService.lambdaQuery().eq(StRsvrR::getStcd, stcd).orderByDesc(StRsvrR::getTm).last("limit 1").one();
if (rsvrLatest == null) {
return vo;
}
BigDecimal rzLatest = new BigDecimal(rsvrLatest.getRz());
//获取水位-流量数据k
List<StZqrlB> zqrlBList = stZqrlBService.list();
//TODO 转换溢洪流量计算
BigDecimal qLatest = stZqrlBService.getQByZqrl(zqrlBList,rzLatest);
//BigDecimal qLatest = stZqrlBService.getQFromZqrl(rzLatest);
vo.setCurrWaterLevel(rzLatest);
vo.setFlowNum(qLatest);//当前溢洪量 就为 流量
vo.setCreateTime(rsvrLatest.getTm());
LocalDateTime now = LocalDateTime.now();
LocalDateTime before24 = now.minusHours(24);
List<StRsvrR> rsvrList = rsvrRService.lambdaQuery().ge(StRsvrR::getTm, before24).le(StRsvrR::getTm, now).orderByAsc(StRsvrR::getTm).list();
//TODO 这个溢洪流量汇总的计算也需要进行公式计算
List<RsvrComplexVo> rsvrComplexVos = stZqrlBService.calculateSpilledVolumeList(rsvrList);
BigDecimal totalSv = rsvrComplexVos.stream().map(RsvrComplexVo::getSv).reduce(BigDecimal.ZERO, BigDecimal::add);
vo.setSum24(totalSv);
return vo;
}
public List<StZqrlB> calculateQtotal(List<StZqrlB> list) {
if (list == null || list.size() < 2) {
return list;
}
// 第一条数据设为0或null
list.get(0).setQtotal(BigDecimal.ZERO);
for (int i = 1; i < list.size(); i++) {
StZqrlB current = list.get(i);
StZqrlB previous = list.get(i - 1);
// 使用Duration计算分钟差(精确到小数)
Duration duration = Duration.between(previous.getModitimeAsLocalDateTime(), current.getModitimeAsLocalDateTime());
double minutesDiff = duration.toMillis() / 60000.0; // 毫秒转分钟
// 使用BigDecimal的valueOf方法避免new BigDecimal(double)的精度问题
BigDecimal minutesDecimal = BigDecimal.valueOf(minutesDiff);
// 计算并设置qtotal
current.setQtotal(current.getQ().multiply(minutesDecimal));
}
return list;
}
private List<StZqrlB> getList(String stcd, LocalDateTime start, LocalDateTime end) {
LambdaQueryWrapper<StZqrlB> qw = new LambdaQueryWrapper();
List<StZqrlB> list = stZqrlBService.list(qw);
return list;
}
private BigDecimal sumVal(String stcd, LocalDateTime start, LocalDateTime end) {
LambdaQueryWrapper<StZqrlB> qw = new LambdaQueryWrapper();
qw.eq(StZqrlB::getStcd, stcd);
qw.ge(StZqrlB::getModitime, start);
qw.le(StZqrlB::getModitime, end);
List<StZqrlB> list = stZqrlBService.list(qw);
if (CollectionUtil.isNotEmpty(list)) {
return list.stream().map(StZqrlB::getQ).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
}
return null;
}
private Long countVal(String stcd, LocalDateTime start, LocalDateTime end) {
LambdaQueryWrapper<StZqrlB> qw = new LambdaQueryWrapper();
qw.eq(StZqrlB::getStcd, stcd);
qw.ge(StZqrlB::getModitime, start);
qw.le(StZqrlB::getModitime, end);
List<StZqrlB> list = stZqrlBService.list(qw);
if (CollectionUtil.isNotEmpty(list)) {
return list.stream().map(StZqrlB::getQ).filter(Objects::nonNull).filter(q -> q.compareTo(BigDecimal.ZERO) > 0).count();
}
return 0l;
}
private BigDecimal maxVal(String stcd, LocalDateTime start, LocalDateTime end) {
LambdaQueryWrapper<StZqrlB> qw = new LambdaQueryWrapper();
qw.eq(StZqrlB::getStcd, stcd);
qw.ge(StZqrlB::getModitime, start);
qw.le(StZqrlB::getModitime, end);
List<StZqrlB> list = stZqrlBService.list(qw);
if (CollectionUtil.isNotEmpty(list)) {
return list.stream().map(StZqrlB::getQ).filter(Objects::nonNull).max(Comparator.naturalOrder()).orElse(null);
}
return null;
}
public List<StStbprpB> getPptnStations() {
return baseMapper.getPptnStations();
}
public List<StStbprpB> getRsvrStations() {
return baseMapper.getRsvrStations();
}
}