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 { @Resource private OsmoticPressRMapper pressRMapper; @Resource private OsmoticShiftRMapper shiftRMapper; @Autowired private StZqrlBService stZqrlBService; @Autowired private StZvarlBService stZvarlBService; @Autowired private StRsvrRService rsvrRService; public List rainfallStationDetailsList(HomeStStbprpBSo dto) { return baseMapper.rainfallStationDetailsList(dto); } public List reservoirStationDetailsList() { return baseMapper.reservoirStationDetailsList(); } public List flowStationDetailsList() { return baseMapper.flowStationDetailsList(); } public StStatusListVo statusList() { StStatusListVo res = new StStatusListVo(); //水雨情站超过2小时为离线;渗压,渗流,位移暂定超过24小时为离线 List list = new ArrayList<>(); List onLineList = new ArrayList<>(); List offLineList = new ArrayList<>(); //雨量站 List rainList = baseMapper.realRainList(); //水位站 List rzList = baseMapper.rzList(); //图像站 List 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 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 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 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 rainList() { return this.baseMapper.rainList(); } public List flowList(StZqrlBDto obj) { /* * 查出时段内的水位列表,按时间升序排,根据水位查水位流量曲线表得到流量 * 第一条数据的累计溢洪量设为0,第二条累计溢洪量=上一条累计溢洪量+本条溢洪流量*60分*60秒,以此类推 */ //TODO 这里得确定一下,这个新建的泄洪道水位站是不是从水库历史水位表中查 //获取水位历史数据 List rsvrList = rsvrRService.lambdaQuery() .eq(StRsvrR::getStcd, obj.getStcd()) .between(StRsvrR::getTm, obj.getDateSo().getStart(), obj.getDateSo().getEnd()) .orderBy(true, true, StRsvrR::getTm) .list(); //查询水位-流量关系 List zqrlList = stZqrlBService.list(); zqrlList.sort(Comparator.comparing(StZqrlB::getZ)); //获取水位-库容关系 List zvarlList = stZvarlBService.list(); zvarlList.sort(Comparator.comparing(StZvarlB::getRz)); List 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 rsvrList = rsvrRService.lambdaQuery() .eq(StRsvrR::getStcd, stcd) .between(StRsvrR::getTm, yearStart, now) .orderByAsc(true, StRsvrR::getTm) .list(); //获取水位流量关系 List zqrlList = stZqrlBService.list(); zqrlList.sort(Comparator.comparing(StZqrlB::getZ)); List 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 complexDayList = complexList.stream().filter(complex -> complex.getTm().after(dayStart)).collect(Collectors.toList()); BigDecimal sumToday = stZqrlBService.getFlowQSum(complexDayList); vo.setCurrDayValSum(sumToday); // 当月累计溢洪量 List 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 0){ if(!isOverFlow){ overFlowCount++; isOverFlow = true; } }else{ isOverFlow = false; } } vo.setCurrYearCount(Long.valueOf(overFlowCount)); // 本年单次最大溢洪量 Optional 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 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 rsvrList = rsvrRService.lambdaQuery().ge(StRsvrR::getTm, before24).le(StRsvrR::getTm, now).orderByAsc(StRsvrR::getTm).list(); //TODO 这个溢洪流量汇总的计算也需要进行公式计算 List rsvrComplexVos = stZqrlBService.calculateSpilledVolumeList(rsvrList); BigDecimal totalSv = rsvrComplexVos.stream().map(RsvrComplexVo::getSv).reduce(BigDecimal.ZERO, BigDecimal::add); vo.setSum24(totalSv); return vo; } public List calculateQtotal(List 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 getList(String stcd, LocalDateTime start, LocalDateTime end) { LambdaQueryWrapper qw = new LambdaQueryWrapper(); List list = stZqrlBService.list(qw); return list; } private BigDecimal sumVal(String stcd, LocalDateTime start, LocalDateTime end) { LambdaQueryWrapper qw = new LambdaQueryWrapper(); qw.eq(StZqrlB::getStcd, stcd); qw.ge(StZqrlB::getModitime, start); qw.le(StZqrlB::getModitime, end); List 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 qw = new LambdaQueryWrapper(); qw.eq(StZqrlB::getStcd, stcd); qw.ge(StZqrlB::getModitime, start); qw.le(StZqrlB::getModitime, end); List 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 qw = new LambdaQueryWrapper(); qw.eq(StZqrlB::getStcd, stcd); qw.ge(StZqrlB::getModitime, start); qw.le(StZqrlB::getModitime, end); List 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 getPptnStations() { return baseMapper.getPptnStations(); } public List getRsvrStations() { return baseMapper.getRsvrStations(); } }