From 816e5b54488621cf3bf57b770641f167190b5b43 Mon Sep 17 00:00:00 2001
From: yuan <123@>
Date: 星期六, 11 七月 2026 17:09:08 +0800
Subject: [PATCH] feat: 添加采购订单导出Word文档功能

---
 src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java |  106 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 106 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
index 09d5d20..8b47a66 100644
--- a/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
+++ b/src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -20,6 +20,7 @@
 import com.ruoyi.basic.utils.FileUtil;
 import com.ruoyi.common.enums.FileNameType;
 import com.ruoyi.common.exception.base.BaseException;
+import com.ruoyi.common.core.text.Convert;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -51,6 +52,10 @@
 import com.ruoyi.sales.pojo.SalesLedger;
 import com.ruoyi.sales.pojo.SalesLedgerProduct;
 import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
+import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
@@ -60,8 +65,11 @@
 import org.springframework.web.multipart.MultipartFile;
 
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -647,4 +655,102 @@
         }
         return sb.toString();
     }
+
+    @Override
+    public void exportPurchaseOrderDocx(HttpServletResponse response, Long id) {
+        // 1. 鏌ヨ涓昏〃鏁版嵁
+        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectById(id);
+        if (purchaseLedger == null) {
+            throw new BaseException("閲囪喘鍙拌处涓嶅瓨鍦�");
+        }
+
+        // 2. 鏌ヨ浜у搧鍒楄〃
+        LambdaQueryWrapper<SalesLedgerProduct> productWrapper = new LambdaQueryWrapper<>();
+        productWrapper.eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId())
+                .eq(SalesLedgerProduct::getType, 2);
+        List<SalesLedgerProduct> products = salesLedgerProductMapper.selectList(productWrapper);
+
+        // 3. 鏌ヨ渚涘簲鍟嗕俊鎭�
+        SupplierManage supplier = null;
+        if (purchaseLedger.getSupplierId() != null) {
+            supplier = supplierManageMapper.selectById(purchaseLedger.getSupplierId());
+        }
+
+        // 4. 璁$畻鍚堣閲戦
+        BigDecimal totalAmount = BigDecimal.ZERO;
+        for (SalesLedgerProduct product : products) {
+            if (product.getTaxInclusiveTotalPrice() != null) {
+                totalAmount = totalAmount.add(product.getTaxInclusiveTotalPrice());
+            }
+        }
+
+        // 5. 鍔犺浇妯℃澘
+        InputStream inputStream = this.getClass().getResourceAsStream("/static/purchase-order-template.docx");
+        if (inputStream == null) {
+            throw new BaseException("閲囪喘璁㈠崟妯℃澘鏂囦欢涓嶅瓨鍦�");
+        }
+
+        // 6. 閰嶇疆 poi-tl锛堜骇鍝佸垪琛ㄤ娇鐢� HackLoopTableRenderPolicy锛宱nSameLine=true 鍥犱负鏍囩鍜屽瓧娈靛湪鍚屼竴琛岋級
+        Configure configure = Configure.builder()
+                .bind("productList", new HackLoopTableRenderPolicy(true))
+                .build();
+
+        // 7. 鏍煎紡鍖栨棩鏈�
+        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String orderDate = "";
+        String signDate = "";
+        if (purchaseLedger.getExecutionDate() != null) {
+            orderDate = dateFormatter.format(purchaseLedger.getExecutionDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+            signDate = orderDate;
+        } else if (purchaseLedger.getEntryDate() != null) {
+            orderDate = dateFormatter.format(purchaseLedger.getEntryDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+            signDate = orderDate;
+        }
+
+        // 8. 缁勮妯℃澘鏁版嵁
+        Map<String, Object> data = new HashMap<>();
+        data.put("orderDate", orderDate);
+        data.put("purchaseContractNumber", purchaseLedger.getPurchaseContractNumber() != null ? purchaseLedger.getPurchaseContractNumber() : "");
+        data.put("supplierName", purchaseLedger.getSupplierName() != null ? purchaseLedger.getSupplierName() : "");
+        data.put("contactUserName", supplier != null && supplier.getContactUserName() != null ? supplier.getContactUserName() : "");
+        data.put("contactPhone", supplier != null && supplier.getContactUserPhone() != null ? supplier.getContactUserPhone() : "");
+        data.put("fax", supplier != null && supplier.getCompanyPhone() != null ? supplier.getCompanyPhone() : "");
+        data.put("supplierAddress", supplier != null && supplier.getCompanyAddress() != null ? supplier.getCompanyAddress() : "");
+        // 缁欎骇鍝佸垪琛ㄦ坊鍔犲簭鍙�
+        List<Map<String, Object>> productList = new ArrayList<>();
+        int seq = 1;
+        for (SalesLedgerProduct p : products) {
+            Map<String, Object> map = new HashMap<>();
+            map.put("index", seq++);
+            map.put("productCategory", p.getProductCategory());
+            map.put("specificationModel", p.getSpecificationModel());
+            map.put("unit", p.getUnit());
+            map.put("quantity", p.getQuantity());
+            map.put("taxInclusiveUnitPrice", p.getTaxInclusiveUnitPrice());
+            map.put("taxInclusiveTotalPrice", p.getTaxInclusiveTotalPrice());
+            productList.add(map);
+        }
+        data.put("productList", productList);
+        data.put("totalAmount", totalAmount.setScale(2, RoundingMode.HALF_UP).toString());
+        data.put("totalAmountChinese", Convert.digitUppercase(totalAmount.doubleValue()));
+        data.put("signDate", signDate);
+
+        // 9. 娓叉煋妯℃澘骞惰緭鍑�
+        XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render(data);
+        try {
+            response.setContentType("application/msword");
+            String fileName = URLEncoder.encode("閲囪喘璁㈠崟", StandardCharsets.UTF_8);
+            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx");
+            OutputStream os = response.getOutputStream();
+            template.write(os);
+            os.flush();
+            os.close();
+            template.close();
+            inputStream.close();
+        } catch (Exception e) {
+            log.error("瀵煎嚭閲囪喘璁㈠崟澶辫触", e);
+            throw new BaseException("瀵煎嚭閲囪喘璁㈠崟澶辫触锛�" + e.getMessage());
+        }
+    }
 }

--
Gitblit v1.9.3