fix:付款单详情添加导出PDF和打印功能,付款单列表导出添加应付单信息
parent
4bdbc1daf7
commit
c2bbeb7cdc
|
|
@ -12,6 +12,11 @@
|
|||
<div class="dialog-body" v-if="detail" ref="paymentDrawer">
|
||||
<div class="section">
|
||||
<el-divider content-position="left">采购-付款单</el-divider>
|
||||
<div class="section-actions">
|
||||
<el-button type="primary" size="mini" :loading="pdfExporting" @click="handleExportPDF">导出PDF</el-button>
|
||||
<el-button size="mini" @click="handlePrint">打印</el-button>
|
||||
</div>
|
||||
<div ref="pdfExportArea">
|
||||
<div class="details-container">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
|
|
@ -94,6 +99,8 @@
|
|||
<el-col :span="24">
|
||||
<div class="detail-item">特别说明: {{ detail.remark }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<div class="detail-item">
|
||||
<span style="margin-right: 10px">附件:</span>
|
||||
|
|
@ -101,7 +108,7 @@
|
|||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" v-if="detail.fileList == null || detail.fileList.length < 10">
|
||||
<el-row :gutter="20" class="export-exclude" v-if="detail.fileList == null || detail.fileList.length < 10">
|
||||
<el-col :span="24">
|
||||
<div class="detail-item">
|
||||
<span style="margin-right: 10px">附件补充:</span>
|
||||
|
|
@ -112,7 +119,6 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<el-divider content-position="left">采购-应付单</el-divider>
|
||||
|
|
@ -143,6 +149,8 @@
|
|||
<el-divider content-position="left">流转意见</el-divider>
|
||||
<flow-opinion-timeline :logs="approveLogs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<edit-form :visible.sync="payableVisible" :data="selectedPayableRow" :z-index="2000" @close="payableVisible = false" />
|
||||
</el-drawer>
|
||||
|
|
@ -153,6 +161,7 @@ import FileUpload from "@/components/FileUpload";
|
|||
import EditForm from "@/views/finance/payable/components/EditForm.vue";
|
||||
import FlowOpinionTimeline from "@/views/finance/components/FlowOpinionTimeline.vue";
|
||||
import { listCompletedFlows } from "@/api/flow";
|
||||
import { exportElementToPDF } from "@/views/approve/finance/pdfUtils";
|
||||
|
||||
export default {
|
||||
name: "DetailDrawer",
|
||||
|
|
@ -180,6 +189,7 @@ export default {
|
|||
approveLogs: [],
|
||||
approveLogsTimer: null,
|
||||
approveLogsLoading: false,
|
||||
pdfExporting: false,
|
||||
};
|
||||
},
|
||||
beforeDestroy() {
|
||||
|
|
@ -276,6 +286,114 @@ export default {
|
|||
this.approveLogsLoading = false;
|
||||
});
|
||||
},
|
||||
async handleExportPDF() {
|
||||
if (!this.$refs.pdfExportArea) {
|
||||
this.$modal.msgWarning("未找到可导出的内容");
|
||||
return;
|
||||
}
|
||||
this.pdfExporting = true;
|
||||
let exportWrapper = null;
|
||||
try {
|
||||
await this.$nextTick();
|
||||
const sourceEl = this.$refs.pdfExportArea;
|
||||
const sourceWidth = Math.ceil(sourceEl.getBoundingClientRect().width) || 1000;
|
||||
|
||||
// 在屏幕外克隆导出区域,避免抽屉滚动容器导致底部内容被裁剪
|
||||
exportWrapper = document.createElement("div");
|
||||
exportWrapper.style.position = "fixed";
|
||||
exportWrapper.style.left = "-10000px";
|
||||
exportWrapper.style.top = "0";
|
||||
exportWrapper.style.width = `${sourceWidth}px`;
|
||||
exportWrapper.style.background = "#F8F5F0";
|
||||
exportWrapper.style.overflow = "visible";
|
||||
exportWrapper.style.zIndex = "-1";
|
||||
exportWrapper.innerHTML = sourceEl.outerHTML;
|
||||
document.body.appendChild(exportWrapper);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 60));
|
||||
const exportTarget = exportWrapper.firstElementChild || exportWrapper;
|
||||
exportTarget.querySelectorAll(".export-exclude").forEach(node => node.remove());
|
||||
const fileName = `付款单详情-${this.detail && this.detail.paymentBillCode ? this.detail.paymentBillCode : ""}.pdf`;
|
||||
await exportElementToPDF(exportTarget, fileName);
|
||||
this.$modal.msgSuccess("PDF导出成功");
|
||||
} catch (error) {
|
||||
console.error("PDF导出失败:", error);
|
||||
this.$modal.msgError("PDF导出失败,请稍后重试");
|
||||
} finally {
|
||||
if (exportWrapper && exportWrapper.parentNode) {
|
||||
exportWrapper.parentNode.removeChild(exportWrapper);
|
||||
}
|
||||
this.pdfExporting = false;
|
||||
}
|
||||
},
|
||||
handlePrint() {
|
||||
const exportArea = this.$refs.pdfExportArea;
|
||||
if (!exportArea) {
|
||||
this.$modal.msgWarning("未找到可打印的内容");
|
||||
return;
|
||||
}
|
||||
|
||||
const printWindow = window.open("", "_blank");
|
||||
if (!printWindow) {
|
||||
this.$modal.msgError("打印窗口被拦截,请允许弹窗后重试");
|
||||
return;
|
||||
}
|
||||
|
||||
const styleContent = Array.from(document.querySelectorAll("style, link[rel='stylesheet']"))
|
||||
.map(node => node.outerHTML)
|
||||
.join("");
|
||||
|
||||
const html = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>付款单详情打印</title>
|
||||
${styleContent}
|
||||
<style>
|
||||
@page { margin: 8mm; size: auto; }
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
.print-root {
|
||||
width: 100%;
|
||||
transform: scale(0.97);
|
||||
transform-origin: top left;
|
||||
page-break-after: avoid;
|
||||
break-after: avoid-page;
|
||||
}
|
||||
.print-root .detail-item:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.export-exclude {
|
||||
display: none !important;
|
||||
}
|
||||
@media print {
|
||||
* {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="print-root">${exportArea.outerHTML}</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
printWindow.document.open();
|
||||
printWindow.document.write(html);
|
||||
printWindow.document.close();
|
||||
printWindow.focus();
|
||||
printWindow.onload = () => {
|
||||
printWindow.print();
|
||||
printWindow.close();
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -307,6 +425,12 @@ export default {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.red-text{
|
||||
color: red;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,27 @@
|
|||
package com.ruoyi.sip.controller;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.config.flow.ProcessConfig;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.sip.domain.OmsFinAttachment;
|
||||
import com.ruoyi.sip.domain.OmsPaymentBill;
|
||||
import com.ruoyi.sip.flowable.service.TodoService;
|
||||
import com.ruoyi.sip.service.IOmsFinAttachmentService;
|
||||
import com.ruoyi.sip.service.IOmsPaymentBillService;
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.sip.domain.OmsPaymentBill;
|
||||
import com.ruoyi.sip.service.IOmsPaymentBillService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 采购付款单Controller
|
||||
*
|
||||
|
|
@ -113,12 +111,7 @@ public class OmsPaymentBillController extends BaseController
|
|||
@ResponseBody
|
||||
public AjaxResult export(OmsPaymentBill omsPaymentBill)
|
||||
{
|
||||
List<OmsPaymentBill> list = omsPaymentBillService.selectOmsPaymentBillList(omsPaymentBill);
|
||||
ExcelUtil<OmsPaymentBill> util = new ExcelUtil<OmsPaymentBill>(OmsPaymentBill.class);
|
||||
todoService.fillApproveNode(list,
|
||||
Arrays.asList(processConfig.getDefinition().getFinancePayment(), processConfig.getDefinition().getFinanceRefund())
|
||||
, OmsPaymentBill::getPaymentBillCode, (a, b) -> a.setApproveNode(b.get(a.getPaymentBillCode())));
|
||||
return util.exportExcel(list, "采购付款单数据");
|
||||
return omsPaymentBillService.exportExcelWithPayableDetails(omsPaymentBill);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ public interface IOmsPaymentBillService
|
|||
*/
|
||||
public int deleteOmsPaymentBillById(Long id);
|
||||
|
||||
AjaxResult exportExcelWithPayableDetails(OmsPaymentBill omsPaymentBill);
|
||||
|
||||
PaymentBillDetailDTO query(Long id);
|
||||
|
||||
AjaxResult returnPaymentBill(Long id);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.ruoyi.sip.service.impl;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
|
@ -17,9 +18,11 @@ import com.ruoyi.common.core.domain.AjaxResult;
|
|||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.enums.ApproveStatusEnum;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import com.ruoyi.common.utils.ShiroUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.mail.TemplateMailUtil;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.sip.domain.*;
|
||||
import com.ruoyi.sip.domain.dto.PaymentBillDetailDTO;
|
||||
import com.ruoyi.sip.domain.dto.PaymentBillPayableDetailDTO;
|
||||
|
|
@ -29,6 +32,7 @@ import com.ruoyi.sip.flowable.domain.Todo;
|
|||
import com.ruoyi.sip.flowable.service.TodoCommonTemplate;
|
||||
import com.ruoyi.sip.flowable.service.TodoService;
|
||||
import com.ruoyi.sip.service.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flowable.engine.ManagementService;
|
||||
import org.flowable.engine.runtime.ProcessInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -45,6 +49,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
* @author ruoyi
|
||||
* @date 2025-10-22
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService , TodoCommonTemplate
|
||||
|
|
@ -108,6 +113,149 @@ public class OmsPaymentBillServiceImpl implements IOmsPaymentBillService , TodoC
|
|||
return omsPaymentBillMapper.selectOmsPaymentBillList(omsPaymentBill);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AjaxResult exportExcelWithPayableDetails(OmsPaymentBill omsPaymentBill) {
|
||||
List<OmsPaymentBill> list = omsPaymentBillMapper.selectOmsPaymentBillList(omsPaymentBill);
|
||||
todoService.fillApproveNode(list,
|
||||
Arrays.asList(processConfig.getDefinition().getFinancePayment(), processConfig.getDefinition().getFinanceRefund())
|
||||
, OmsPaymentBill::getPaymentBillCode, (a, b) -> a.setApproveNode(b.get(a.getPaymentBillCode())));
|
||||
|
||||
List<List<PaymentBillPayableDetailDTO>> payableDetailsGroup = new ArrayList<>();
|
||||
int maxPayableCount = 0;
|
||||
for (OmsPaymentBill bill : list) {
|
||||
List<PaymentBillPayableDetailDTO> payableDetails = Collections.emptyList();
|
||||
if (bill.getId() != null) {
|
||||
PaymentBillDetailDTO detailDTO = this.query(bill.getId());
|
||||
if (detailDTO != null && detailDTO.getPayableDetails() != null) {
|
||||
payableDetails = detailDTO.getPayableDetails();
|
||||
}
|
||||
}
|
||||
payableDetailsGroup.add(payableDetails);
|
||||
maxPayableCount = Math.max(maxPayableCount, payableDetails.size());
|
||||
}
|
||||
|
||||
List<List<String>> header = buildExportHeader(maxPayableCount);
|
||||
List<List<Object>> data = buildExportData(list, payableDetailsGroup, maxPayableCount);
|
||||
|
||||
try {
|
||||
ExcelUtil<OmsPaymentBill> util = new ExcelUtil<>(OmsPaymentBill.class);
|
||||
String fileName = util.encodingFilename("采购付款单数据");
|
||||
String filePath = util.getAbsoluteFile(fileName);
|
||||
EasyExcel.write(filePath).head(header).sheet("采购付款单数据").doWrite(data);
|
||||
return AjaxResult.success(fileName);
|
||||
} catch (Exception e) {
|
||||
log.error("导出采购付款单失败", e);
|
||||
return AjaxResult.error("导出采购付款单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<List<String>> buildExportHeader(int maxPayableCount) {
|
||||
List<List<String>> header = new ArrayList<>();
|
||||
Collections.addAll(header,
|
||||
Collections.singletonList("项目编号"),
|
||||
Collections.singletonList("项目名称"),
|
||||
Collections.singletonList("付款单编号"),
|
||||
Collections.singletonList("备注"),
|
||||
Collections.singletonList("预计付款时间"),
|
||||
Collections.singletonList("制造商名称"),
|
||||
Collections.singletonList("合同编号"),
|
||||
Collections.singletonList("含税总价"),
|
||||
Collections.singletonList("未税总价"),
|
||||
Collections.singletonList("税额"),
|
||||
Collections.singletonList("实际付款时间"),
|
||||
Collections.singletonList("付款状态"),
|
||||
Collections.singletonList("审批状态"),
|
||||
Collections.singletonList("审批节点"),
|
||||
Collections.singletonList("审批时间"),
|
||||
Collections.singletonList("支付方式"),
|
||||
Collections.singletonList("应付单编号"),
|
||||
Collections.singletonList("账户名称"),
|
||||
Collections.singletonList("银行账号"),
|
||||
Collections.singletonList("银行开户行"),
|
||||
Collections.singletonList("银行行号")
|
||||
);
|
||||
for (int i = 1; i <= maxPayableCount; i++) {
|
||||
header.add(Collections.singletonList("应付单" + i + "-项目编号"));
|
||||
header.add(Collections.singletonList("应付单" + i + "-项目名称"));
|
||||
header.add(Collections.singletonList("应付单" + i + "-采购应付单编号"));
|
||||
header.add(Collections.singletonList("应付单" + i + "-含税总价"));
|
||||
header.add(Collections.singletonList("应付单" + i + "-本次付款金额"));
|
||||
header.add(Collections.singletonList("应付单" + i + "-本次付款比例"));
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
private List<List<Object>> buildExportData(List<OmsPaymentBill> list,
|
||||
List<List<PaymentBillPayableDetailDTO>> payableDetailsGroup,
|
||||
int maxPayableCount) {
|
||||
List<List<Object>> data = new ArrayList<>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
OmsPaymentBill bill = list.get(i);
|
||||
List<PaymentBillPayableDetailDTO> payableDetails = payableDetailsGroup.get(i);
|
||||
List<Object> row = new ArrayList<>();
|
||||
Collections.addAll(row,
|
||||
bill.getProjectCode(),
|
||||
bill.getProjectName(),
|
||||
bill.getPaymentBillCode(),
|
||||
resolvePaymentBillTypeDesc(bill.getPaymentBillType()),
|
||||
formatDateTime(bill.getPaymentTime()),
|
||||
bill.getVendorName(),
|
||||
bill.getOrderCode(),
|
||||
bill.getTotalPriceWithTax(),
|
||||
bill.getTotalPriceWithoutTax(),
|
||||
bill.getTaxAmount(),
|
||||
formatDateTime(bill.getActualPaymentTime()),
|
||||
DictUtils.getDictLabel("payment_status", bill.getPaymentStatus()),
|
||||
DictUtils.getDictLabel("approve_status", bill.getApproveStatus()),
|
||||
bill.getApproveNode(),
|
||||
formatDateTime(bill.getApproveTime()),
|
||||
DictUtils.getDictLabel("payment_method", bill.getPaymentMethod()),
|
||||
bill.getPayableBillCode(),
|
||||
bill.getPayName(),
|
||||
bill.getPayBankNumber(),
|
||||
bill.getPayBankOpenAddress(),
|
||||
bill.getBankNumber()
|
||||
);
|
||||
for (int index = 0; index < maxPayableCount; index++) {
|
||||
if (index < payableDetails.size()) {
|
||||
PaymentBillPayableDetailDTO detail = payableDetails.get(index);
|
||||
row.add(detail.getProjectCode());
|
||||
row.add(detail.getProjectName());
|
||||
row.add(detail.getPayableBillCode());
|
||||
row.add(detail.getTotalPriceWithTax());
|
||||
row.add(detail.getPaymentAmount());
|
||||
row.add(detail.getPaymentRate());
|
||||
} else {
|
||||
row.add("");
|
||||
row.add("");
|
||||
row.add("");
|
||||
row.add("");
|
||||
row.add("");
|
||||
row.add("");
|
||||
}
|
||||
}
|
||||
data.add(row);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private String formatDateTime(Date date) {
|
||||
return date == null ? "" : DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", date);
|
||||
}
|
||||
|
||||
private String resolvePaymentBillTypeDesc(String paymentBillType) {
|
||||
if (OmsPaymentBill.PaymentBillTypeEnum.FROM_PAYABLE.getCode().equals(paymentBillType)) {
|
||||
return OmsPaymentBill.PaymentBillTypeEnum.FROM_PAYABLE.getDesc();
|
||||
}
|
||||
if (OmsPaymentBill.PaymentBillTypeEnum.PRE_PAYMENT.getCode().equals(paymentBillType)) {
|
||||
return OmsPaymentBill.PaymentBillTypeEnum.PRE_PAYMENT.getDesc();
|
||||
}
|
||||
if (OmsPaymentBill.PaymentBillTypeEnum.REFUND.getCode().equals(paymentBillType)) {
|
||||
return OmsPaymentBill.PaymentBillTypeEnum.REFUND.getDesc();
|
||||
}
|
||||
return paymentBillType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增采购付款单
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue