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/processCardPrint.js |  261 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 261 insertions(+), 0 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/components/processCardPrint.js b/src/views/salesManagement/salesLedger/components/processCardPrint.js
new file mode 100644
index 0000000..d1c0472
--- /dev/null
+++ b/src/views/salesManagement/salesLedger/components/processCardPrint.js
@@ -0,0 +1,261 @@
+const PRINT_TITLE = "鐢熶骇娴佺▼鍗�(鎴愬搧)";
+
+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 getCurrentDate = () => {
+  const date = new Date();
+  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 escapeHtml = (value) =>
+  String(value ?? "")
+    .replaceAll("&", "&amp;")
+    .replaceAll("<", "&lt;")
+    .replaceAll(">", "&gt;")
+    .replaceAll('"', "&quot;")
+    .replaceAll("'", "&#39;");
+
+const renderRouteHeader = (routeNodes) => {
+  const columns = (Array.isArray(routeNodes) ? routeNodes : [])
+    .sort((a, b) => (a?.dragSort ?? 0) - (b?.dragSort ?? 0))
+    .map((node) => `<th class="route-col">${escapeHtml(node?.processRouteItemName)}</th>`)
+    .join("");
+  return columns || '<th class="route-col">宸ュ簭</th>';
+};
+
+const renderRouteRow = (routeNodes) => {
+  const columns = (Array.isArray(routeNodes) ? routeNodes : [])
+    .sort((a, b) => (a?.dragSort ?? 0) - (b?.dragSort ?? 0))
+    .map(() => '<td class="route-col">娆″搧</td>')
+    .join("");
+  return columns || '<td class="route-col">娆″搧</td>';
+};
+
+const renderRouteEmptyCells = (routeNodes) => {
+  const columns = (Array.isArray(routeNodes) ? routeNodes : [])
+    .sort((a, b) => (a?.dragSort ?? 0) - (b?.dragSort ?? 0))
+    .map(() => '<td class="route-col"></td>')
+    .join("");
+  return columns || '<td class="route-col"></td>';
+};
+
+const renderItems = (items, startIndex, routeNodes, totalCols) => {
+  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);
+  return list
+    .map(
+      (item, index) => `
+      <tr>
+        <td>${startIndex + index + 1}</td>
+        <td class="no-wrap">${escapeHtml(item?.floorCode)}</td>
+        <td class="no-wrap">${escapeHtml(item?.width)} * ${escapeHtml(item?.height)}</td>
+        <td class="no-wrap">${escapeHtml(item?.quantity)}</td>
+        <td class="no-wrap">${escapeHtml(item?.area)}</td>
+        <td class="no-wrap">${escapeHtml(item?.processRequirement)}</td>
+        ${routeEmptyCells}
+      </tr>
+    `
+    )
+    .join("");
+};
+
+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;
+};
+
+export const printFinishedProcessCard = (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 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 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: 6mm 3mm 5mm; box-sizing: border-box; page-break-after: always; }
+      .page:last-child { page-break-after: auto; }
+      .table-wrap { position: relative; }
+      .page-mark {
+        position: absolute;
+        left: 0;
+        top: -16px;
+        z-index: 2;
+        font-size: 12px;
+        line-height: 1;
+        background: #fff;
+        padding: 0 2px;
+      }
+      .title { text-align: center; font-size: 18px; font-weight: 700; margin-bottom: 4px; line-height: 1.2; }
+      .sub-title { font-size: 14px; }
+      table { width: 100%; border-collapse: collapse; table-layout: auto; }
+      td, th { border: 0.8px solid #6f7f95; padding: 2px 4px; font-size: 12px; text-align: center; vertical-align: middle; word-break: break-all; }
+      .left { text-align: left; }
+      .no-wrap { white-space: nowrap; word-break: keep-all; }
+      .route-col { min-width: 48px; white-space: nowrap; word-break: keep-all; }
+      .section-title { font-weight: 700; text-align: left; padding-left: 6px; }
+      .sign-label { text-align: left; padding-left: 8px; vertical-align: top; line-height: 1.2; }
+      .sign-blank { vertical-align: top; min-height: 18px; }
+      .order-req-content { min-height: 82px; vertical-align: top; padding-top: 6px; }
+      .sign-row td { height: 18px; }
+      .order-require-title { width: 34px; padding: 0; }
+      .order-require-title-text {
+        display: flex;
+        height: 100%;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        line-height: 1.25;
+        letter-spacing: 0;
+        font-weight: 500;
+      }
+      .footer { margin-top: 10px; font-size: 12px; line-height: 1.7; padding: 0 2px; }
+      .footer-row { display: flex; justify-content: space-between; }
+      .footer-item { width: 33%; }
+      .continued { text-align: right; font-size: 12px; padding-right: 8px; }
+      @media print {
+        @page { size: A4 portrait; margin: 8mm; }
+        .page { width: 100%; margin: 0; padding: 0; }
+      }
+    </style>
+  </head>
+  <body>
+    ${itemPages
+      .map((pageItems, pageIndex) => {
+        const isLastPage = pageIndex === totalPages - 1;
+        const startIndex = pageIndex * pageSize;
+        return `
+    <div class="page">
+      <div class="title">楣ゅ澶╂矏閽㈠寲鐜荤拑鍘�<br /><span class="sub-title">鐢熶骇娴佺▼鍗�(鎴愬搧)</span></div>
+      <div class="table-wrap">
+      <div class="page-mark">绗�${pageIndex + 1}椤碉紝鍏�${totalPages}椤�</div>
+      <table>
+        <thead>
+          <tr>
+            <td colspan="5" class="left">璁㈠崟缂栧彿:${escapeHtml(data.salesContractNo)}</td>
+            <td colspan="${totalCols - 5}" class="left">浜よ揣鏃ユ湡:${escapeHtml(formatDisplayDate(data.deliveryDate))}</td>
+          </tr>
+          <tr>
+            <td colspan="5" class="left">瀹㈡埛鍚嶇О:${escapeHtml(data.customerName)}</td>
+            <td colspan="${totalCols - 5}" class="left">宸ヨ壓娴佺▼:${escapeHtml(data.processPathDisplay)}</td>
+          </tr>
+          <tr>
+            <th rowspan="2" style="width:6%;">璁㈠簭</th>
+            <th rowspan="2" style="width:22%;" class="no-wrap">妤煎眰缂栧彿</th>
+            <th rowspan="2" style="width:20%;" class="no-wrap">瀹�(寮ч暱)*楂�</th>
+            <th rowspan="2" style="width:8%;" class="no-wrap">鏁伴噺</th>
+            <th rowspan="2" style="width:8%;" class="no-wrap">闈㈢Н</th>
+            <th rowspan="2" style="width:20%;" class="no-wrap">鏄庣粏鍔犲伐瑕佹眰</th>
+            ${renderRouteHeader(routeNodes)}
+          </tr>
+          <tr>${renderRouteRow(routeNodes)}</tr>
+        </thead>
+        <tbody>
+          <tr>
+            <td colspan="${totalCols}" class="section-title">浜у搧鍚嶇О:${escapeHtml(productName)}</td>
+          </tr>
+          ${renderItems(pageItems, startIndex, routeNodes, totalCols)}
+          ${
+            isLastPage
+              ? `<tr>
+            <td colspan="3" class="left"><strong>鍚堣:</strong></td>
+            <td>${escapeHtml(data.totalQuantity)}</td>
+            <td>${escapeHtml(data.totalArea)}</td>
+            <td colspan="${signLabelCols}" class="sign-label">瀹屽伐绛惧悕</td>
+            <td colspan="${signBlankCols}" class="sign-blank"></td>
+          </tr>
+          <tr class="sign-row">
+            <td rowspan="3" class="order-require-title">
+              <div class="order-require-title-text">
+                <span>璁㈠崟</span>
+                <span>鍔犲伐</span>
+                <span>瑕佹眰</span>
+              </div>
+            </td>
+            <td colspan="4" rowspan="3" class="left order-req-content">${escapeHtml(data.orderProcessRequirement)}</td>
+            <td colspan="${signLabelCols}" class="sign-label">璐ㄦ绛惧悕</td>
+            <td colspan="${signBlankCols}" class="sign-blank"></td>
+          </tr>
+          <tr class="sign-row">
+            <td colspan="${signLabelCols}" class="sign-label">鎺ユ敹绛惧悕</td>
+            <td colspan="${signBlankCols}" class="sign-blank"></td>
+          </tr>
+          <tr class="sign-row">
+            <td colspan="${signLabelCols}" class="sign-label">鐢熶骇鏃ユ湡</td>
+            <td colspan="${signBlankCols}" class="sign-blank"></td>
+          </tr>`
+              : `<tr><td colspan="${totalCols}" class="continued">涓嬮〉缁�...</td></tr>`
+          }
+        </tbody>
+      </table>
+      </div>
+
+      ${
+        isLastPage
+          ? `<div class="footer">
+        <div class="footer-row">
+          <div class="footer-item">鍒跺崟鍛�:${escapeHtml(data.register)}</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">瀹℃牳鏃ユ湡:${escapeHtml(formatDisplayDate(data.registerDate))}</div>
+          <div class="footer-item">鎵撳嵃鏃ユ湡:${getCurrentDate()}</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