From 91e3bd28292a252fc14fabb07b729b29c7292fdd Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 29 四月 2026 10:33:00 +0800
Subject: [PATCH] 打印领料单

---
 src/views/productionManagement/productionOrder/index.vue                               |   55 +++++++++++
 src/views/productionManagement/productionOrder/components/PrintMaterialRequisition.vue |  225 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 280 insertions(+), 0 deletions(-)

diff --git a/src/views/productionManagement/productionOrder/components/PrintMaterialRequisition.vue b/src/views/productionManagement/productionOrder/components/PrintMaterialRequisition.vue
new file mode 100644
index 0000000..d1aa267
--- /dev/null
+++ b/src/views/productionManagement/productionOrder/components/PrintMaterialRequisition.vue
@@ -0,0 +1,225 @@
+<template>
+  <div class="print-container"
+       id="print-requisition">
+    <div class="print-content">
+      <div class="bill-title">鐢熶骇棰嗘枡鍗�</div>
+      <div class="info-grid">
+        <div class="info-row">
+          <div class="info-item">
+            <span class="label">鍒涘缓鏃ユ湡锛�</span>
+            <span class="value">{{ formatDate(orderRow?.createTime) }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">棰嗘枡鍗曞彿锛�</span>
+            <span class="value">{{ orderRow?.npsNo }}</span>
+          </div>
+          <div class="info-item">
+            <span class="label">鐢宠浜猴細</span>
+            <span class="value">{{ userName }}</span>
+          </div>
+        </div>
+        <div class="info-row">
+          <div class="info-item"
+               style="width: 50%;">
+            <span class="label">浜у搧鍚嶇О/鍨嬪彿锛�</span>
+            <span class="value">{{ orderRow?.productName }} / {{ orderRow?.model }}</span>
+          </div>
+          <div class="info-item"
+               style="width: 25%;">
+            <span class="label">鐢熶骇鏁伴噺锛�</span>
+            <span class="value">{{ orderRow?.quantity }}</span>
+          </div>
+          <div class="info-item"
+               style="width: 25%;">
+            <span class="label">闇�姹傛棩鏈燂細</span>
+            <span class="value">{{ formatDate(orderRow?.planCompleteTime) }}</span>
+          </div>
+        </div>
+      </div>
+      <table class="material-table">
+        <thead>
+          <tr>
+            <th width="50">搴忓彿</th>
+            <th>宸ュ簭鍚嶇О</th>
+            <th>瑙勬牸/鍚嶇О</th>
+            <th>鎵瑰彿</th>
+            <th width="80">闇�姹傛暟閲�</th>
+            <th width="80">棰嗘枡鏁伴噺</th>
+            <th width="60">鍗曚綅</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(item, index) in materialList"
+              :key="index">
+            <td align="center">{{ index + 1 }}</td>
+            <td>{{ item.operationName || '-' }}</td>
+            <td>{{ item.materialName || item.productName }} {{ item.materialModel || item.model }}</td>
+            <td>{{ item.batchNo || '-' }}</td>
+            <td align="right">{{ item.demandedQuantity }}</td>
+            <td align="right">{{ item.pickQuantity || item.pickQty || 0 }}</td>
+            <td align="center">{{ item.unit }}</td>
+          </tr>
+        </tbody>
+      </table>
+      <div class="print-footer">
+        <div class="footer-item">棰嗘枡锛歘_______________</div>
+        <div class="footer-item">鍙戞枡锛歘_______________</div>
+        <div class="footer-item">瀹℃牳锛歘_______________</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  import dayjs from "dayjs";
+  import useUserStore from "@/store/modules/user";
+  import { computed } from "vue";
+
+  const props = defineProps({
+    orderRow: {
+      type: Object,
+      default: () => ({}),
+    },
+    materialList: {
+      type: Array,
+      default: () => [],
+    },
+  });
+
+  const userStore = useUserStore();
+  const userName = computed(() => userStore.nickName || userStore.name || "-");
+
+  const formatDate = date => {
+    return date ? dayjs(date).format("YYYY骞碝M鏈圖D鏃�") : "-";
+  };
+</script>
+
+<style lang="scss">
+  /* 灞忓箷鏄剧ず鏍峰紡 */
+  .print-requisition-wrapper {
+    display: none;
+  }
+
+  /* 鎵撳嵃涓撶敤鏍峰紡 */
+  @media print {
+    @page {
+      size: landscape;
+      margin: 10mm;
+    }
+
+    /* 鍩虹鎵撳嵃璁剧疆 */
+    html,
+    body {
+      visibility: hidden;
+      height: auto !important;
+      overflow: visible !important;
+      margin: 0 !important;
+      padding: 0 !important;
+      width: 100%;
+    }
+
+    /* 鏄惧紡鏄剧ず鎵撳嵃瀹瑰櫒鍙婂叾鎵�鏈夊瓙鍏冪礌 */
+    .print-requisition-wrapper,
+    .print-requisition-wrapper * {
+      visibility: visible !important;
+    }
+
+    /* 纭繚鎵撳嵃瀹瑰櫒鍗犳嵁鏁翠釜椤甸潰骞剁Щ闄ょ粷瀵瑰畾浣嶅共鎵� */
+    .print-requisition-wrapper {
+      display: block !important;
+      position: absolute;
+      left: 0;
+      top: 0;
+      width: 100%;
+      height: auto;
+      background: white;
+      margin: 0 !important;
+      padding: 0 !important;
+      z-index: 99999;
+    }
+
+    .print-container {
+      width: 100% !important;
+      padding: 0 10mm; /* 浣跨敤瀵圭О鐨勫乏鍙冲唴杈硅窛纭繚灞呬腑 */
+      box-sizing: border-box;
+      height: auto;
+      overflow: visible;
+      color: #000;
+      font-family: "SimSun", "STSong", serif;
+      page-break-inside: avoid;
+      display: block;
+      .print-content {
+        width: 100%;
+        text-align: center;
+      }
+      .bill-title {
+        font-size: 20px;
+        font-weight: bold;
+        text-align: center;
+        margin-bottom: 20px;
+        letter-spacing: 5px;
+        text-decoration: underline;
+      }
+
+      .info-grid {
+        margin-bottom: 10px;
+        font-size: 14px;
+
+        .info-row {
+          display: flex;
+          flex-wrap: wrap;
+          margin-bottom: 8px;
+
+          .info-item {
+            width: 33.33%;
+            display: flex;
+            align-items: flex-end;
+
+            .label {
+              font-weight: bold;
+              white-space: nowrap;
+            }
+            .value {
+              border-bottom: 1px solid #000;
+              padding: 0 5px;
+              flex: 1;
+              min-height: 20px;
+            }
+          }
+        }
+      }
+
+      .material-table {
+        width: 100%;
+        border-collapse: collapse;
+        border: 2px solid #000;
+        font-size: 13px;
+
+        th,
+        td {
+          border: 1px solid #000 !important;
+          padding: 6px 4px;
+          height: 25px;
+          -webkit-print-color-adjust: exact;
+          print-color-adjust: exact;
+        }
+
+        th {
+          background-color: #f2f2f2 !important;
+          font-weight: bold;
+        }
+      }
+
+      .print-footer {
+        display: flex;
+        justify-content: space-between;
+        margin-top: 30px;
+        padding: 0 10px;
+
+        .footer-item {
+          font-size: 14px;
+        }
+      }
+    }
+  }
+</style>
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 5f4fa61..28356dd 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -181,6 +181,12 @@
     <new-product-order v-if="isShowNewModal"
                        v-model:visible="isShowNewModal"
                        @completed="handleQuery" />
+    <!-- 鎵撳嵃棰嗘枡鍗曠粍浠� -->
+    <div class="print-requisition-wrapper">
+      <PrintMaterialRequisition ref="printRef"
+                                :order-row="printOrderRow"
+                                :material-list="printMaterialList" />
+    </div>
   </div>
 </template>
 
@@ -209,8 +215,13 @@
   import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue";
   import MaterialDetailDialog from "@/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue";
   import MaterialSupplementDialog from "@/views/productionManagement/productionOrder/components/MaterialSupplementDialog.vue";
+  import PrintMaterialRequisition from "@/views/productionManagement/productionOrder/components/PrintMaterialRequisition.vue";
   import PIMTable from "@/components/PIMTable/PIMTable.vue";
   import { listPage } from "@/api/productionManagement/processRoute.js";
+  import {
+    listMaterialPickingDetail,
+    listMaterialPickingBom,
+  } from "@/api/productionManagement/productionOrder.js";
   const NewProductOrder = defineAsyncComponent(() =>
     import("@/views/productionManagement/productionOrder/New.vue")
   );
@@ -365,6 +376,14 @@
             openMaterialDetailDialog(row);
           },
         },
