feat(project): 实现合同模板导出功能并优化页面交互
- 在项目订单信息中新增“partnerAddress”字段,并在 Mapper 中关联查询该字段 - 增加导出填充订单信息的合同模板接口与实现逻辑,支持根据 orderId 动态生成 docx 文件 - 修改前端页面: - 当 POC 选择“否”时,默认选中第一个 tab(工作进度) - 注释掉订单编辑页中的“合同信息”tab 项 - 调整导出逻辑,通过 orderId 获取数据并传递给后端生成文件 - 完善产品信息实体类及 Mapper,增加 vendorName 字段支持- 优化前端下载请求逻辑,使用 orderId 替代固定文件名方式 ```dev_1.0.0
parent
92218dac59
commit
940fe11624
|
|
@ -357,6 +357,11 @@
|
||||||
let val = $('#poc').val();
|
let val = $('#poc').val();
|
||||||
if (val==='0'){
|
if (val==='0'){
|
||||||
$('#pocLogTab').attr('style','display:none')
|
$('#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{
|
}else{
|
||||||
$('#pocLogTab').attr('style','display:inline')
|
$('#pocLogTab').attr('style','display:inline')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -421,6 +421,11 @@
|
||||||
console.log(val)
|
console.log(val)
|
||||||
if (val==='0'){
|
if (val==='0'){
|
||||||
$('#pocLogTab').attr('style','display:none')
|
$('#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{
|
}else{
|
||||||
$('#pocLogTab').attr('style','display:inline')
|
$('#pocLogTab').attr('style','display:inline')
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@
|
||||||
<li lay-id="22">流转过程</li>
|
<li lay-id="22">流转过程</li>
|
||||||
<li lay-id="33">备货信息</li>
|
<li lay-id="33">备货信息</li>
|
||||||
<li lay-id="44">物流信息</li>
|
<li lay-id="44">物流信息</li>
|
||||||
<li lay-id="55">合同信息</li>
|
<!-- <li lay-id="55">合同信息</li>-->
|
||||||
</ul>
|
</ul>
|
||||||
<div class="layui-tab-content">
|
<div class="layui-tab-content">
|
||||||
<div class="layui-tab-item layui-show">
|
<div class="layui-tab-item layui-show">
|
||||||
|
|
|
||||||
|
|
@ -1165,14 +1165,15 @@
|
||||||
|
|
||||||
function downloadTem() {
|
function downloadTem() {
|
||||||
var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象
|
var xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象
|
||||||
|
let orderId= $('[name="id"]').val()
|
||||||
if (!$('[name="orderChannel"]').val()) {
|
if (!$('[name="orderChannel"]').val()) {
|
||||||
$.modal.alertWarning("请先选择下单通路");
|
$.modal.alertWarning("请先选择下单通路");
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ($('[name="orderChannel"]').val() == 1) {
|
if ($('[name="orderChannel"]').val() == 1) {
|
||||||
window.location.href = prefix + "/contract/export?fileName=文件111.xlsx"
|
window.location.href = prefix + "/contract/export?orderId="+orderId
|
||||||
} else {
|
} else {
|
||||||
window.location.href = prefix + "/contract/export?fileName=文件222.xlsx"
|
window.location.href = prefix + "/contract/export?orderId="+orderId
|
||||||
}
|
}
|
||||||
|
|
||||||
$.modal.closeLoading()
|
$.modal.closeLoading()
|
||||||
|
|
|
||||||
|
|
@ -399,15 +399,35 @@ public class ProjectOrderInfoController extends BaseController
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/contract/export")
|
@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 {
|
try {
|
||||||
// 本地资源路径
|
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 localPath = RuoYiConfig.getExcelTemplate();
|
||||||
// 下载名称
|
String downloadPath = localPath + File.separator + (StringUtils.isEmpty(fileName) ? "orderDownloadTemplate.docx" : fileName);
|
||||||
String downloadPath = localPath + File.separator + fileName;
|
|
||||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||||
FileUtils.setAttachmentResponseHeader(response, fileName);
|
FileUtils.setAttachmentResponseHeader(response, StringUtils.isEmpty(fileName) ? "orderDownloadTemplate.docx" : fileName);
|
||||||
FileUtils.writeBytes(downloadPath, response.getOutputStream());
|
FileUtils.writeBytes(downloadPath, response.getOutputStream());
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("下载文件失败", e);
|
log.error("下载文件失败", e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ public class ProjectOrderInfo extends BaseEntity {
|
||||||
private String partnerCode;
|
private String partnerCode;
|
||||||
@Excel(name = "进货商")
|
@Excel(name = "进货商")
|
||||||
private String partnerName;
|
private String partnerName;
|
||||||
|
private String partnerAddress;
|
||||||
private String projectPartnerName;
|
private String projectPartnerName;
|
||||||
private List<String> productCodeList;
|
private List<String> productCodeList;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ public class ProjectProductInfo extends BaseEntity
|
||||||
// @Excel(name = "指导折扣")
|
// @Excel(name = "指导折扣")
|
||||||
private BigDecimal guidanceDiscount;
|
private BigDecimal guidanceDiscount;
|
||||||
private String vendorCode;
|
private String vendorCode;
|
||||||
|
private String vendorName;
|
||||||
|
|
||||||
/** 折扣 */
|
/** 折扣 */
|
||||||
// @Excel(name = "折扣")
|
// @Excel(name = "折扣")
|
||||||
|
|
|
||||||
|
|
@ -89,4 +89,11 @@ public interface IProjectOrderInfoService
|
||||||
|
|
||||||
// Boolean foldOnFold(ProjectOrderInfo info);
|
// Boolean foldOnFold(ProjectOrderInfo info);
|
||||||
List<OrderInfoVo> getOrderInfo(ApiDataQueryDto dto);
|
List<OrderInfoVo> getOrderInfo(ApiDataQueryDto dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出合同模板,填充订单信息
|
||||||
|
* @param orderId 订单ID
|
||||||
|
* @return 填充后的文件字节数组
|
||||||
|
*/
|
||||||
|
byte[] exportContractTemplate(ProjectOrderInfo orderInfo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
package com.ruoyi.sip.service.impl;
|
package com.ruoyi.sip.service.impl;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
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.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
@ -8,6 +11,7 @@ import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.convert.NumberChineseFormatter;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.lang.Dict;
|
import cn.hutool.core.lang.Dict;
|
||||||
import cn.hutool.core.util.StrUtil;
|
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.HorizontalCellStyleStrategy;
|
||||||
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
|
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
|
|
@ -46,6 +51,7 @@ import com.ruoyi.system.service.ISysUserService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.poi.ss.usermodel.*;
|
import org.apache.poi.ss.usermodel.*;
|
||||||
|
import org.apache.poi.xwpf.usermodel.*;
|
||||||
import org.flowable.engine.ManagementService;
|
import org.flowable.engine.ManagementService;
|
||||||
import org.flowable.engine.TaskService;
|
import org.flowable.engine.TaskService;
|
||||||
import org.flowable.engine.runtime.ProcessInstance;
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
|
|
@ -58,6 +64,8 @@ import com.ruoyi.common.core.text.Convert;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.io.*;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
|
||||||
import static com.ruoyi.common.utils.ShiroUtils.getSysUser;
|
import static com.ruoyi.common.utils.ShiroUtils.getSysUser;
|
||||||
import static com.ruoyi.sip.service.impl.ProjectInfoServiceImpl.*;
|
import static com.ruoyi.sip.service.impl.ProjectInfoServiceImpl.*;
|
||||||
|
|
@ -1273,4 +1281,329 @@ public class ProjectOrderInfoServiceImpl implements IProjectOrderInfoService, To
|
||||||
log.error("处理订单审批通过失败,订单编号:{}", businessKey, e);
|
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<String, String> replacements = createReplacementMap(orderInfo);
|
||||||
|
|
||||||
|
// 替换文本
|
||||||
|
for (Map.Entry<String, String> 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<String, String> createReplacementMap(ProjectOrderInfo orderInfo) {
|
||||||
|
Map<String, String> 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<String, String> 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<String, String> 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<ProjectProductInfo> 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<ProjectProductInfo> 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<XWPFTableCell> 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 : "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
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.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
|
,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
|
,t4.agent_name
|
||||||
,t5.user_name as duty_name
|
,t5.user_name as duty_name
|
||||||
from project_order_info t1
|
from project_order_info t1
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="selectProjectProductRelationInfoVo">
|
<sql id="selectProjectProductRelationInfoVo">
|
||||||
select t1.id, t1.project_id, t1.product_bom_code, t1.model, t1.product_code, t1.product_desc, t1.quantity, t1.catalogue_price,
|
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
|
from project_product_info t1
|
||||||
left join product_info t2 on t1.product_bom_code = t2.product_code
|
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
|
||||||
|
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue