From 0af12dc242cd9b771b8ea7c2cff6ace54441718f Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期二, 21 四月 2026 10:23:35 +0800
Subject: [PATCH] 添加Tab键滚动跟随功能,优化可见区域滚动逻辑

---
 src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js |  153 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 138 insertions(+), 15 deletions(-)

diff --git a/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js b/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js
index e23fd53..696e94d 100644
--- a/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js
+++ b/src/views/salesManagement/salesLedger/components/salesDeliveryPrint.js
@@ -1,3 +1,5 @@
+import QRCode from "qrcode";
+
 const PRINT_TITLE = "閿�鍞彂璐у崟";
 
 const escapeHtml = (value) =>
@@ -28,6 +30,69 @@
 const getOrderNo = (data, row, item) =>
   item?.salesContractNo || item?.orderNo || data?.salesContractNo || row?.salesContractNo || "";
 
+const PRODUCT_NAME_FIELD_KEYS = [
+  "productDescription",
+  "productName",
+  "name",
+  "title",
+  "goodsName",
+  "materialName",
+  "glassName",
+];
+
+const PRODUCT_NAME_LIST_FIELD_KEYS = [
+  "productDescriptionList",
+  "productNameList",
+  "productDescriptions",
+  "productNames",
+  "nameList",
+  "goodsNameList",
+  "detailProductNames",
+  "productInfoList",
+];
+
+const normalizeNameList = (value) => {
+  if (Array.isArray(value)) {
+    return value
+      .flatMap((item) => normalizeNameList(item))
+      .map((item) => String(item).trim())
+      .filter(Boolean);
+  }
+  if (value && typeof value === "object") {
+    const objectListNames = PRODUCT_NAME_LIST_FIELD_KEYS.flatMap((key) => normalizeNameList(value?.[key]));
+    if (objectListNames.length) return objectListNames;
+    return PRODUCT_NAME_FIELD_KEYS.flatMap((key) => normalizeNameList(value?.[key]));
+  }
+  if (typeof value === "string") {
+    const text = value.trim();
+    if (!text) return [];
+    const parts = text
+      .split(/[,\n锛屻�侊紱;]/)
+      .map((item) => item.trim())
+      .filter(Boolean);
+    return parts.length > 1 ? parts : [text];
+  }
+  if (value === null || value === undefined) return [];
+  const text = String(value).trim();
+  return text ? [text] : [];
+};
+
+const extractNameListByKeys = (source, keys) => {
+  if (!source || typeof source !== "object") return [];
+  return keys.flatMap((key) => normalizeNameList(source?.[key]));
+};
+
+const resolveProductName = (item, fallbackNames, index) => {
+  const itemNames = [
+    ...extractNameListByKeys(item, PRODUCT_NAME_LIST_FIELD_KEYS),
+    ...extractNameListByKeys(item, PRODUCT_NAME_FIELD_KEYS),
+  ];
+  if (itemNames.length > 1) {
+    return itemNames[index] || itemNames[0] || "";
+  }
+  return itemNames[0] || fallbackNames[index] || fallbackNames[0] || "";
+};
+
 const splitItemsByPage = (items, pageSize) => {
   const list = Array.isArray(items) ? items : [];
   if (list.length === 0) return [[]];
@@ -40,17 +105,36 @@
 
 const normalizeInvoiceData = (raw, selectedRow) => {
   const data = raw ?? {};
-  const groups = Array.isArray(data.groups) ? data.groups : [];
-  if (!groups.length) return data;
+  const groups = Array.isArray(data.groups)
+    ? data.groups
+    : Array.isArray(data.groupList)
+      ? data.groupList
+      : [];
+  const dataLevelNames = [
+    ...extractNameListByKeys(data, PRODUCT_NAME_LIST_FIELD_KEYS),
+    ...extractNameListByKeys(data, PRODUCT_NAME_FIELD_KEYS),
+  ];
 
-  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 || "",
-    }))
-  );
+  const items = groups.length
+    ? groups.flatMap((group) => {
+        const groupItems = Array.isArray(group?.items) ? group.items : [];
+        const groupNames = [
+          ...extractNameListByKeys(group, PRODUCT_NAME_LIST_FIELD_KEYS),
+          ...extractNameListByKeys(group, PRODUCT_NAME_FIELD_KEYS),
+        ];
+        return groupItems.map((item, index) => ({
+          ...item,
+          // 浼樺厛浣跨敤鏄庣粏鑷韩浜у搧鍚嶏紝鍏煎鈥滃悕绉版暟缁�/鍒嗛殧瀛楃涓测�濈殑鎺ュ彛鏍煎紡
+          productDescription: resolveProductName(item, groupNames, index),
+          salesContractNo: group?.salesContractNo || item?.salesContractNo || "",
+          widthHeight: item?.widthHeight || "",
+        }));
+      })
+    : (Array.isArray(data.items) ? data.items : []).map((item, index) => ({
+        ...item,
+        productDescription: resolveProductName(item, dataLevelNames, index),
+        widthHeight: item?.widthHeight || "",
+      }));
 
   return {
     ...data,
@@ -105,12 +189,33 @@
     })
     .join("");
 
-export const printSalesDeliveryNote = (rawData, selectedRow = {}) => {
+export const printSalesDeliveryNote = async (rawData, selectedRow = {}, ledgerIds = null) => {
   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 ids =
+    Array.isArray(ledgerIds) && ledgerIds.length > 0
+      ? ledgerIds
+      : selectedRow?.id !== undefined && selectedRow?.id !== null && selectedRow?.id !== ""
+        ? [selectedRow.id]
+        : [];
+  const shipmentRef = String(
+    data.shipmentNo || data.deliveryNo || data.externalOrderNo || selectedRow?.expressNumber || ""
+  ).trim();
+  const qrPayload = JSON.stringify({
+    type: "FH",
+    shipmentNo: shipmentRef,
+    ledgerIds: ids,
+  });
+  let qrDataUrl = "";
+  try {
+    qrDataUrl = await QRCode.toDataURL(qrPayload, { width: 160, margin: 1 });
+  } catch {
+    qrDataUrl = "";
+  }
 
   const printWindow = window.open("", "_blank", "width=1200,height=900");
   if (!printWindow) {
@@ -146,17 +251,32 @@
         font-size: 12px;
         margin-right: 8mm;
         margin-bottom: 1px;
+        position: relative;
+        top: 6mm;
       }
       .head-mid {
         display: grid;
         grid-template-columns: 1fr auto 1fr;
         align-items: center;
-        margin-bottom: 2px;
+        margin-top: 6mm;
+        margin-bottom: 0;
+        position: relative;
       }
       .head-mid-left { font-size: 13px; text-align: left; }
-      .head-mid-title { font-size: 20px; font-weight: 700; text-align: center; }
+      .head-mid-title-wrap { grid-column: 2; }
+      .head-mid-title { font-size: 20px; font-weight: 700; text-align: center; line-height: 1; }
+      .head-qr {
+        width: 18mm;
+        height: 18mm;
+        object-fit: contain;
+        display: block;
+        position: absolute;
+        left: calc(50% + 30mm);
+        top: calc(50% - 4mm);
+        transform: translateY(-50%);
+      }
       .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; }
+      table { width: 100%; margin-top: 3mm; 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; }
@@ -185,7 +305,10 @@
       </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-title-wrap">
+          <div class="head-mid-title">閿�鍞彂璐у崟</div>
+        </div>
+        ${qrDataUrl ? `<img class="head-qr" src="${qrDataUrl}" alt="浜岀淮鐮�" />` : ""}
         <div class="head-mid-right">鍙戣揣鍗曞彿: ${escapeHtml(data.shipmentNo || data.deliveryNo || "")}</div>
       </div>
       <table>

--
Gitblit v1.9.3