parent
59a67a3b61
commit
1b02203a6c
|
|
@ -107,7 +107,11 @@ public class SyncRainfallService implements SyncTableRService<JcskStPptnR, StPpt
|
|||
if (existingTarget == null) {
|
||||
StPptnR targetEntity = new StPptnR();
|
||||
BeanUtils.copyProperties(sourceEntity, targetEntity);
|
||||
targetEntity.setTm(LocalDateTimeConverter.toDate(sourceEntity.getTm()));
|
||||
targetEntity.setChtm(new Date());
|
||||
if(sourceEntity.getDrp() != null){
|
||||
targetEntity.setDrp(sourceEntity.getDrp().toString());
|
||||
}
|
||||
targetMapper.insert(targetEntity);
|
||||
}
|
||||
count++;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ public class SyncRsvrWaterLevelService implements SyncTableRService<JcskStRsvrR,
|
|||
StRsvrR targetEntity = new StRsvrR();
|
||||
BeanUtils.copyProperties(sourceEntity, targetEntity);
|
||||
targetEntity.setTm(LocalDateTimeConverter.toDate(sourceEntity.getTm()));
|
||||
if(sourceEntity.getRz() != null){
|
||||
targetEntity.setRz(sourceEntity.getRz().toString());
|
||||
}
|
||||
targetMapper.insert(targetEntity);
|
||||
}
|
||||
count++;
|
||||
|
|
|
|||
|
|
@ -7,14 +7,17 @@ import com.gunshi.project.hsz.entity.dto.ProjectSaveReportDto;
|
|||
import com.gunshi.project.hsz.entity.dto.SyRegressionDataDto;
|
||||
import com.gunshi.project.hsz.entity.vo.ForecastResultVo;
|
||||
import com.gunshi.project.hsz.entity.vo.ProjectSafeCalculateVo;
|
||||
import com.gunshi.project.hsz.entity.vo.ProjectSaveReportVo;
|
||||
import com.gunshi.project.hsz.model.ForecastTask;
|
||||
import com.gunshi.project.hsz.model.RegressionEquation;
|
||||
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||
import com.gunshi.project.hsz.service.ForecastResultsService;
|
||||
import com.gunshi.project.hsz.service.JcskSyRService;
|
||||
import com.gunshi.project.hsz.service.SyRegressionDataService;
|
||||
import com.gunshi.project.hsz.util.RegressionEquationFormatter;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
|
@ -46,9 +49,17 @@ public class ProjectSafeAnalyseController {
|
|||
return R.ok(ans);
|
||||
}
|
||||
|
||||
@Operation(summary = "多项式回归-导出")
|
||||
@PostMapping("/caculate/export")
|
||||
public void caculateExport(@RequestBody ProjectSafeCalculateDto dto, HttpServletResponse response){
|
||||
ProjectSafeCalculateVo ans = jcskSyRService.calculate(dto);
|
||||
syRegressionDataService.export(dto.getDvcd(),ans,response);
|
||||
}
|
||||
|
||||
@Operation(summary = "预报")
|
||||
@PostMapping("/report")
|
||||
public R<List<OsmoticPressDetailVo>> report(@RequestBody ProjectSaveReportDto projectSaveReportDto){
|
||||
public R<ProjectSaveReportVo> report(@RequestBody ProjectSaveReportDto projectSaveReportDto){
|
||||
ProjectSaveReportVo res = new ProjectSaveReportVo();
|
||||
ForecastTask forecastTask = projectSaveReportDto.getForecastTask();
|
||||
List<ForecastResultVo> voList = forecastResultsService.getHumanForecastResult(forecastTask);
|
||||
SyRegressionData syRegressionData = new SyRegressionData();
|
||||
|
|
@ -59,10 +70,33 @@ public class ProjectSafeAnalyseController {
|
|||
return R.ok(null);
|
||||
}
|
||||
//计算
|
||||
List<OsmoticPressDetailVo> res = forecastResultsService.calculateY(queryReg.get(0),voList);
|
||||
List<OsmoticPressDetailVo> datas = forecastResultsService.calculateY(queryReg.get(0),voList);
|
||||
res.setDatas(datas);
|
||||
String formatEquation = RegressionEquationFormatter.formatEquation(queryReg.get(0).getRegressionEquation());
|
||||
res.setRegression(formatEquation);
|
||||
return R.ok(res);
|
||||
}
|
||||
|
||||
@Operation(summary = "预报-导出")
|
||||
@PostMapping("/report/export")
|
||||
public void reportExport(@RequestBody ProjectSaveReportDto projectSaveReportDto,HttpServletResponse response){
|
||||
ForecastTask forecastTask = projectSaveReportDto.getForecastTask();
|
||||
List<ForecastResultVo> voList = forecastResultsService.getHumanForecastResult(forecastTask);
|
||||
SyRegressionData syRegressionData = new SyRegressionData();
|
||||
syRegressionData.setDvcd(projectSaveReportDto.getDvcd());
|
||||
syRegressionData.setOrder(projectSaveReportDto.getOrder());
|
||||
List<SyRegressionData> queryReg = syRegressionDataService.queryData(syRegressionData);//获取方程组
|
||||
if(queryReg.isEmpty()){
|
||||
return;
|
||||
}
|
||||
//计算
|
||||
List<OsmoticPressDetailVo> res = forecastResultsService.calculateY(queryReg.get(0),voList);
|
||||
String formatEquation = RegressionEquationFormatter.formatEquation(queryReg.get(0).getRegressionEquation());
|
||||
forecastResultsService.reportExport(res,formatEquation,projectSaveReportDto.getDvcd(),response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Operation(summary = "保存多线程回归方程")
|
||||
@PostMapping("/save")
|
||||
public R<Boolean> save(@RequestBody SyRegressionDataDto dto){
|
||||
|
|
|
|||
|
|
@ -15,4 +15,6 @@ public class SyDataCheckRulePageSo {
|
|||
private PageSo pageSo;
|
||||
|
||||
private String dvcd;
|
||||
|
||||
private String dm;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
package com.gunshi.project.hsz.entity.vo;
|
||||
|
||||
|
||||
import com.gunshi.project.hsz.common.model.vo.OsmoticPressDetailVo;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class ProjectSaveReportVo {
|
||||
|
||||
private String regression;
|
||||
|
||||
private List<OsmoticPressDetailVo> datas;
|
||||
|
||||
}
|
||||
|
|
@ -67,4 +67,8 @@ public class SyDataCheckRule implements Serializable {
|
|||
@TableField(value = "is_available")
|
||||
@Schema(description = "是否启用 0:否 1:是")
|
||||
private Integer isAvailable;
|
||||
|
||||
@TableField(value = "dm")
|
||||
@Schema(description = "断面编码")
|
||||
private String dm;
|
||||
}
|
||||
|
|
@ -19,13 +19,19 @@ import com.gunshi.project.hsz.grb.RainGrib2Layer;
|
|||
import com.gunshi.project.hsz.mapper.ForecastResultsMapper;
|
||||
import com.gunshi.project.hsz.model.*;
|
||||
import com.gunshi.project.hsz.util.DataHandleUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
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.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
|
@ -55,6 +61,8 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
|
||||
private static SimpleDateFormat sixteenSdf = new SimpleDateFormat("yyyy-MM-dd 16");
|
||||
|
||||
private static SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-dd HH");
|
||||
|
||||
@Autowired
|
||||
private ForecastUseparamService forecastUseparamService;
|
||||
|
||||
|
|
@ -421,299 +429,6 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
|
||||
|
||||
private List<Map<String, Object>> excuteForecastDebug(ForecastTask forecastTask) throws Exception {
|
||||
List<ForecastResultVo> voList = new ArrayList<>();
|
||||
// 获取配置参数
|
||||
List<ForecastUseparam> paramList = forecastUseparamService.list(new QueryWrapper<ForecastUseparam>().isNotNull("param_code").isNotNull("param_value"));
|
||||
if (CollectionUtils.isEmpty(paramList)) {
|
||||
throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查入参是否缺失。");
|
||||
}
|
||||
// 获取系统当前的水库站编码、汛限水位
|
||||
AttResBase attResBase = attResBaseService.getOne(new QueryWrapper<>());
|
||||
// 多站点水库面雨量
|
||||
// List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("res_code", attResBase.getResCode()));
|
||||
// 单站点
|
||||
List<StStbprpB> stbs = stStbprpBService.list(new QueryWrapper<StStbprpB>().eq("stcd", attResBase.getStcd()));
|
||||
if (CollectionUtils.isEmpty(stbs)) {
|
||||
return null;
|
||||
}
|
||||
Date nowHourTime = forecastTask.getNowTime();
|
||||
Date startTime = forecastTask.getStartTime();
|
||||
Date endTime = forecastTask.getEndTime();
|
||||
// 获取整个时间线的降雨数据
|
||||
List<StPptnR> pptnRAllList = new ArrayList<>();
|
||||
List<StPptnR> pptnRFutureList = new ArrayList<>();
|
||||
QueryWrapper<StPptnR> qwExisted = new QueryWrapper<>();
|
||||
Boolean isHaveFuturePPtn = true;
|
||||
// 檀树岗修改:实测降雨查询表数据,预测降雨使用geom参数。最后按时间算数平均
|
||||
// for(StStbprpB b : stbs){
|
||||
// String stcd = b.getStcd();
|
||||
// // 如果结束时间在当前时间之前,降雨序列从历史降雨表获取
|
||||
// if (endTime.compareTo(nowHourTime) <= 0) {
|
||||
// qwExisted = new QueryWrapper<StPptnR>().eq("stcd", stcd).ge("tm", startTime).le("tm", endTime).orderBy(true, true, "tm");
|
||||
// } else {
|
||||
// qwExisted = new QueryWrapper<StPptnR>().eq("stcd", stcd).ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm");
|
||||
// try {
|
||||
// // 获取预报数据
|
||||
// pptnRFutureList = getForecastDrpData(nowHourTime, stcd);
|
||||
// } catch (IllegalArgumentException e) {
|
||||
// if(stcd.equals(attResBase.getStcd())){
|
||||
// isHaveFuturePPtn = false;
|
||||
// }
|
||||
// log.error("该时间无预报数据");
|
||||
// }
|
||||
// }
|
||||
// List<StPptnR> pptnRExistedList = stPptnRService.list(qwExisted);
|
||||
// pptnRAllList.addAll(pptnRExistedList);
|
||||
// pptnRAllList.addAll(pptnRFutureList);
|
||||
// }
|
||||
if (endTime.compareTo(nowHourTime) <= 0) {
|
||||
qwExisted = new QueryWrapper<StPptnR>().in("stcd", stbs.stream().map(StStbprpB::getStcd).toArray(String[]::new)).ge("tm", startTime).le("tm", endTime).orderBy(true, true, "tm");
|
||||
} else {
|
||||
qwExisted = new QueryWrapper<StPptnR>().in("stcd", stbs.stream().map(StStbprpB::getStcd).toArray(String[]::new)).ge("tm", startTime).le("tm", nowHourTime).orderBy(true, true, "tm");
|
||||
// 获取预报数据
|
||||
try {
|
||||
pptnRFutureList = getForecastDrpData(nowHourTime, attResBase.getStcd());
|
||||
if(CollectionUtils.isEmpty(pptnRFutureList)) {
|
||||
isHaveFuturePPtn = false;
|
||||
log.error("该时间无预报数据");
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
isHaveFuturePPtn = false;
|
||||
log.error("该时间无预报数据");
|
||||
}
|
||||
}
|
||||
List<StPptnR> pptnRExistedList = stPptnRService.list(qwExisted);
|
||||
pptnRAllList.addAll(pptnRExistedList);
|
||||
pptnRAllList.addAll(pptnRFutureList);
|
||||
|
||||
if (CollectionUtils.isEmpty(pptnRAllList)) {
|
||||
return null;
|
||||
}
|
||||
// 多站点面雨量结果list
|
||||
List<StPptnR> polyPptnRList = pptnRAllList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
StPptnR::getTm,
|
||||
Collectors.mapping(
|
||||
pptn -> Double.parseDouble(pptn.getDrp()), // 将String转换为double
|
||||
Collectors.averagingDouble(d -> d) // 计算平均值
|
||||
)
|
||||
))
|
||||
.entrySet().stream()
|
||||
.map(entry -> new StPptnRAverage(entry.getKey(), String.valueOf(entry.getValue())))
|
||||
.sorted(Comparator.comparing(StPptnRAverage::getTm))
|
||||
.collect(Collectors.toList());
|
||||
double dt = 0.0;
|
||||
double Wm = 0.0;
|
||||
double qOther = 0.0;
|
||||
Map<String, String> paramMap = paramList.stream().collect(Collectors.toMap(ForecastUseparam::getParamCode, ForecastUseparam::getParamValue, (existing, replacement) -> existing));
|
||||
if (paramMap.get("dt").isEmpty()) {
|
||||
throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查时间单元△T是否缺失。");
|
||||
}
|
||||
if (paramMap.get("Im").isEmpty()) {
|
||||
throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查最大初损值Im是否缺失。");
|
||||
}
|
||||
if (!paramMap.get("qOther").isEmpty()) {
|
||||
qOther = Double.parseDouble(paramMap.get("qOther"));
|
||||
}
|
||||
dt = Double.parseDouble(paramMap.get("dt"));
|
||||
// dt = Double.parseDouble("1.0");
|
||||
Wm = Double.parseDouble(paramMap.get("Im"));
|
||||
List<ForecastU> uList = forecastUService.list();
|
||||
if (CollectionUtils.isEmpty(uList)) {
|
||||
throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查U(I)单位线是否缺失。");
|
||||
}
|
||||
// 每小时的单位径流量,单位m³/s
|
||||
double[] u = uList.stream().mapToDouble(forecastU -> forecastU.getUValue().doubleValue()).toArray();
|
||||
// 根据开始结束时间查询pa
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(startTime);
|
||||
// 将日期往前推一天
|
||||
cal.add(Calendar.DATE, -1);
|
||||
List<ForecastPa> paList = forecastPaService.list(new QueryWrapper<ForecastPa>().eq("stcd", attResBase.getStcd()).ge("tm", sdfDay.format(cal.getTime())).le("tm", sdfDay.format(endTime)));
|
||||
if (CollectionUtils.isEmpty(paList)) {
|
||||
throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查每日土壤含水量Pa是否缺失。");
|
||||
}
|
||||
Map<String, ForecastPa> paMap = paList.stream().collect(Collectors.toMap(ForecastPa::getTm, entity -> entity, (existing, replacement) -> existing));
|
||||
// 获取预测开始时间前的最后水库水位
|
||||
double H1 = 0.0;// 初始水库水位,可以根据H1->V1,H1->q1得到初始的水库库容和下泄流量
|
||||
StRsvrR rsvrR = stRsvrRService.getOne(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).le("tm", startTime).orderBy(true, false, "tm").last("limit 1"));
|
||||
if (ObjectUtils.isEmpty(rsvrR)) {
|
||||
return null;
|
||||
}
|
||||
H1 = Double.parseDouble(rsvrR.getRz());
|
||||
// 泄流量
|
||||
List<StZqrlB> stZqrlBList = stZqrlBService.list(new QueryWrapper<StZqrlB>().eq("stcd", attResBase.getStcd()).orderBy(true, true, "z"));
|
||||
// 库容曲线
|
||||
List<StZvarlB> zvarlBS = stZvarlBService.list(new QueryWrapper<StZvarlB>().eq("stcd", attResBase.getStcd()).orderBy(true, true, "rz"));
|
||||
// 水位历史数据
|
||||
List<StRsvrR> rsvrRRealList = stRsvrRService.list(new QueryWrapper<StRsvrR>().eq("stcd", attResBase.getStcd()).ge("tm", startTime).le("tm", endTime));
|
||||
List<StRsvrR> resultList = reorganizeRsvrRData(rsvrRRealList, dt);
|
||||
List<Date[]> periods = splitByDay8To8(startTime, endTime);
|
||||
// v:累计降雨
|
||||
BigDecimal vValue = BigDecimal.ZERO;
|
||||
BigDecimal vSum = BigDecimal.ZERO;
|
||||
// Rsum:累计径流深
|
||||
BigDecimal Rsum = BigDecimal.ZERO;
|
||||
BigDecimal Psum = BigDecimal.ZERO;
|
||||
List<Map<String, Object>> res = new ArrayList<>();
|
||||
// 存储最后u的长度-1个r值
|
||||
for (int k = 0; k < periods.size(); k++) {
|
||||
Date[] period = periods.get(k);
|
||||
Calendar calNew = Calendar.getInstance();
|
||||
calNew.setTime(period[0]);
|
||||
// 根据每段时间的开始时间,如果在08点前,则采用前一天的pa值计算
|
||||
if (isBeforeEightAM(period[0])) {
|
||||
// 将日期往前推一天
|
||||
calNew.add(Calendar.DATE, -1);
|
||||
}
|
||||
ForecastPa forecastPa = paMap.get(sdfDay.format(calNew.getTime()));
|
||||
if (ObjectUtils.isEmpty(forecastPa)) {
|
||||
continue;
|
||||
// throw new IllegalArgumentException("温馨提示:当前洪水预报所依赖的数据尚不完整,请检查每日土壤含水量Pa、K值是否缺失。");
|
||||
}
|
||||
// 根据降雨数据,按照△t的颗粒度,均分
|
||||
// 筛选时间段内的降雨数据。不包前但包后
|
||||
List<StPptnR> filterList = polyPptnRList.stream().filter(e -> e.getTm().compareTo(period[0]) >= 0).filter(e -> e.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
|
||||
Map<String, List<StPptnR>> retMap = new HashMap<>();
|
||||
if (CollectionUtils.isNotEmpty(filterList)) {
|
||||
retMap = reorganizePptnRData(filterList, dt, period[0], period[1], nowHourTime, isHaveFuturePPtn);
|
||||
}
|
||||
if (ObjectUtils.isEmpty(retMap.get("listForForecast"))) {
|
||||
continue;
|
||||
}
|
||||
List<String> pForecastList = retMap.get("listForForecast").stream().map(s -> s.getDrp()).collect(Collectors.toList());
|
||||
if (pForecastList.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (ObjectUtils.isEmpty(retMap.get("listForReal"))) {
|
||||
continue;
|
||||
}
|
||||
Map<String, String> pRealMap = retMap.get("listForReal").stream().collect(Collectors.toMap(pptnR -> sdfMinute.format(pptnR.getTm()), StPptnR::getDrp, (existing, replacement) -> existing));
|
||||
double[] PList = pForecastList.stream().mapToDouble(Double::parseDouble).toArray();
|
||||
vSum = vSum.add(vValue);
|
||||
vValue = BigDecimal.ZERO;
|
||||
for (double value : PList) {
|
||||
BigDecimal bd = BigDecimal.valueOf(value);
|
||||
// 累加到总和中
|
||||
vValue = vValue.add(bd);
|
||||
}
|
||||
|
||||
// 存储上一次的径流深r,最开始默认全部为0
|
||||
List<Double> lastRArr = new ArrayList<>();
|
||||
for (int i = 0; i < u.length - 1; i++) {
|
||||
lastRArr.add(0.0); // 填充初始值
|
||||
}
|
||||
// 从后往前遍历不定长的实体列表
|
||||
for (int i = voList.size() - 1; i >= 0; i--) {
|
||||
int index = lastRArr.size() - 1 - (voList.size() - 1 - i);
|
||||
lastRArr.set(index, voList.get(i).getR().doubleValue());
|
||||
if(index <= 0){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 预测执行
|
||||
Map<String,Object> map = new HashMap<>();
|
||||
map.put("in period" + k, sdf.format(period[0]));
|
||||
map.put("in K" + k, forecastPa.getK().doubleValue());
|
||||
map.put("in pa0" + k, forecastPa.getPa0().doubleValue());
|
||||
map.put("in Wm" + k, Wm);
|
||||
map.put("in pt0" + k, forecastPa.getPt0().doubleValue());
|
||||
map.put("in H1" + k, H1);
|
||||
map.put("in dt" + k, dt);
|
||||
map.put("in pa" + k, forecastPa.getPa().doubleValue());
|
||||
map.put("in PList" + k, PList);
|
||||
map.put("in u" + k, u);
|
||||
map.put("in stcd" + k, attResBase.getStcd());
|
||||
map.put("in qOther" + k, qOther);
|
||||
map.put("in vSum" + k, vSum.doubleValue());
|
||||
map.put("in Rsum" + k, Rsum.doubleValue());
|
||||
map.put("in lastRArr" + k, lastRArr);
|
||||
List<FloodAlgorithemVo> forecastVoList = RrainfallForecast.getData(sdf.format(period[0]), forecastPa.getK().doubleValue(), forecastPa.getPa0().doubleValue(), Wm, forecastPa.getPt0().doubleValue(), H1, dt,
|
||||
forecastPa.getPa().doubleValue(), PList, u, attResBase.getStcd(), qOther, vSum.doubleValue(), Rsum.doubleValue(), lastRArr);
|
||||
map.put("out res" + k, forecastVoList);
|
||||
res.add(map);
|
||||
if (CollectionUtils.isNotEmpty(forecastVoList)) {
|
||||
// 筛选同时段的真实水位数据
|
||||
List<StRsvrR> realRsvrList = resultList.stream().filter(item -> item.getTm().compareTo(period[0]) >= 0 && item.getTm().compareTo(period[1]) <= 0).collect(Collectors.toList());
|
||||
Map<String, String> realRsvrMap = realRsvrList.stream().collect(Collectors.toMap(rsvr -> sdfMinute.format(rsvr.getTm()), StRsvrR::getRz, (existing, replacement) -> existing));
|
||||
forecastVoList = forecastVoList.subList(0, PList.length + 1);
|
||||
// 去除预测出来的最后一条与第二次实际的相同时间的数据
|
||||
if (voList.size() > 0 && voList.get(voList.size() - 1).getTm().equals(forecastVoList.get(0).getDateStr())) {
|
||||
voList.remove(voList.size() - 1);
|
||||
}
|
||||
for (int j = 0; j < forecastVoList.size(); j++) {
|
||||
FloodAlgorithemVo floodAlgorithemVo = forecastVoList.get(j);
|
||||
// dt不同,预测结果的条数不同(跟new_q参数有关)
|
||||
if (floodAlgorithemVo.getDateStr().substring(0, 15).compareTo(sdfMinute.format(period[1])) > 0) {
|
||||
break;
|
||||
}
|
||||
String dateStr = floodAlgorithemVo.getDateStr();
|
||||
ForecastResultVo resultVo = new ForecastResultVo();
|
||||
resultVo.setTm(dateStr);
|
||||
resultVo.setYcRkQValue(floodAlgorithemVo.getRq());// 预测入库流量
|
||||
// resultVo.setRealRkQValue();// 暂无真实入库流量
|
||||
resultVo.setYcCkQValue(floodAlgorithemVo.getCq());// 预测出库流量
|
||||
resultVo.setYcSwHValue(floodAlgorithemVo.getKh());// 预测水库水位
|
||||
H1 = resultVo.getYcSwHValue().doubleValue();// 以预测水位作为下一次预测段起始值
|
||||
String dateMinuteStr = dateStr.substring(0, dateStr.length() - 3);// 年月日 时分
|
||||
if (realRsvrMap.containsKey(dateMinuteStr)) {
|
||||
BigDecimal realSwHValue = new BigDecimal(realRsvrMap.get(dateMinuteStr));// 根据时间取更准确
|
||||
resultVo.setRealSwHValue(realSwHValue);// 真实水库水位
|
||||
calculateCap(zvarlBS, resultVo, realSwHValue);// 有真实水位就用真实水位算(作为实测库容)
|
||||
resultVo.setSwHDValue(resultVo.getYcSwHValue().subtract(resultVo.getRealSwHValue()));// 预测与真实水位差
|
||||
// 注释:修复跨8点时的陡升陡降
|
||||
// H1 = realSwHValue.doubleValue();// 如果有真实水位,将最后一条的真实水位作为下一次预测段的初始水位
|
||||
// 真实出库流量=真实水库水位与泄流量曲线差值法
|
||||
if (realSwHValue != null && CollectionUtils.isNotEmpty(stZqrlBList)) {
|
||||
BigDecimal maxZ = stZqrlBList.stream().max(Comparator.comparing(StZqrlB::getZ)).get().getZ();
|
||||
BigDecimal minZ = stZqrlBList.stream().min(Comparator.comparing(StZqrlB::getZ)).get().getZ();
|
||||
if (realSwHValue.compareTo(minZ) < 0 || realSwHValue.compareTo(maxZ) > 0) {
|
||||
resultVo.setRealCkQValue(BigDecimal.ZERO);// 真实出库流量
|
||||
} else {
|
||||
Map<BigDecimal, BigDecimal> stZvalMap = stZqrlBList.stream().collect(Collectors.toMap(StZqrlB::getZ, StZqrlB::getQ, (existing, replacement) -> existing));
|
||||
List<BigDecimal> list = stZqrlBList.stream().map(StZqrlB::getZ).collect(Collectors.toList());
|
||||
resultVo.setRealCkQValue(DataHandleUtil.calcData(realSwHValue, stZvalMap, list));// 真实出库流量
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有真实水位就用预测水位算(作为预测库容)
|
||||
calculateCap(zvarlBS, resultVo, resultVo.getYcSwHValue());
|
||||
}
|
||||
|
||||
String pRealDrp = "0.0";
|
||||
if (pRealMap.containsKey(dateMinuteStr)) {
|
||||
pRealDrp = pRealMap.get(dateMinuteStr);
|
||||
}
|
||||
BigDecimal drp = new BigDecimal(pRealDrp);// 根据时间取更准确
|
||||
if (drp.compareTo(BigDecimal.ZERO) < 0) {
|
||||
resultVo.setDrp(BigDecimal.ZERO);
|
||||
} else {
|
||||
resultVo.setDrp(drp);
|
||||
}
|
||||
Psum = Psum.add(resultVo.getDrp());
|
||||
resultVo.setPSum(Psum);
|
||||
Date dateTm = sdf.parse(floodAlgorithemVo.getDateStr());
|
||||
resultVo.setIspreDrp(dateTm.compareTo(nowHourTime) <= 0 ? "0" : "1");// 0:真实 1:预测
|
||||
resultVo.setR(floodAlgorithemVo.getR());
|
||||
if (resultVo.getR() != null) {
|
||||
Rsum = Rsum.add(resultVo.getR());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
resultVo.setRSum(Rsum);
|
||||
resultVo.setFlLowLimLev(attResBase.getFlLowLimLev());
|
||||
resultVo.setCurrentYdgdyjz(MapUtil.get(paramMap, "ydgdyjz", BigDecimal.class, BigDecimal.ZERO));
|
||||
resultVo.setPa(floodAlgorithemVo.getPa());
|
||||
voList.add(resultVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 根据水位计算库容
|
||||
* @param zvarlBS 库容曲线
|
||||
|
|
@ -1122,23 +837,6 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
return jsonBuilder.toString();
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getHumanForecastResultDebug(ForecastTask forecastTask) {
|
||||
// 当前时间整点,作为获取雨量数据历史、预测分隔点
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.MINUTE, 0);
|
||||
calendar.set(Calendar.SECOND, 0);
|
||||
calendar.set(Calendar.MILLISECOND, 0);
|
||||
Date nowHourTime = calendar.getTime();
|
||||
forecastTask.setNowTime(nowHourTime);
|
||||
List<Map<String, Object>> maps;
|
||||
try {
|
||||
maps = excuteForecastDebug(forecastTask);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
return maps;
|
||||
}
|
||||
|
||||
public List<OsmoticPressDetailVo> calculateY(SyRegressionData syRegressionData, List<ForecastResultVo> voList) {
|
||||
//过滤出预测时间的数据
|
||||
|
|
@ -1188,7 +886,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* 根据回归方程计算y值
|
||||
* 根据回归方程计算y值(高精度计算)
|
||||
* @param equation 回归方程字符串
|
||||
* @param x 自变量x的值
|
||||
* @return 计算得到的y值
|
||||
|
|
@ -1213,7 +911,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
} else {
|
||||
result = calculateFirstOrder(cleanEquation, x);
|
||||
}
|
||||
// 四舍五入保留两位小数
|
||||
// 只在最后结果保留两位小数,中间计算过程保持高精度
|
||||
return result.setScale(2, RoundingMode.HALF_UP);
|
||||
} catch (Exception e) {
|
||||
// 计算异常时返回0
|
||||
|
|
@ -1222,7 +920,7 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
/**
|
||||
* 计算一阶线性方程 y = ax + b
|
||||
* 计算一阶线性方程 y = ax + b(高精度)
|
||||
*/
|
||||
private BigDecimal calculateFirstOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:0.0455x+94.2395
|
||||
|
|
@ -1234,15 +932,15 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
BigDecimal a = parseCoefficient(parts[0]);
|
||||
BigDecimal b = parseCoefficient(parts[1]);
|
||||
|
||||
return a.multiply(x).add(b);
|
||||
// 高精度计算:a * x + b
|
||||
return a.multiply(x, MathContext.DECIMAL128).add(b, MathContext.DECIMAL128);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算二阶方程 y = ax² + bx + c
|
||||
* 计算二阶方程 y = ax² + bx + c(高精度)
|
||||
*/
|
||||
private BigDecimal calculateSecondOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:-68.4211x²+16312.8684x-972224.1397
|
||||
// 支持两种格式:x² 和 x^2
|
||||
String normalizedEquation = equation.replace("x^2", "x²");
|
||||
String[] parts = normalizedEquation.split("x");
|
||||
if (parts.length < 3) {
|
||||
|
|
@ -1253,16 +951,20 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
BigDecimal b = parseCoefficient(parts[1].replace("²", ""));
|
||||
BigDecimal c = parseCoefficient(parts[2]);
|
||||
|
||||
BigDecimal x2 = x.multiply(x); // x²
|
||||
return a.multiply(x2).add(b.multiply(x)).add(c);
|
||||
// 高精度计算:x² = x * x
|
||||
BigDecimal x2 = x.multiply(x, MathContext.DECIMAL128);
|
||||
|
||||
// 高精度计算:a * x² + b * x + c
|
||||
BigDecimal term1 = a.multiply(x2, MathContext.DECIMAL128);
|
||||
BigDecimal term2 = b.multiply(x, MathContext.DECIMAL128);
|
||||
return term1.add(term2, MathContext.DECIMAL128).add(c, MathContext.DECIMAL128);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算三阶方程 y = ax³ + bx² + cx + d
|
||||
* 计算三阶方程 y = ax³ + bx² + cx + d(高精度)
|
||||
*/
|
||||
private BigDecimal calculateThirdOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:-2291.6667x³+819497.9167x²-97683901.8750x+3881297151.1650
|
||||
// 支持两种格式:x³ 和 x^3, x² 和 x^2
|
||||
String normalizedEquation = equation.replace("x^3", "x³").replace("x^2", "x²");
|
||||
String[] parts = normalizedEquation.split("x");
|
||||
if (parts.length < 4) {
|
||||
|
|
@ -1274,18 +976,22 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
BigDecimal c = parseCoefficient(parts[2].replace("²", ""));
|
||||
BigDecimal d = parseCoefficient(parts[3]);
|
||||
|
||||
BigDecimal x2 = x.multiply(x); // x²
|
||||
BigDecimal x3 = x2.multiply(x); // x³
|
||||
// 高精度计算:x² = x * x, x³ = x² * x
|
||||
BigDecimal x2 = x.multiply(x, MathContext.DECIMAL128);
|
||||
BigDecimal x3 = x2.multiply(x, MathContext.DECIMAL128);
|
||||
|
||||
return a.multiply(x3).add(b.multiply(x2)).add(c.multiply(x)).add(d);
|
||||
// 高精度计算:a * x³ + b * x² + c * x + d
|
||||
BigDecimal term1 = a.multiply(x3, MathContext.DECIMAL128);
|
||||
BigDecimal term2 = b.multiply(x2, MathContext.DECIMAL128);
|
||||
BigDecimal term3 = c.multiply(x, MathContext.DECIMAL128);
|
||||
return term1.add(term2, MathContext.DECIMAL128).add(term3, MathContext.DECIMAL128).add(d, MathContext.DECIMAL128);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算四阶方程 y = ax⁴ + bx³ + cx² + dx + e
|
||||
* 计算四阶方程 y = ax⁴ + bx³ + cx² + dx + e(高精度)
|
||||
*/
|
||||
private BigDecimal calculateFourthOrder(String equation, BigDecimal x) {
|
||||
// 解析方程系数,格式如:-5.9039x⁴+523.5482x³+316095.2736x²-57676816.2672x+2688986002.6804
|
||||
// 支持两种格式:x⁴ 和 x^4, x³ 和 x^3, x² 和 x^2
|
||||
String normalizedEquation = equation.replace("x^4", "x⁴").replace("x^3", "x³").replace("x^2", "x²");
|
||||
String[] parts = normalizedEquation.split("x");
|
||||
if (parts.length < 5) {
|
||||
|
|
@ -1298,15 +1004,24 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
BigDecimal d = parseCoefficient(parts[3].replace("²", ""));
|
||||
BigDecimal e = parseCoefficient(parts[4]);
|
||||
|
||||
BigDecimal x2 = x.multiply(x); // x²
|
||||
BigDecimal x3 = x2.multiply(x); // x³
|
||||
BigDecimal x4 = x3.multiply(x); // x⁴
|
||||
// 高精度计算:x² = x * x, x³ = x² * x, x⁴ = x³ * x
|
||||
BigDecimal x2 = x.multiply(x, MathContext.DECIMAL128);
|
||||
BigDecimal x3 = x2.multiply(x, MathContext.DECIMAL128);
|
||||
BigDecimal x4 = x3.multiply(x, MathContext.DECIMAL128);
|
||||
|
||||
return a.multiply(x4).add(b.multiply(x3)).add(c.multiply(x2)).add(d.multiply(x)).add(e);
|
||||
// 高精度计算:a * x⁴ + b * x³ + c * x² + d * x + e
|
||||
BigDecimal term1 = a.multiply(x4, MathContext.DECIMAL128);
|
||||
BigDecimal term2 = b.multiply(x3, MathContext.DECIMAL128);
|
||||
BigDecimal term3 = c.multiply(x2, MathContext.DECIMAL128);
|
||||
BigDecimal term4 = d.multiply(x, MathContext.DECIMAL128);
|
||||
return term1.add(term2, MathContext.DECIMAL128)
|
||||
.add(term3, MathContext.DECIMAL128)
|
||||
.add(term4, MathContext.DECIMAL128)
|
||||
.add(e, MathContext.DECIMAL128);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析系数,处理正负号和数字格式
|
||||
* 解析系数,处理正负号和数字格式(高精度)
|
||||
*/
|
||||
private BigDecimal parseCoefficient(String coeffStr) {
|
||||
if (coeffStr == null || coeffStr.isEmpty()) {
|
||||
|
|
@ -1324,7 +1039,8 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
}
|
||||
|
||||
try {
|
||||
return new BigDecimal(coeffStr);
|
||||
// 使用BigDecimal的高精度解析
|
||||
return new BigDecimal(coeffStr, MathContext.DECIMAL128);
|
||||
} catch (NumberFormatException e) {
|
||||
// 如果解析失败,尝试处理特殊情况
|
||||
if (coeffStr.equals("+")) {
|
||||
|
|
@ -1335,4 +1051,99 @@ public class ForecastResultsService extends ServiceImpl<ForecastResultsMapper, F
|
|||
return BigDecimal.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
public void reportExport(List<OsmoticPressDetailVo> data, String regression, String dvcd, HttpServletResponse response) {
|
||||
try {
|
||||
// 设置响应头
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
String fileName = URLEncoder.encode("渗透压力预测报告", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
// 创建Excel工作簿
|
||||
Workbook workbook = new XSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("渗透压力预测报告");
|
||||
|
||||
// 创建单元格样式 - 支持换行
|
||||
CellStyle wrapStyle = workbook.createCellStyle();
|
||||
wrapStyle.setWrapText(true);
|
||||
|
||||
// 设置行号
|
||||
int rowNum = 0;
|
||||
|
||||
// 第一行:测点编号(不合并)
|
||||
Row row1 = sheet.createRow(rowNum++);
|
||||
Cell label1 = row1.createCell(0);
|
||||
label1.setCellValue("测点编号:");
|
||||
Cell value1 = row1.createCell(1);
|
||||
value1.setCellValue(dvcd);
|
||||
|
||||
// 第二行:回归方程(从D列开始合并10个单元格)
|
||||
Row row2 = sheet.createRow(rowNum++);
|
||||
Cell label2 = row2.createCell(0);
|
||||
label2.setCellValue("回归方程:");
|
||||
Cell value2 = row2.createCell(3); // D列(索引为3)
|
||||
value2.setCellValue(regression != null ? regression : "");
|
||||
value2.setCellStyle(wrapStyle);
|
||||
// 合并D列到M列(共10个单元格):从第3列到第12列
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 3, 12));
|
||||
|
||||
// 空一行
|
||||
rowNum++;
|
||||
|
||||
// 表头行
|
||||
Row headerRow = sheet.createRow(rowNum++);
|
||||
String[] headers = {"预测时间", "预测值", "预测库水位"};
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell headerCell = headerRow.createCell(i);
|
||||
headerCell.setCellValue(headers[i]);
|
||||
}
|
||||
|
||||
// 数据行
|
||||
if (data != null && !data.isEmpty()) {
|
||||
for (OsmoticPressDetailVo detail : data) {
|
||||
Row dataRow = sheet.createRow(rowNum++);
|
||||
|
||||
// 预测时间
|
||||
Cell timeCell = dataRow.createCell(0);
|
||||
timeCell.setCellValue(detail.getTm() != null ? detail.getTm() : "");
|
||||
|
||||
// 预测值
|
||||
Cell valueCell = dataRow.createCell(1);
|
||||
if (detail.getValue() != null) {
|
||||
valueCell.setCellValue(detail.getValue().doubleValue());
|
||||
} else {
|
||||
valueCell.setCellValue("");
|
||||
}
|
||||
|
||||
// 预测库水位
|
||||
Cell rzCell = dataRow.createCell(2);
|
||||
if (detail.getRz() != null) {
|
||||
rzCell.setCellValue(detail.getRz().doubleValue());
|
||||
} else {
|
||||
rzCell.setCellValue("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置列宽
|
||||
sheet.setColumnWidth(0, 15 * 256); // A列:标签列,固定宽度
|
||||
sheet.setColumnWidth(1, 12 * 256); // B列:测点编号值,固定宽度
|
||||
sheet.setColumnWidth(2, 12 * 256); // C列:空列,固定宽度
|
||||
sheet.setColumnWidth(3, 50 * 256); // D列:方程列开始,固定宽度
|
||||
|
||||
// 自动调整数据表格的列宽
|
||||
sheet.autoSizeColumn(0); // 预测时间列
|
||||
sheet.autoSizeColumn(1); // 预测值列
|
||||
sheet.autoSizeColumn(2); // 预测库水位列
|
||||
|
||||
// 写入响应流
|
||||
workbook.write(response.getOutputStream());
|
||||
workbook.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("导出Excel失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ public class SyDataCheckRuleService extends ServiceImpl<SyDataCheckRuleMapper, S
|
|||
if(!StringUtils.isBlank(page.getDvcd())){
|
||||
queryWrapper.eq(SyDataCheckRule::getDvcd,page.getDvcd());
|
||||
}
|
||||
if(!StringUtils.isBlank(page.getDm())){
|
||||
queryWrapper.eq(SyDataCheckRule::getDm,page.getDm());
|
||||
}
|
||||
Page<SyDataCheckRule> syDataCheckRulePage = this.baseMapper.selectPage(page.getPageSo().toPage(), queryWrapper);
|
||||
return syDataCheckRulePage;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,21 @@ package com.gunshi.project.hsz.service;
|
|||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gunshi.project.hsz.mapper.StZvarlBMapper;
|
||||
import com.gunshi.project.hsz.common.model.vo.OsmoticPressDetailVo;
|
||||
import com.gunshi.project.hsz.entity.vo.ProjectSafeCalculateVo;
|
||||
|
||||
import com.gunshi.project.hsz.mapper.SyRegressionDataMapper;
|
||||
import com.gunshi.project.hsz.model.StZvarlB;
|
||||
import com.gunshi.project.hsz.model.SyRegressionData;
|
||||
import com.gunshi.project.hsz.util.RegressionEquationFormatter;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
|
|
@ -33,4 +39,133 @@ public class SyRegressionDataService extends ServiceImpl<SyRegressionDataMapper,
|
|||
List<SyRegressionData> syRegressionData = this.baseMapper.selectList(queryWrapper);
|
||||
return syRegressionData;
|
||||
}
|
||||
|
||||
public void export(String dvcd, ProjectSafeCalculateVo ans, HttpServletResponse response) {
|
||||
try {
|
||||
// 设置响应头
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
String fileName = URLEncoder.encode("渗透压力监测数据", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
// 创建Excel工作簿
|
||||
Workbook workbook = new XSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet("渗透压力监测数据");
|
||||
|
||||
// 创建单元格样式 - 支持换行
|
||||
CellStyle wrapStyle = workbook.createCellStyle();
|
||||
wrapStyle.setWrapText(true); // 设置自动换行
|
||||
|
||||
// 设置行号
|
||||
int rowNum = 0;
|
||||
|
||||
// 第一行:测点编号(不合并)
|
||||
Row row1 = sheet.createRow(rowNum++);
|
||||
Cell label1 = row1.createCell(0);
|
||||
label1.setCellValue("测点编号:");
|
||||
Cell value1 = row1.createCell(1);
|
||||
value1.setCellValue(dvcd);
|
||||
|
||||
// 第二行:一阶回归方程(从D列开始合并10个单元格)
|
||||
Row row2 = sheet.createRow(rowNum++);
|
||||
Cell label2 = row2.createCell(0);
|
||||
label2.setCellValue("一阶回归方程:");
|
||||
Cell value2 = row2.createCell(3); // D列(索引为3)
|
||||
String one = RegressionEquationFormatter.formatEquation(ans.getOne());
|
||||
value2.setCellValue(one != null ? one : "");
|
||||
value2.setCellStyle(wrapStyle);
|
||||
// 合并D列到M列(共10个单元格):从第3列到第12列
|
||||
sheet.addMergedRegion(new CellRangeAddress(1, 1, 3, 12));
|
||||
|
||||
// 第三行:二阶回归方程(从D列开始合并10个单元格)
|
||||
Row row3 = sheet.createRow(rowNum++);
|
||||
Cell label3 = row3.createCell(0);
|
||||
label3.setCellValue("二阶回归方程:");
|
||||
Cell value3 = row3.createCell(3); // D列(索引为3)
|
||||
String tow = RegressionEquationFormatter.formatEquation(ans.getTwo());
|
||||
value3.setCellValue(tow != null ? tow : "");
|
||||
value3.setCellStyle(wrapStyle);
|
||||
// 合并D列到M列(共10个单元格):从第3列到第12列
|
||||
sheet.addMergedRegion(new CellRangeAddress(2, 2, 3, 12));
|
||||
|
||||
// 第四行:三阶回归方程(从D列开始合并10个单元格)
|
||||
Row row4 = sheet.createRow(rowNum++);
|
||||
Cell label4 = row4.createCell(0);
|
||||
label4.setCellValue("三阶回归方程:");
|
||||
Cell value4 = row4.createCell(3); // D列(索引为3)
|
||||
String three = RegressionEquationFormatter.formatEquation(ans.getThree());
|
||||
value4.setCellValue(three != null ? three : "");
|
||||
value4.setCellStyle(wrapStyle);
|
||||
// 合并D列到M列(共10个单元格):从第3列到第12列
|
||||
sheet.addMergedRegion(new CellRangeAddress(3, 3, 3, 12));
|
||||
|
||||
// 第五行:四阶回归方程(从D列开始合并10个单元格)
|
||||
Row row5 = sheet.createRow(rowNum++);
|
||||
Cell label5 = row5.createCell(0);
|
||||
label5.setCellValue("四阶回归方程:");
|
||||
Cell value5 = row5.createCell(3); // D列(索引为3)
|
||||
String four = RegressionEquationFormatter.formatEquation(ans.getFour());
|
||||
value5.setCellValue(four != null ? four : "");
|
||||
value5.setCellStyle(wrapStyle);
|
||||
// 合并D列到M列(共10个单元格):从第3列到第12列
|
||||
sheet.addMergedRegion(new CellRangeAddress(4, 4, 3, 12));
|
||||
|
||||
// 空一行
|
||||
rowNum++;
|
||||
|
||||
// 表头行 - 从第0列开始正常显示
|
||||
Row headerRow = sheet.createRow(rowNum++);
|
||||
String[] headers = {"监测时间", "监测值", "库水位"};
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
Cell headerCell = headerRow.createCell(i);
|
||||
headerCell.setCellValue(headers[i]);
|
||||
}
|
||||
|
||||
// 数据行
|
||||
if (ans.getDatas() != null && !ans.getDatas().isEmpty()) {
|
||||
for (OsmoticPressDetailVo data : ans.getDatas()) {
|
||||
Row dataRow = sheet.createRow(rowNum++);
|
||||
|
||||
// 监测时间 - 第0列
|
||||
Cell timeCell = dataRow.createCell(0);
|
||||
timeCell.setCellValue(data.getTm() != null ? data.getTm() : "");
|
||||
|
||||
// 监测值 - 第1列
|
||||
Cell valueCell = dataRow.createCell(1);
|
||||
if (data.getValue() != null) {
|
||||
valueCell.setCellValue(data.getValue().doubleValue());
|
||||
} else {
|
||||
valueCell.setCellValue("");
|
||||
}
|
||||
|
||||
// 库水位 - 第2列
|
||||
Cell rzCell = dataRow.createCell(2);
|
||||
if (data.getRz() != null) {
|
||||
rzCell.setCellValue(data.getRz().doubleValue());
|
||||
} else {
|
||||
rzCell.setCellValue("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置列宽
|
||||
sheet.setColumnWidth(0, 15 * 256); // A列:标签列,固定宽度
|
||||
sheet.setColumnWidth(1, 12 * 256); // B列:测点编号值,固定宽度
|
||||
sheet.setColumnWidth(2, 12 * 256); // C列:空列,固定宽度
|
||||
sheet.setColumnWidth(3, 50 * 256); // D列:方程列开始,固定宽度
|
||||
|
||||
// 自动调整数据表格的列宽(只对数据区域有效)
|
||||
sheet.autoSizeColumn(0); // 监测时间列
|
||||
sheet.autoSizeColumn(1); // 监测值列
|
||||
sheet.autoSizeColumn(2); // 库水位列
|
||||
|
||||
// 写入响应流
|
||||
workbook.write(response.getOutputStream());
|
||||
workbook.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("导出Excel失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
package com.gunshi.project.hsz.util;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 回归方程格式化工具类
|
||||
*/
|
||||
public class RegressionEquationFormatter {
|
||||
|
||||
/**
|
||||
* 格式化回归方程,保留小数点后指定有效小数位数(四舍五入)
|
||||
* @param equation 原始方程字符串
|
||||
* @param decimalDigits 小数点后有效小数位数
|
||||
* @return 格式化后的方程字符串
|
||||
*/
|
||||
public static String formatEquation(String equation, int decimalDigits) {
|
||||
if (equation == null || equation.trim().isEmpty()) {
|
||||
return equation;
|
||||
}
|
||||
|
||||
// 使用正则表达式匹配数字
|
||||
String regex = "-?\\d+\\.\\d+";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(equation);
|
||||
|
||||
StringBuffer result = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
String numberStr = matcher.group();
|
||||
try {
|
||||
// 截取小数点后指定位数,进行四舍五入
|
||||
String formatted = roundDecimal(numberStr, decimalDigits);
|
||||
matcher.appendReplacement(result, formatted);
|
||||
} catch (Exception e) {
|
||||
// 如果处理失败,保留原数字
|
||||
matcher.appendReplacement(result, numberStr);
|
||||
}
|
||||
}
|
||||
matcher.appendTail(result);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取小数点后指定位数,进行四舍五入
|
||||
*/
|
||||
private static String roundDecimal(String numberStr, int decimalDigits) {
|
||||
boolean isNegative = numberStr.startsWith("-");
|
||||
if (isNegative) {
|
||||
numberStr = numberStr.substring(1);
|
||||
}
|
||||
|
||||
// 使用BigDecimal进行精确的四舍五入
|
||||
BigDecimal bd = new BigDecimal(numberStr);
|
||||
bd = bd.setScale(decimalDigits, RoundingMode.HALF_UP);
|
||||
|
||||
// 转换为字符串
|
||||
String result = bd.toPlainString();
|
||||
|
||||
// 确保显示所有小数位(即使末尾是0)
|
||||
if (result.contains(".")) {
|
||||
String[] parts = result.split("\\.");
|
||||
String integerPart = parts[0];
|
||||
String decimalPart = parts[1];
|
||||
|
||||
// 如果小数部分长度不足,补0
|
||||
while (decimalPart.length() < decimalDigits) {
|
||||
decimalPart += "0";
|
||||
}
|
||||
result = integerPart + "." + decimalPart;
|
||||
}
|
||||
|
||||
return isNegative ? "-" + result : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化回归方程,默认保留小数点后4位有效小数(四舍五入)
|
||||
* @param equation 原始方程字符串
|
||||
* @return 格式化后的方程字符串
|
||||
*/
|
||||
public static String formatEquation(String equation) {
|
||||
return formatEquation(equation, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单个数字,保留小数点后指定有效小数位数(四舍五入)
|
||||
* @param number 原始数字
|
||||
* @param decimalDigits 小数点后有效小数位数
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
public static String formatNumber(double number, int decimalDigits) {
|
||||
String numberStr = String.valueOf(number);
|
||||
return roundDecimal(numberStr, decimalDigits);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单个数字,默认保留小数点后4位有效小数(四舍五入)
|
||||
* @param number 原始数字
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
public static String formatNumber(double number) {
|
||||
return formatNumber(number, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单个数字,保留小数点后指定有效小数位数(四舍五入)
|
||||
* @param number 原始数字
|
||||
* @param decimalDigits 小数点后有效小数位数
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
public static String formatNumber(BigDecimal number, int decimalDigits) {
|
||||
if (number == null) {
|
||||
return "0";
|
||||
}
|
||||
number = number.setScale(decimalDigits, RoundingMode.HALF_UP);
|
||||
String result = number.toPlainString();
|
||||
|
||||
// 确保显示所有小数位(即使末尾是0)
|
||||
if (result.contains(".")) {
|
||||
String[] parts = result.split("\\.");
|
||||
String integerPart = parts[0];
|
||||
String decimalPart = parts[1];
|
||||
|
||||
// 如果小数部分长度不足,补0
|
||||
while (decimalPart.length() < decimalDigits) {
|
||||
decimalPart += "0";
|
||||
}
|
||||
result = integerPart + "." + decimalPart;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单个数字,默认保留小数点后4位有效小数(四舍五入)
|
||||
* @param number 原始数字
|
||||
* @return 格式化后的字符串
|
||||
*/
|
||||
public static String formatNumber(BigDecimal number) {
|
||||
return formatNumber(number, 4);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue