From f3f855be1fd86d28485fceb02c30b6c6b2853aef Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期三, 04 十一月 2026 18:15:40 +0800
Subject: [PATCH] feat(mes): 质检附件与来源关联界面,新增工单技术文件、废料登记与领料单打印

---
 src/views/mes/workbench/components/tabs/ProductIssueTab.vue |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 51 insertions(+), 1 deletions(-)

diff --git a/src/views/mes/workbench/components/tabs/ProductIssueTab.vue b/src/views/mes/workbench/components/tabs/ProductIssueTab.vue
index 27f62be..52c91e7 100644
--- a/src/views/mes/workbench/components/tabs/ProductIssueTab.vue
+++ b/src/views/mes/workbench/components/tabs/ProductIssueTab.vue
@@ -22,10 +22,13 @@
   cancelProductIssue,
   createProductIssue,
   deleteProductIssue,
+  getProductIssue,
   getProductIssuePage,
   submitProductIssue,
   updateProductIssue,
 } from '#/api/mes/wm/productissue';
+import { getProductIssueLinesByIssue } from '#/api/mes/wm/productissue/line';
+import dayjs from 'dayjs';
 import { MdWorkstationSelect } from '#/views/mes/md/workstation/components';
 import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components';
 
@@ -240,7 +243,7 @@
       props: { type: DICT_TYPE.MES_WM_PRODUCT_ISSUE_STATUS },
     },
   },
-  { title: '鎿嶄綔', width: 260, fixed: 'right', slots: { default: 'actions' } },
+  { title: '鎿嶄綔', width: 360, fixed: 'right', slots: { default: 'actions' } },
 ];
 
 const gridHeight = ref(300);
@@ -304,6 +307,52 @@
 /** 鏄惁宸查�変腑宸ヤ綔绔欏拰浠诲姟锛屾湭閫変腑鏃朵笉灞曠ず琛ㄦ牸 */
 const isReady = computed(() => !!props.taskId && !!props.workstationId);
 
