From 878d74493c18747097294f3e6b9c6ab2269783ec Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期一, 20 四月 2026 14:59:18 +0800
Subject: [PATCH] 优化生产流程卡打印功能,增加产品名称变化的行渲染逻辑

---
 src/views/salesManagement/salesLedger/components/processCardPrint.js |   91 +++++++++++++++++++++++++++++++++++++--------
 1 files changed, 74 insertions(+), 17 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/components/processCardPrint.js b/src/views/salesManagement/salesLedger/components/processCardPrint.js
index d89ee18..a48bc88 100644
--- a/src/views/salesManagement/salesLedger/components/processCardPrint.js
+++ b/src/views/salesManagement/salesLedger/components/processCardPrint.js
@@ -1,3 +1,5 @@
+import QRCode from "qrcode";
+
 const PRINT_TITLE = "鐢熶骇娴佺▼鍗�(鎴愬搧)";
 
 const formatDisplayDate = (value) => {
@@ -50,15 +52,28 @@
   return columns || '<td class="route-col"></td>';
 };
 
-const renderItems = (items, startIndex, routeNodes, totalCols) => {
+const renderItems = (
+  items,
+  startIndex,
+  routeNodes,
+  totalCols,
+  previousProductName,
+  fallbackProductName
+) => {
   const list = Array.isArray(items) ? items : [];
   if (list.length === 0) {
     return `<tr><td colspan="${totalCols}" style="text-align:center;">鏆傛棤鏄庣粏</td></tr>`;
   }
   const routeEmptyCells = renderRouteEmptyCells(routeNodes);
+  let lastProductName = String(previousProductName ?? "").trim();
   return list
-    .map(
-      (item, index) => `
+    .map((item, index) => {
+      const currentProductName =
+        String(item?.productDescription ?? "").trim() || fallbackProductName;
+      const shouldRenderProductRow = currentProductName !== lastProductName;
+      lastProductName = currentProductName;
+      return `
+      ${shouldRenderProductRow ? `<tr><td colspan="${totalCols}" class="section-title">浜у搧鍚嶇О:${escapeHtml(currentProductName)}</td></tr>` : ""}
       <tr>
         <td>${startIndex + index + 1}</td>
         <td class="no-wrap">${escapeHtml(item?.floorCode)}</td>
@@ -68,8 +83,8 @@
         <td class="no-wrap">${escapeHtml(item?.processRequirement)}</td>
         ${routeEmptyCells}
       </tr>
-    `
-    )
+    `;
+    })
     .join("");
 };
 
@@ -83,18 +98,32 @@
   return pages;
 };
 
