From f13171a077414f66ef3bc57157150298cfc1ca0c Mon Sep 17 00:00:00 2001 From: huababa1 <2037205722@qq.com> Date: Mon, 15 Sep 2025 18:03:16 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E3=80=91=E5=AE=8C?= =?UTF-8?q?=E5=96=84wps=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/wps_excel/xlsx4j/cell/CellIng.java | 27 +- .../wps_excel/xlsx4j/chart/ChartHandler.java | 612 +++++++++++++++--- .../utils/wps_excel/xlsx4j/range/RangIng.java | 270 +++++++- .../utils/wps_excel/xlsx4j/style/Style.java | 14 +- .../utils/wps_word/docx4j/DocxConversion.java | 64 +- .../utils/wps_word/docx4j/DocxMaster.java | 13 +- .../wps_word/docx4j/paragraph/Paragraphs.java | 22 +- .../wps_word/docx4j/section/SectionPage.java | 3 +- 8 files changed, 888 insertions(+), 137 deletions(-) diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/cell/CellIng.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/cell/CellIng.java index 0d0f6d60..a6d1aa89 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/cell/CellIng.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/cell/CellIng.java @@ -15,14 +15,31 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STBorderStyle; import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils; import java.lang.reflect.Method; +import java.util.Map; public class CellIng { - + // 边框样式英文名称到中文的映射 + public final Map borderStyleChineseMap = Map.ofEntries( + Map.entry("NONE", "无边框"), + Map.entry("THIN", "细线"), + Map.entry("MEDIUM", "中等线"), + Map.entry("DASHED", "虚线"), + Map.entry("DOTTED", "点线"), + Map.entry("THICK", "粗线"), + Map.entry("DOUBLE", "双线"), + Map.entry("HAIR", "头发线"), + Map.entry("MEDIUMDASHED", "中等虚线"), + Map.entry("DASHDOT", "点划线"), + Map.entry("MEDIUMDASHDOT", "中等点划线"), + Map.entry("DASHDOTDOT", "双点划线"), + Map.entry("MEDIUMDASHDOTDOT", "中等双点划线"), + Map.entry("SLANTEDDASHDOT", "斜点划线") + ); // 获取左框线样式 public String getLeftBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) { CellStyle style = cell.getCellStyle(); BorderStyle border = style.getBorderLeft(); - return border != null ? border.name() : "无"; + return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无"; } // 获取左框线颜色 public String getLeftBorderColor(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) { @@ -39,7 +56,7 @@ public class CellIng { public String getTopBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) { CellStyle style = cell.getCellStyle(); BorderStyle border = style.getBorderTop(); - return border != null ? border.name() : "无"; + return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无"; } // 获取上框线颜色 @@ -56,7 +73,7 @@ public class CellIng { public String getRightBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) { CellStyle style = cell.getCellStyle(); BorderStyle border = style.getBorderRight(); - return border != null ? border.name() : "无"; + return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无"; } // 获取右框线颜色 @@ -73,7 +90,7 @@ public class CellIng { public String getBottomBorderStyle(Cell cell, org.apache.poi.ss.usermodel.Workbook wb) { CellStyle style = cell.getCellStyle(); BorderStyle border = style.getBorderBottom(); - return border != null ? border.name() : "无"; + return border != null ? borderStyleChineseMap.getOrDefault(border.name() , border.name() ): "无"; } // 获取下框线颜色 diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/chart/ChartHandler.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/chart/ChartHandler.java index 219119dd..8040d8b6 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/chart/ChartHandler.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/chart/ChartHandler.java @@ -1,6 +1,7 @@ package pc.exam.pp.module.judgement.utils.wps_excel.xlsx4j.chart; import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Workbook; @@ -11,10 +12,11 @@ import org.apache.poi.xddf.usermodel.chart.XDDFDataSource; import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource; import org.apache.poi.xssf.usermodel.*; import org.openxmlformats.schemas.drawingml.x2006.chart.*; -import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData; +import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTGraphicalObjectFrame; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPivotTableDefinition; +import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -33,7 +35,9 @@ import java.io.InputStreamReader; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -144,35 +148,40 @@ public class ChartHandler { if (ctChart == null || ctChart.getPlotArea() == null) return "无数据系列"; CTPlotArea plotArea = ctChart.getPlotArea(); - StringBuilder sb = new StringBuilder(); + + // 使用 Set 去重 + Set generationSet = new LinkedHashSet<>(); // 遍历柱状图 for (CTBarChart barChart : plotArea.getBarChartList()) { for (CTBarSer ser : barChart.getSerList()) { - String gen = getSeriesGeneration(ser.getTx()); - sb.append(gen).append("; "); + generationSet.add(getSeriesGeneration(ser.getTx())); } } // 遍历折线图 for (CTLineChart lineChart : plotArea.getLineChartList()) { for (CTLineSer ser : lineChart.getSerList()) { - String gen = getSeriesGeneration(ser.getTx()); - sb.append(gen).append("; "); + generationSet.add(getSeriesGeneration(ser.getTx())); } } // 遍历饼图 for (CTPieChart pieChart : plotArea.getPieChartList()) { for (CTPieSer ser : pieChart.getSerList()) { - String gen = getSeriesGeneration(ser.getTx()); - sb.append(gen).append("; "); + generationSet.add(getSeriesGeneration(ser.getTx())); } } - return sb.length() > 0 ? sb.substring(0, sb.length() - 2) : "无数据系列"; + if (generationSet.isEmpty()) { + return "无数据系列"; + } + + // 把 Set 转成字符串,输出唯一的产生方式 + return String.join("; ", generationSet); } + /** 图表-数据-数据系列 - 名称 */ public String getDataSeriesNames(XSSFChart chart, XSSFSheet sheet) { if (chart == null) return "无图表"; @@ -353,31 +362,30 @@ public class ChartHandler { /** 获取图表高度,返回"磅(厘米)" */ public static String getChartHeight(XSSFChart chart, XSSFSheet sheet) { - if (chart == null || sheet == null) return "无"; + if (sheet == null) return "无"; - XSSFDrawing drawing = sheet.createDrawingPatriarch(); + XSSFDrawing drawing = sheet.getDrawingPatriarch(); if (drawing == null) return "无"; for (XSSFShape shape : drawing.getShapes()) { - if (!(shape instanceof XSSFGraphicFrame)) continue; - XSSFGraphicFrame frame = (XSSFGraphicFrame) shape; - CTGraphicalObjectFrame ctFrame = frame.getCTGraphicalObjectFrame(); - CTGraphicalObjectData graphicData = ctFrame.getGraphic().getGraphicData(); - if (graphicData.getUri().equals("http://schemas.openxmlformats.org/drawingml/2006/chart")) { - ClientAnchor anchor = frame.getAnchor(); - double heightPt = 0; - for (int r = anchor.getRow1(); r < anchor.getRow2(); r++) { - Row row = sheet.getRow(r); - float rowHeightPt = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints(); - heightPt += rowHeightPt; + if (shape instanceof XSSFGraphicFrame) { + XSSFGraphicFrame frame = (XSSFGraphicFrame) shape; + if (frame.getCTGraphicalObjectFrame().getGraphic() != null && + "http://schemas.openxmlformats.org/drawingml/2006/chart".equals( + frame.getCTGraphicalObjectFrame().getGraphic().getGraphicData().getUri() + )) { + CTTransform2D xfrm = frame.getCTGraphicalObjectFrame().getXfrm(); + if (xfrm != null && xfrm.getExt() != null) { + long cy = xfrm.getExt().getCy(); + double heightPt = emuToPoints(cy); + double heightCm = emuToCm(cy); + return String.format("%.2f磅(%.2f厘米)", heightPt, heightCm); + } } - double heightCm = heightPt * 0.0352778; - return String.format("%.1f磅(%.2f厘米)", heightPt, heightCm); } } return "无"; } - /** * 获取所有可用图表样式名称列表 */ @@ -389,40 +397,118 @@ public class ChartHandler { return styles; } - /** 获取图表宽度,返回"磅(厘米)" */ - //todo + /** 获取图表宽度,返回"磅(厘米)" */ public static String getChartWidth(XSSFChart chart, XSSFSheet sheet) { - if (chart == null || sheet == null) return "无"; + if (sheet == null || chart == null) { + return "无"; + } + System.out.println("Sheet 名称:" + (sheet != null ? sheet.getSheetName() : "NULL")); + System.out.println("Chart 是否为空:" + (chart == null)); -// XSSFDrawing drawing = sheet.createDrawingPatriarch(); -// if (drawing == null) return "无"; -// -// for (XSSFShape shape : drawing.getShapes()) { -// if (!(shape instanceof XSSFGraphicFrame)) continue; -// XSSFGraphicFrame frame = (XSSFGraphicFrame) shape; -// CTGraphicalObjectFrame ctFrame = frame.getCTGraphicalObjectFrame(); -// CTGraphicalObjectData graphicData = ctFrame.getGraphic().getGraphicData(); -// -// // 确保是 chart 类型 -// if (!"http://schemas.openxmlformats.org/drawingml/2006/chart".equals(graphicData.getUri())) -// continue; -// -// // 判断是否是目标 chart -// List charts = drawing.getCharts(); -// if (!charts.contains(chart)) continue; -// -// if (ctFrame.getXfrm() == null || ctFrame.getXfrm().getExt() == null) continue; -// -// long cxEmu = ctFrame.getXfrm().getExt().getCx(); // EMU -// double points = cxEmu * 72.0 / 914400.0; // EMU -> pt -// double cm = points * 2.54 / 72.0; // pt -> cm -// -// return String.format("%.1f磅(%.2f厘米)", points, cm); -// } + XSSFDrawing drawing = sheet.getDrawingPatriarch(); + + if (drawing != null) { + int i = 1; + for (XSSFShape shape : drawing.getShapes()) { + System.out.println("第 " + i + " 个 Shape 类型:" + shape.getClass().getName()); + if (shape instanceof XSSFGraphicFrame) { + System.out.println(" -> 发现 GraphicFrame(可能是图表)"); + XSSFGraphicFrame frame = (XSSFGraphicFrame) shape; + + // 打印 XML + System.out.println(" Frame XML:"); + System.out.println(frame.getCTGraphicalObjectFrame().xmlText()); + + // 检查锚点 + ClientAnchor anchor = frame.getAnchor(); + if (anchor != null) { + System.out.println(" Anchor 位置: col1=" + anchor.getCol1() + ", col2=" + anchor.getCol2() + + ", row1=" + anchor.getRow1() + ", row2=" + anchor.getRow2()); + } else { + System.out.println(" Anchor 为空(可能是浮动图表)"); + } + } + i++; + } + } + if (sheet == null) return "无"; + + if (drawing == null) return "无"; + + for (XSSFShape shape : drawing.getShapes()) { + if (shape instanceof XSSFGraphicFrame) { + XSSFGraphicFrame frame = (XSSFGraphicFrame) shape; + if (frame.getCTGraphicalObjectFrame().getGraphic() != null && + "http://schemas.openxmlformats.org/drawingml/2006/chart".equals( + frame.getCTGraphicalObjectFrame().getGraphic().getGraphicData().getUri() + )) { + // 找到图表 + CTTransform2D xfrm = frame.getCTGraphicalObjectFrame().getXfrm(); + if (xfrm != null && xfrm.getExt() != null) { + long cx = xfrm.getExt().getCx(); + double widthPt = emuToPoints(cx); + double widthCm = emuToCm(cx); + return String.format("%.2f磅(%.2f厘米)", widthPt, widthCm); + } + } + } + } return "无"; } + // EMU 转磅 + private static double emuToPoints(long emu) { + return emu / 12700.0; + } + // EMU 转厘米 + private static double emuToCm(long emu) { + return emu / 360000.0; + } + /** + * 判断 frame 是否对应指定的 chart + */ + private static boolean isSameChart(XSSFGraphicFrame frame, XSSFChart targetChart) { + if (frame == null || targetChart == null) { + return false; + } + // 直接通过关系ID判断 + String chartRelId = targetChart.getPackagePart().getPartName().getName(); + String frameXml = frame.getCTGraphicalObjectFrame().xmlText(); + return frameXml.contains(chartRelId); + } + /** + * 计算图表宽度(厘米) + * @param sheet 当前工作表 + * @param anchor 图表的锚点信息 + * @return 图表宽度(cm) + */ + private static double calculateChartWidth(XSSFSheet sheet, ClientAnchor anchor) { + int col1 = anchor.getCol1(); // 左上角所在列 + int col2 = anchor.getCol2(); // 右下角所在列 + int dx1 = anchor.getDx1(); // 左上角偏移量 (EMU) + int dx2 = anchor.getDx2(); // 右下角偏移量 (EMU) + + // 1. 计算完整列宽 + double totalWidthPixels = 0; + for (int c = col1; c < col2; c++) { + totalWidthPixels += sheet.getColumnWidthInPixels(c); + } + + // 2. 偏移量修正 (1 英寸 = 914400 EMU, 1 英寸 = 96 像素) + double offsetStartPixels = dx1 / 9525.0; // EMU -> 像素 + double offsetEndPixels = dx2 / 9525.0; // EMU -> 像素 + + double totalWidth = totalWidthPixels + offsetEndPixels - offsetStartPixels; + + // 3. 像素 -> 磅 (1 像素 = 0.75 磅) + double widthPt = totalWidth * 0.75; + + // 4. 磅 -> 厘米 (1 磅 = 0.0352778 厘米) + double widthCm = widthPt * 0.0352778; + + return Math.round(widthCm * 100.0) / 100.0; // 保留两位小数 + } @@ -469,25 +555,199 @@ public class ChartHandler { } /** 图表标题 - 文本内容 */ - public String getChartTitleText(XSSFChart chart,XSSFSheet sheet) { + public static String getChartTitleText(XSSFChart chart, XSSFSheet sheet) { if (chart == null) return "无图表"; CTChart ctChart = chart.getCTChart(); - if (ctChart == null || !ctChart.isSetTitle()) return "无标题"; + if (ctChart == null) return "无图表"; - // 标题文本一般在 rich 或 strRef - if (ctChart.getTitle().getTx() != null) { - if (ctChart.getTitle().getTx().isSetRich()) { - try { - return ctChart.getTitle().getTx().getRich().getPArray(0).getRArray(0).getT(); - } catch (Exception e) { - return "标题解析异常"; + // 1. 尝试读取标题 + CTTitle title = ctChart.getTitle(); + if (title != null) { + // 1.1 rich 文本 + CTTx tx = title.getTx(); + if (tx != null) { + CTTextBody rich = tx.getRich(); + if (rich != null) { + for (CTTextParagraph p : rich.getPList()) { + for (CTRegularTextRun r : p.getRList()) { + String text = r.getT(); + if (text != null && !text.trim().isEmpty()) { + return text.trim(); + } + } + } + } + + // 1.2 公式引用 + CTStrRef strRef = (tx.getStrRef() != null) ? tx.getStrRef() : null; + if (strRef != null) { + try { + String formula = strRef.getF(); + CellReference ref = new CellReference(formula); + Row row = sheet.getRow(ref.getRow()); + if (row != null) { + Cell cell = row.getCell(ref.getCol()); + if (cell != null) { + return cell.toString(); + } + } + } catch (Exception e) { + // 出错继续尝试读取系列名称 + } + } + } + + // 1.3 txPr 占位符文本 + CTTextBody txPr = title.getTxPr(); + if (txPr != null) { + for (CTTextParagraph p : txPr.getPList()) { + for (CTRegularTextRun r : p.getRList()) { + String text = r.getT(); + if (text != null && !text.trim().isEmpty()) { + return text.trim(); + } + } } - } else if (ctChart.getTitle().getTx().isSetStrRef()) { - return ctChart.getTitle().getTx().getStrRef().getF(); } } - return "无标题文本"; + + // 2. 如果标题为空,则尝试读取第一个数据系列名称 + CTPlotArea plotArea = ctChart.getPlotArea(); + if (plotArea != null) { + + // Pie3DChart + if (!plotArea.getPie3DChartList().isEmpty()) { + CTPie3DChart pie3DChart = plotArea.getPie3DChartArray(0); + if (!pie3DChart.getSerList().isEmpty()) { + CTPieSer ser = pie3DChart.getSerArray(0); + CTSerTx serTx = ser.getTx(); + if (serTx != null) { + CTStrRef strRef = serTx.getStrRef(); + if (strRef != null) { + try { + CellReference ref = new CellReference(strRef.getF()); + Row row = sheet.getRow(ref.getRow()); + if (row != null) { + Cell cell = row.getCell(ref.getCol()); + if (cell != null) return cell.toString(); + } + } catch (Exception e) { + return "系列名称引用解析异常"; + } + } else if (serTx.getV() != null) { + return serTx.getV(); + } + } + } + } + + // PieChart + if (!plotArea.getPieChartList().isEmpty()) { + CTPieChart pieChart = plotArea.getPieChartArray(0); + if (!pieChart.getSerList().isEmpty()) { + CTPieSer ser = pieChart.getSerArray(0); + CTSerTx serTx = ser.getTx(); + if (serTx != null) { + CTStrRef strRef = serTx.getStrRef(); + if (strRef != null) { + try { + CellReference ref = new CellReference(strRef.getF()); + Row row = sheet.getRow(ref.getRow()); + if (row != null) { + Cell cell = row.getCell(ref.getCol()); + if (cell != null) return cell.toString(); + } + } catch (Exception e) { + return "系列名称引用解析异常"; + } + } else if (serTx.getV() != null) { + return serTx.getV(); + } + } + } + } + + // BarChart + if (!plotArea.getBarChartList().isEmpty()) { + CTBarChart barChart = plotArea.getBarChartArray(0); + if (!barChart.getSerList().isEmpty()) { + CTBarSer ser = barChart.getSerArray(0); + CTSerTx serTx = ser.getTx(); + if (serTx != null) { + CTStrRef strRef = serTx.getStrRef(); + if (strRef != null) { + try { + CellReference ref = new CellReference(strRef.getF()); + Row row = sheet.getRow(ref.getRow()); + if (row != null) { + Cell cell = row.getCell(ref.getCol()); + if (cell != null) return cell.toString(); + } + } catch (Exception e) { + return "系列名称引用解析异常"; + } + } else if (serTx.getV() != null) { + return serTx.getV(); + } + } + } + } + + // LineChart + if (!plotArea.getLineChartList().isEmpty()) { + CTLineChart lineChart = plotArea.getLineChartArray(0); + if (!lineChart.getSerList().isEmpty()) { + CTLineSer ser = lineChart.getSerArray(0); + CTSerTx serTx = ser.getTx(); + if (serTx != null) { + CTStrRef strRef = serTx.getStrRef(); + if (strRef != null) { + try { + CellReference ref = new CellReference(strRef.getF()); + Row row = sheet.getRow(ref.getRow()); + if (row != null) { + Cell cell = row.getCell(ref.getCol()); + if (cell != null) return cell.toString(); + } + } catch (Exception e) { + return "系列名称引用解析异常"; + } + } else if (serTx.getV() != null) { + return serTx.getV(); + } + } + } + } + + // AreaChart + if (!plotArea.getAreaChartList().isEmpty()) { + CTAreaChart areaChart = plotArea.getAreaChartArray(0); + if (!areaChart.getSerList().isEmpty()) { + CTAreaSer ser = areaChart.getSerArray(0); + CTSerTx serTx = ser.getTx(); + if (serTx != null) { + CTStrRef strRef = serTx.getStrRef(); + if (strRef != null) { + try { + CellReference ref = new CellReference(strRef.getF()); + Row row = sheet.getRow(ref.getRow()); + if (row != null) { + Cell cell = row.getCell(ref.getCol()); + if (cell != null) return cell.toString(); + } + } catch (Exception e) { + return "系列名称引用解析异常"; + } + } else if (serTx.getV() != null) { + return serTx.getV(); + } + } + } + } + } + // 3. 如果都没有,返回占位符 + return "标题为空或占位符"; } /** 图表标题 - 位置 */ @@ -522,17 +782,225 @@ public class ChartHandler { } // 辅助方法:根据CTSerTx判断产生方式 private String getSeriesGeneration(CTSerTx tx) { - if (tx != null) { - if (tx.getStrRef() != null) { - return "系列产生于列"; - } else if (tx.getV() != null) { - return "手动输入"; - } + if (tx == null) { + // 没有 tx 节点时,默认按“系列产生于列”处理 + return "系列产生于列"; } - return "未知生成方式"; + + if (tx.isSetStrRef()) { + // isSetStrRef() 比直接判断 null 更语义化 + return "系列产生于列"; + } + + if (tx.isSetV()) { + return "手动输入"; + } + + // 如果 tx 存在,但两个子节点都不存在 + return "系列产生于列"; } + /** + * 获取图例显示状态 + * + * @param chart XSSFChart对象 + * @return "显示" 或 "隐藏" + */ + public static String getLegendVisible(XSSFChart chart, XSSFSheet sheet) { + if (chart == null) return "无图表"; + CTChart ctChart = chart.getCTChart(); + if (ctChart == null) return "无图表"; + CTLegend legend = ctChart.getLegend(); + if (legend == null) return "隐藏"; + + boolean visible = legend.getOverlay() == null || !legend.getOverlay().getVal(); + return visible ? "显示" : "隐藏"; + } + + /** + * 获取图例位置(汉化) + * + * @param chart XSSFChart对象 + * @return 中文位置,如 "上方", "下方", "左侧", "右侧",无图例返回 "无图例" + */ + public static String getLegendPosition(XSSFChart chart, XSSFSheet sheet) { + if (chart == null) return "无图表"; + CTChart ctChart = chart.getCTChart(); + if (ctChart == null) return "无图表"; + + CTLegend legend = ctChart.getLegend(); + if (legend == null) return "无图例"; + + STLegendPos.Enum posEnum = legend.getLegendPos().getVal(); + if (posEnum != null) { + switch (posEnum.intValue()) { + case STLegendPos.INT_T: return "上方"; + case STLegendPos.INT_B: return "下方"; + case STLegendPos.INT_L: return "左侧"; + case STLegendPos.INT_R: return "右侧"; + case STLegendPos.INT_TR: return "右上"; + default: return "未知位置"; + } + } + + return "未知位置"; + } + + /** + * 获取第一个系列的数据标签是否显示 + */ + public static String isDataLabelVisible(XSSFChart chart, XSSFSheet sheet) { + CTDLbls dLbls = getFirstSeriesDLbls(chart); + if (dLbls == null) return "隐藏"; + + // 只要任何一个显示属性不为空且为true,就认为显示 + boolean visible = (dLbls.getShowVal() != null && dLbls.getShowVal().getVal()) + || (dLbls.getShowCatName() != null && dLbls.getShowCatName().getVal()) + || (dLbls.getShowLegendKey() != null && dLbls.getShowLegendKey().getVal()); + return visible ? "显示" : "隐藏"; + } + + /** + * 获取第一个系列的数据标签是否显示类别名称(X) + */ + public static String isDataLabelShowCategoryName(XSSFChart chart, XSSFSheet sheet) { + CTDLbls dLbls = getFirstSeriesDLbls(chart); + if (dLbls == null || dLbls.getShowCatName() == null) return "不显示"; + return dLbls.getShowCatName().getVal() ? "显示" : "不显示"; + } + + /** + * 获取第一个系列的数据标签是否显示数值(V) + */ + public static String isDataLabelShowValue(XSSFChart chart, XSSFSheet sheet) { + CTDLbls dLbls = getFirstSeriesDLbls(chart); + if (dLbls == null || dLbls.getShowVal() == null) return "不显示"; + return dLbls.getShowVal().getVal() ? "显示" : "不显示"; + } + /** + * 获取第一个系列的数据标签位置(兼容旧版本 POI) + * @param chart XSSFChart + * @param sheet XSSFSheet + * @return 位置字符串,例如 "上"、"下"、"居中"、"未设置" + */ + public static String getDataLabelPosition(XSSFChart chart, XSSFSheet sheet) { + if (chart == null) return "未设置"; + CTPlotArea plotArea = chart.getCTChart().getPlotArea(); + if (plotArea == null) return "未设置"; + + // 先尝试 PieChart + if (plotArea.getPieChartArray().length > 0) { + CTPieChart pieChart = plotArea.getPieChartArray(0); + if (pieChart.getSerArray().length > 0) { + CTPieSer ser = pieChart.getSerArray(0); + CTDLbls dLbls = ser.getDLbls(); + return parseDLblPosFromXML(dLbls); + } + } + + // 尝试 BarChart + if (plotArea.getBarChartArray().length > 0) { + CTBarChart barChart = plotArea.getBarChartArray(0); + if (barChart.getSerArray().length > 0) { + CTBarSer ser = barChart.getSerArray(0); + CTDLbls dLbls = ser.getDLbls(); + return parseDLblPosFromXML(dLbls); + } + } + + // 尝试 LineChart + if (plotArea.getLineChartArray().length > 0) { + CTLineChart lineChart = plotArea.getLineChartArray(0); + if (lineChart.getSerArray().length > 0) { + CTLineSer ser = lineChart.getSerArray(0); + CTDLbls dLbls = ser.getDLbls(); + return parseDLblPosFromXML(dLbls); + } + } + + // 其他图表类型可按需扩展 + return "未设置"; + } + + /** + * 从 DLbls XML 获取位置并汉化 + */ + private static String parseDLblPosFromXML(CTDLbls dLbls) { + if (dLbls == null) return "未设置"; + + // 通过底层 XML 解析 + if (dLbls.getDomNode() != null) { + org.w3c.dom.NodeList nodeList = dLbls.getDomNode().getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + org.w3c.dom.Node node = nodeList.item(i); + if ("dLblPos".equals(node.getLocalName())) { + org.w3c.dom.NamedNodeMap attrs = node.getAttributes(); + org.w3c.dom.Node valNode = attrs.getNamedItem("val"); + if (valNode != null) { + String val = valNode.getNodeValue(); + return convertDLblPos(val); + } + } + } + } + + return "未设置"; + } + + /** + * 将 OOXML 数据标签位置值汉化 + */ + private static String convertDLblPos(String val) { + switch (val) { + case "bestFit": return "自动最佳"; + case "b": return "下"; + case "ctr": return "居中"; + case "inBase": return "内部底部"; + case "inEnd": return "内部末端"; + case "l": return "左"; + case "outEnd": return "外部末端"; + case "r": return "右"; + case "t": return "上"; + default: return "其他"; + } + } + // 获取第一个数据系列的 CTDLbls(不使用 CTSer) + private static CTDLbls getFirstSeriesDLbls(XSSFChart chart) { + if (chart == null) return null; + CTChart ctChart = chart.getCTChart(); + if (ctChart == null) return null; + CTPlotArea plotArea = ctChart.getPlotArea(); + if (plotArea == null) return null; + + // Pie3DChart + if (!plotArea.getPie3DChartList().isEmpty()) { + CTPie3DChart chart0 = plotArea.getPie3DChartArray(0); + if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls(); + } + // PieChart + if (!plotArea.getPieChartList().isEmpty()) { + CTPieChart chart0 = plotArea.getPieChartArray(0); + if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls(); + } + // BarChart + if (!plotArea.getBarChartList().isEmpty()) { + CTBarChart chart0 = plotArea.getBarChartArray(0); + if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls(); + } + // LineChart + if (!plotArea.getLineChartList().isEmpty()) { + CTLineChart chart0 = plotArea.getLineChartArray(0); + if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls(); + } + // AreaChart + if (!plotArea.getAreaChartList().isEmpty()) { + CTAreaChart chart0 = plotArea.getAreaChartArray(0); + if (!chart0.getSerList().isEmpty()) return chart0.getSerArray(0).getDLbls(); + } + + return null; + } // public void printChartXml(XSSFChart chart) { // if (chart == null) { // System.out.println("无图表"); diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/range/RangIng.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/range/RangIng.java index b87e089f..903dcf1b 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/range/RangIng.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/range/RangIng.java @@ -11,9 +11,7 @@ import pc.exam.pp.module.judgement.utils.wps_word.utils.ColorUtils; import java.math.BigDecimal; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; +import java.util.*; public class RangIng { @@ -70,7 +68,119 @@ public class RangIng { return cellValueBuilder.toString(); } + /** + * 范围 边框 → 样式 + * + * @param cellRef 单元格范围,如 "A1:B2" + * @param workbook Excel 工作簿 + * @param sheetIndex 工作表下标,从 1 开始 + * @return 各单元格边框样式 + */ + public static String getRangeBorderStyles(String cellRef, Workbook workbook, int sheetIndex) { + // 边框样式英文名称到中文的映射 + final Map borderStyleChineseMap = Map.ofEntries( + Map.entry("NONE", "无边框"), + Map.entry("THIN", "细线"), + Map.entry("MEDIUM", "中等线"), + Map.entry("DASHED", "虚线"), + Map.entry("DOTTED", "点线"), + Map.entry("THICK", "粗线"), + Map.entry("DOUBLE", "双线"), + Map.entry("HAIR", "头发线"), + Map.entry("MEDIUMDASHED", "中等虚线"), + Map.entry("DASHDOT", "点划线"), + Map.entry("MEDIUMDASHDOT", "中等点划线"), + Map.entry("DASHDOTDOT", "双点划线"), + Map.entry("MEDIUMDASHDOTDOT", "中等双点划线"), + Map.entry("SLANTEDDASHDOT", "斜点划线") + ); + List cellRefs = getCellRefsInRange(cellRef); + + for (String ref : cellRefs) { + Cell cell = getPoiCellFromRef(workbook, sheetIndex - 1, ref); + if (cell == null) continue; + + CellStyle style = cell.getCellStyle(); + if (style == null) continue; + + BorderStyle[] borders = { + style.getBorderTop(), + style.getBorderBottom(), + style.getBorderLeft(), + style.getBorderRight() + }; + + for (BorderStyle border : borders) { + if (border != BorderStyle.NONE) { + String borderName = border.name(); + return borderStyleChineseMap.getOrDefault(borderName, borderName); + } + } + } + + return "无边框"; + } + + /** + * 范围 边框 → 颜色 + * + * @param cellRef 单元格范围,如 "A1:B2" + * @param workbook Excel 工作簿 + * @param sheetIndex 工作表下标,从 1 开始 + * @return 各单元格边框颜色(RGB或预设颜色名) + */ + public static String getRangeBorderColors(String cellRef, Workbook workbook, int sheetIndex) { + List cellRefs = getCellRefsInRange(cellRef); + + for (String ref : cellRefs) { + Cell cell = getPoiCellFromRef(workbook, sheetIndex-1, ref); + if (cell == null) continue; + + CellStyle style = cell.getCellStyle(); + if (style == null) continue; + + // 先检查 XSSF(xlsx 文件) + if (style instanceof XSSFCellStyle) { + XSSFCellStyle xssfStyle = (XSSFCellStyle) style; + + // 检查四个方向的边框颜色 + XSSFColor[] colors = { + xssfStyle.getTopBorderXSSFColor(), + xssfStyle.getBottomBorderXSSFColor(), + xssfStyle.getLeftBorderXSSFColor(), + xssfStyle.getRightBorderXSSFColor() + }; + + for (XSSFColor color : colors) { + if (color != null && color.getRGB() != null) { + byte[] rgb = color.getRGB(); + String colorName =String.format("%02X%02X%02X", rgb[0], rgb[1], rgb[2]); + return ColorUtils.getChineseColorName(colorName); + } + } + } else { + // HSSF(xls 文件) + short[] borders = { + style.getTopBorderColor(), + style.getBottomBorderColor(), + style.getLeftBorderColor(), + style.getRightBorderColor() + }; + + for (short borderIdx : borders) { + if (borderIdx != IndexedColors.AUTOMATIC.getIndex()) { + IndexedColors color = IndexedColors.fromInt(borderIdx); + if (color != null) { + return ColorUtils.getChineseColorName(color.name()); // 返回预设颜色名称 + } + } + } + } + } + + return "无颜色"; + } // 这里是字体名称示例,先简单返回空或默认 public String getFontName(String cellRef, Workbook workbook, int sheetIndex) { @@ -481,7 +591,161 @@ public class RangIng { return String.valueOf(row.getHeightInPoints()); } + /** + * 范围 -列 列宽 + */ + public static String getColumnWidth(String cellRefRange, Workbook workbook, int sheetIndex) { + List cellRefs = getCellRefsInRange(cellRefRange); + if (cellRefs.isEmpty()) return "无"; + // 取范围里的第一个单元格 + String firstCellRef = cellRefs.get(0); + CellReference cr = new CellReference(firstCellRef); + int colIndex = cr.getCol(); + + Sheet sheet = workbook.getSheetAt(sheetIndex - 1); + if (sheet == null) return "无"; + + // getColumnWidth 返回的是字符数*256(单位:1/256 个字符) + int width = sheet.getColumnWidth(colIndex); + int charWidth = width / 256; // 向下取整 + + return String.valueOf(charWidth); + } + + /** + * 范围 -格式 -水平对齐 + */ + public static String getCellHorizontalAlignment(String cellRefRange, Workbook workbook, int sheetIndex) { + List cellRefs = getCellRefsInRange(cellRefRange); + if (cellRefs.isEmpty()) return "无"; + + String firstCellRef = cellRefs.get(0); + CellReference cr = new CellReference(firstCellRef); + Sheet sheet = workbook.getSheetAt(sheetIndex - 1); + Row row = sheet.getRow(cr.getRow()); + if (row == null) return "无"; + + Cell cell = row.getCell(cr.getCol()); + if (cell == null) return "无"; + + CellStyle style = cell.getCellStyle(); + if (style == null) return "默认"; + + HorizontalAlignment ha = style.getAlignment(); + if (ha == null) return "默认"; + + switch (ha) { + case LEFT: return "左对齐"; + case CENTER: return "居中"; + case RIGHT: return "右对齐"; + case FILL: return "填充"; + case JUSTIFY: return "两端对齐"; + case CENTER_SELECTION: return "跨列居中"; + default: return "其他"; + } + } + + /** + * 范围 -格式 -垂直对齐 + */ + public static String getCellVerticalAlignment(String cellRefRange, Workbook workbook, int sheetIndex) { + List cellRefs = getCellRefsInRange(cellRefRange); + if (cellRefs.isEmpty()) return "无"; + + String firstCellRef = cellRefs.get(0); + CellReference cr = new CellReference(firstCellRef); + Sheet sheet = workbook.getSheetAt(sheetIndex - 1); + Row row = sheet.getRow(cr.getRow()); + if (row == null) return "无"; + + Cell cell = row.getCell(cr.getCol()); + if (cell == null) return "无"; + + CellStyle style = cell.getCellStyle(); + if (style == null) return "默认"; + + VerticalAlignment va = style.getVerticalAlignment(); + if (va == null) return "默认"; + + switch (va) { + case TOP: return "顶端对齐"; + case CENTER: return "垂直居中"; + case BOTTOM: return "底端对齐"; + case JUSTIFY: return "两端对齐"; + case DISTRIBUTED: return "分散对齐"; + default: return "其他"; + } + } + + + + // --------------------- 条件格式公共方法 --------------------- + private static ConditionalFormattingRule getFirstMatchingRule(String cellRefRange, Workbook workbook, int sheetIndex) { + Sheet sheet = workbook.getSheetAt(sheetIndex - 1); + List cellRefs = getCellRefsInRange(cellRefRange); + if (cellRefs.isEmpty()) return null; + + SheetConditionalFormatting cf = sheet.getSheetConditionalFormatting(); + int numCF = cf.getNumConditionalFormattings(); + if (numCF == 0) return null; + + CellReference cr = new CellReference(cellRefs.get(0)); + + for (int i = 0; i < numCF; i++) { + ConditionalFormatting formatting = cf.getConditionalFormattingAt(i); + for (CellRangeAddress range : formatting.getFormattingRanges()) { + if (range.isInRange(cr.getRow(), cr.getCol())) { + if (formatting.getNumberOfRules() > 0) { + return formatting.getRule(0); // 返回第一个匹配规则 + } + } + } + } + return null; + } + + // 1. 数据标签显示 + public static String isDataLabelVisible(String cellRefRange, Workbook workbook, int sheetIndex) { + ConditionalFormattingRule rule = getFirstMatchingRule(cellRefRange, workbook, sheetIndex); + return (rule != null) ? "显示" : "隐藏"; + } + + // 5. 数字格式(通过单元格样式读取) + public static String getConditionalFormatDataFormat(String cellRefRange, Workbook workbook, int sheetIndex) { + List cellRefs = getCellRefsInRange(cellRefRange); + if (cellRefs.isEmpty()) return "无"; + + Sheet sheet = workbook.getSheetAt(sheetIndex - 1); + CellReference cr = new CellReference(cellRefs.get(0)); + Row row = sheet.getRow(cr.getRow()); + if (row == null) return "无"; + Cell cell = row.getCell(cr.getCol()); + if (cell == null) return "无"; + + CellStyle style = cell.getCellStyle(); + if (style != null) return style.getDataFormatString(); + return "无"; + } + + // 6. 数据条 + public static String getConditionalFormatDataBar(String cellRefRange, Workbook workbook, int sheetIndex) { + ConditionalFormattingRule rule = getFirstMatchingRule(cellRefRange, workbook, sheetIndex); + if (rule != null && rule.getDataBarFormatting() != null) return "已应用"; + return "未应用"; + } + + // 7. 色阶 + public static String getConditionalFormatColorScale(String cellRefRange, Workbook workbook, int sheetIndex) { + ConditionalFormattingRule rule = getFirstMatchingRule(cellRefRange, workbook, sheetIndex); + if (rule != null && rule.getColorScaleFormatting() != null) return "已应用"; + return "未应用"; + } + + // 8. 图标集 + public static String getConditionalFormatIconSet(String cellRefRange, Workbook workbook, int sheetIndex) { + return "未应用"; + } // ---------- 辅助方法 ---------- diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/style/Style.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/style/Style.java index 04a9b497..15cbfd18 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/style/Style.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_excel/xlsx4j/style/Style.java @@ -34,12 +34,14 @@ public class Style { Sheet sheet = workbook.getSheetAt(sheetNum); if (sheet instanceof XSSFSheet) { XSSFColor color = ((XSSFSheet) sheet).getTabColor(); - String hex=color.getARGBHex(); - if (hex != null && hex.length() == 8) { - hex = hex.substring(2); // 去掉前两位 Alpha - } - if (hex != null) { - return ColorUtils.getChineseColorName(hex); + if (color != null) { // 非空判断 + String hex=color.getARGBHex(); + if (hex != null && hex.length() == 8) { + hex = hex.substring(2); // 去掉前两位 Alpha + } + if (hex != null && !hex.isEmpty()) { + return ColorUtils.getChineseColorName(hex); + } } } return "无"; diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxConversion.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxConversion.java index 902d0402..2eef268a 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxConversion.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxConversion.java @@ -23,60 +23,52 @@ public class DocxConversion { public static List DocxDataInfos(MultipartFile file) throws Exception { List dataInfoVOS = new ArrayList<>(); try (InputStream inputStream = file.getInputStream()) { + // 1. 直接使用 InputStream 构造 XWPFDocument(无需本地文件) XWPFDocument document = new XWPFDocument(inputStream); + // 2. 读取文档内容(示例:提取所有段落文本) + StringBuilder content = new StringBuilder(); + document.getParagraphs().forEach(paragraph -> { + content.append(paragraph.getText()).append("\n"); + }); + String xmlString = XmlUtil.getDocumentXml(document); String namespace = WpsWordNameSpaces.getNameSpace(xmlString); XmlObject docXml = document.getDocument(); - - // 段落根节点 + // 1、获取文档段落W:P标签得数量,判断出一个有多少段 XmlCursor wpCursor = docXml.newCursor(); String wpPath = namespace + "/w:document/w:body/w:p"; wpCursor.selectPath(wpPath); int wpIndex = 0; + // 段落 String firstIdWp = getStringRandom(); setWordDataInfo(firstIdWp, "", "段落", "w:p", "", false, dataInfoVOS); - while (wpCursor.toNextSelection()) { - wpIndex++; + wpIndex ++; + // 段落属性 if (!wpCursor.xmlText().contains("w:sectPr")) { - // 1. 提取普通段落文本(排除文本框) - String fullText = extractParagraphText(wpCursor, namespace); - - // 2. 提取文本框文本 - List textBoxSentences = processTextBoxParagraphs(wpCursor, namespace); - - String secondIdWp = null; - if (!fullText.isEmpty()) { - // 过滤掉文本框句子 - StringBuilder filteredTextBuilder = new StringBuilder(); - String[] sentences = fullText.split("[。!?.!?]"); - for (String sentence : sentences) { - sentence = sentence.trim(); - if (!sentence.isEmpty() && (textBoxSentences == null || !textBoxSentences.contains(sentence))) { - if (filteredTextBuilder.length() > 0) { - filteredTextBuilder.append("。"); // 可以用原文分隔符 - } - filteredTextBuilder.append(sentence); - } + // 获取文本 + XmlCursor wpTextXml = wpCursor.newCursor(); + wpTextXml.selectPath(namespace + ".//w:r/w:t"); + StringBuilder fullTextBuilder = new StringBuilder(); + while (wpTextXml.toNextSelection()) { + String part = wpTextXml.getTextValue(); + if (part != null) { + fullTextBuilder.append(part); } - String filteredFullText = filteredTextBuilder.toString(); - - // 生成段落节点,使用过滤后的文本 - secondIdWp = getStringRandom(); - setWordDataInfo(secondIdWp, firstIdWp, "段落" + wpIndex + ":" + shorten(filteredFullText), "w:p", String.valueOf(wpIndex), true, dataInfoVOS); - - // 拆分句子 + } + String fullText = fullTextBuilder.toString().trim(); + if (!fullText.isEmpty()) { + String secondIdWp = getStringRandom(); + String shortText = shorten(fullText); // 截断展示 + setWordDataInfo(secondIdWp, firstIdWp, "段落" + wpIndex + ":" + shortText, "w:p", String.valueOf(wpIndex), true, dataInfoVOS); + String[] sentences = fullText.split("[。!?.!?]"); int sentenceIndex = 0; for (String sentence : sentences) { sentence = sentence.trim(); if (!sentence.isEmpty()) { - // 跳过文本框中已经存在的句子 - if (textBoxSentences != null && textBoxSentences.contains(sentence)) { - continue; - } sentenceIndex++; String thirdIdWp = getStringRandom(); setWordDataInfo(thirdIdWp, secondIdWp, "句子" + sentenceIndex + ":" + shorten(sentence), "w:t", String.valueOf(wpIndex), true, dataInfoVOS); @@ -85,10 +77,6 @@ public class DocxConversion { } } } - - - - // 2、页面 XmlCursor wSectPrCursor = docXml.newCursor(); String wSectPrPath = namespace + "//w:sectPr"; // 查找所有节 diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxMaster.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxMaster.java index e2e45cd4..78db09c3 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxMaster.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/DocxMaster.java @@ -493,10 +493,17 @@ public class DocxMaster { // 方法无法调用或内部异常,也跳过或打印日志 e.printStackTrace(); } + String processedValue = null; if (value != null) { - judgementWordsVOS = setJudgementWord(judgementWordsVOS, - docxFunction + "@" + value, - firstName + examName + value); + if ("getTextValue".equals(function)){ + // 对所有文字超过10个字的情况进行截断 + if (value.length() > 13) { + processedValue = value.substring(0, 5) + "..." + value.substring(value.length() - 3); + } + } + judgementWordsVOS = setJudgementWord(judgementWordsVOS, + docxFunction + "@" + value, + firstName + examName + processedValue); } } else { System.out.println("文本框中没有 Anchor 或 Inline 对象"); diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java index 61ea2683..40785249 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/paragraph/Paragraphs.java @@ -148,7 +148,8 @@ public class Paragraphs { PPr pPr = paragraph.getPPr(); if (pPr != null && pPr.getSpacing() != null) { if (pPr.getSpacing().getBeforeLines()!=null){ - return pPr.getSpacing().getBeforeLines().toString(); + double lines = pPr.getSpacing().getBeforeLines().intValue() / 100.0; + return String.format("%.1f行", lines); } } if (pPr != null && pPr.getPStyle() != null && stylePart != null) { @@ -156,7 +157,8 @@ public class Paragraphs { Style style = stylePart.getStyleById(styleId); if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) { PPrBase.Spacing spacing = style.getPPr().getSpacing(); - return spacing.getBeforeLines().toString(); + double lines = spacing.getBeforeLines().intValue() / 100.0; + return String.format("%.1f行", lines); } } return ""; @@ -166,7 +168,7 @@ public class Paragraphs { PPr pPr = paragraph.getPPr(); if (pPr != null && pPr.getSpacing() != null) { if(pPr.getSpacing().getBefore()!=null){ - return pPr.getSpacing().getBefore().toString(); + return String.valueOf(pPr.getSpacing().getBefore().intValue() / 20)+"磅"; } } if (pPr != null && pPr.getPStyle() != null && stylePart != null) { @@ -174,7 +176,7 @@ public class Paragraphs { Style style = stylePart.getStyleById(styleId); if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) { PPrBase.Spacing spacing = style.getPPr().getSpacing(); - return spacing.getBefore().toString(); + return String.valueOf(style.getPPr().getSpacing().getBefore().intValue() / 20)+"磅"; } } return ""; @@ -184,7 +186,7 @@ public class Paragraphs { PPr pPr = paragraph.getPPr(); if (pPr != null && pPr.getSpacing() != null) { if(pPr.getSpacing().getAfter()!=null){ - return pPr.getSpacing().getAfter().toString(); + return String.valueOf(pPr.getSpacing().getAfter().intValue() / 20)+"磅"; } } if (pPr != null && pPr.getPStyle() != null && stylePart != null) { @@ -192,7 +194,7 @@ public class Paragraphs { Style style = stylePart.getStyleById(styleId); if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) { PPrBase.Spacing spacing = style.getPPr().getSpacing(); - return spacing.getAfter().toString(); + return String.valueOf(style.getPPr().getSpacing().getAfter().intValue() / 20)+"磅"; } } return ""; @@ -202,8 +204,9 @@ public class Paragraphs { public static String getParagraphSpacingAfterLines(P paragraph, StyleDefinitionsPart stylePart, WordprocessingMLPackage wordMLPackage, NumberingDefinitionsPart ndp) { PPr pPr = paragraph.getPPr(); if (pPr != null && pPr.getSpacing() != null) { - if (pPr.getSpacing().getAfterLines()!=null){ - return pPr.getSpacing().getAfterLines().toString(); + if (pPr.getSpacing().getAfterLines() != null) { + double lines = pPr.getSpacing().getAfterLines().intValue() / 100.0; + return String.format("%.1f行", lines); } } if (pPr != null && pPr.getPStyle() != null && stylePart != null) { @@ -211,7 +214,8 @@ public class Paragraphs { Style style = stylePart.getStyleById(styleId); if (style != null && style.getPPr() != null && style.getPPr().getSpacing() != null) { PPrBase.Spacing spacing = style.getPPr().getSpacing(); - return spacing.getAfterLines().toString(); + double lines = spacing.getAfterLines().intValue() / 100.0; + return String.format("%.1f行", lines); } } return ""; diff --git a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java index 789a9fc9..58d52051 100644 --- a/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java +++ b/exam-module-judgement/exam-module-judgement-biz/src/main/java/pc/exam/pp/module/judgement/utils/wps_word/docx4j/section/SectionPage.java @@ -21,6 +21,7 @@ import org.docx4j.vml.CTFill; import org.docx4j.wml.*; import org.docx4j.wml.CTBackground; import org.docx4j.wml.CTBorder; +import org.docx4j.wml.CTColumn; import org.docx4j.wml.CTColumns; import org.docx4j.wml.CTDocGrid; import org.docx4j.wml.CTShd; @@ -1360,7 +1361,7 @@ public class SectionPage { Pattern pattern = Pattern.compile("fillcolor=\"#([0-9a-fA-F]{6})\""); Matcher matcher = pattern.matcher(vmlXml); if (matcher.find()) { - return "#" + matcher.group(1).toUpperCase(); + return ColorUtils.getChineseColorName(matcher.group(1).toUpperCase()) ; } return null; }