确 定
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 || ''}