| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package com.smartor.common; |
| | | |
| | | import com.ruoyi.common.utils.poi.ExcelUtil; |
| | | import com.smartor.domain.ServiceSubtaskDetailRatioExport; |
| | | import org.apache.poi.ss.usermodel.Row; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | import org.apache.poi.xddf.usermodel.chart.AxisCrosses; |
| | | import org.apache.poi.xddf.usermodel.chart.AxisPosition; |
| | | import org.apache.poi.xddf.usermodel.chart.BarDirection; |
| | | import org.apache.poi.xddf.usermodel.chart.ChartTypes; |
| | | import org.apache.poi.xddf.usermodel.chart.LegendPosition; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFChartData; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFDataSource; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource; |
| | | import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis; |
| | | import org.apache.poi.xssf.usermodel.XSSFChart; |
| | | import org.apache.poi.xssf.usermodel.XSSFClientAnchor; |
| | | import org.apache.poi.xssf.usermodel.XSSFDrawing; |
| | | import org.apache.poi.xssf.usermodel.XSSFSheet; |
| | | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | /** |
| | | * 导åºãé®é¢è¯¦æ
å æ¯å¾è¡¨ãSheet çæå»ºå¨ |
| | | * <p> |
| | | * æä»»å¡åç§°åç»ï¼æ¯ä¸ªä»»å¡åä¸åæ°æ®ï¼è¡=é¢ç®ï¼å=é项ï¼å¼=æ°éï¼ï¼å¹¶å¨æ°æ®å³ä¾§ç»ä¸å¼ æ±ç¶å¾ã |
| | | * |
| | | * @author smartor |
| | | */ |
| | | public class MydOptionRatioChartBuilder implements ExcelUtil.ChartSheetBuilder { |
| | | |
| | | /** |
| | | * å¾è¡¨ Sheet åç§° |
| | | */ |
| | | public static final String SHEET_NAME = "é®é¢è¯¦æ
å æ¯å¾è¡¨"; |
| | | |
| | | private final List<ServiceSubtaskDetailRatioExport> rows; |
| | | |
| | | public MydOptionRatioChartBuilder(List<ServiceSubtaskDetailRatioExport> rows) { |
| | | this.rows = rows == null ? new ArrayList<>() : rows; |
| | | } |
| | | |
| | | @Override |
| | | public void build(XSSFWorkbook workbook) { |
| | | if (rows.isEmpty()) { |
| | | return; |
| | | } |
| | | XSSFSheet sheet = workbook.createSheet(SHEET_NAME); |
| | | |
| | | int startRow = 0; |
| | | for (Map.Entry<String, List<ServiceSubtaskDetailRatioExport>> entry : groupByTask().entrySet()) { |
| | | // æ¯åå®ä¸åæ°æ®ç«å»å»ºå¾ï¼SXSSF æµå¼å·¥ä½ç°¿éååçè¡è¿å¨å
åä¸ï¼å¾è¡¨æè½è¯»å°åå
æ ¼ |
| | | startRow = writeTaskBlockWithChart(sheet, entry.getKey(), entry.getValue(), startRow) + 2; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * æä»»å¡åç§°åç»ï¼ä¿æå表åæé¡ºåºï¼å³ SQL ç task_name æåºï¼ |
| | | */ |
| | | private Map<String, List<ServiceSubtaskDetailRatioExport>> groupByTask() { |
| | | Map<String, List<ServiceSubtaskDetailRatioExport>> grouped = new LinkedHashMap<>(); |
| | | for (ServiceSubtaskDetailRatioExport row : rows) { |
| | | String taskName = row.getTaskname() == null ? "" : row.getTaskname(); |
| | | grouped.computeIfAbsent(taskName, k -> new ArrayList<>()).add(row); |
| | | } |
| | | return grouped; |
| | | } |
| | | |
| | | /** |
| | | * åä¸ä¸ªä»»å¡çæ°æ®åå¹¶ç»æ±ç¶å¾ï¼è¿åä¸ä¸ä¸ªåå¯ç¨çèµ·å§è¡ |
| | | */ |
| | | private int writeTaskBlockWithChart(XSSFSheet sheet, String taskName, |
| | | List<ServiceSubtaskDetailRatioExport> taskRows, int startRow) { |
| | | // é¢ç® -> (é项 -> é该é项ç人æ°)ï¼é项æåºç°é¡ºåºæ¶éææ¬ä»»å¡çç³»å |
| | | Map<String, Map<String, Double>> questionOptions = new LinkedHashMap<>(); |
| | | LinkedHashSet<String> optionSet = new LinkedHashSet<>(); |
| | | String taskid = ""; |
| | | for (ServiceSubtaskDetailRatioExport row : taskRows) { |
| | | String question = row.getQuestiontext() == null ? "" : row.getQuestiontext(); |
| | | String option = row.getOptionresult() == null ? "" : row.getOptionresult(); |
| | | questionOptions.computeIfAbsent(question, k -> new LinkedHashMap<>()).put(option, parseCount(row.getCount())); |
| | | optionSet.add(option); |
| | | if (taskid.isEmpty() && row.getTaskid() != null) { |
| | | taskid = row.getTaskid(); |
| | | } |
| | | } |
| | | List<String> optionList = new ArrayList<>(optionSet); |
| | | List<String> questionList = new ArrayList<>(questionOptions.keySet()); |
| | | |
| | | int rowIdx = startRow; |
| | | // æ é¢è¡ |
| | | Row titleRow = sheet.createRow(rowIdx++); |
| | | titleRow.createCell(0).setCellValue("ä»»å¡åç§°ï¼" + taskName + "ï¼ä»»å¡ç¼å· " + taskid + "ï¼"); |
| | | |
| | | // 表头è¡ï¼é¢ç® + åé项ï¼å¾è¡¨ç³»åçæ é¢å°±æ¯è¿ä¸è¡ï¼ |
| | | Row headerRow = sheet.createRow(rowIdx++); |
| | | headerRow.createCell(0).setCellValue("é¢ç®"); |
| | | for (int i = 0; i < optionList.size(); i++) { |
| | | headerRow.createCell(i + 1).setCellValue(optionList.get(i)); |
| | | } |
| | | |
| | | // æ°æ®è¡ï¼å¼ = é该é项çäººæ° |
| | | int firstDataRow = rowIdx; |
| | | for (String question : questionList) { |
| | | Row dataRow = sheet.createRow(rowIdx++); |
| | | dataRow.createCell(0).setCellValue(question); |
| | | Map<String, Double> optionMap = questionOptions.get(question); |
| | | for (int i = 0; i < optionList.size(); i++) { |
| | | Double count = optionMap.get(optionList.get(i)); |
| | | dataRow.createCell(i + 1).setCellValue(count == null ? 0D : count); |
| | | } |
| | | } |
| | | int lastDataRow = rowIdx - 1; |
| | | |
| | | // æ±ç¶å¾ï¼åç±»=é¢ç®ï¼ç³»å=éé¡¹ï¼æ°å¼=é该é项çäººæ° |
| | | int chartCol = optionList.size() + 3; |
| | | int chartHeight = Math.max(16, questionList.size() + 4); |
| | | XSSFDrawing drawing = sheet.createDrawingPatriarch(); |
| | | XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, |
| | | chartCol, firstDataRow - 1, chartCol + 10, firstDataRow - 1 + chartHeight); |
| | | XSSFChart chart = drawing.createChart(anchor); |
| | | chart.setTitleText(taskName); |
| | | chart.setTitleOverlay(false); |
| | | |
| | | XDDFChartLegend legend = chart.getOrAddLegend(); |
| | | legend.setPosition(LegendPosition.BOTTOM); |
| | | |
| | | XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); |
| | | bottomAxis.setTitle("é¢ç®"); |
| | | XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); |
| | | leftAxis.setTitle("æ°é"); |
| | | leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); |
| | | |
| | | XDDFDataSource<String> categories = XDDFDataSourcesFactory.fromStringCellRange(sheet, |
| | | new CellRangeAddress(firstDataRow, lastDataRow, 0, 0)); |
| | | XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis); |
| | | for (int i = 0; i < optionList.size(); i++) { |
| | | XDDFNumericalDataSource<Double> values = XDDFDataSourcesFactory.fromNumericCellRange(sheet, |
| | | new CellRangeAddress(firstDataRow, lastDataRow, i + 1, i + 1)); |
| | | XDDFChartData.Series series = barChart.addSeries(categories, values); |
| | | series.setTitle(optionList.get(i), null); |
| | | } |
| | | barChart.setBarDirection(BarDirection.COL); |
| | | // å
³é®ï¼ä¸è°ç¨ plot å¾è¡¨ä¸ä¼æ¾ç¤º |
| | | chart.plot(barChart); |
| | | |
| | | return rowIdx; |
| | | } |
| | | |
| | | /** |
| | | * æ°éå符串 -> æ°åï¼å¼å¸¸å¼æ 0 å¤ç |
| | | */ |
| | | private double parseCount(String count) { |
| | | if (count == null || count.isEmpty()) { |
| | | return 0D; |
| | | } |
| | | try { |
| | | return Double.parseDouble(count.trim()); |
| | | } catch (NumberFormatException e) { |
| | | return 0D; |
| | | } |
| | | } |
| | | } |