From a5323aea76d8994821dccd32a37f53c4b3efa9c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= <2178503051@qq.com> Date: Fri, 5 Jun 2026 10:41:33 +0800 Subject: [PATCH] =?UTF-8?q?fix(crm/contract):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=90=88=E5=90=8C=E9=A2=84=E8=A7=88=E4=B8=8E=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 隐藏打印预览按钮 2. 调整合同预览页面样式间距与logo位置 3. 修改合同金额字段保留小数位数为3位 4. 优化PDF导出分页逻辑,按空白行自动分页 --- klp-ui/src/views/cost/comprehensive.vue | 10 +-- .../crm/contract/components/ContractList.vue | 82 ++++++++++++++----- .../contract/components/ContractPreview.vue | 25 +++--- 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/klp-ui/src/views/cost/comprehensive.vue b/klp-ui/src/views/cost/comprehensive.vue index 06f3965a..5c9d8319 100644 --- a/klp-ui/src/views/cost/comprehensive.vue +++ b/klp-ui/src/views/cost/comprehensive.vue @@ -232,9 +232,9 @@ - - - + + +
确 定取 消
@@ -242,8 +242,8 @@ - - + +
确 定 diff --git a/klp-ui/src/views/crm/contract/components/ContractList.vue b/klp-ui/src/views/crm/contract/components/ContractList.vue index 9e2c1a1a..f584e0e6 100644 --- a/klp-ui/src/views/crm/contract/components/ContractList.vue +++ b/klp-ui/src/views/crm/contract/components/ContractList.vue @@ -326,10 +326,10 @@ export default { if (hasCol('quantity')) cells += `${product.quantity || ''}`; if (hasCol('taxPrice')) cells += `${product.taxPrice || ''}`; if (hasCol('taxDivisor')) cells += `${product.taxDivisor || '1.13'}`; - if (hasCol('noTaxPrice')) cells += `${(product.noTaxPrice || 0).toFixed(2)}`; - if (hasCol('taxTotal')) cells += `${(product.taxTotal || 0).toFixed(2)}`; - if (hasCol('noTaxTotal')) cells += `${(product.noTaxTotal || 0).toFixed(2)}`; - if (hasCol('taxAmount')) cells += `${(product.taxAmount || 0).toFixed(2)}`; + if (hasCol('noTaxPrice')) cells += `${(product.noTaxPrice || 0).toFixed(3)}`; + if (hasCol('taxTotal')) cells += `${(product.taxTotal || 0).toFixed(3)}`; + if (hasCol('noTaxTotal')) cells += `${(product.noTaxTotal || 0).toFixed(3)}`; + if (hasCol('taxAmount')) cells += `${(product.taxAmount || 0).toFixed(3)}`; if (hasCol('remark')) cells += `${product.remark || ''}`; bodyRows += `${cells}`; }); @@ -352,10 +352,10 @@ export default { } } else { let val = ''; - if (col.key === 'quantity') val = totalQty.toFixed(2); - else if (col.key === 'taxTotal') val = totalTax.toFixed(2); - else if (col.key === 'noTaxTotal') val = totalNoTax.toFixed(2); - else if (col.key === 'taxAmount') val = totalTaxAmt.toFixed(2); + if (col.key === 'quantity') val = totalQty.toFixed(3); + else if (col.key === 'taxTotal') val = totalTax.toFixed(3); + else if (col.key === 'noTaxTotal') val = totalNoTax.toFixed(3); + else if (col.key === 'taxAmount') val = totalTaxAmt.toFixed(3); totalCells += `${val}`; } cellIdx++; @@ -605,23 +605,63 @@ export default { document.body.removeChild(container); + const pdf = new jsPDF('p', 'mm', 'a4'); const pdfWidth = 210; const pdfHeight = 297; - const imgWidth = pdfWidth; - const imgHeight = (canvas.height * pdfWidth) / canvas.width; - const pdf = new jsPDF('p', 'mm', 'a4'); - const imgData = canvas.toDataURL('image/jpeg', 0.95); - let heightLeft = imgHeight; - let position = 0; + const margin = 5; + const contentWidth = pdfWidth - margin * 2; + const contentHeight = pdfHeight - margin * 2; + const scale = contentWidth / canvas.width; - pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); - heightLeft -= pdfHeight; + function isBlankRow(canvas, y) { + const ctx = canvas.getContext('2d'); + const row = ctx.getImageData(0, y, canvas.width, 1).data; + let whiteCount = 0; + const total = row.length / 4; + for (let i = 0; i < row.length; i += 4) { + if (row[i] > 250 && row[i + 1] > 250 && row[i + 2] > 250) whiteCount++; + } + return whiteCount / total >= 0.95; + } - while (heightLeft > 0) { - position = heightLeft - imgHeight; - pdf.addPage(); - pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight); - heightLeft -= pdfHeight; + function findBreakY(canvas, targetY, range) { + range = range || 40; + for (let offset = 0; offset < range; offset++) { + if (targetY + offset < canvas.height && isBlankRow(canvas, targetY + offset)) return targetY + offset; + if (targetY - offset > 0 && isBlankRow(canvas, targetY - offset)) return targetY - offset; + } + return targetY; + } + + let currentY = 0; + let firstPage = true; + + while (currentY < canvas.height) { + const pageHeightPx = Math.round(contentHeight / scale); + let endY = Math.min(currentY + pageHeightPx, canvas.height); + + if (endY < canvas.height) { + endY = findBreakY(canvas, endY); + } + + const sliceHeight = endY - currentY; + const pageCanvas = document.createElement('canvas'); + pageCanvas.width = canvas.width; + pageCanvas.height = sliceHeight; + pageCanvas.getContext('2d').drawImage(canvas, 0, currentY, canvas.width, sliceHeight, 0, 0, canvas.width, sliceHeight); + + const imgData = pageCanvas.toDataURL('image/jpeg', 0.95); + const pageImgHeight = sliceHeight * scale; + + if (firstPage) { + pdf.addImage(imgData, 'JPEG', margin, margin, contentWidth, pageImgHeight); + firstPage = false; + } else { + pdf.addPage(); + pdf.addImage(imgData, 'JPEG', margin, margin, contentWidth, pageImgHeight); + } + + currentY = endY; } pdf.save(`合同_${row.contractCode || row.contractName || '未命名'}.pdf`); diff --git a/klp-ui/src/views/crm/contract/components/ContractPreview.vue b/klp-ui/src/views/crm/contract/components/ContractPreview.vue index 6e3a7da1..9f4131a5 100644 --- a/klp-ui/src/views/crm/contract/components/ContractPreview.vue +++ b/klp-ui/src/views/crm/contract/components/ContractPreview.vue @@ -4,7 +4,7 @@

