From e482e7d9d40b52c9ed3d2621d87b575c18a7fda0 Mon Sep 17 00:00:00 2001 From: lcj <2331845269@qq.com> Date: Tue, 19 Aug 2025 15:43:22 +0800 Subject: [PATCH] =?UTF-8?q?[add]=20=E7=89=A9=E8=B5=84=E9=87=87=E8=B4=AD?= =?UTF-8?q?=E8=81=94=E7=B3=BB=E5=8D=95=E8=AF=A6=E6=83=85=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/物资采购联系单模版.docx | Bin 19788 -> 19654 bytes .../controller/BusPurchaseDocController.java | 12 ++ .../cailiaoshebei/controller/constant.java | 22 +++ .../service/IBusPurchaseDocService.java | 15 ++ .../impl/BusPurchaseDocServiceImpl.java | 136 +++++++++++++----- .../documentOperations/WordToPdfToImg.java | 72 ++++++++-- 6 files changed, 211 insertions(+), 46 deletions(-) diff --git a/xinnengyuan/ruoyi-admin/src/main/resources/template/物资采购联系单模版.docx b/xinnengyuan/ruoyi-admin/src/main/resources/template/物资采购联系单模版.docx index 892087aca212a812fb405ddbc6d3db3a42a86652..f0785a2ab532a163cce6c8c38139dd5d6635637c 100644 GIT binary patch delta 14827 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 JBK@C~{}1`uj8y;t delta 14979 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 getPic(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok("操作成功", busPurchaseDocService.queryPicBase64ById(id)); + } + /** * 新增物资-采购联系单 */ diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/controller/constant.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/controller/constant.java index 5964bab9..224fcc33 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/controller/constant.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/controller/constant.java @@ -1,5 +1,10 @@ package org.dromara.cailiaoshebei.controller; +import org.dromara.cailiaoshebei.domain.BusPurchaseDoc; +import org.dromara.common.core.utils.DateUtils; + +import java.text.SimpleDateFormat; + /** * @Author 铁憨憨 * @Date 2025/8/8 11:15 @@ -10,5 +15,22 @@ public class constant { public static final String MaterialsPlans = "materialsPlans"; //计划 public static final String BatchRequirements = "batchRequirements"; //需求 public static final String EquipmentOrdering = "equipmentOrdering"; //订货 + public static final String PURCHASE_DOC_FILE_URL = "docs/purchase/doc/"; // 采购联系单文件路径 public static final String PURCHASE_DOC_TEMPLATE_PATH = "template/物资采购联系单模版.docx"; // 采购联系单文件路径 + + /** + * 获取物资采购联系单文件名 + */ + public static String getBusPurchaseDocFileUrl(BusPurchaseDoc purchaseDoc) { + String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(purchaseDoc.getUpdateTime()); + return String.format("%s%s/%s", PURCHASE_DOC_FILE_URL, purchaseDoc.getId(), timestamp); + } + + /** + * 获取物资采购联系单文件名 + */ + public static String getBusPurchaseDocFileName(BusPurchaseDoc purchaseDoc) { + String createDate = DateUtils.formatDate(purchaseDoc.getCreateTime()); + return String.format("物资采购联系单(%s).docx", createDate); + } } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/IBusPurchaseDocService.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/IBusPurchaseDocService.java index 1a03bb74..6ff7307c 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/IBusPurchaseDocService.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/IBusPurchaseDocService.java @@ -76,10 +76,25 @@ public interface IBusPurchaseDocService extends IService { */ void create(Long id, HashMap map); + /** + * 创建Word + * + * @param purchaseDoc 采购联系单对象 + */ + void createWord(BusPurchaseDoc purchaseDoc); + /** * 根据主键导出Word * * @param id 主键id */ void exportWordById(Long id, HttpServletResponse response); + + /** + * 根据主键查询详情图片base64 + * + * @param id 主键id + * @return 详情图片base64 + */ + String queryPicBase64ById(Long id); } diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusPurchaseDocServiceImpl.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusPurchaseDocServiceImpl.java index 3fa9fa6d..f5cc1834 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusPurchaseDocServiceImpl.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/cailiaoshebei/service/impl/BusPurchaseDocServiceImpl.java @@ -10,10 +10,10 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy; -import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.docx4j.openpackaging.exceptions.Docx4JException; import org.dromara.cailiaoshebei.controller.constant; import org.dromara.cailiaoshebei.domain.BusMaterialbatchdemandplan; import org.dromara.cailiaoshebei.domain.BusPlanDocAssociation; @@ -36,21 +36,24 @@ import org.dromara.common.core.enums.BusinessStatusEnum; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.oss.exception.OssException; +import org.dromara.common.utils.documentOperations.WordToPdfToImg; +import org.dromara.project.domain.BusProject; +import org.dromara.project.service.IBusProjectService; import org.springframework.beans.BeanUtils; import org.springframework.context.event.EventListener; -import org.springframework.http.MediaType; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.math.BigDecimal; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -75,6 +78,9 @@ public class BusPurchaseDocServiceImpl extends ServiceImpl items = new ArrayList<>(); + List planDocAssociationList = planDocAssociationService.lambdaQuery() + .eq(BusPlanDocAssociation::getDocId, purchaseDoc.getId()) + .list(); + if (CollUtil.isNotEmpty(planDocAssociationList)) { + List planIds = planDocAssociationList.stream().map(BusPlanDocAssociation::getPlanId).toList(); + items = materialbatchdemandplanService.listByIds(planIds); + } + BusPurchaseDocWordDto data = this.getReplacementDto(purchaseDoc, items); + // 生成文件 + try (InputStream is = getClass().getClassLoader().getResourceAsStream(constant.PURCHASE_DOC_TEMPLATE_PATH)) { + if (is == null) { + throw new ServiceException("模板文件不存在"); + } + LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy(); + Configure config = Configure.builder().bind("items", hackLoopTableRenderPolicy).build(); + XWPFTemplate template = XWPFTemplate.compile(is, config); + template.render(data); + // 创建目标目录 + if (!Files.exists(targetDir)) { + Files.createDirectories(targetDir); + } + // 组合目标文件名 + String fileName = constant.getBusPurchaseDocFileName(purchaseDoc); + // 保存修改后的文件 + try (FileOutputStream fos = new FileOutputStream(targetDir.resolve(fileName).toFile())) { + template.write(fos); + } + template.close(); + } catch (IOException e) { + throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + } + } + } + /** * 根据主键导出Word * @@ -271,38 +333,33 @@ public class BusPurchaseDocServiceImpl extends ServiceImpl items = new ArrayList<>(); - List planDocAssociationList = planDocAssociationService.lambdaQuery() - .eq(BusPlanDocAssociation::getDocId, id) - .list(); - if (CollUtil.isNotEmpty(planDocAssociationList)) { - List planIds = planDocAssociationList.stream().map(BusPlanDocAssociation::getPlanId).toList(); - items = materialbatchdemandplanService.listByIds(planIds); - } - BusPurchaseDocWordDto data = this.getReplacementDto(purchaseDoc, items); - // 生成文件 - try (InputStream is = getClass().getClassLoader().getResourceAsStream(constant.PURCHASE_DOC_TEMPLATE_PATH)) { - if (is == null) { - throw new ServiceException("模板文件不存在"); - } - LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy(); - Configure config = Configure.builder().bind("items", hackLoopTableRenderPolicy).build(); - XWPFTemplate template = XWPFTemplate.compile(is, config); - template.render(data); + // 创建Word + this.createWord(purchaseDoc); + } - // 设置响应头,通知浏览器下载 Word 文件 - String fileName = URLEncoder.encode("物料领料单_" + id + ".docx", StandardCharsets.UTF_8); - response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); - response.setHeader("Content-Disposition", "attachment; filename=" + fileName); - try (ServletOutputStream out = response.getOutputStream()) { - template.write(out); // 将文件写入响应流 - out.flush(); - } - template.close(); - } catch (IOException e) { - throw new OssException("生成Word文件失败,错误信息: " + e.getMessage()); + /** + * 根据主键查询详情图片base64 + * + * @param id 主键id + * @return 详情图片base64 + */ + @Override + public String queryPicBase64ById(Long id) { + BusPurchaseDoc purchaseDoc = this.getById(id); + if (purchaseDoc == null) { + throw new ServiceException("物料领料单不存在"); } + this.createWord(purchaseDoc); + String filePath = constant.getBusPurchaseDocFileUrl(purchaseDoc) + "/"; + String fileName = constant.getBusPurchaseDocFileName(purchaseDoc); + File file = new File(filePath + fileName); + String base64; + try (FileInputStream inputStream = new FileInputStream(file)) { + base64 = wordToPdfToImg.wordToImgBase64(inputStream); + } catch (IOException | Docx4JException e) { + throw new ServiceException("获取物资采购联系单详情失败,错误信息: " + e.getMessage()); + } + return "data:image/png;base64," + base64; } /** @@ -315,11 +372,14 @@ public class BusPurchaseDocServiceImpl extends ServiceImpl items) { BusPurchaseDocWordDto dto = new BusPurchaseDocWordDto(); BeanUtils.copyProperties(purchaseDoc, dto); + // 获取项目名称 + BusProject project = projectService.getById(purchaseDoc.getProjectId()); + dto.setProjectName(project != null ? project.getProjectName() : ""); // 日期转换 LocalDate arrivalDate = purchaseDoc.getArrivalDate(); - dto.setArrivalDate(arrivalDate.format(DateTimeFormatter.ofPattern("yyyy 年 MM 月 dd 日"))); + dto.setArrivalDate(arrivalDate != null ? arrivalDate.format(DateTimeFormatter.ofPattern("yyyy 年 MM 月 dd 日")) : ""); LocalDate signingDate = purchaseDoc.getSigningDate(); - dto.setSigningDate(signingDate.format(DateTimeFormatter.ofPattern("yyyy 年 MM 月 dd 日"))); + dto.setSigningDate(signingDate != null ? signingDate.format(DateTimeFormatter.ofPattern("yyyy 年 MM 月 dd 日")) : ""); // 明细项信息 if (CollUtil.isNotEmpty(items)) { List dtoItems = new ArrayList<>(); diff --git a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java index a0891668..e01e27db 100644 --- a/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java +++ b/xinnengyuan/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/common/utils/documentOperations/WordToPdfToImg.java @@ -15,11 +15,9 @@ import org.springframework.web.multipart.MultipartFile; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.util.ArrayList; +import java.util.Base64; import java.util.List; import static org.dromara.common.constant.MinioPathConstant.ContactNotice; @@ -33,16 +31,18 @@ public class WordToPdfToImg { /** * wordToImg 根据file生成缩略图(路径) * - * @param file 文件 + * @param file 文件 + * @param filePath 文件路径 + * @param fileName 文件名 */ - public String wordToImg(MultipartFile file) throws Docx4JException, IOException { - String mergedPath = "output/merged.png"; + public String wordToImg(InputStream file, String filePath, String fileName) throws Docx4JException, IOException { + String mergedPath = filePath + "/" + fileName + ".png"; // ✅ 1. Word → PDF(内存) ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); // 直接走路径 // WordprocessingMLPackage wordML = WordprocessingMLPackage.load(new File(docxPath)); // 直接走文件,word不落地 - WordprocessingMLPackage wordML = WordprocessingMLPackage.load(file.getInputStream()); + WordprocessingMLPackage wordML = WordprocessingMLPackage.load(file); Docx4J.toPDF(wordML, pdfOut); // ✅ 2. PDF → 各页 PNG List pages = new ArrayList<>(); @@ -73,6 +73,62 @@ public class WordToPdfToImg { return mergedPath; } + /** + * wordToImg 根据 InputStream 生成缩略图(Base64) + * + * @param file word 文件流 + * @return base64 图片字符串(png 格式) + */ + public String wordToImgBase64(InputStream file) throws Docx4JException, IOException { + // ✅ 1. Word → PDF(内存) + ByteArrayOutputStream pdfOut = new ByteArrayOutputStream(); + WordprocessingMLPackage wordML = WordprocessingMLPackage.load(file); + Docx4J.toPDF(wordML, pdfOut); + + // ✅ 2. PDF → 各页 PNG + List pages = new ArrayList<>(); + try (PDDocument pdf = PDDocument.load(new ByteArrayInputStream(pdfOut.toByteArray()))) { + PDFRenderer renderer = new PDFRenderer(pdf); + for (int i = 0; i < pdf.getNumberOfPages(); i++) { + BufferedImage img = renderer.renderImageWithDPI(i, 144); // 144 DPI,清晰度可调 + pages.add(img); + } + } + + // ✅ 3. 合成所有页为一张长图 + int totalHeight = pages.stream().mapToInt(BufferedImage::getHeight).sum(); + int maxWidth = pages.stream().mapToInt(BufferedImage::getWidth).max().orElse(0); + BufferedImage merged = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_RGB); + + Graphics2D g = merged.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, maxWidth, totalHeight); + + int y = 0; + for (BufferedImage img : pages) { + g.drawImage(img, 0, y, null); + y += img.getHeight(); + } + g.dispose(); + + // ✅ 4. 转换为 Base64 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ImageIO.write(merged, "png", out); + byte[] bytes = out.toByteArray(); + + return Base64.getEncoder().encodeToString(bytes); + } + + /** + * wordToImg 根据file生成缩略图(路径) + * + * @param file 文件 + * @param filePath 文件路径 + * @param fileName 文件名 + */ + public String wordToImg(MultipartFile file, String filePath, String fileName) throws Docx4JException, IOException { + return this.wordToImg(file.getInputStream(), filePath, fileName); + } /** * convertWordToImage 根据MultipartFile转成缩略图 并上传至minio