From 6441ad9f4dc3c1b2af1b9dad505c62ff75d69c4e Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 08 十月 2026 15:52:17 +0800
Subject: [PATCH] 项目重构

---
 inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java |  302 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 302 insertions(+), 0 deletions(-)

diff --git a/inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java b/inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java
new file mode 100644
index 0000000..9791a1e
--- /dev/null
+++ b/inspect-server/src/main/java/com/ruoyi/inspect/util/ReportSealLayoutUtil.java
@@ -0,0 +1,302 @@
+package com.ruoyi.inspect.util;
+
+import com.aspose.words.Document;
+import com.aspose.words.LayoutCollector;
+import com.aspose.words.LayoutEnumerator;
+import com.aspose.words.License;
+import com.aspose.words.Node;
+import com.aspose.words.NodeCollection;
+import com.aspose.words.NodeType;
+import com.aspose.words.PageSetup;
+import com.aspose.words.Paragraph;
+import com.aspose.words.RelativeHorizontalPosition;
+import com.aspose.words.RelativeVerticalPosition;
+import com.aspose.words.SaveFormat;
+import com.aspose.words.Section;
+import com.aspose.words.Shape;
+import com.aspose.words.ShapeType;
+import com.aspose.words.WrapType;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 灏嗘姤鍛婁腑鐨勫嵃绔犳敼涓烘诞鍔ㄥ浘鐗囷紝閬垮厤鍥剧墖鍙備笌姝f枃琛岄珮璁$畻鑰屾敼鍙樺師鎶ュ憡鍒嗛〉銆�
+ */
+public final class ReportSealLayoutUtil {
+
+    private static final double MA_LEFT = 30D;
+    private static final double MA_TOP = 30D;
+    private static final double MA_MAX_WIDTH = 90D;
+    private static final double MA_MAX_HEIGHT = 80D;
+    private static final double REPORT_MAX_WIDTH = 105D;
+    private static final double REPORT_MAX_HEIGHT = 105D;
+    private static final double LAST_PAGE_MAX_WIDTH = 110D;
+    private static final double LAST_PAGE_MAX_HEIGHT = 110D;
+    private static final double POSITION_GAP = 14D;
+
+    private ReportSealLayoutUtil() {
+    }
+
+    public static void apply(String wordPath, String reportSealPath, String maSealPath) throws Exception {
+        applyAsposeLicense();
+        Document document = new Document(wordPath);
+        byte[] reportSealBytes = readImage(reportSealPath);
+        byte[] maSealBytes = readImage(maSealPath);
+
+        if (reportSealBytes != null) {
+            removeMatchingImages(document, reportSealBytes);
+            document.updatePageLayout();
+            addCoverReportSeal(document, reportSealPath);
+            addConclusionReportSeal(document, reportSealPath);
+            addLastPageReportSeal(document, reportSealPath);
+        }
+        if (maSealBytes != null) {
+            removeMatchingImages(document, maSealBytes);
+            document.updatePageLayout();
+            // reportSeal 涓� maSeal 鍙兘閫夋嫨鍚屼竴寮犲浘鐗囷紝绉婚櫎鍚庨渶瑕佹仮澶嶄笁涓姤鍛婄珷浣嶇疆銆�
+            if (reportSealBytes != null && Arrays.equals(reportSealBytes, maSealBytes)) {
+                addCoverReportSeal(document, reportSealPath);
+                addConclusionReportSeal(document, reportSealPath);
+                addLastPageReportSeal(document, reportSealPath);
+            }
+            addFirstPageMaSeal(document, maSealPath);
+        }
+
+        document.updatePageLayout();
+        document.save(wordPath, SaveFormat.DOCX);
+    }
+
+    private static void applyAsposeLicense() throws Exception {
+        try (InputStream inputStream = ReportSealLayoutUtil.class.getResourceAsStream("/lib/license.xml")) {
+            if (inputStream == null) {
+                throw new IllegalStateException("鏈壘鍒� Aspose 鎺堟潈鏂囦欢");
+            }
+            License license = new License();
+            license.setLicense(inputStream);
+            if (!license.getIsLicensed()) {
+                throw new IllegalStateException("Aspose 鎺堟潈楠岃瘉澶辫触");
+            }
+        }
+    }
+
+    private static byte[] readImage(String imagePath) throws Exception {
+        if (imagePath == null || imagePath.trim().isEmpty()) {
+            return null;
+        }
+        Path path = java.nio.file.Paths.get(imagePath);
+        return Files.isRegularFile(path) ? Files.readAllBytes(path) : null;
+    }
+
+    private static void removeMatchingImages(Document document, byte[] imageBytes) throws Exception {
+        for (Shape shape : imageShapes(document)) {
+            if (sameImage(shape, imageBytes)) {
+                shape.remove();
+            }
+        }
+    }
+
+    private static void addFirstPageMaSeal(Document document, String imagePath) throws Exception {
+        Paragraph anchor = firstBodyParagraph(document);
+        double[] size = fitImage(imagePath, MA_MAX_WIDTH, MA_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft(MA_LEFT);
+        shape.setTop(MA_TOP);
+        anchor.appendChild(shape);
+    }
+
+    private static void addCoverReportSeal(Document document, String imagePath) throws Exception {
+        Paragraph anchor = firstBodyParagraph(document);
+        PageSetup pageSetup = document.getFirstSection().getPageSetup();
+        double[] size = fitImage(imagePath, REPORT_MAX_WIDTH, REPORT_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft(pageSetup.getLeftMargin() + 20D);
+        shape.setTop(pageSetup.getPageHeight() - pageSetup.getBottomMargin()
+                - size[1] - POSITION_GAP);
+        shape.setBehindText(true);
+        anchor.appendChild(shape);
+    }
+
+    private static void addConclusionReportSeal(Document document, String imagePath) throws Exception {
+        document.updatePageLayout();
+        LayoutCollector collector = new LayoutCollector(document);
+        Paragraph anchor = findBodyParagraphContaining(document, "鐩栫珷", collector, null);
+        if (anchor == null) {
+            return;
+        }
+        Rectangle2D rectangle = getLayoutRectangle(document, collector, anchor);
+        Section section = (Section) anchor.getAncestor(NodeType.SECTION);
+        PageSetup pageSetup = section.getPageSetup();
+        int page = collector.getStartPageIndex(anchor);
+        Paragraph placementAnchor = findPageBodyAnchor(document, collector, page);
+        if (placementAnchor == null) {
+            placementAnchor = anchor;
+        }
+        double[] size = fitImage(imagePath, REPORT_MAX_WIDTH, REPORT_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft((pageSetup.getPageWidth() - size[0]) / 2D);
+        double preferredTop = rectangle == null
+                ? pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1] - 120D
+                : rectangle.getY() - size[1] + rectangle.getHeight() / 2D;
+        shape.setTop(clamp(preferredTop,
+                pageSetup.getTopMargin(),
+                pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1]));
+        // 缁撹绔犱綅浜庤〃鏍煎崟鍏冩牸鍐咃紝蹇呴』缃簬鏂囧瓧涓婃柟锛屽惁鍒欎細琚崟鍏冩牸搴曠汗閬綇銆�
+        shape.setBehindText(false);
+        placementAnchor.appendChild(shape);
+    }
+
+    private static void addLastPageReportSeal(Document document, String imagePath) throws Exception {
+        int lastPage = document.getPageCount();
+        LayoutCollector collector = new LayoutCollector(document);
+        Paragraph anchor = findLastPageAnchor(document, collector, lastPage);
+        if (anchor == null) {
+            return;
+        }
+        Section section = (Section) anchor.getAncestor(NodeType.SECTION);
+        PageSetup pageSetup = section.getPageSetup();
+        double[] size = fitImage(imagePath, LAST_PAGE_MAX_WIDTH, LAST_PAGE_MAX_HEIGHT);
+        Shape shape = createFloatingImage(document, imagePath, size[0], size[1]);
+        shape.setLeft((pageSetup.getPageWidth() - size[0]) / 2D);
+        Rectangle2D rectangle = getLayoutRectangle(document, collector, anchor);
+        double preferredTop = rectangle == null
+                ? pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1] - POSITION_GAP
+                : rectangle.getY() + rectangle.getHeight() + POSITION_GAP;
+        shape.setTop(clamp(preferredTop,
+                pageSetup.getTopMargin(),
+                pageSetup.getPageHeight() - pageSetup.getBottomMargin() - size[1]));
+        shape.setBehindText(true);
+        anchor.appendChild(shape);
+    }
+
+    private static Shape createFloatingImage(Document document, String imagePath,
+                                              double width, double height) throws Exception {
+        Shape shape = new Shape(document, ShapeType.IMAGE);
+        shape.getImageData().setImage(imagePath);
+        shape.setWidth(width);
+        shape.setHeight(height);
+        shape.setWrapType(WrapType.NONE);
+        shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
+        shape.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
+        shape.setAllowOverlap(true);
+        return shape;
+    }
+
+    private static Paragraph firstBodyParagraph(Document document) {
+        Paragraph paragraph = document.getFirstSection().getBody().getFirstParagraph();
+        if (paragraph != null) {
+            return paragraph;
+        }
+        return document.getFirstSection().getBody().appendParagraph("");
+    }
+
+    private static Paragraph findLastPageAnchor(Document document, LayoutCollector collector, int lastPage)
+            throws Exception {
+        Paragraph fallback = null;
+        NodeCollection paragraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
+        for (int i = paragraphs.getCount() - 1; i >= 0; i--) {
+            Paragraph paragraph = (Paragraph) paragraphs.get(i);
+            if (paragraph.getAncestor(NodeType.BODY) == null) {
+                continue;
+            }
+            if (collector.getStartPageIndex(paragraph) != lastPage) {
+                continue;
+            }
+            if (fallback == null) {
+                fallback = paragraph;
+            }
+            if (paragraph.getText().contains("鎶ュ憡缁撴潫")) {
+                return paragraph;
+            }
+        }
+        return fallback;
+    }
+
+    private static Paragraph findBodyParagraphContaining(Document document, String text,
+                                                          LayoutCollector collector, Integer page)
+            throws Exception {
+        NodeCollection paragraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
+        for (int i = 0; i < paragraphs.getCount(); i++) {
+            Paragraph paragraph = (Paragraph) paragraphs.get(i);
+            if (paragraph.getAncestor(NodeType.BODY) == null || !paragraph.getText().contains(text)) {
+                continue;
+            }
+            if (page == null || collector.getStartPageIndex(paragraph) == page) {
+                return paragraph;
+            }
+        }
+        return null;
+    }
+
+    private static Paragraph findPageBodyAnchor(Document document, LayoutCollector collector, int page)
+            throws Exception {
+        NodeCollection paragraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
+        for (int i = 0; i < paragraphs.getCount(); i++) {
+            Paragraph paragraph = (Paragraph) paragraphs.get(i);
+            if (paragraph.getAncestor(NodeType.BODY) == null
+                    || paragraph.getAncestor(NodeType.CELL) != null) {
+                continue;
+            }
+            if (collector.getStartPageIndex(paragraph) == page) {
+                return paragraph;
+            }
+        }
+        return null;
+    }
+
+    private static Rectangle2D getLayoutRectangle(Document document, LayoutCollector collector,
+                                                   Paragraph paragraph) throws Exception {
+        Object entity = collector.getEntity(paragraph);
+        if (entity == null) {
+            NodeCollection runs = paragraph.getChildNodes(NodeType.RUN, true);
+            for (int i = 0; i < runs.getCount() && entity == null; i++) {
+                entity = collector.getEntity(runs.get(i));
+            }
+        }
+        if (entity == null) {
+            return null;
+        }
+        LayoutEnumerator enumerator = new LayoutEnumerator(document);
+        enumerator.setCurrent(entity);
+        return enumerator.getRectangle();
+    }
+
+    private static double clamp(double value, double min, double max) {
+        return Math.max(min, Math.min(value, max));
+    }
+
+    private static List<Shape> imageShapes(Document document) throws Exception {
+        List<Shape> result = new ArrayList<>();
+        NodeCollection nodes = document.getChildNodes(NodeType.SHAPE, true);
+        for (int i = 0; i < nodes.getCount(); i++) {
+            Shape shape = (Shape) nodes.get(i);
+            if (shape.hasImage()) {
+                result.add(shape);
+            }
+        }
+        return result;
+    }
+
+    private static boolean sameImage(Shape shape, byte[] imageBytes) throws Exception {
+        return Arrays.equals(shape.getImageData().toByteArray(), imageBytes);
+    }
+
+    private static double[] fitImage(String imagePath, double maxWidth, double maxHeight) throws Exception {
+        BufferedImage image = ImageIO.read(new ByteArrayInputStream(Files.readAllBytes(
+                java.nio.file.Paths.get(imagePath))));
+        if (image == null || image.getWidth() <= 0 || image.getHeight() <= 0) {
+            return new double[]{maxWidth, maxHeight};
+        }
+        double scale = Math.min(maxWidth / image.getWidth(), maxHeight / image.getHeight());
+        return new double[]{image.getWidth() * scale, image.getHeight() * scale};
+    }
+
+}

--
Gitblit v1.9.3