{{ contract.contractName }} - 打印预览 + @@ -172,15 +172,14 @@ export default { * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'SimSun','宋体',serif; color: #000; background: #e8e8e8; font-size: 12px; line-height: 1.6; display: flex; flex-direction: column; align-items: center; padding: 20px 0; } .a4-page { width: 794px; min-height: 1123px; padding: 30px 40px; background: #fff; margin-bottom: 20px; box-shadow: 0 2px 12px rgba(0,0,0,0.15); } - .company-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 8px; } - .contract-title { text-align: center; font-size: 22px; font-weight: bold; letter-spacing: 6px; margin-bottom: 18px; } - .info-row { display: flex; justify-content: space-between; margin-bottom: 6px; font-size: 13px; line-height: 2; } - .section-title { font-size: 13px; font-weight: bold; margin-bottom: 4px; margin-top: 10px; } - table { width: 100%; border-collapse: collapse; font-size: 11px; } - th, td { border: 1px solid #000; padding: 3px 4px; text-align: center; } - th { background-color: #f5f5f5; font-weight: bold; } - .total-row td { font-weight: bold; } - .sign-section { margin-top: 30px; font-size: 12px; line-height: 2.2; } + .company-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 6px; } + .contract-title { text-align: center; font-size: 20px; font-weight: bold; letter-spacing: 6px; margin-bottom: 14px; } + .info-row { display: flex; justify-content: space-between; margin-bottom: 4px; font-size: 13px; line-height: 2; } + .section-title { font-size: 13px; font-weight: bold; margin-bottom: 4px; margin-top: 8px; } + table { width: 100%; border-collapse: collapse; } + th, td { border: 1px solid #000; padding: 3px 4px; text-align: center; font-size: 11px; } + th { font-weight: bold; } + .sign-section { margin-top: 24px; font-size: 12px; line-height: 2.2; } .sign-section .col { width: 48%; } .sign-row { display: flex; justify-content: space-between; } .print-toolbar { position: fixed; top: 0; right: 20px; z-index: 100; display: flex; gap: 8px; padding: 10px; } @@ -197,13 +196,13 @@ export default {
- +
嘉祥科伦普重工有限公司
-
+
产 品 销 售 合 同
-
合同编号:${row.contractCode || ''}
+
合同编号:${row.contractCode || ''}