From 940fe11624d4ee7b37bb9174401160a467f5a264 Mon Sep 17 00:00:00 2001
From: chenhao <852066789@qq.com>
Date: Mon, 22 Sep 2025 16:37:59 +0800
Subject: [PATCH] =?UTF-8?q?feat(project):=20=E5=AE=9E=E7=8E=B0=E5=90=88?=
=?UTF-8?q?=E5=90=8C=E6=A8=A1=E6=9D=BF=E5=AF=BC=E5=87=BA=E5=8A=9F=E8=83=BD?=
=?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E9=A1=B5=E9=9D=A2=E4=BA=A4=E4=BA=92?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在项目订单信息中新增“partnerAddress”字段,并在 Mapper 中关联查询该字段
- 增加导出填充订单信息的合同模板接口与实现逻辑,支持根据 orderId 动态生成 docx 文件
- 修改前端页面:
- 当 POC 选择“否”时,默认选中第一个 tab(工作进度)
- 注释掉订单编辑页中的“合同信息”tab 项
- 调整导出逻辑,通过 orderId 获取数据并传递给后端生成文件
- 完善产品信息实体类及 Mapper,增加 vendorName 字段支持- 优化前端下载请求逻辑,使用 orderId 替代固定文件名方式
```
---
.../resources/templates/project/info/add.html | 5 +
.../templates/project/info/edit.html | 5 +
.../templates/project/order/add.html | 2 +-
.../templates/project/order/edit.html | 5 +-
.../ProjectOrderInfoController.java | 36 +-
.../ruoyi/sip/domain/ProjectOrderInfo.java | 1 +
.../ruoyi/sip/domain/ProjectProductInfo.java | 1 +
.../sip/service/IProjectOrderInfoService.java | 7 +
.../impl/ProjectOrderInfoServiceImpl.java | 333 ++++++++++++++++++
.../mapper/sip/ProjectOrderInfoMapper.xml | 2 +-
.../mapper/sip/ProjectProductInfoMapper.xml | 3 +-
11 files changed, 387 insertions(+), 13 deletions(-)
diff --git a/ruoyi-admin/src/main/resources/templates/project/info/add.html b/ruoyi-admin/src/main/resources/templates/project/info/add.html
index 54485058..2b9bf393 100644
--- a/ruoyi-admin/src/main/resources/templates/project/info/add.html
+++ b/ruoyi-admin/src/main/resources/templates/project/info/add.html
@@ -357,6 +357,11 @@
let val = $('#poc').val();
if (val==='0'){
$('#pocLogTab').attr('style','display:none')
+ // 当POC=否时,选中第一个tab页(工作进度)
+ $('.layui-tab-title li').removeClass('layui-this');
+ $('.layui-tab-title li:first').addClass('layui-this');
+ $('.layui-tab-content .layui-tab-item').removeClass('layui-show');
+ $('.layui-tab-content .layui-tab-item:first').addClass('layui-show');
}else{
$('#pocLogTab').attr('style','display:inline')
}
diff --git a/ruoyi-admin/src/main/resources/templates/project/info/edit.html b/ruoyi-admin/src/main/resources/templates/project/info/edit.html
index c1327fbd..c2a84b87 100644
--- a/ruoyi-admin/src/main/resources/templates/project/info/edit.html
+++ b/ruoyi-admin/src/main/resources/templates/project/info/edit.html
@@ -421,6 +421,11 @@
console.log(val)
if (val==='0'){
$('#pocLogTab').attr('style','display:none')
+ // 当POC=否时,选中第一个tab页(工作进度)
+ $('.layui-tab-title li').removeClass('layui-this');
+ $('.layui-tab-title li:first').addClass('layui-this');
+ $('.layui-tab-content .layui-tab-item').removeClass('layui-show');
+ $('.layui-tab-content .layui-tab-item:first').addClass('layui-show');
}else{
$('#pocLogTab').attr('style','display:inline')
}
diff --git a/ruoyi-admin/src/main/resources/templates/project/order/add.html b/ruoyi-admin/src/main/resources/templates/project/order/add.html
index 344787c5..7fd73251 100644
--- a/ruoyi-admin/src/main/resources/templates/project/order/add.html
+++ b/ruoyi-admin/src/main/resources/templates/project/order/add.html
@@ -337,7 +337,7 @@
diff --git a/ruoyi-admin/src/main/resources/templates/project/order/edit.html b/ruoyi-admin/src/main/resources/templates/project/order/edit.html
index 71e3f414..5c537cc8 100644
--- a/ruoyi-admin/src/main/resources/templates/project/order/edit.html
+++ b/ruoyi-admin/src/main/resources/templates/project/order/edit.html
@@ -1165,14 +1165,15 @@
function downloadTem() {
var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象
+ let orderId= $('[name="id"]').val()
if (!$('[name="orderChannel"]').val()) {
$.modal.alertWarning("请先选择下单通路");
return
}
if ($('[name="orderChannel"]').val() == 1) {
- window.location.href = prefix + "/contract/export?fileName=文件111.xlsx"
+ window.location.href = prefix + "/contract/export?orderId="+orderId
} else {
- window.location.href = prefix + "/contract/export?fileName=文件222.xlsx"
+ window.location.href = prefix + "/contract/export?orderId="+orderId
}
$.modal.closeLoading()
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/ProjectOrderInfoController.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/ProjectOrderInfoController.java
index 133078c9..9d6a2e66 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/ProjectOrderInfoController.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/controller/ProjectOrderInfoController.java
@@ -399,15 +399,35 @@ public class ProjectOrderInfoController extends BaseController
@GetMapping("/contract/export")
- public void contractExport(String fileName, HttpServletRequest request, HttpServletResponse response) {
+ public void contractExport(@RequestParam(required = false) String fileName,
+ @RequestParam(required = false) Long orderId,
+ HttpServletRequest request, HttpServletResponse response) {
try {
- // 本地资源路径
- String localPath = RuoYiConfig.getExcelTemplate();
- // 下载名称
- String downloadPath = localPath + File.separator + fileName;
- response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
- FileUtils.setAttachmentResponseHeader(response, fileName);
- FileUtils.writeBytes(downloadPath, response.getOutputStream());
+ if (orderId != null) {
+ // 获取订单信息
+ ProjectOrderInfo orderInfo = projectOrderInfoService.selectProjectOrderInfoById(orderId);
+ if (orderInfo == null) {
+ throw new ServiceException("订单信息不存在");
+ }
+ // 新逻辑:生成填充了订单信息的合同模板
+ byte[] fileBytes = projectOrderInfoService.exportContractTemplate(orderInfo);
+
+ // 设置响应头
+ response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ String downloadFileName = StringUtils.isEmpty(fileName) ? "合同模板_" + orderInfo.getProjectName() + ".docx" : fileName;
+ FileUtils.setAttachmentResponseHeader(response, downloadFileName);
+
+ // 写入响应流
+ response.getOutputStream().write(fileBytes);
+ response.getOutputStream().flush();
+ } else {
+ // 原逻辑:直接下载模板文件
+ String localPath = RuoYiConfig.getExcelTemplate();
+ String downloadPath = localPath + File.separator + (StringUtils.isEmpty(fileName) ? "orderDownloadTemplate.docx" : fileName);
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+ FileUtils.setAttachmentResponseHeader(response, StringUtils.isEmpty(fileName) ? "orderDownloadTemplate.docx" : fileName);
+ FileUtils.writeBytes(downloadPath, response.getOutputStream());
+ }
} catch (Exception e) {
log.error("下载文件失败", e);
}
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java
index 95d225e9..d893275f 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectOrderInfo.java
@@ -133,6 +133,7 @@ public class ProjectOrderInfo extends BaseEntity {
private String partnerCode;
@Excel(name = "进货商")
private String partnerName;
+ private String partnerAddress;
private String projectPartnerName;
private List
productCodeList;
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectProductInfo.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectProductInfo.java
index c251a49e..bda8f7bd 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectProductInfo.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/domain/ProjectProductInfo.java
@@ -71,6 +71,7 @@ public class ProjectProductInfo extends BaseEntity
// @Excel(name = "指导折扣")
private BigDecimal guidanceDiscount;
private String vendorCode;
+ private String vendorName;
/** 折扣 */
// @Excel(name = "折扣")
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java
index c1460839..4bc79ea2 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/IProjectOrderInfoService.java
@@ -89,4 +89,11 @@ public interface IProjectOrderInfoService
// Boolean foldOnFold(ProjectOrderInfo info);
List getOrderInfo(ApiDataQueryDto dto);
+
+ /**
+ * 导出合同模板,填充订单信息
+ * @param orderId 订单ID
+ * @return 填充后的文件字节数组
+ */
+ byte[] exportContractTemplate(ProjectOrderInfo orderInfo);
}
diff --git a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java
index a969d9d6..a9b040d7 100644
--- a/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java
+++ b/ruoyi-sip/src/main/java/com/ruoyi/sip/service/impl/ProjectOrderInfoServiceImpl.java
@@ -1,6 +1,9 @@
package com.ruoyi.sip.service.impl;
import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
@@ -8,6 +11,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
@@ -19,6 +23,7 @@ import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.alibaba.fastjson.JSON;
+import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
@@ -46,6 +51,7 @@ import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xwpf.usermodel.*;
import org.flowable.engine.ManagementService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
@@ -58,6 +64,8 @@ import com.ruoyi.common.core.text.Convert;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
+import java.io.*;
+import java.text.SimpleDateFormat;
import static com.ruoyi.common.utils.ShiroUtils.getSysUser;
import static com.ruoyi.sip.service.impl.ProjectInfoServiceImpl.*;
@@ -1273,4 +1281,329 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
log.error("处理订单审批通过失败,订单编号:{}", businessKey, e);
}
}
+
+ @Override
+ public byte[] exportContractTemplate( ProjectOrderInfo orderInfo) {
+ try {
+
+
+ // 加载模板文件 - 模板文件位于 ruoyi-admin/src/main/resources/wordTemplate/
+ String localPath = RuoYiConfig.getExcelTemplate() + File.separator + "orderDownloadTemplate.docx" ;
+ InputStream templateStream = Files.newInputStream(Paths.get(localPath));
+ if (templateStream == null) {
+ throw new ServiceException("模板文件不存在,请确认 wordTemplate/orderDownloadTemplate.docx 文件是否在资源目录中");
+ }
+ XWPFDocument document = new XWPFDocument(templateStream);
+
+ // 替换文档中的占位符
+ replaceTextInDocument(document, orderInfo);
+
+ // 将文档写入字节数组
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ document.write(baos);
+ document.close();
+ templateStream.close();
+
+ return baos.toByteArray();
+
+ } catch (Exception e) {
+ log.error("导出合同模板失败", e);
+ throw new ServiceException("导出合同模板失败: " + e.getMessage());
+ }
+ }
+
+ private void replaceTextInDocument(XWPFDocument document, ProjectOrderInfo orderInfo) {
+ // 替换段落中的文本
+ for (XWPFParagraph paragraph : document.getParagraphs()) {
+ replaceTextInParagraph(paragraph, orderInfo);
+ }
+
+ // 替换表格中的文本,并处理产品列表
+ for (XWPFTable table : document.getTables()) {
+ replaceProductTableContent(table, orderInfo);
+ for (XWPFTableRow row : table.getRows()) {
+ for (XWPFTableCell cell : row.getTableCells()) {
+ for (XWPFParagraph paragraph : cell.getParagraphs()) {
+ replaceTextInParagraph(paragraph, orderInfo);
+ }
+ }
+ }
+ }
+ }
+
+ private void replaceTextInParagraph(XWPFParagraph paragraph, ProjectOrderInfo orderInfo) {
+ String text = paragraph.getText();
+ if (text != null && text.contains("${")) {
+ // 创建替换映射
+ Map replacements = createReplacementMap(orderInfo);
+
+ // 替换文本
+ for (Map.Entry entry : replacements.entrySet()) {
+ String placeholder = "${" + entry.getKey() + "}";
+ if (text.contains(placeholder)) {
+ text = text.replace(placeholder, entry.getValue() != null ? entry.getValue() : "");
+ }
+ }
+
+ // 清除原有运行并设置新文本
+ for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
+ paragraph.removeRun(i);
+ }
+
+ XWPFRun run = paragraph.createRun();
+ run.setText(text);
+ }
+ }
+
+ private Map createReplacementMap(ProjectOrderInfo orderInfo) {
+ Map replacements = new HashMap<>();
+
+ // 基本订单信息
+ replacements.put("orderCode", orderInfo.getOrderCode());
+
+ replacements.put("projectName", orderInfo.getProjectName());
+
+ // 金额信息
+ replacements.put("shipmentAmount", orderInfo.getShipmentAmount() != null ? orderInfo.getShipmentAmount().toString() : "");
+ replacements.put("shipmentAmountChinese", orderInfo.getShipmentAmount() != null ?NumberChineseFormatter.format(orderInfo.getShipmentAmount().doubleValue(),true,true) : "");
+ BigDecimal shipmentAmountNotTax=BigDecimal.ZERO;
+ BigDecimal taxAmount=BigDecimal.ZERO;
+ if (orderInfo.getShipmentAmount() != null){
+ shipmentAmountNotTax = orderInfo.getShipmentAmount().divide(new BigDecimal("1.13"), 2, RoundingMode.HALF_UP);
+ taxAmount=orderInfo.getShipmentAmount().subtract(shipmentAmountNotTax);
+ }
+ replacements.put("shipmentAmountNotTax", shipmentAmountNotTax.toString());
+ replacements.put("taxAmount", taxAmount.toString());
+
+
+
+
+ // 日期信息
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
+
+ replacements.put("updateTime", orderInfo.getUpdateTime() != null ? dateFormat.format(orderInfo.getUpdateTime()) : "");
+
+
+ // 责任人信息
+ replacements.put("dutyName", orderInfo.getDutyName());
+
+ replacements.put("dutyPhone", orderInfo.getDutyPhone());
+
+
+
+ // 进货商信息
+ replacements.put("partnerName", orderInfo.getPartnerName());
+ replacements.put("partnerCode", orderInfo.getPartnerCode());
+ replacements.put("partnerEmail", orderInfo.getPartnerEmail());
+ replacements.put("partnerUserName", orderInfo.getPartnerUserName());
+ replacements.put("partnerPhone", orderInfo.getPartnerPhone());
+ replacements.put("partnerAddress", orderInfo.getPartnerAddress());
+
+
+
+
+
+ // 其他信息
+
+ replacements.put("supplier", orderInfo.getSupplier());
+ replacements.put("paymentMethod", orderInfo.getPaymentMethod());
+ replacements.put("paymentDescription", orderInfo.getPaymentDescription());
+ replacements.put("paymentRatio", orderInfo.getPaymentRatio() != null ? orderInfo.getPaymentRatio().toString() : "");
+ replacements.put("discountFold", orderInfo.getDiscountFold() != null ? orderInfo.getDiscountFold().toString() : "");
+ replacements.put("paymentMethodNum",(orderInfo.getPaymentMethod()!=null && orderInfo.getPaymentMethod().endsWith("1"))?"1":"3");
+ replacements.put("paymentDay",(orderInfo.getPaymentMethod()!=null && orderInfo.getPaymentMethod().endsWith("1"))?"3":"");
+
+
+
+
+ // 添加产品信息占位符
+ addProductReplacements(replacements, orderInfo);
+
+ return replacements;
+ }
+
+ private void addProductReplacements(Map replacements, ProjectOrderInfo orderInfo) {
+ // 软件产品信息
+ if (CollUtil.isNotEmpty(orderInfo.getSoftwareProjectProductInfoList())) {
+ for (int i = 0; i < orderInfo.getSoftwareProjectProductInfoList().size(); i++) {
+ ProjectProductInfo product = orderInfo.getSoftwareProjectProductInfoList().get(i);
+ String prefix = "software" + (i + 1);
+ addSingleProductReplacement(replacements, product, prefix);
+ }
+ }
+
+ // 硬件产品信息
+ if (CollUtil.isNotEmpty(orderInfo.getHardwareProjectProductInfoList())) {
+ for (int i = 0; i < orderInfo.getHardwareProjectProductInfoList().size(); i++) {
+ ProjectProductInfo product = orderInfo.getHardwareProjectProductInfoList().get(i);
+ String prefix = "hardware" + (i + 1);
+ addSingleProductReplacement(replacements, product, prefix);
+ }
+ }
+
+ // 维保产品信息
+ if (CollUtil.isNotEmpty(orderInfo.getMaintenanceProjectProductInfoList())) {
+ for (int i = 0; i < orderInfo.getMaintenanceProjectProductInfoList().size(); i++) {
+ ProjectProductInfo product = orderInfo.getMaintenanceProjectProductInfoList().get(i);
+ String prefix = "maintenance" + (i + 1);
+ addSingleProductReplacement(replacements, product, prefix);
+ }
+ }
+ }
+
+ private void addSingleProductReplacement(Map replacements, ProjectProductInfo product, String prefix) {
+ if (product == null) {
+ return;
+ }
+
+ replacements.put(prefix + "BomCode", product.getProductBomCode());
+ replacements.put(prefix + "Name", product.getProductName());
+ replacements.put(prefix + "Model", product.getModel());
+ replacements.put(prefix + "Code", product.getProductCode());
+ replacements.put(prefix + "Desc", product.getProductDesc());
+ replacements.put(prefix + "Quantity", product.getQuantity() != null ? product.getQuantity().toString() : "");
+ replacements.put(prefix + "CataloguePrice", product.getCataloguePrice() != null ? product.getCataloguePrice().toString() : "");
+ replacements.put(prefix + "CatalogueAllPrice", product.getCatalogueAllPrice() != null ? product.getCatalogueAllPrice().toString() : "");
+ replacements.put(prefix + "Price", product.getPrice() != null ? product.getPrice().toString() : "");
+ replacements.put(prefix + "AllPrice", product.getAllPrice() != null ? product.getAllPrice().toString() : "");
+ replacements.put(prefix + "AllPriceDisCount", product.getAllPriceDisCount() != null ? product.getAllPriceDisCount().toString() : "");
+ replacements.put(prefix + "GuidanceDiscount", product.getGuidanceDiscount() != null ? product.getGuidanceDiscount().toString() : "");
+ replacements.put(prefix + "VendorCode", product.getVendorCode());
+ replacements.put(prefix + "Discount", product.getDiscount() != null ? product.getDiscount().toString() : "");
+ replacements.put(prefix + "Type", product.getType());
+ replacements.put(prefix + "Value", product.getValue());
+ replacements.put(prefix + "TaxRate", product.getTaxRate() != null ? product.getTaxRate().toString() : "");
+ }
+
+ private void replaceProductTableContent(XWPFTable table, ProjectOrderInfo orderInfo) {
+ // 查找包含产品占位符的行(如 ${productList} 或 ${softwareList} 等)
+ for (int rowIndex = 0; rowIndex < table.getRows().size(); rowIndex++) {
+ XWPFTableRow row = table.getRow(rowIndex);
+ String rowText = getRowText(row);
+
+ // 检查是否包含产品列表占位符
+ if (rowText.contains("${softwareList}")) {
+ replaceProductListInTable(table, rowIndex, orderInfo.getSoftwareProjectProductInfoList(), "软件");
+ } else if (rowText.contains("${hardwareList}")) {
+ replaceProductListInTable(table, rowIndex, orderInfo.getHardwareProjectProductInfoList(), "硬件");
+ } else if (rowText.contains("${maintenanceList}")) {
+ replaceProductListInTable(table, rowIndex, orderInfo.getMaintenanceProjectProductInfoList(), "维保");
+ } else if (rowText.contains("${productList}")) {
+ // 处理所有产品的列表
+ List allProducts = new ArrayList<>();
+ if (CollUtil.isNotEmpty(orderInfo.getSoftwareProjectProductInfoList())) {
+ allProducts.addAll(orderInfo.getSoftwareProjectProductInfoList());
+ }
+ if (CollUtil.isNotEmpty(orderInfo.getHardwareProjectProductInfoList())) {
+ allProducts.addAll(orderInfo.getHardwareProjectProductInfoList());
+ }
+ if (CollUtil.isNotEmpty(orderInfo.getMaintenanceProjectProductInfoList())) {
+ allProducts.addAll(orderInfo.getMaintenanceProjectProductInfoList());
+ }
+ replaceProductListInTable(table, rowIndex, allProducts, "产品");
+ }
+ }
+ }
+
+ private String getRowText(XWPFTableRow row) {
+ StringBuilder text = new StringBuilder();
+ for (XWPFTableCell cell : row.getTableCells()) {
+ text.append(cell.getText()).append(" ");
+ }
+ return text.toString();
+ }
+
+ private void replaceProductListInTable(XWPFTable table, int templateRowIndex, List products, String productType) {
+ if (CollUtil.isEmpty(products)) {
+ // 如果没有产品,清空模板行
+ XWPFTableRow templateRow = table.getRow(templateRowIndex);
+ clearRow(templateRow);
+ return;
+ }
+
+ XWPFTableRow templateRow = table.getRow(templateRowIndex);
+
+ // 为每个产品创建一行
+ for (int i = 0; i < products.size(); i++) {
+ ProjectProductInfo product = products.get(i);
+ XWPFTableRow productRow;
+
+ if (i == 0) {
+ // 第一个产品使用模板行
+ productRow = templateRow;
+ } else {
+ // 后续产品插入新行
+ productRow = table.insertNewTableRow(templateRowIndex + i);
+ copyRowStyle(templateRow, productRow);
+ }
+
+ // 填充产品信息到行中
+ fillProductRow(productRow, product, i + 1);
+ }
+ }
+
+ private void clearRow(XWPFTableRow row) {
+ for (XWPFTableCell cell : row.getTableCells()) {
+ for (XWPFParagraph paragraph : cell.getParagraphs()) {
+ for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
+ paragraph.removeRun(i);
+ }
+ paragraph.createRun().setText("");
+ }
+ }
+ }
+
+ private void copyRowStyle(XWPFTableRow sourceRow, XWPFTableRow targetRow) {
+ // 确保目标行有足够的单元格
+ while (targetRow.getTableCells().size() < sourceRow.getTableCells().size()) {
+ targetRow.createCell();
+ }
+
+ // 复制每个单元格的样式
+ for (int i = 0; i < sourceRow.getTableCells().size(); i++) {
+ XWPFTableCell sourceCell = sourceRow.getCell(i);
+ XWPFTableCell targetCell = targetRow.getCell(i);
+
+ // 复制单元格文本和样式
+ for (XWPFParagraph sourcePara : sourceCell.getParagraphs()) {
+ XWPFParagraph targetPara = targetCell.addParagraph();
+ targetPara.setAlignment(sourcePara.getAlignment());
+ }
+ }
+ }
+
+ private void fillProductRow(XWPFTableRow row, ProjectProductInfo product, int index) {
+ List cells = row.getTableCells();
+
+ if (cells.size() >= 7) {
+ // 假设表格列顺序:序号、产品编码、产品名称、型号、数量、单价、总价
+ setCellText(cells.get(0), String.valueOf(index));
+ setCellText(cells.get(1), product.getVendorName());
+ setCellText(cells.get(2), product.getProductBomCode());
+ setCellText(cells.get(3), product.getProductDesc());
+ setCellText(cells.get(4), product.getModel());
+ setCellText(cells.get(5), product.getQuantity() != null ? product.getQuantity().toString() : "");
+ setCellText(cells.get(6), product.getPrice() != null ? product.getPrice().toString() : "");
+
+ setCellText(cells.get(7), product.getAllPrice() != null ? product.getAllPrice().toString() : "");
+
+ }
+ }
+
+ private void setCellText(XWPFTableCell cell, String text) {
+ // 清除原有内容
+ for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
+ if (i > 0) { // 保留第一个段落
+ cell.removeParagraph(i);
+ }
+ }
+
+ XWPFParagraph paragraph = cell.getParagraphs().get(0);
+ for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
+ paragraph.removeRun(i);
+ }
+
+ XWPFRun run = paragraph.createRun();
+ run.setText(text != null ? text : "");
+ }
}
diff --git a/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml b/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml
index fd1487ea..cd93cb84 100644
--- a/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml
+++ b/ruoyi-sip/src/main/resources/mapper/sip/ProjectOrderInfoMapper.xml
@@ -57,7 +57,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
t1.delivery_status,t1.sign_status,t1.outer_status,t1.approve_time,t1.payment_method,t1.payment_ratio,t1.payment_description
,t2.project_code,t2.project_name,t2.province,t2.customer_name,t2.customer_code,t2.industry_type,t2.bg_property,t2.agent_code,t2.estimated_order_time
,t2.customer_phone,t2.customer_user_name,t2.agent_code,t2.customer_code,t2.partner_name project_partner_name
- ,t3.partner_name,t3.level,t3.system_user_id
+ ,t3.partner_name,t3.level,t3.system_user_id,t3.address partner_address
,t4.agent_name
,t5.user_name as duty_name
from project_order_info t1
diff --git a/ruoyi-sip/src/main/resources/mapper/sip/ProjectProductInfoMapper.xml b/ruoyi-sip/src/main/resources/mapper/sip/ProjectProductInfoMapper.xml
index 350a9a60..af490b83 100644
--- a/ruoyi-sip/src/main/resources/mapper/sip/ProjectProductInfoMapper.xml
+++ b/ruoyi-sip/src/main/resources/mapper/sip/ProjectProductInfoMapper.xml
@@ -27,9 +27,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select t1.id, t1.project_id, t1.product_bom_code, t1.model, t1.product_code, t1.product_desc, t1.quantity, t1.catalogue_price,
- t1.catalogue_all_price, t1.price, t1.all_price, t1.guidance_discount, t1.discount, t1.remark,t1.tax_rate,t2.type,t2.product_name,t2.vendor_code,t2.value
+ t1.catalogue_all_price, t1.price, t1.all_price, t1.guidance_discount, t1.discount, t1.remark,t1.tax_rate,t2.type,t2.product_name,t2.vendor_code,t2.value,t3.vendor_name
from project_product_info t1
left join product_info t2 on t1.product_bom_code = t2.product_code
+ left join oms_vendor_info t3 on t2.vendor_code = t3.vendor_code