+        {
+          name: "鎵撳嵃棰嗘枡鍗�",
+          type: "text",
+          color: "#409eff",
+          clickFun: row => {
+            handlePrint(row);
+          },
+        },
       ],
     },
   ]);
@@ -440,6 +459,42 @@
   const materialSupplementDialogVisible = ref(false);
   const currentMaterialSupplementOrder = ref(null);
 
+  // 鎵撳嵃鐩稿叧
+  const printOrderRow = ref(null);
+  const printMaterialList = ref([]);
+  const handlePrint = async row => {
+    printOrderRow.value = row;
+    proxy.$modal.loading("姝e湪鑾峰彇棰嗘枡鏁版嵁...");
+    try {
+      printMaterialList.value = [];
+      const detailRes = await listMaterialPickingDetail(row.id);
+      const detailList = Array.isArray(detailRes?.data)
+        ? detailRes.data
+        : detailRes?.data?.records || [];
+
+      if (detailList.length > 0) {
+        printMaterialList.value = detailList;
+      }
+
+      if (printMaterialList.value.length === 0) {
+        proxy.$modal.msgWarning("鏆傛棤棰嗘枡鏁版嵁");
+        return;
+      }
+
+      // 绛夊緟 DOM 鏇存柊鍚庢墽琛屾墦鍗�
+      proxy.$nextTick(() => {
+        setTimeout(() => {
+          window.print();
+        }, 800);
+      });
+    } catch (e) {
+      console.error("鑾峰彇棰嗘枡鏁版嵁澶辫触锛�", e);
+      proxy.$modal.msgError("鑾峰彇棰嗘枡鏁版嵁澶辫触");
+    } finally {
+      proxy.$modal.closeLoading();
+    }
+  };
+
   const openBindRouteDialog = async (row, type) => {
     bindForm.orderId = row.id;
     bindForm.routeId = type === "add" ? null : row.processRouteCode;

--
Gitblit v1.9.3