+/** 鍗曟嵁鍐呭鍏ㄩ儴鎸夋枃鏈浆涔夛紝閬垮厤鐗╂枡鍚嶇О鎴栧娉ㄥ奖鍝嶆墦鍗伴〉闈㈢粨鏋勩�� */
+function escapePrintText(value: unknown) {
+  return String(value ?? '').replace(/[&<>"']/g, (char) => ({
+    '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
+  })[char] || char);
+}
+
+async function handlePrintIssue(row: MesWmProductIssueApi.ProductIssue) {
+  if (!row.id) return;
+  // 鍏堟墦寮�绐楀彛锛岄伩鍏嶅紓姝ヨ姹傜粨鏉熷悗琚祻瑙堝櫒浣滀负寮圭獥鎷︽埅銆�
+  const popup = window.open('', '_blank');
+  if (!popup) { message.warning('娴忚鍣ㄦ嫤鎴簡鎵撳嵃绐楀彛锛岃鍏佽寮圭獥鍚庨噸璇�'); return; }
+  popup.document.title = '姝e湪鍑嗗棰嗘枡鍗�';
+  popup.document.body.textContent = '姝e湪鍑嗗棰嗘枡鍗曗��';
+  try {
+    const [issue, lines] = await Promise.all([getProductIssue(row.id), getProductIssueLinesByIssue(row.id)]);
+    if (!issue) throw new Error('棰嗘枡鍗曚笉瀛樺湪');
+    const safe = escapePrintText;
+    const date = (value: unknown) => value && dayjs(value as string | number | Date).isValid()
+      ? dayjs(value as string | number | Date).format('YYYY-MM-DD HH:mm') : '';
+    const statusNames: Record<number, string> = {
+      [MesWmProductIssueStatusEnum.PREPARE]: '鑽夌',
+      [MesWmProductIssueStatusEnum.APPROVING]: '寰呮嫞璐�',
+      [MesWmProductIssueStatusEnum.APPROVED]: '寰呴鍑�',
+      [MesWmProductIssueStatusEnum.FINISHED]: '宸插畬鎴�',
+      [MesWmProductIssueStatusEnum.CANCELED]: '宸插彇娑�',
+    };
+    const rows = lines.map((item, index) => `<tr><td>${index + 1}</td><td>${safe(item.itemCode)}</td><td>${safe(item.itemName)}</td><td>${safe(item.specification)}</td><td>${safe(item.unitMeasureName)}</td><td>${safe(item.quantity)}</td><td>${safe(item.remark)}</td></tr>`).join('');
+    popup.document.open();
+    popup.document.write(`<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"><title>棰嗘枡鍗� ${safe(issue.code)}</title><style>
+      @page { size: A4; margin: 15mm; } body { color: #111; font: 13px 'Microsoft YaHei', sans-serif; margin: 0 auto; max-width: 180mm; }
+      h1 { text-align: center; font-size: 22px; margin: 12px 0 20px; } .meta { display: grid; grid-template-columns: 1fr 1fr; gap: 9px 16px; margin-bottom: 16px; overflow-wrap: anywhere; }
+      table { border-collapse: collapse; width: 100%; table-layout: fixed; } th,td { border: 1px solid #555; padding: 7px 4px; word-break: break-word; text-align: left; } th:first-child,td:first-child { width: 32px; text-align: center; } th:nth-child(5),td:nth-child(5) { width: 42px; } th:nth-child(6),td:nth-child(6) { width: 56px; } thead { display: table-header-group; } tr { break-inside: avoid; }
+      .sign { display: flex; justify-content: space-between; gap: 18px; margin-top: 32px; } .toolbar { text-align: right; padding: 12px 0; } button { padding: 7px 14px; cursor: pointer; } @media print { .toolbar { display: none; } }
+    </style></head><body><div class="toolbar"><button onclick="window.print()">鎵撳嵃 / 淇濆瓨涓� PDF</button></div><h1>棰嗘枡鍗�</h1>
+      <div class="meta"><div>棰嗘枡鍗曞彿锛�${safe(issue.code)}</div><div>棰嗘枡鍗曞悕绉帮細${safe(issue.name)}</div><div>鐢熶骇浠诲姟锛�${safe(issue.taskCode)}</div><div>鐢熶骇璁㈠崟锛�${safe(issue.workOrderCode)}</div><div>宸ヤ綔绔欙細${safe(issue.workstationName || issue.workstationCode)}</div><div>闇�姹傛椂闂达細${safe(date(issue.requiredTime))}</div><div>鐘舵�侊細${safe(statusNames[issue.status ?? -1] ?? '鏈煡')}</div><div>澶囨敞锛�${safe(issue.remark)}</div></div>
+      <table><thead><tr><th>搴忓彿</th><th>鐗╂枡缂栫爜</th><th>鐗╂枡鍚嶇О</th><th>瑙勬牸鍨嬪彿</th><th>鍗曚綅</th><th>鐢宠鏁伴噺</th><th>澶囨敞</th></tr></thead><tbody>${rows || '<tr><td colspan="7">鏆傛棤棰嗘枡鏄庣粏</td></tr>'}</tbody></table>
+      <div class="sign"><span>鐢宠浜猴細____________</span><span>鍙戞枡浜猴細____________</span><span>棰嗘枡浜猴細____________</span><span>鏃ユ湡锛歘___________</span></div></body></html>`);
+    popup.document.close();
+  } catch (error) {
+    popup.close();
+    message.error('鏃犳硶鐢熸垚棰嗘枡鍗曪紝璇风◢鍚庨噸璇�');
+    console.error(error);
+  }
+}
+
 /** 缂栬緫寮圭獥 */
 const [EditFormModal, editFormModalApi] = useVbenModal({
   connectedComponent: ProductIssueFormModal,
@@ -361,6 +410,7 @@
       <div ref="listRef" class="issue-tab__list">
         <Grid table-title="棰嗘枡璁板綍">
           <template #actions="{ row }">
+            <Button type="link" size="small" @click="handlePrintIssue(row)">鎵撳嵃 / 瀵煎嚭 PDF</Button>
             <Button
               v-if="row.status === MesWmProductIssueStatusEnum.PREPARE"
               type="link"

--
Gitblit v1.9.3