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

278 lines
10 KiB
Java
Raw Normal View History

2025-12-29 17:13:09 +08:00
package com.gunshi.project.ss.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
2025-12-29 17:13:09 +08:00
import com.gunshi.project.ss.common.mapper.StFlowRMapper;
import com.gunshi.project.ss.common.model.StFlowR;
import com.gunshi.project.ss.common.model.StStbprpB;
import com.gunshi.project.ss.entity.dto.StFlowDataCheckDto;
import com.gunshi.project.ss.entity.vo.StFlowLowerDataCheckVo;
import com.gunshi.project.ss.entity.vo.StFlowRListVo;
2025-12-29 17:13:09 +08:00
import com.gunshi.project.ss.entity.vo.StFlowRVo;
import com.gunshi.project.ss.mapper.StFlowRVoMapper;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class StFlowRService extends ServiceImpl<StFlowRMapper, StFlowR> {
@Autowired
private StFlowRVoMapper voMapper;
@Autowired
private StStbprpBService stStbprpBService;
public StFlowR getNewDataByStcd(String stcd) {
LambdaQueryWrapper<StFlowR> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StFlowR::getStcd, stcd);
queryWrapper.orderByDesc(StFlowR::getTm);
queryWrapper.last("limit 1");
return baseMapper.selectOne(queryWrapper);
}
2025-12-02 15:18:17 +08:00
public List<StFlowR> listNewData() {
return this.baseMapper.listNewData();
}
public List<String> getStcdList() {
return voMapper.listStcds();
}
public List<StFlowRVo> getDataByStcdAndTm(String stcd, Date tm) {
return voMapper.getDataByStcdAndTm(stcd, tm);
}
public List<StFlowRListVo> listLatestData() {
List<StFlowRListVo> res = new ArrayList<>();
List<StStbprpB> flowStations = stStbprpBService.getFlowStations();
LocalDateTime now = LocalDateTime.now();
LocalDateTime lastDay = now.minusDays(1);
for (StStbprpB flowStation : flowStations) {
StFlowRListVo stFlowR = new StFlowRListVo();
stFlowR.setStcd(flowStation.getStcd());
stFlowR.setStnm(flowStation.getStnm());
// 获取24小时内的所有流量数据
List<StFlowR> list = lambdaQuery()
.eq(StFlowR::getStcd, flowStation.getStcd())
.ge(StFlowR::getTm, lastDay)
.le(StFlowR::getTm, now)
.orderByAsc(StFlowR::getTm) // 按时间升序排列,方便计算
.list();
if(list.isEmpty()){
res.add(stFlowR);
continue;
}
// 设置最新时间点的数据
StFlowR latestData = list.get(list.size() - 1);
stFlowR.setTm(latestData.getTm());
stFlowR.setQ(latestData.getQ());
// 计算统计值
calculateTotalVolume(list, stFlowR);
res.add(stFlowR);
}
return res;
}
// 替代的累计水量计算方法(使用梯形法,更精确)
private void calculateTotalVolume(List<StFlowR> flowList, StFlowRListVo vo) {
if (flowList == null || flowList.size() < 2) {
vo.setTotal24V(BigDecimal.ZERO);
return;
}
BigDecimal totalVolume = BigDecimal.ZERO;
for (int i = 0; i < flowList.size() - 1; i++) {
StFlowR current = flowList.get(i);
StFlowR next = flowList.get(i + 1);
if (current.getQ() != null && next.getQ() != null &&
current.getTm() != null && next.getTm() != null) {
// 计算时间间隔(秒)
long seconds = Duration.between(current.getTm(), next.getTm()).getSeconds();
// 使用梯形法计算水量:(当前流量 + 下一流量) / 2 × 时间间隔
BigDecimal avgQ = current.getQ().add(next.getQ())
.divide(BigDecimal.valueOf(2), 4, RoundingMode.HALF_UP);
// 水量 = 平均流量(m³/s) × 时间(秒)
BigDecimal volume = avgQ.multiply(BigDecimal.valueOf(seconds));
totalVolume = totalVolume.add(volume);
}
}
// 转换为万立方米1万立方米 = 10000立方米
totalVolume = totalVolume.divide(BigDecimal.valueOf(10000), 4, RoundingMode.HALF_UP);
vo.setTotal24V(totalVolume);
}
public List<StFlowRListVo> upperDataCheck(StFlowDataCheckDto dto) {
List<StFlowRListVo> res = new ArrayList<>();
List<StFlowR> list = lambdaQuery()
.eq(StFlowR::getStcd, dto.getStcd())
.ge(StFlowR::getTm, dto.getDateTimeRangeSo().getStart())
.le(StFlowR::getTm, dto.getDateTimeRangeSo().getEnd())
.orderByDesc(StFlowR::getTm)
.list();
if(list.isEmpty()){
return res;
}
if(dto.getType() == 0){
for (StFlowR stFlowR : list) {
StFlowRListVo stFlowRListVo = new StFlowRListVo();
stFlowRListVo.setStcd(stFlowR.getStcd());
stFlowRListVo.setQ(stFlowR.getQ());
stFlowRListVo.setTm(stFlowR.getTm());
res.add(stFlowRListVo);
}
}else{
// 使用Map按日期分组
Map<LocalDate, List<StFlowR>> dailyMap = new LinkedHashMap<>();
for (StFlowR flow : list) {
LocalDate date = flow.getTm().toLocalDate();
dailyMap.computeIfAbsent(date, k -> new ArrayList<>()).add(flow);
}
// 计算每天的平均流量
for (Map.Entry<LocalDate, List<StFlowR>> entry : dailyMap.entrySet()) {
LocalDate date = entry.getKey();
List<StFlowR> dayList = entry.getValue();
if (!dayList.isEmpty()) {
StFlowR sample = dayList.get(0);
BigDecimal totalQ = BigDecimal.ZERO;
int count = 0;
// 计算当日流量总和
for (StFlowR flow : dayList) {
if (flow.getQ() != null) {
totalQ = totalQ.add(flow.getQ());
count++;
}
}
// 创建结果对象
StFlowRListVo vo = new StFlowRListVo();
vo.setStcd(sample.getStcd());
// 计算平均值并保留2位小数
if (count > 0) {
BigDecimal avgQ = totalQ.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP);
vo.setQ(avgQ);
}
// 设置时间为当天的开始时间00:00:00
vo.setTm(date.atStartOfDay());
res.add(vo);
}
}
}
return res;
}
public StFlowLowerDataCheckVo lowerDataCheckVoR(StFlowDataCheckDto dto) {
return null;
}
public List<StFlowR> getByStcd(StFlowDataCheckDto dto) {
StStbprpB one = stStbprpBService.lambdaQuery()
.eq(StStbprpB::getStcd, dto.getStcd()).one();
if(one == null){
throw new IllegalArgumentException("对不起,该站点不存在");
}
LambdaQueryWrapper<StFlowR> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(StFlowR::getStcd, dto.getStcd());
queryWrapper.ge(StFlowR::getTm, dto.getDateTimeRangeSo().getStart());
queryWrapper.le(StFlowR::getTm, dto.getDateTimeRangeSo().getEnd());
queryWrapper.orderByDesc(StFlowR::getTm);
List<StFlowR> stFlowRS = this.baseMapper.selectList(queryWrapper);
stFlowRS.stream().forEach(o -> o.setStnm(one.getStnm()));
return stFlowRS;
}
public void export(StFlowDataCheckDto dto, HttpServletResponse response) {
// 1. 获取数据
List<StFlowR> dataList = getByStcd(dto);
// 2. 创建Excel工作簿
try (Workbook workbook = new XSSFWorkbook()) {
Sheet sheet = workbook.createSheet("流量数据");
// 3. 创建标题行
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("站点名称");
headerRow.createCell(1).setCellValue("时间");
headerRow.createCell(2).setCellValue("瞬时流量(m³/s)");
// 4. 填充数据
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (int i = 0; i < dataList.size(); i++) {
StFlowR flowData = dataList.get(i);
Row row = sheet.createRow(i + 1);
// 站点名称
row.createCell(0).setCellValue(flowData.getStnm() != null ? flowData.getStnm() : "");
// 时间
String timeStr = "";
if (flowData.getTm() != null) {
timeStr = flowData.getTm().format(formatter);
}
row.createCell(1).setCellValue(timeStr);
// 流量
if (flowData.getQ() != null) {
row.createCell(2).setCellValue(flowData.getQ().doubleValue());
} else {
row.createCell(2).setCellValue("");
}
}
// 5. 自动调整列宽
for (int i = 0; i < 3; i++) {
sheet.autoSizeColumn(i);
}
// 6. 设置响应头
String fileName = "流量数据_" + System.currentTimeMillis() + ".xlsx";
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 7. 写入响应流
workbook.write(response.getOutputStream());
} catch (IOException e) {
throw new RuntimeException("导出Excel失败", e);
}
}
}