-export const printFinishedProcessCard = (cardData) => {
+export const printFinishedProcessCard = async (cardData) => {
   const data = cardData ?? {};
   const routeNodes = Array.isArray(data.routeNodes) ? data.routeNodes : [];
   const items = Array.isArray(data.items) ? data.items : [];
-  const firstItem = items[0] ?? {};
-  const productName = firstItem.productDescription || "";
+  const fallbackProductName = String(data?.productName ?? "").trim();
   const totalCols = 6 + Math.max(routeNodes.length, 1);
   const signLabelCols = 2;
   const signBlankCols = Math.max(totalCols - 5 - signLabelCols, 1);
   const pageSize = 10;
   const itemPages = splitItemsByPage(items, pageSize);
   const totalPages = itemPages.length;
+
+  const ledgerId =
+    data?.salesLedgerId ?? data?.ledgerId ?? data?.id ?? data?.salesLedgerID;
+  const salesContractNo = String(data?.salesContractNo ?? "").trim();
+  const qrPayload = JSON.stringify({
+    id: ledgerId ?? "",
+    salesContractNo,
+    type: "XS",
+  });
+  let qrDataUrl = "";
+  try {
+    qrDataUrl = await QRCode.toDataURL(qrPayload, { width: 180, margin: 2 });
+  } catch {
+    qrDataUrl = "";
+  }
 
   const printWindow = window.open("", "_blank", "width=1200,height=900");
   if (!printWindow) {
@@ -109,9 +138,19 @@
     <title>${PRINT_TITLE}</title>
     <style>
       body { margin: 0; padding: 0; font-family: "SimSun", serif; color: #222; }
-      .page { width: 198mm; margin: 0 auto; padding: 6mm 3mm 5mm; box-sizing: border-box; page-break-after: always; }
+      .page { position: relative; width: 198mm; margin: 0 auto; padding: 6mm 3mm 5mm; box-sizing: border-box; page-break-after: always; }
       .page:last-child { page-break-after: auto; }
-      .table-wrap { position: relative; }
+      .table-wrap { position: relative; margin-top: 22mm; }
+      .header { position: relative; padding-top: 0; }
+      .qr-block {
+        position: absolute;
+        right: 2mm;
+        top: -1mm;
+        width: 32mm;
+        text-align: center;
+        z-index: 3;
+      }
+      .qr-block img { width: 32mm; height: 32mm; display: block; margin: 0 auto; }
       .page-mark {
         position: absolute;
         left: 0;
@@ -160,9 +199,23 @@
       .map((pageItems, pageIndex) => {
         const isLastPage = pageIndex === totalPages - 1;
         const startIndex = pageIndex * pageSize;
+        const previousProductName =
+          startIndex > 0
+            ? String(items[startIndex - 1]?.productDescription ?? "").trim() ||
+              fallbackProductName
+            : "";
         return `
     <div class="page">
-      <div class="title">楣ゅ澶╂矏閽㈠寲鐜荤拑鍘�<br /><span class="sub-title">鐢熶骇娴佺▼鍗�(鎴愬搧)</span></div>
+      <div class="header">
+        ${
+          qrDataUrl
+            ? `<div class="qr-block">
+          <img src="${qrDataUrl}" alt="浜岀淮鐮�" />
+        </div>`
+            : ""
+        }
+        <div class="title">楣ゅ澶╂矏閽㈠寲鐜荤拑鍘�<br /><span class="sub-title">鐢熶骇娴佺▼鍗�(鎴愬搧)</span></div>
+      </div>
       <div class="table-wrap">
       <div class="page-mark">绗�${pageIndex + 1}椤碉紝鍏�${totalPages}椤�</div>
       <table>
@@ -187,10 +240,14 @@
           <tr>${renderRouteRow(routeNodes)}</tr>
         </thead>
         <tbody>
-          <tr>
-            <td colspan="${totalCols}" class="section-title">浜у搧鍚嶇О:${escapeHtml(productName)}</td>
-          </tr>
-          ${renderItems(pageItems, startIndex, routeNodes, totalCols)}
+          ${renderItems(
+            pageItems,
+            startIndex,
+            routeNodes,
+            totalCols,
+            previousProductName,
+            fallbackProductName
+          )}
           ${
             isLastPage
               ? `<tr>
@@ -231,12 +288,12 @@
           ? `<div class="footer">
         <div class="footer-row">
           <div class="footer-item">鍒跺崟鍛�:${escapeHtml(data.register)}</div>
-          <div class="footer-item">瀹℃牳鍛�:__________</div>
+          <div class="footer-item">瀹℃牳鍛�:${escapeHtml(data.register)}</div>
           <div class="footer-item">宸ヨ壓鍛�:${escapeHtml(data.technician ?? "")}</div>
         </div>
         <div class="footer-row">
           <div class="footer-item">鍒跺崟鏃ユ湡:${escapeHtml(formatDisplayDate(data.registerDate))}</div>
-          <div class="footer-item">瀹℃牳鏃ユ湡:__________</div>
+          <div class="footer-item">瀹℃牳鏃ユ湡:${escapeHtml(formatDisplayDate(data.registerDate))}</div>
           <div class="footer-item">鎵撳嵃鏃ユ湡:${getCurrentDate()}</div>
         </div>
       </div>`

--
Gitblit v1.9.3