package com.whyc.service; import com.whyc.mapper.CommonMapper; import com.whyc.pojo.db_batt.PowerInf; import com.whyc.pojo.db_dis_batt.BattTestInf; import com.whyc.pojo.db_power_history.BattRealTimeDataHistory; import com.whyc.util.DateUtil; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xddf.usermodel.CompoundLine; import org.apache.poi.xddf.usermodel.XDDFLineProperties; import org.apache.poi.xddf.usermodel.XDDFShapeProperties; import org.apache.poi.xddf.usermodel.chart.*; import org.apache.poi.xssf.usermodel.*; import org.openxmlformats.schemas.drawingml.x2006.chart.*; import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; @Service public class ExcelService { @Autowired private PowerInfService powerInfService; @Autowired private BattTestInfService battTestInfService; @Autowired //private static BattRealTimeDataHistoryService battRTDataHisService; private BattRealTimeDataHistoryService battRTDataHisService; @Autowired private CommonMapper commonMapper; /** * 将电池组放电充电数据写入excel * 传入参数: * 电池组id,放电第几次 * * @throws IOException */ public void dcReport(int battGroupId,int testRecordCount) throws IOException { String filePath = "C:\\Users\\29550\\Desktop\\当前项目\\2023\\0乌东德系统\\测试.xlsx"; //创建一个工作簿 XSSFWorkbook workbook = new XSSFWorkbook(); //创建sheet1 createSheet1(workbook,battGroupId,testRecordCount); //创建sheet2 -- 每月电压,12个月,取每月1号零点零分 //创建sheet3 -- 每月内阻, 12个月,取每月1号零点零分 //createSheet2And3(workbook,battGroupId); //创建sheet4 -- 每天温度, 30天, 取每天零点零分 //createSheet4(workbook,battGroupId); // 将工作簿写入文件 FileOutputStream fileOut = new FileOutputStream(filePath); workbook.write(fileOut); // 关闭工作簿 workbook.close(); } private void createSheet2And3(XSSFWorkbook workbook, int battGroupId) { XSSFSheet sheet2 = workbook.createSheet("每月电压"); XSSFSheet sheet3 = workbook.createSheet("每月内阻"); //数据准备 PowerInf battInfo = powerInfService.getByBattGroupId(battGroupId); //创建第一行 XSSFCell cellOfSheet2 = sheet2.createRow(0).createCell(0); XSSFCell cellOfSheet3 = sheet3.createRow(0).createCell(0); cellOfSheet2.setCellValue( battInfo.getPowerName()+ battInfo.getBattGroupName()+"浮充电压"); cellOfSheet3.setCellValue( battInfo.getPowerName()+ battInfo.getBattGroupName()+"内阻数据"); int columnCount = 2; //查询历史实时表. 存在的月份. 如果存在的话,取第一笔记录(104条) //首先查询当前月份对应的日期 List tableListLike = commonMapper.getTableListLike("db_power_history", "tb_batt_realdata_"+battGroupId); //当前月份往前推11个月 List tableListInDB = new ArrayList<>(); Calendar calendar = Calendar.getInstance(); for (int i = 0; i < 12; i++) { int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; String monthStr; if (month < 10) { monthStr = "0" + month; } else { monthStr = String.valueOf(month); } if (tableListLike.contains("tb_batt_realdata_" + battGroupId + "_" + year + "_" + monthStr)) { //存在,列数+1 columnCount++; tableListInDB.add("tb_batt_realdata_" + battGroupId + "_" + year + "_" + monthStr); } calendar.add(Calendar.MONTH, -1); } //列根据实际情况变动 sheet2.addMergedRegion(new CellRangeAddress(0, 0, 0, columnCount-1)); sheet3.addMergedRegion(new CellRangeAddress(0, 0, 0, columnCount-1)); //列宽 for (int j = 0; j < columnCount; j++ ) { if(j==0){ sheet2.setColumnWidth(j, 170 * 20); sheet3.setColumnWidth(j, 170 * 20); }else { sheet2.setColumnWidth(j, 128 * 20); sheet3.setColumnWidth(j, 128 * 20); } } //行宽 sheet2.getRow(0).setHeightInPoints(40); sheet3.getRow(0).setHeightInPoints(40); //List元素升序排序 tableListInDB.sort(Comparator.comparing(String::toString)); //创建第二行 XSSFRow row1OfSheet2 = sheet2.createRow(1); XSSFRow row1OfSheet3 = sheet3.createRow(1); row1OfSheet2.createCell(0).setCellValue("蓄电池号(#)"); row1OfSheet3.createCell(0).setCellValue("蓄电池号(#)"); //总列数-1 for (int i = 0; i < columnCount - 1; i++) { if(i == columnCount-2){ row1OfSheet2.createCell(i+1).setCellValue("备注"); row1OfSheet3.createCell(i+1).setCellValue("备注"); }else { row1OfSheet2.createCell(i + 1).setCellValue("记录" + (i + 1)); row1OfSheet3.createCell(i + 1).setCellValue("记录" + (i + 1)); } } //填充数据 for (int i = 1; i <= 109; i++) { if(i<=104) { sheet2.createRow(i + 2).createCell(0).setCellValue(i + "#"); sheet3.createRow(i + 2).createCell(0).setCellValue(i + "#"); }else{ if(i == 105){ sheet2.createRow(i + 2).createCell(0).setCellValue("单节平均电压"); sheet3.createRow(i + 2).createCell(0).setCellValue("单节平均内阻"); }else if (i == 106){ sheet2.createRow(i + 2).createCell(0).setCellValue("单节最大电压"); sheet3.createRow(i + 2).createCell(0).setCellValue("单节最大内阻"); } else if (i == 107) { sheet2.createRow(i + 2).createCell(0).setCellValue("单节最小电压"); sheet3.createRow(i + 2).createCell(0).setCellValue("单节最小内阻"); }else if (i == 108) { sheet2.createRow(i + 2).createCell(0).setCellValue("单节最大差值"); sheet3.createRow(i + 2).createCell(0).setCellValue("单节最大内阻差值"); }else { sheet2.createRow(i + 2).createCell(0).setCellValue("均压系数"); } } } //创建第三行 XSSFRow row2OfSheet2 = sheet2.createRow(2); XSSFRow row2OfSheet3 = sheet3.createRow(2); sheet2.getRow(0).createCell(columnCount-1); sheet3.getRow(0).createCell(columnCount-1); for (int i = 0; i <= tableListInDB.size(); i++) { //这个是列的遍历 if (i == tableListInDB.size()) { //最后一列备注:全部填空 row2OfSheet2.createCell(i + 1); row2OfSheet3.createCell(i + 1); for (int j = 1; j <= 108; j++) { //这个是行的遍历 sheet2.getRow(j + 2).createCell(i + 1); sheet3.getRow(j + 2).createCell(i + 1); } sheet2.getRow(108 + 2 + 1).createCell(i + 1); } else { //获取数据 List list = battRTDataHisService.getFirstRecordList(tableListInDB.get(i)); list.sort(Comparator.comparing(BattRealTimeDataHistory::getMonNum)); //第三行的时间列填充 Date testStartTime = list.get(0).getTestStartTime(); //获取年月 String testMonth = DateUtil.YYYY_DOT_MM.format(testStartTime); row2OfSheet2.createCell(i + 1).setCellValue(testMonth); row2OfSheet3.createCell(i + 1).setCellValue(testMonth); addStatistics(list, "vol", "res"); for (int j = 1; j <= 108; j++) { //这个是行的遍历 sheet2.getRow(j + 2).createCell(i + 1).setCellValue((list.get(j - 1).getMonVol())); sheet3.getRow(j + 2).createCell(i + 1).setCellValue((list.get(j - 1).getMonRes())); } Float volAvg = list.get(104).getMonVol(); Float volMax = list.get(105).getMonVol(); sheet2.getRow(108 + 2 + 1).createCell(i + 1).setCellValue(new BigDecimal(volAvg).divide(new BigDecimal(volMax), 4, RoundingMode.HALF_UP).floatValue()); } } addGlobalStylesToAllCells(sheet2, workbook); addGlobalStylesToAllCells(sheet3, workbook); //设置sheet2和sheet3的标题样式 XSSFCellStyle cellStyleOriginal = cellOfSheet2.getCellStyle(); XSSFCellStyle cellStyleNew = getCellStyleFont(cellStyleOriginal,workbook, true, 15); cellOfSheet2.setCellStyle(cellStyleNew); XSSFCellStyle cellStyleOriginal2 = cellOfSheet3.getCellStyle(); XSSFCellStyle cellStyleNew2 = getCellStyleFont(cellStyleOriginal2,workbook, true, 15); cellOfSheet3.setCellStyle(cellStyleNew2); // 创建绘图工具 createChart(sheet2, columnCount,3,"电压折线图"); createChart(sheet3, columnCount,3,"内阻折线图"); } private void createChart(XSSFSheet sheet2, int columnCount,int rowStartIndex, String titleTextSuffix) { XSSFDrawing drawing = sheet2.createDrawingPatriarch(); //108个单体,10个单体一个图标 int chartCol = 1; for (int i = 0; i < 104; i += 10) { //XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 15, chartCol, 25, chartCol+12); XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, columnCount+1, chartCol, columnCount+11, chartCol+12); //图表间每十二列一个间隔 chartCol += 12; String titleText; if(i == 100){ titleText = "101~104#蓄电池"+titleTextSuffix; }else{ titleText = (i+1)+"~"+(i+10)+"#蓄电池"+titleTextSuffix; } // 创建图表 XSSFChart chart = drawing.createChart(anchor); //chart.setTitleText(titleText); CTChart ctChart = chart.getCTChart(); CTTitle title = ctChart.getTitle(); if (title == null) { title = ctChart.addNewTitle(); } // 创建文本体(如果不存在) CTTx tx = title.addNewTx(); CTTextBody txBody = tx.isSetStrRef() ? null : tx.addNewRich(); if (txBody == null) { txBody = tx.getRich(); } // 清空已有段落 txBody.setPArray(new CTTextParagraph[0]); // 添加新的段落和文本运行 CTTextParagraph p = txBody.addNewP(); CTRegularTextRun r = p.addNewR(); r.setT(titleText); // 设置字体大小(14pt -> 1400) CTTextCharacterProperties rPr = r.addNewRPr(); rPr.setSz(900); // 字号:14pt // 设置坐标轴 XDDFCategoryAxis categoryAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); //categoryAxis.setTitle("电池编号"); CTCatAx ctCatAx = getCTCatAx(categoryAxis, chart); if(ctCatAx.isSetTitle()){ ctCatAx.unsetTitle(); } XDDFValueAxis valueAxis = chart.createValueAxis(AxisPosition.LEFT); valueAxis.setCrosses(AxisCrosses.AUTO_ZERO); CTValAx ctValAx = getCTValAx(valueAxis, chart); if(ctValAx.isSetTitle()){ ctValAx.unsetTitle(); } //增加 网格线和图例 XDDFShapeProperties gridProperties = valueAxis.getOrAddMajorGridProperties(); XDDFLineProperties lineProperties = new XDDFLineProperties(); lineProperties.setCompoundLine(CompoundLine.SINGLE); lineProperties.setWidth(0.5); gridProperties.setLineProperties(lineProperties); chart.getOrAddLegend().setPosition(LegendPosition.TOP_RIGHT); chart.setTitleOverlay(true); // X轴数据源-记录编号 //XDDFDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet2, new CellRangeAddress(2, 2, 1, 12)); XDDFDataSource xs = XDDFDataSourcesFactory.fromStringCellRange(sheet2, new CellRangeAddress(2, 2, 1, columnCount-2)); // 每个电池单体作为一个系列,对应一条折线 // 创建折线图系列 XDDFLineChartData dataChart = (XDDFLineChartData) chart.createData(ChartTypes.LINE, categoryAxis, valueAxis); for (int j = i ; j < i+10; j++) { if(j<104) { XDDFNumericalDataSource ys = XDDFDataSourcesFactory.fromNumericCellRange(sheet2, new CellRangeAddress(j + rowStartIndex, j + rowStartIndex, 1, columnCount -2)); XDDFLineChartData.Series series = (XDDFLineChartData.Series) dataChart.addSeries(xs, ys); //选择布局1 series.setTitle(((XSSFRow) sheet2.getRow(j + 6)).getCell(0).getStringCellValue(), new CellReference(sheet2.getSheetName(), j + rowStartIndex, 0, true, true)); series.setMarkerStyle(MarkerStyle.CIRCLE); // 设置标记点 } } // 将数据填充到图表中 chart.plot(dataChart); } } private void createSheet4(XSSFWorkbook workbook, int battGroupId) { XSSFSheet sheet4 = workbook.createSheet("每天温度"); //数据准备 PowerInf battInfo = powerInfService.getByBattGroupId(battGroupId); //创建第一行 XSSFCell cellOfSheet4 = sheet4.createRow(0).createCell(0); cellOfSheet4.setCellValue( battInfo.getPowerName()+ battInfo.getBattGroupName()+"温度数据"); //30天+2列其他列 int columnCount = 30+2; //查询历史实时表. 存在的月份. 如果存在的话,取第一笔记录(104条) //首先查询当前月份对应的日期 List tableListLike = commonMapper.getTableListLike("db_power_history", "tb_batt_realdata_"+battGroupId); //获取当前日期往前30天的凌晨零秒的数据. 往前推30天 List tableListInDB = new ArrayList<>(); Calendar calendar = Calendar.getInstance(); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; String monthStr; if (month < 10) { monthStr = "0" + month; } else { monthStr = String.valueOf(month); } //当前时间往前30天 calendar.add(Calendar.DAY_OF_MONTH, -30); Date timeAgo = calendar.getTime(); int yearAgo = calendar.get(Calendar.YEAR); int monthAgo = calendar.get(Calendar.MONTH) + 1; String monthAgoStr; if (monthAgo < 10) { monthAgoStr = "0" + (monthAgo); } else { monthAgoStr = String.valueOf(monthAgo); } String tableName = "tb_batt_realdata_" + battGroupId + "_" + year + "_" + monthStr; //30天前的时间 String tableNameAgo = "tb_batt_realdata_" + battGroupId + "_" + yearAgo + "_" + monthAgoStr; if (tableListLike.contains(tableName)) { tableListInDB.add(tableName); } if (tableListLike.contains(tableNameAgo)) { tableListInDB.add(tableNameAgo); } //获取所有数据 List dataList = new ArrayList<>(); for (int i = 0; i < tableListInDB.size(); i++) { String tableNameTmp = tableListInDB.get(i); List list; if(tableNameTmp.equals(tableName)){ list = battRTDataHisService.getFirstRecordListOfDay(tableNameTmp, null); }else{ //说明是上个月的记录,需要记录时间大于30天前的时间 list = battRTDataHisService.getFirstRecordListOfDay(tableNameTmp, timeAgo); } dataList.addAll(list); } //按时间排序和分组 dataList.sort(Comparator.comparing(BattRealTimeDataHistory::getRecordTime)); Map> dataListMap = dataList.stream().collect(Collectors.groupingBy(BattRealTimeDataHistory::getRecordTime)); Set dateKeySet = dataListMap.keySet(); dataListMap.forEach((key,data)->{ addStatistics(data, "tmp"); }); //给列数赋值 columnCount = dateKeySet.size()+2; //列根据实际情况变动 sheet4.addMergedRegion(new CellRangeAddress(0, 0, 0, columnCount-1)); //列宽 for (int j = 0; j < columnCount; j++ ) { if(j==0){ sheet4.setColumnWidth(j, 170 * 20); }else { sheet4.setColumnWidth(j, 138 * 20); } } //行宽 sheet4.getRow(0).setHeightInPoints(40); //List元素升序排序 tableListInDB.sort(Comparator.comparing(String::toString)); //创建第二行 XSSFRow row1OfSheet4 = sheet4.createRow(1); row1OfSheet4.createCell(0).setCellValue("蓄电池号(#)"); //总列数-1 for (int i = 0; i < columnCount - 1; i++) { if(i == columnCount-2){ row1OfSheet4.createCell(i+1).setCellValue("备注"); }else { row1OfSheet4.createCell(i + 1).setCellValue("记录" + (i + 1)); } } //填充数据 for (int i = 1; i <= 109; i++) { if(i<=104) { sheet4.createRow(i + 2).createCell(0).setCellValue(i + "#"); }else{ if(i == 105){ sheet4.createRow(i + 2).createCell(0).setCellValue("单节平均温度"); }else if (i == 106){ sheet4.createRow(i + 2).createCell(0).setCellValue("单节最大温度"); } else if (i == 107) { sheet4.createRow(i + 2).createCell(0).setCellValue("单节最小温度"); }else if (i == 108) { sheet4.createRow(i + 2).createCell(0).setCellValue("单节最大差值"); } } } //创建第三行 XSSFRow row2OfSheet4 = sheet4.createRow(2); row2OfSheet4.setHeightInPoints(40); sheet4.getRow(0).createCell(columnCount-1); //填充数据列,key是列日期. value是列数据 AtomicInteger count = new AtomicInteger(); //对dateKeySet按时间排序 Stream dateKeySetSorted = dateKeySet.stream().sorted(Comparator.comparing(Date::getTime)); dateKeySetSorted.forEach(key -> { List value = dataListMap.get(key); //第三行时间列填充 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd\nHH:mm:ss"); row2OfSheet4.createCell(count.get() + 1).setCellValue(format.format(key)); for (int j = 1; j <= 108; j++) { //这个是行的遍历 sheet4.getRow(j + 2).createCell(count.get() + 1).setCellValue(value.get(j - 1).getMonTmp()); } count.getAndIncrement(); }); //最后一列备注:全部填空 row2OfSheet4.createCell(columnCount-1); for (int j = 1; j <= 108; j++) { //这个是行的遍历 sheet4.getRow(j + 2).createCell(columnCount-1); } addGlobalStylesToAllCells(sheet4, workbook); //设置sheet4和sheet3的标题样式 XSSFCellStyle cellStyleOriginal = cellOfSheet4.getCellStyle(); XSSFCellStyle cellStyleNew = getCellStyleFont(cellStyleOriginal,workbook, true, 15); cellOfSheet4.setCellStyle(cellStyleNew); //第三行 所有列水平垂直居中,自动换行 for (int i = 1; i < columnCount; i++) { XSSFCell cell = sheet4.getRow(2).getCell(i); XSSFCellStyle cellStyle = cell.getCellStyle(); cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); cellStyle.setWrapText(true); cell.setCellStyle(cellStyle); } createChart(sheet4, columnCount,3,"温度折线图"); } public CTValAx getCTValAx(XDDFValueAxis valueAxis, XSSFChart chart) { // 使用反射获取私有字段 try { java.lang.reflect.Field field = valueAxis.getClass().getDeclaredField("ctValAx"); field.setAccessible(true); return (CTValAx) field.get(valueAxis); } catch (Exception e) { throw new RuntimeException("无法获取 CTValAx 实例", e); } } public CTCatAx getCTCatAx(XDDFCategoryAxis categoryAxis, XSSFChart chart) { // 使用反射获取私有字段 try { java.lang.reflect.Field field = categoryAxis.getClass().getDeclaredField("ctCatAx"); field.setAccessible(true); return (CTCatAx) field.get(categoryAxis); } catch (Exception e) { throw new RuntimeException("无法获取 CTCatAx 实例", e); } } public static void main(String[] args) throws IOException { //dcReport(1,1); } //private static void createSheet1(XSSFWorkbook workbook, int battGroupId, int testRecordCount) { private void createSheet1(XSSFWorkbook workbook, int battGroupId, int testRecordCount) { XSSFSheet sheet = workbook.createSheet("放电充电电压数据报表"); //总的列数根据 放电时长和充电时长决定 //数据准备 PowerInf battInfo = powerInfService.getByBattGroupId(battGroupId); //TODO 测试数据 //PowerInf battInfo = new PowerInf(); //battInfo.setPowerName("测试直流系统"); //battInfo.setBattGroupName("蓄电池组1"); BattTestInf battTestInf = battTestInfService.getDischargeRecord(battGroupId,testRecordCount); //TODO 测试数据 //BattTestInf battTestInf = new BattTestInf(); //battTestInf.setTestTimelong(36000); //battTestInf.setTestStarttime(new Date()); //单位是秒,转化为分钟 Integer testTimeLong = battTestInf.getTestTimelong(); Integer testTimeMinutes = testTimeLong /60; //testTimeLong转为小时.保留1位小数,取小进行切割 Float testTimeHours = BigDecimal.valueOf(testTimeLong).divide(BigDecimal.valueOf(60 * 60), 1, RoundingMode.FLOOR).floatValue(); //获取放电开始时间和终止时间 Date dischargeStartTime = battTestInf.getTestStarttime(); //终止时间为开始时间加 测试时长 Calendar dischargeEndTime = Calendar.getInstance(); dischargeEndTime.setTime(dischargeStartTime); dischargeEndTime.add(Calendar.SECOND, testTimeLong); //放电结束后的充电终止记录 //BattRealTimeDataHistory hisChargeEnd = battRTDataHisService.getChargeEnd(battGroupId,dischargeEndTime); //TODO 测试数据 //BattRealTimeDataHistory hisChargeEnd = new BattRealTimeDataHistory(); //Calendar chargeEndTime = Calendar.getInstance(); //chargeEndTime.setTime(new Date()); //chargeEndTime.add(Calendar.HOUR,15); //hisChargeEnd.setRecordTime(chargeEndTime.getTime()); //充电时长=充电终止时间-放电终止时间 long chargeTimeSeconds = (dischargeEndTime.getTime().getTime() - dischargeStartTime.getTime()) / 1000; //long chargeTimeSeconds = (hisChargeEnd.getRecordTime().getTime() - dischargeStartTime.getTime()) / 1000; //chargeTimeSeconds转为小时.保留1位小数,取小进行切割 Float chargeTimeHours = BigDecimal.valueOf(chargeTimeSeconds).divide(BigDecimal.valueOf(60 * 60), 1, RoundingMode.FLOOR).floatValue(); //行数是固定的.总列数是根据放电时长和充电时长决定的 //放电时长导致的列数计算,列为0.5h,1h,2h,3h,...; //小于0.5h,没列. 0.5h~1h之间,1列-0.5h. 大于1h,1+ 放电时长的列数. int dischargeColumnCount; if (testTimeHours < 0.5) { dischargeColumnCount = 0; } else if (testTimeHours >= 0.5 && testTimeHours < 1) { //0.5h 占两列 dischargeColumnCount = 2; } else if (testTimeHours >= 1 && testTimeHours < 2) { //0.5h 占两列,1h 占两列 dischargeColumnCount = 4; } else { dischargeColumnCount = (int) (testTimeHours + 3); } //充电时长导致的列数计算,列为0.5h,1h,2h,3h,...; int chargeColumnCount; if (chargeTimeHours < 0.5) { chargeColumnCount = 0; } else if (chargeTimeHours >= 0.5 && chargeTimeHours < 1) { chargeColumnCount = 1; } else { chargeColumnCount = (int) (chargeTimeHours + 1); } //列数的计算= 蓄电池号(1行)+浮充电压值(2行)+放电前开路电压(2行)+放电特定时间电压(dischargeColumnCount行)+放电结束0.5h开路电压值(1行)+充电特定时间电压(chargeColumnCount行)+满电开路电压值(1行)+备注(1行) int columnCount = 1 + 2 + 2 + dischargeColumnCount + 1 + chargeColumnCount + 1 + 1; //XSSFCellStyle cellStyleFontBold = getCellStyleFont(cellStyleOriginal, workbook,true,20); //创建第一行是标题行 XSSFCell cellRow1 = sheet.createRow(0).createCell(0); //setRowStyle(sheet.getRow(0),cellStyleFontBold); cellRow1.setCellValue(battInfo.getPowerName()+battInfo.getBattGroupName()+"核对性放电、充电试验记录表"); //合并行列,占据的列是columnCount列合并为1列并居中 CellRangeAddress region = new CellRangeAddress(0, 0, 0, columnCount-1); sheet.addMergedRegion(region); //TODO 第二行的合并列是根据变动的,后续调整 CellRangeAddress region21 = new CellRangeAddress(1, 1, 0, 1); sheet.addMergedRegion(region21); CellRangeAddress region22 = new CellRangeAddress(1, 1, 3, 9); sheet.addMergedRegion(region22); CellRangeAddress region23 = new CellRangeAddress(1, 1, 10, 13); sheet.addMergedRegion(region23); CellRangeAddress region24 = new CellRangeAddress(1, 1, 14, 17); sheet.addMergedRegion(region24); CellRangeAddress region25 = new CellRangeAddress(1, 1, 18, 24); sheet.addMergedRegion(region25); //第三行的合并列,前两个单元模块是固定的,其中1个合并单元 CellRangeAddress region31 = new CellRangeAddress(2, 2, 2, 3); sheet.addMergedRegion(region31); // 创建居中样式 CellStyle style = workbook.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); // 应用样式到单元格 cellRow1.setCellStyle(style); //第二行是放电基本信息 XSSFRow row1 = sheet.createRow(1); XSSFCell cell1Row2 = row1.createCell(0); cell1Row2.setCellValue("蓄电池组号:" + battInfo.getBattGroupName()); XSSFCell cell2Row2 = row1.createCell(2); cell2Row2.setCellValue(""); XSSFCell cell3Row2 = row1.createCell(3); cell3Row2.setCellValue("工作票号:2273925\n" + "工作负责人:马云燕\n" + "工作成员:周素文、李志标、王月灿等"); XSSFCell cell4Row2 = row1.createCell(10); cell4Row2.setCellValue("放电日期:2021.10.30\n" + "放电开始时间:10:00\n" + "放电结束时间:19:47"); XSSFCell cell5Row2 = row1.createCell(14); cell5Row2.setCellValue("放电电流(A):35\n" + "放电时长(时.分):600min\n" + "放电容量(Ah):300"); XSSFCell cell6Row2 = row1.createCell(18); cell6Row2.setCellValue("环境温度(℃):24.5\n" + "环境湿度(%):46.7"); //第二行设置加粗 //setRowStyle(sheet.getRow(1),cellStyleFontBold); //第三行是电池号和电压等相关抬头 //第四行是电压列和温度列标识 XSSFRow row2 = sheet.createRow(2); XSSFRow row3 = sheet.createRow(3); row2.createCell(0).setCellValue("蓄电池号(#)"); row2.createCell(1).setCellValue("蓄电池浮充电压值(V)"); row2.createCell(2).setCellValue("放电前蓄电池开路电压值(V)"); row3.createCell(0).setCellValue("项目"); row3.createCell(1).setCellValue("-1(电压)"); row3.createCell(2).setCellValue("0(电压)"); row3.createCell(3).setCellValue("0(温度)"); //放电特定电压值 int columnIndex = 3; if(dischargeColumnCount > 0){ row2.createCell(5).setCellValue("放电0.5h蓄电池电压值(V)"); CellRangeAddress region33 = new CellRangeAddress(2, 2, 4, 5); sheet.addMergedRegion(region33); row3.createCell(4).setCellValue("0.5(电压)"); row3.createCell(5).setCellValue("0.5(温度)"); columnIndex+=2; if(dischargeColumnCount > 2){ //合并单元格了,所以索引+2 row2.createCell(7).setCellValue("放电1h蓄电池电压值(V)"); CellRangeAddress region34 = new CellRangeAddress(2, 2, 6, 7); sheet.addMergedRegion(region34); row3.createCell(6).setCellValue("1(电压)"); row3.createCell(7).setCellValue("1(温度)"); columnIndex+=2; if(dischargeColumnCount > 4){ columnIndex++; //放电nh蓄电池电压值(V),n从2开始 for(int i = 4;i < dischargeColumnCount;i++){ row2.createCell(i+5).setCellValue("放电" + (i-2) + "h蓄电池电压值(V)"); row3.createCell(i+5).setCellValue(String.valueOf(i-2)); columnIndex++; } } } } //充电特定电压值 row2.createCell(++columnIndex).setCellValue("放电结束0.5h后蓄电池开路电压值(V)"); row3.createCell(columnIndex).setCellValue("10.5"); if(chargeColumnCount > 0){ columnIndex++; row2.createCell(columnIndex).setCellValue("充电0.5h"); if(chargeColumnCount > 1){ //充电nh,n从1开始 for(int i = 1;i < chargeColumnCount;i++){ columnIndex++; row2.createCell(columnIndex).setCellValue("充电" + (i) + "h蓄电池电压值(V)"); row3.createCell(columnIndex);//填充单元格的作用 } } } row2.createCell(++columnIndex).setCellValue("充满后蓄电池电压值(V)(电流为0)"); row3.createCell(columnIndex).setCellValue("11"); row2.createCell(++columnIndex).setCellValue("备注"); row3.createCell(columnIndex);//填充单元格的作用 //从rowIndex=6开始 int rowIndex = 6; // 共104节单体,104行. 进行遍历,填充 //蓄电池浮充电压值列表 List fcVolList = new ArrayList<>(); fcVolList = battRTDataHisService.getFcVolList(battGroupId,dischargeStartTime); //按单体编号排序,按编号升序 fcVolList.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); //放点前蓄电池开路电压值 List preVolList = new ArrayList<>(); preVolList = battRTDataHisService.getPreVolList(battGroupId,dischargeStartTime); addStatistics(fcVolList,"vol"); addStatistics(preVolList,"vol","tmp"); //放电结束0.5h后蓄电池开路电压值 Calendar dischargeEndCalendar = Calendar.getInstance(); dischargeEndCalendar.setTime(dischargeEndTime.getTime()); dischargeEndCalendar.add(Calendar.MINUTE,30); List dischargeSetVolListOne = battRTDataHisService.getRecordList(battGroupId, dischargeEndCalendar.getTime()); dischargeSetVolListOne.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(dischargeSetVolListOne,"vol","tmp"); //定位到充电开始时间,状态变为充电的记录时间 Date chargeStartTime = battRTDataHisService.getChargeStartTime(battGroupId, dischargeEndTime.getTime()); //充满后蓄电池的电压 Calendar chargeCalendar = Calendar.getInstance(); chargeCalendar.setTime(chargeStartTime); List fcVolListAfter = battRTDataHisService.getFcVolListAfter(battGroupId, chargeCalendar.getTime()); fcVolListAfter.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(fcVolListAfter,"vol","tmp"); //一共104节单体,再加上统计数据4列,一共108 for(int j = 0; j < 108; j++){ XSSFRow rowTemp = sheet.createRow(rowIndex++); if(j<104) { rowTemp.createCell(0).setCellValue((j + 1) + "#"); }else{ if(j == 104){ rowTemp.createCell(0).setCellValue("单节平均电压"); }else if (j == 105){ rowTemp.createCell(0).setCellValue("单节最大电压"); }else if (j == 106){ rowTemp.createCell(0).setCellValue("单节最小电压"); }else{ rowTemp.createCell(0).setCellValue("单节最大差值"); } } //rowTemp.createCell(1).setCellValue("蓄电池浮充电压值(V):"+(j+1)+"#"); //rowTemp.createCell(2).setCellValue("蓄电池浮充温度值:"+(j+1)+"#"); //rowTemp.createCell(3).setCellValue("放电前蓄电池开路电压值(V):"+(j+1)+"#"); //rowTemp.createCell(4).setCellValue("放电前蓄电池开路温度值:"+(j+1)+"#"); rowTemp.createCell(1).setCellValue(fcVolList.get(j).getMonVol()); rowTemp.createCell(2).setCellValue(preVolList.get(j).getMonVol()); rowTemp.createCell(3).setCellValue(preVolList.get(j).getMonTmp()); //放电特定电压值 int columnIndexTemp = 3; Calendar dischargeCalendar = Calendar.getInstance(); dischargeCalendar.setTime(dischargeStartTime); if(dischargeColumnCount > 0){ //时间在测试开始时间+0.5h dischargeCalendar.add(Calendar.MINUTE,30); Date recordTime = dischargeCalendar.getTime(); List dischargeListOne = battRTDataHisService.getRecordList(battGroupId,recordTime); //按单体编号排序,按编号升序 dischargeListOne.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(dischargeListOne,"vol"); //rowTemp.createCell(5).setCellValue("放电0.5h电压值(V):"+(j+1)+"#"); //rowTemp.createCell(6).setCellValue("放电0.5h温度值:"+(j+1)+"#"); rowTemp.createCell(4).setCellValue(dischargeListOne.get(j).getMonVol()); rowTemp.createCell(5).setCellValue(dischargeListOne.get(j).getMonTmp()); columnIndexTemp+=2; if(dischargeColumnCount > 2){ //合并单元格了,所以索引+2 //时间在测试开始时间+1h dischargeCalendar.setTime(dischargeStartTime); dischargeCalendar.add(Calendar.HOUR,1); Date recordTimeTwo = dischargeCalendar.getTime(); List dischargeListTwo = battRTDataHisService.getRecordList(battGroupId,recordTimeTwo); dischargeListTwo.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(dischargeListTwo,"vol"); //rowTemp.createCell(7).setCellValue("放电1h电压值(V):"+(j+1)+"#"); //rowTemp.createCell(8).setCellValue("放电1h温度值:"+(j+1)+"#"); rowTemp.createCell(6).setCellValue(dischargeListTwo.get(j).getMonVol()); rowTemp.createCell(7).setCellValue(dischargeListTwo.get(j).getMonTmp()); columnIndexTemp+=2; if(dischargeColumnCount > 4){ columnIndexTemp++; //放电nh蓄电池电压值(V),n从2开始 for(int i = 4;i < dischargeColumnCount;i++){ int dischargeHour = i-2; //时间在测试开始时间+nh dischargeCalendar.setTime(dischargeStartTime); dischargeCalendar.add(Calendar.HOUR,dischargeHour); Date recordTimeN = dischargeCalendar.getTime(); List dischargeListN = battRTDataHisService.getRecordList(battGroupId,recordTimeN); dischargeListN.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(dischargeListN,"vol"); //rowTemp.createCell(i+5).setCellValue("放电" + dischargeHour + "h蓄电池电压值(V)"); rowTemp.createCell(i+5).setCellValue(dischargeListN.get(j).getMonVol()); columnIndexTemp++; } } } } //填充放电0.5h后开路电压值 rowTemp.createCell(++columnIndexTemp).setCellValue(dischargeSetVolListOne.get(j).getMonVol()); if(chargeColumnCount > 0){ chargeCalendar = Calendar.getInstance(); chargeCalendar.setTime(chargeStartTime); chargeCalendar.add(Calendar.MINUTE,30); List chargeVolListOne = battRTDataHisService.getRecordList(battGroupId, chargeCalendar.getTime()); chargeVolListOne.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(chargeVolListOne,"vol"); columnIndexTemp++; //rowTemp.createCell(columnIndexTemp).setCellValue("充电0.5h"); rowTemp.createCell(columnIndexTemp).setCellValue(chargeVolListOne.get(j).getMonVol()); if(chargeColumnCount > 1){ //充电nh,n从1开始 for(int i = 1;i < chargeColumnCount;i++){ columnIndexTemp++; chargeCalendar.setTime(chargeStartTime); chargeCalendar.add(Calendar.HOUR,i); List chargeVolListN = battRTDataHisService.getRecordList(battGroupId, chargeCalendar.getTime()); chargeVolListN.sort(Comparator.comparingInt(BattRealTimeDataHistory::getMonNum)); addStatistics(chargeVolListN,"vol"); //rowTemp.createCell(columnIndexTemp).setCellValue("充电" + (i) + "h蓄电池电压值(V)"); rowTemp.createCell(columnIndexTemp).setCellValue(chargeVolListN.get(j).getMonVol()); } } } //填充充满后蓄电池电压 //rowTemp.createCell(++columnIndexTemp).setCellValue("充满后蓄电池电压值(V)(电流为0)"); if (fcVolListAfter.size() > 0){ rowTemp.createCell(++columnIndexTemp).setCellValue(fcVolListAfter.get(j).getMonVol()); }else { rowTemp.createCell(++columnIndexTemp).setCellValue("-"); } rowTemp.createCell(++columnIndexTemp).setCellValue("-"); } //=====================格式设置=====================// //设置列宽 for (int i = 0; i < columnCount; i++) { sheet.setColumnWidth(i, 256 * 20); } //对整个表格进行全局设置,暂为设置边框 addGlobalStylesToAllCells(sheet, workbook); //创建第一行是标题行 setRowStyle(workbook,sheet.getRow(0),true,15); //第二行设置加粗 setRowStyle(workbook,sheet.getRow(1),true,15); //生成图表 createChart(sheet, columnCount, 6,""); } private XSSFCellStyle getCellStyleFont(XSSFCellStyle cellStyleOriginal, XSSFWorkbook workbook, boolean isFontBold, int fontSize) { //字体加粗样式 Font font = workbook.createFont(); font.setFontHeightInPoints((short) (fontSize)); font.setBold(isFontBold); XSSFCellStyle cellStyle = workbook.createCellStyle(); cellStyle.cloneStyleFrom(cellStyleOriginal); cellStyle.setFont(font); cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); return cellStyle; } //对传入的BattRealTimeDataHistory列表进行统计,将统计结果也追加到列表中. 统计的为电压 public void addStatistics(List battRealTimeDataHistoryList,String... fields) { List fieldList = Arrays.asList(fields); if(battRealTimeDataHistoryList != null && battRealTimeDataHistoryList.size() > 0){ BattRealTimeDataHistory hisAvg = new BattRealTimeDataHistory(); BattRealTimeDataHistory hisMax = new BattRealTimeDataHistory(); BattRealTimeDataHistory hisMin = new BattRealTimeDataHistory(); BattRealTimeDataHistory hisGap = new BattRealTimeDataHistory(); if(fieldList.contains("vol")) { //电压平均值,最大值,最小值,最大差值 List volList = battRealTimeDataHistoryList.stream().map(BattRealTimeDataHistory::getMonVol).collect(Collectors.toList()); Double volAvgDouble = volList.stream().collect(Collectors.averagingDouble(Float::floatValue)); BigDecimal avg = new BigDecimal(volAvgDouble).setScale(4, RoundingMode.HALF_UP); float volAvg = avg.floatValue(); //最大值 float volMax = volList.stream().max(Float::compareTo).get(); BigDecimal max = new BigDecimal(volMax).setScale(4, RoundingMode.HALF_UP); volMax = max.floatValue(); //最小值 float volMin = volList.stream().min(Float::compareTo).get(); BigDecimal min = new BigDecimal(volMin).setScale(4, RoundingMode.HALF_UP); volMin = min.floatValue(); //最大差值 float volGap = volMax - volMin; hisAvg.setMonVol(volAvg); hisMax.setMonVol(volMax); hisMin.setMonVol(volMin); hisGap.setMonVol(volGap); } if(fieldList.contains("res")) { //平均值,最大值,最小值,最大差值 List resList = battRealTimeDataHistoryList.stream().map(BattRealTimeDataHistory::getMonRes).collect(Collectors.toList()); Double resAvgDouble = resList.stream().collect(Collectors.averagingDouble(Float::floatValue)); BigDecimal avg = new BigDecimal(resAvgDouble).setScale(4, RoundingMode.HALF_UP); float resAvg = avg.floatValue(); //最大值 float resMax = resList.stream().max(Float::compareTo).get(); BigDecimal max = new BigDecimal(resMax).setScale(4, RoundingMode.HALF_UP); resMax = max.floatValue(); //最小值 float resMin = resList.stream().min(Float::compareTo).get(); BigDecimal min = new BigDecimal(resMin).setScale(4, RoundingMode.HALF_UP); resMin = min.floatValue(); //最大差值 float resGap = resMax - resMin; hisAvg.setMonRes(resAvg); hisMax.setMonRes(resMax); hisMin.setMonRes(resMin); hisGap.setMonRes(resGap); } if(fieldList.contains("tmp")) { //平均值,最大值,最小值,最大差值 List tmpList = battRealTimeDataHistoryList.stream().map(BattRealTimeDataHistory::getMonTmp).collect(Collectors.toList()); Double tmpAvgDouble = tmpList.stream().collect(Collectors.averagingDouble(Float::floatValue)); BigDecimal avg = new BigDecimal(tmpAvgDouble).setScale(4, RoundingMode.HALF_UP); float tmpAvg = avg.floatValue(); //最大值 float tmpMax = tmpList.stream().max(Float::compareTo).get(); BigDecimal max = new BigDecimal(tmpMax).setScale(4, RoundingMode.HALF_UP); tmpMax = max.floatValue(); //最小值 float tmpMin = tmpList.stream().min(Float::compareTo).get(); BigDecimal min = new BigDecimal(tmpMin).setScale(4, RoundingMode.HALF_UP); tmpMin = min.floatValue(); //最大差值 float tmpGap = tmpMax - tmpMin; Date now = new Date(); hisAvg.setMonTmp(tmpAvg); hisAvg.setRecordTime(now); hisMax.setMonTmp(tmpMax); hisMax.setRecordTime(now); hisMin.setMonTmp(tmpMin); hisMin.setRecordTime(now); hisGap.setMonTmp(tmpGap); hisGap.setRecordTime(now); } battRealTimeDataHistoryList.add(hisAvg); battRealTimeDataHistoryList.add(hisMax); battRealTimeDataHistoryList.add(hisMin); battRealTimeDataHistoryList.add(hisGap); } } public void setRowStyle(Workbook workbook,Row row,boolean isFontBold,int fontSize) { for (Cell cell : row) { //先克隆原来的属性 CellStyle cellStyleNew = workbook.createCellStyle(); cellStyleNew.cloneStyleFrom(cell.getCellStyle()); //设置字体和加粗 Font font = workbook.createFont(); font.setFontHeightInPoints((short) (fontSize)); font.setBold(isFontBold); cellStyleNew.setFont(font); cell.setCellStyle(cellStyleNew); } } /** * 这个方法最后执行,用于对已被创建的行内的所有单元格添加边框.能自动识别被创建的所有列和所有单元格 * @param sheet * @param workbook */ public void addGlobalStylesToAllCells(Sheet sheet, Workbook workbook) { //所有边框样式 CellStyle borderedStyle = workbook.createCellStyle(); //borderedStyle.cloneStyleFrom(sheet.getRow(0).getCell(0).getCellStyle()); // 可选:复制已有样式 borderedStyle.setBorderTop(BorderStyle.THIN); borderedStyle.setBorderBottom(BorderStyle.THIN); borderedStyle.setBorderLeft(BorderStyle.THIN); borderedStyle.setBorderRight(BorderStyle.THIN); for (Row row : sheet) { for (Cell cell : row) { cell.setCellStyle(borderedStyle); } } } }