From 53e0b9466d3fdd3e5caf7c42e476fffdb468bc2a Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 27 三月 2026 17:17:22 +0800
Subject: [PATCH] 1
---
src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js | 276 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 276 insertions(+), 0 deletions(-)
diff --git a/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js b/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js
new file mode 100644
index 0000000..e23fd53
--- /dev/null
+++ b/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js
@@ -0,0 +1,276 @@
+const PRINT_TITLE = "閿�鍞彂璐у崟";
+
+const escapeHtml = (value) =>
+ String(value ?? "")
+ .replaceAll("&", "&")
+ .replaceAll("<", "<")
+ .replaceAll(">", ">")
+ .replaceAll('"', """)
+ .replaceAll("'", "'");
+
+const toNumber = (value) => {
+ const num = Number(value);
+ return Number.isFinite(num) ? num : 0;
+};
+
+const formatDisplayDate = (value) => {
+ if (!value) return "";
+ const date = new Date(value);
+ if (Number.isNaN(date.getTime())) return String(value);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const day = String(date.getDate()).padStart(2, "0");
+ return `${year}/${month}/${day}`;
+};
+
+const getItemArea = (item) => toNumber(item?.area || item?.settleTotalArea || item?.actualTotalArea);
+
+const getOrderNo = (data, row, item) =>
+ item?.salesContractNo || item?.orderNo || data?.salesContractNo || row?.salesContractNo || "";
+
+const splitItemsByPage = (items, pageSize) => {
+ const list = Array.isArray(items) ? items : [];
+ if (list.length === 0) return [[]];
+ const pages = [];
+ for (let i = 0; i < list.length; i += pageSize) {
+ pages.push(list.slice(i, i + pageSize));
+ }
+ return pages;
+};
+
+const normalizeInvoiceData = (raw, selectedRow) => {
+ const data = raw ?? {};
+ const groups = Array.isArray(data.groups) ? data.groups : [];
+ if (!groups.length) return data;
+
+ const items = groups.flatMap((group) =>
+ (Array.isArray(group?.items) ? group.items : []).map((item) => ({
+ ...item,
+ productDescription: group?.productName || item?.productDescription || "",
+ salesContractNo: group?.salesContractNo || item?.salesContractNo || "",
+ widthHeight: item?.widthHeight || "",
+ }))
+ );
+
+ return {
+ ...data,
+ items,
+ customerName: data.customerName || selectedRow?.customerName || "",
+ contactPerson: data.contactPerson || selectedRow?.contactPerson || "",
+ contactPhone: data.contactPhone || selectedRow?.contactPhone || "",
+ deliveryAddress:
+ data.companyAddress || data.deliveryAddress || data.shippingAddress || selectedRow?.deliveryAddress || "",
+ shipmentNo: data.externalOrderNo || data.shipmentNo || "",
+ register: data.orderMaker || data.register || selectedRow?.entryPersonName || "",
+ registerDate: data.executionDate || data.registerDate || data.entryDate || selectedRow?.entryDate || "",
+ };
+};
+
+const groupByProduct = (items, data, row) => {
+ const list = Array.isArray(items) ? items : [];
+ const map = new Map();
+ list.forEach((item) => {
+ const key = `${item?.productDescription || ""}__${getOrderNo(data, row, item)}`;
+ if (!map.has(key)) {
+ map.set(key, {
+ productName: item?.productDescription || "",
+ orderNo: getOrderNo(data, row, item),
+ items: [],
+ });
+ }
+ map.get(key).items.push(item);
+ });
+ return Array.from(map.values());
+};
+
+const renderItemRows = (items, startIndex) =>
+ items
+ .map((item, idx) => {
+ const sizeText = item?.widthHeight
+ ? escapeHtml(item.widthHeight)
+ : item?.width || item?.height
+ ? `${escapeHtml(item?.width)} * ${escapeHtml(item?.height)}`
+ : "";
+ return `
+ <tr>
+ <td>${startIndex + idx + 1}</td>
+ <td class="left">${escapeHtml(item?.floorCode)}</td>
+ <td>${sizeText}</td>
+ <td>${toNumber(item?.quantity) || ""}</td>
+ <td>${getItemArea(item) ? getItemArea(item).toFixed(2) : ""}</td>
+ <td class="left">${escapeHtml(item?.remark)}</td>
+ <td class="left">${escapeHtml(item?.processRequirement)}</td>
+ </tr>
+ `;
+ })
+ .join("");
+
+export const printSalesDeliveryNote = (rawData, selectedRow = {}) => {
+ const data = normalizeInvoiceData(rawData, selectedRow);
+ const allItems = Array.isArray(data.items) ? data.items : [];
+ const pageSize = 18;
+ const itemPages = splitItemsByPage(allItems, pageSize);
+ const totalPages = itemPages.length;
+
+ const printWindow = window.open("", "_blank", "width=1200,height=900");
+ if (!printWindow) {
+ throw new Error("娴忚鍣ㄦ嫤鎴簡寮圭獥锛岃鍏佽寮圭獥鍚庨噸璇�");
+ }
+
+ const html = `
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>${PRINT_TITLE}</title>
+ <style>
+ body { margin: 0; padding: 0; font-family: "SimSun", serif; color: #222; }
+ .page { width: 198mm; margin: 0 auto; padding: 4mm 4mm 6mm; box-sizing: border-box; page-break-after: always; }
+ .page:last-child { page-break-after: auto; }
+ .head-top {
+ display: grid;
+ grid-template-columns: 1fr auto 1fr;
+ align-items: end;
+ margin-bottom: 1px;
+ }
+ .factory {
+ grid-column: 2;
+ text-align: center;
+ font-size: 20px;
+ font-weight: 700;
+ line-height: 1.2;
+ }
+ .page-mark {
+ grid-column: 3;
+ justify-self: end;
+ font-size: 12px;
+ margin-right: 8mm;
+ margin-bottom: 1px;
+ }
+ .head-mid {
+ display: grid;
+ grid-template-columns: 1fr auto 1fr;
+ align-items: center;
+ margin-bottom: 2px;
+ }
+ .head-mid-left { font-size: 13px; text-align: left; }
+ .head-mid-title { font-size: 20px; font-weight: 700; text-align: center; }
+ .head-mid-right { font-size: 13px; text-align: right; padding-right: 8mm; }
+ table { width: 100%; border-collapse: collapse; table-layout: fixed; border: 1px solid #222; }
+ td, th { border: 1px solid #222; padding: 2px 4px; font-size: 13px; text-align: center; vertical-align: middle; }
+ .left { text-align: left; }
+ .group-title td { font-weight: 700; }
+ .subtotal td, .total-row td { font-weight: 700; }
+ .empty td { height: 120px; color: #666; }
+ .footer { margin-top: 6px; display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 6px; font-size: 13px; }
+ @media print {
+ @page { size: A4 portrait; margin: 8mm; }
+ .page { width: 100%; margin: 0; padding: 0; }
+ }
+ </style>
+ </head>
+ <body>
+ ${itemPages
+ .map((pageItems, pageIndex) => {
+ const pageGroups = groupByProduct(pageItems, data, selectedRow);
+ let serial = pageIndex * pageSize;
+ const totalQty = toNumber(data.totalQuantity) || allItems.reduce((s, it) => s + toNumber(it?.quantity), 0);
+ const totalArea = toNumber(data.totalArea) || allItems.reduce((s, it) => s + getItemArea(it), 0);
+ return `
+ <div class="page">
+ <div class="head-top">
+ <div></div>
+ <div class="factory">楣ゅ澶╂矏閽㈠寲鐜荤拑鍘�</div>
+ <div class="page-mark">绗�${pageIndex + 1}椤�,鍏�${totalPages}椤�</div>
+ </div>
+ <div class="head-mid">
+ <div class="head-mid-left">瀵规柟鍗曞彿: ${escapeHtml(data.deliveryNo || data.shippingNo || selectedRow.expressNumber || "")}</div>
+ <div class="head-mid-title">閿�鍞彂璐у崟</div>
+ <div class="head-mid-right">鍙戣揣鍗曞彿: ${escapeHtml(data.shipmentNo || data.deliveryNo || "")}</div>
+ </div>
+ <table>
+ <tr>
+ <td class="left" colspan="4">瀹㈡埛鍚嶇О: ${escapeHtml(data.customerName || selectedRow.customerName || "")}</td>
+ <td class="left" colspan="3">鑱旂郴浜�: ${escapeHtml(data.contactPerson || selectedRow.contactPerson || "")}</td>
+ </tr>
+ <tr>
+ <td class="left" colspan="4">鍙戣揣鍦板潃: ${escapeHtml(data.deliveryAddress || data.shippingAddress || selectedRow.deliveryAddress || "")}</td>
+ <td class="left" colspan="3">鑱旂郴鐢佃瘽: ${escapeHtml(data.contactPhone || selectedRow.contactPhone || "")}</td>
+ </tr>
+ <tr>
+ <th style="width:8%;">搴忓彿</th>
+ <th style="width:22%;">妤煎眰缂栧彿</th>
+ <th style="width:20%;">瀹�(寮ч暱)*楂�</th>
+ <th style="width:10%;">鏁伴噺</th>
+ <th style="width:12%;">闈㈢Н</th>
+ <th style="width:10%;">澶囨敞</th>
+ <th style="width:18%;">鍔犲伐瑕佹眰</th>
+ </tr>
+ ${
+ pageGroups.length
+ ? pageGroups
+ .map((group) => {
+ const subQty = group.items.reduce((s, it) => s + toNumber(it?.quantity), 0);
+ const subArea = group.items.reduce((s, it) => s + getItemArea(it), 0);
+ const rows = renderItemRows(group.items, serial);
+ serial += group.items.length;
+ return `
+ <tr class="group-title">
+ <td colspan="5" class="left">浜у搧鍚嶇О: ${escapeHtml(group.productName)}</td>
+ <td colspan="2" class="left">璁㈠崟缂栧彿: ${escapeHtml(group.orderNo)}</td>
+ </tr>
+ ${rows}
+ <tr class="subtotal">
+ <td colspan="3">灏忚:</td>
+ <td>${subQty || ""}</td>
+ <td>${subArea ? subArea.toFixed(2) : ""}</td>
+ <td colspan="2"></td>
+ </tr>
+ `;
+ })
+ .join("")
+ : `<tr class="empty"><td colspan="7">鏆傛棤鏄庣粏</td></tr>`
+ }
+ ${
+ pageIndex === totalPages - 1
+ ? `
+ <tr class="total-row">
+ <td colspan="3">鍚堣:</td>
+ <td>${totalQty || ""}</td>
+ <td>${totalArea ? totalArea.toFixed(2) : ""}</td>
+ <td colspan="2"></td>
+ </tr>
+ `
+ : ""
+ }
+ </table>
+ ${
+ pageIndex === totalPages - 1
+ ? `
+ <div class="footer">
+ <div>鍒� 鍗� 鍛�: ${escapeHtml(data.register || selectedRow.entryPersonName || "")}</div>
+ <div>鍒跺崟鏃ユ湡: ${escapeHtml(formatDisplayDate(data.registerDate || data.entryDate || selectedRow.entryDate))}</div>
+ <div>瀹㈡埛绛惧瓧:</div>
+ <div>绛炬敹鏃ユ湡:</div>
+ </div>
+ `
+ : ""
+ }
+ </div>
+ `;
+ })
+ .join("")}
+ </body>
+</html>
+`;
+
+ printWindow.document.write(html);
+ printWindow.document.close();
+ printWindow.onload = () => {
+ setTimeout(() => {
+ printWindow.focus();
+ printWindow.print();
+ printWindow.close();
+ }, 300);
+ };
+};
--
Gitblit v1.9.3