App稳态、暂态报告功能支持

This commit is contained in:
xy
2026-03-25 13:28:46 +08:00
parent fcddc064f6
commit 7b9fb1628b
25 changed files with 850 additions and 62 deletions

View File

@@ -1,5 +1,6 @@
package com.njcn.harmonic.common.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.harmonic.pojo.param.ReportSearchParam;
@@ -19,6 +20,7 @@ import java.util.Map;
* @author cdf
* @date 2022/8/16
*/
@DS("sjzx")
public interface ExcelRptTempMapper extends BaseMapper<ExcelRptTemp> {
Page<ReportTemplateVO> getReportTemplateListPage(Page<BaseParam> page, @Param("baseParam")BaseParam baseParam);

View File

@@ -24,4 +24,10 @@ public interface CustomReportTableService {
* @date 2022/10/18
*/
void getCustomReport(ReportSearchParam reportSearchParam, Map<String,String> newMap, DeviceUnitCommDTO deviceUnitCommDTO, HttpServletResponse response);
/**
* 存储稳态事件报表,并返回存储路径
*/
String saveStableEventReport(ReportSearchParam reportSearchParam, Map<String, String> newMap, DeviceUnitCommDTO deviceUnitCommDTO);
}

View File

@@ -18,8 +18,6 @@ import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsCommTerminalFeignClient;
import com.njcn.device.biz.commApi.CommTerminalGeneralClient;
import com.njcn.harmonic.common.mapper.ExcelRptTempMapper;
import com.njcn.harmonic.common.pojo.dto.DeviceUnitCommDTO;
import com.njcn.harmonic.common.service.CustomReportTableService;
@@ -29,6 +27,7 @@ import com.njcn.harmonic.pojo.param.ReportSearchParam;
import com.njcn.harmonic.pojo.po.ExcelRptTemp;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.enums.OssResponseEnum;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.system.api.DicDataFeignClient;
@@ -40,13 +39,16 @@ import com.njcn.system.pojo.po.EleEpdPqd;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
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.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
@@ -69,18 +71,9 @@ import java.util.stream.Collectors;
public class CustomReportTableServiceImpl implements CustomReportTableService {
private final ExcelRptTempMapper excelRptTempMapper;
private final EpdFeignClient epdFeignClient;
private final FileStorageUtil fileStorageUtil;
private final DicDataFeignClient dicDataFeignClient;
private final CommTerminalGeneralClient commTerminalGeneralClient;
private final CsCommTerminalFeignClient csCommTerminalFeignClient;
private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
private final String CELL_DATA = "celldata";
@@ -113,8 +106,286 @@ public class CustomReportTableServiceImpl implements CustomReportTableService {
}
}
@Override
public String saveStableEventReport(ReportSearchParam reportSearchParam, Map<String, String> newMap, DeviceUnitCommDTO deviceUnitCommDTO) {
String filePath = "";
ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(reportSearchParam.getTempId());
if (Objects.isNull(excelRptTemp)) {
throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_ACTIVE);
} else {
if (Objects.isNull(reportSearchParam.getCustomType())) {
filePath = this.analyzeReport2(reportSearchParam, excelRptTemp, newMap, deviceUnitCommDTO);
}
}
return filePath;
}
/**
private String analyzeReport2(ReportSearchParam reportSearchParam, ExcelRptTemp excelRptTemp,Map<String,String> newMap,DeviceUnitCommDTO deviceUnitCommDTO) {
Map<String, Object> dataMap = new HashMap<>();
//定义一个线程集合
List<Future<?>> futures = new ArrayList<>();
//指标
List<ReportTemplateDTO> reportTemplateDTOList = new ArrayList<>();
//限值
List<ReportTemplateDTO> reportLimitList = new ArrayList<>();
//台账
List<ReportTemplateDTO> terminalList = new ArrayList<>();
JSONArray jsonArray;
try (InputStream fileStream = fileStorageUtil.getFileStream(excelRptTemp.getContent())) {
jsonArray = new JSONArray(new JSONTokener(fileStream, new JSONConfig()));
parseTemplate(jsonArray, reportTemplateDTOList, reportLimitList, terminalList);
} catch (Exception e) {
if(e instanceof BusinessException){
throw new BusinessException(e.getMessage());
}else {
throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
}
}
//查询不分相别的指标
DictData dictData = dicDataFeignClient.getDicDataByCodeAndType(DicDataEnum.EPD.getCode(), DicDataTypeEnum.CS_DATA_TYPE.getCode()).getData();
if(Objects.isNull(dictData)){
throw new BusinessException(CommonResponseEnum.FAIL,"字典类型模板缺少!");
}
DictData epdDic = dicDataFeignClient.getDicDataByCodeAndType(DicDataEnum.EPD.getCode(),DicDataTypeEnum.CS_DATA_TYPE.getCode()).getData();
List<EleEpdPqd> eleEpdPqdList= epdFeignClient.dictMarkByDataType(epdDic.getId()).getData();
Map<String, String> tMap = new HashMap<>();
eleEpdPqdList.forEach(item->{
String phase;
if (Objects.isNull(PHASE_MAPPING.get(item.getPhase()))) {
phase = item.getPhase();
} else {
phase = PHASE_MAPPING.get(item.getPhase());
}
if (ObjectUtils.isNotNull(item.getHarmStart()) && ObjectUtils.isNotNull(item.getHarmEnd())) {
for (int i = item.getHarmStart(); i <= item.getHarmEnd() + 1; i++) {
tMap.put((item.getOtherName() + "_" + i + phase + item.getResourcesId()).toUpperCase(), item.getPrimaryFormula());
}
} else {
tMap.put((item.getOtherName() + phase + item.getResourcesId()).toUpperCase(), item.getPrimaryFormula());
}
});
eleEpdPqdList = eleEpdPqdList.stream().filter(it->"T".equals(it.getPhase())||"M".equals(it.getPhase())).collect(Collectors.toList());
List<String> noPhaseList = eleEpdPqdList.stream().filter(it->StrUtil.isNotBlank(it.getOtherName())).map(it->it.getOtherName().toUpperCase()).collect(Collectors.toList());
//处理指标是否合格
reportLimitList = new LinkedHashSet<>(reportLimitList).stream().sorted(Comparator.comparing(ReportTemplateDTO::getItemName)).collect(Collectors.toList());
Map<String, Float> limitMap = overLimitDeal(reportLimitList, reportSearchParam);
//存放限值指标的map
Map<String, ReportTemplateDTO> limitTargetMapX = reportLimitList.stream().collect(Collectors.toMap(ReportTemplateDTO::getItemName, Function.identity()));
List<ReportTemplateDTO> endList = new CopyOnWriteArrayList<>();
if (CollUtil.isNotEmpty(reportTemplateDTOList)) {
//开始组织sql
reportTemplateDTOList = new LinkedHashSet<>(reportTemplateDTOList).stream().sorted(Comparator.comparing(ReportTemplateDTO::getItemName)).collect(Collectors.toList());
Map<String, List<ReportTemplateDTO>> classMap = reportTemplateDTOList.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getResourceId));
//定义存放越限指标的map
Map<String, ReportTemplateDTO> assNoPassMap = new HashMap<>();
classMap.forEach((classKey, templateValue) -> {
Map<String, List<ReportTemplateDTO>> valueTypeMap = templateValue.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getStatMethod));
//每张表开启一个独立线程查询
futures.add(executorService.submit(() -> {
DynamicDataSourceContextHolder.push("sjzx");
//avg.max,min,cp95
try {
valueTypeMap.forEach((valueTypeKey, valueTypeVal) -> {
//相别分组
Map<String, List<ReportTemplateDTO>> phaseMap = valueTypeVal.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getPhase));
phaseMap.forEach((phaseKey, phaseVal) -> {
StringBuilder sql = new StringBuilder(InfluxDbSqlConstant.SELECT);
if (InfluxDbSqlConstant.MAX.equalsIgnoreCase(valueTypeKey)) {
assSqlByMysql(tMap,newMap.get("LEVEL"),newMap.get("PT"),newMap.get("CT"),phaseVal, sql, endList, InfluxDbSqlConstant.MAX, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap,noPhaseList);
} else if (InfluxDbSqlConstant.MIN.equalsIgnoreCase(valueTypeKey)) {
assSqlByMysql(tMap,newMap.get("LEVEL"),newMap.get("PT"),newMap.get("CT"),phaseVal, sql, endList, InfluxDbSqlConstant.MIN, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap,noPhaseList);
} else if (InfluxDbSqlConstant.AVG_WEB.equalsIgnoreCase(valueTypeKey)) {
assSqlByMysql(tMap,newMap.get("LEVEL"),newMap.get("PT"),newMap.get("CT"),phaseVal, sql, endList, InfluxDbSqlConstant.AVG_WEB, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap,noPhaseList);
} else if (InfluxDbSqlConstant.CP95.equalsIgnoreCase(valueTypeKey)) {
assSqlByMysql(tMap,newMap.get("LEVEL"),newMap.get("PT"),newMap.get("CT"),phaseVal, sql, endList, InfluxDbSqlConstant.CP95, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap,noPhaseList);
}
});
});
}finally {
DynamicDataSourceContextHolder.poll();
}
}));
});
// 等待所有任务完成
for (Future<?> future : futures) {
try {
future.get(); // 这会阻塞直到任务完成或抛出异常
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
log.error("自定义报表多线程查询流程出错!错误信息{}",e.getMessage());
}
}
//处理指标最终判定合格还是不合格
dealTargetResult(assNoPassMap, limitTargetMapX, endList);
}
resultAssemble2(endList,reportSearchParam,newMap,deviceUnitCommDTO,jsonArray,dataMap);
//存储自定义报表
return saveReport(jsonArray,dataMap);
}
public void resultAssemble2(List<ReportTemplateDTO> endList, ReportSearchParam reportSearchParam, Map<String, String> finalTerminalMap, DeviceUnitCommDTO deviceUnitCommDTO, JSONArray jsonArray,Map<String, Object> dataMap) {
if (CollUtil.isNotEmpty(endList)) {
Map<String, String> unit = this.unitMap(deviceUnitCommDTO);
Map<String, List<ReportTemplateDTO>> assMap = (Map)endList.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getItemName));
jsonArray.forEach((item) -> {
JSONObject jsonObject = (JSONObject)item;
JSONArray itemArr = (JSONArray)jsonObject.get("celldata");
itemArr.forEach((it) -> {
if (Objects.nonNull(it) && !"null".equals(it.toString())) {
JSONObject data = (JSONObject)it;
JSONObject son = (JSONObject)data.get("v");
if (son.containsKey("v")) {
String v = son.getStr("v");
String tem;
List rDto;
if (v.charAt(0) == '$' && v.contains("#")) {
tem = "";
rDto = (List)assMap.get(v.replace("$", "").toUpperCase());
if (Objects.nonNull(rDto)) {
tem = ((ReportTemplateDTO)rDto.get(0)).getValue();
if (StringUtils.isBlank(tem)) {
tem = "/";
}
son.set("v", tem);
dataMap.put(v, tem);
if (Objects.nonNull(((ReportTemplateDTO)rDto.get(0)).getOverLimitFlag()) && ((ReportTemplateDTO)rDto.get(0)).getOverLimitFlag() == 1) {
son.set("fc", "#990000");
}
}
} else if (v.charAt(0) == '%' && v.contains("#")) {
tem = "";
rDto = (List)assMap.get(v.replace("%", "").toUpperCase());
if (Objects.nonNull(rDto)) {
tem = ((ReportTemplateDTO)rDto.get(0)).getValue();
if (StringUtils.isBlank(tem)) {
tem = "/";
}
son.set("v", tem);
dataMap.put(v, tem);
if ("不合格".equals(tem)) {
son.set("fc", "#990000");
dataMap.put("fc", "#990000");
}
}
} else if (v.charAt(0) == '&') {
tem = v.replace("&", "").toUpperCase();
if (finalTerminalMap.size() > 0) {
if ("STATIS_TIME".equals(tem)) {
String localTime = " 23:59:59";
LocalDate localDate = LocalDateTimeUtil.parseDate(reportSearchParam.getEndTime(), "yyyy-MM-dd");
LocalDate nowDate = LocalDate.now();
if (nowDate.isAfter(localDate)) {
son.set("v", reportSearchParam.getStartTime() + " 00:00:00" + "_" + reportSearchParam.getEndTime() + localTime);
dataMap.put(v, reportSearchParam.getStartTime() + " 00:00:00" + "_" + reportSearchParam.getEndTime() + localTime);
} else {
localTime = " " + LocalTime.now().format(DatePattern.NORM_TIME_FORMATTER);
son.set("v", reportSearchParam.getStartTime() + " 00:00:00" + "_" + nowDate + localTime);
dataMap.put(v, reportSearchParam.getStartTime() + " 00:00:00" + "_" + nowDate + localTime);
}
} else {
son.set("v", finalTerminalMap.getOrDefault(tem, "/"));
dataMap.put(v, finalTerminalMap.getOrDefault(tem, "/"));
}
}
}
if (v.charAt(0) == '@' && v.contains("#")) {
tem = v.replace("@", "");
son.set("v", unit.getOrDefault(tem, "/"));
dataMap.put(v, unit.getOrDefault(tem, "/"));
}
}
}
});
});
}
}
private String saveReport(JSONArray jsonArray, Map<String, Object> dataMap) {
String filePath = "";
Workbook workbook = new XSSFWorkbook();
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String sheetName = jsonObject.getStr("name");
JSONArray data = jsonObject.getJSONArray("data");
Sheet sheet = workbook.createSheet(sheetName);
if (data != null) {
for (int j = 0; j < data.size(); j++) {
Row row = sheet.createRow(j);
JSONArray rowData = data.getJSONArray(j);
if (rowData != null) {
for (int k = 0; k < rowData.size(); k++) {
Cell cell = row.createCell(k);
JSONObject cellObj = rowData.getJSONObject(k);
if (cellObj != null && !cellObj.isEmpty()) {
Object v = cellObj.get("v");
if (v != null) {
Object vData = dataMap.get(v);
if (vData != null) {
if (vData instanceof String) {
cell.setCellValue((String) vData);
} else if (vData instanceof Number) {
cell.setCellValue(((Number) vData).doubleValue());
} else if (vData instanceof Boolean) {
cell.setCellValue((Boolean) vData);
} else {
cell.setCellValue(vData.toString());
}
} else {
if (v instanceof String) {
cell.setCellValue((String) v);
} else if (v instanceof Number) {
cell.setCellValue(((Number) v).doubleValue());
} else if (v instanceof Boolean) {
cell.setCellValue((Boolean) v);
} else {
cell.setCellValue(v.toString());
}
}
}
}
}
}
}
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
workbook.write(baos);
workbook.close();
} catch (IOException e) {
throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
filePath = fileStorageUtil.uploadStream(bais, OssPath.APP_HARMONIC_REPORT, "稳态报表.xlsx");
try {
bais.close();
baos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return filePath;
}
/**
* 处理
*
* @author cdf