From e5f80b8f2604f0423128c0811f716919ae0a9cef Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期三, 23 九月 2026 10:05:27 +0800
Subject: [PATCH] 1.代码提交
---
smartor/src/main/java/com/smartor/common/MydOptionRatioChartBuilder.java | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 172 insertions(+), 0 deletions(-)
diff --git a/smartor/src/main/java/com/smartor/common/MydOptionRatioChartBuilder.java b/smartor/src/main/java/com/smartor/common/MydOptionRatioChartBuilder.java
new file mode 100644
index 0000000..3c0d163
--- /dev/null
+++ b/smartor/src/main/java/com/smartor/common/MydOptionRatioChartBuilder.java
@@ -0,0 +1,172 @@
+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;
+
+/**
+ * 瀵煎嚭銆岄棶棰樿鎯呭崰姣斿浘琛ㄣ�峉heet 鐨勬瀯寤哄櫒
+ * <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;
+ }
+ }
+}
--
Gitblit v1.9.3