From 74f21d10c2f29e4631ff1c17d07e3bd6b73ca0b8 Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期五, 20 三月 2026 17:54:14 +0800
Subject: [PATCH] 造粒报工

---
 src/views/productionManagement/workOrder/index.vue | 1088 +++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 666 insertions(+), 422 deletions(-)

diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
index 291ca18..3b193f8 100644
--- a/src/views/productionManagement/workOrder/index.vue
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -1,3 +1,4 @@
+// 鐢熶骇宸ュ崟
 <template>
   <div class="app-container">
     <div class="search_form">
@@ -9,11 +10,12 @@
                     placeholder="璇疯緭鍏�"
                     @change="handleQuery"
                     clearable
-                    prefix-icon="Search" />
+                    prefix-icon="Search"/>
         </div>
         <div class="search-item">
           <el-button type="primary"
-                     @click="handleQuery">鎼滅储</el-button>
+                     @click="handleQuery">鎼滅储
+          </el-button>
         </div>
       </div>
     </div>
@@ -24,10 +26,12 @@
                 :page="page"
                 :tableLoading="tableLoading"
                 @pagination="pagination">
-                <template #completionStatus="{ row }">
-                  <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
-                </template>
-              </PIMTable>
+        <template #completionStatus="{ row }">
+          <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
+                       :color="progressColor(toProgressPercentage(row?.completionStatus))"
+                       :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''"/>
+        </template>
+      </PIMTable>
     </div>
     <el-dialog v-model="editDialogVisible"
                title="缂栬緫鏃堕棿"
@@ -39,28 +43,28 @@
                           type="date"
                           placeholder="璇烽�夋嫨"
                           value-format="YYYY-MM-DD"
-                          style="width: 300px" />
+                          style="width: 300px"/>
         </el-form-item>
         <el-form-item label="璁″垝缁撴潫鏃堕棿">
           <el-date-picker v-model="editrow.planEndTime"
                           type="date"
                           placeholder="璇烽�夋嫨"
                           value-format="YYYY-MM-DD"
-                          style="width: 300px" />
+                          style="width: 300px"/>
         </el-form-item>
         <el-form-item label="瀹為檯寮�濮嬫椂闂�">
           <el-date-picker v-model="editrow.actualStartTime"
                           type="date"
                           placeholder="璇烽�夋嫨"
                           value-format="YYYY-MM-DD"
-                          style="width: 300px" />
+                          style="width: 300px"/>
         </el-form-item>
         <el-form-item label="瀹為檯缁撴潫鏃堕棿">
           <el-date-picker v-model="editrow.actualEndTime"
                           type="date"
                           placeholder="璇烽�夋嫨"
                           value-format="YYYY-MM-DD"
-                          style="width: 300px" />
+                          style="width: 300px"/>
         </el-form-item>
       </el-form>
       <template #footer>
@@ -104,7 +108,7 @@
                 transferCardRowData.status 
               }}</span>
             </div> -->
-           
+
             <div class="info-item">
               <span class="info-label">璁″垝寮�濮嬫椂闂�</span>
               <span class="info-value">{{ transferCardRowData.planStartTime }}</span>
@@ -149,7 +153,7 @@
           <div class="qr-container">
             <img :src="transferCardQrUrl"
                  alt="娴佽浆鍗′簩缁寸爜"
-                 style="width: 200px; height: 200px;" />
+                 style="width: 200px; height: 200px;"/>
             <!-- <div class="qr-tip"
                  style="margin-top: 10px; text-align: center;">娴佽浆鍗′簩缁寸爜</div> -->
           </div>
@@ -160,32 +164,39 @@
       margin-bottom: 40px;">
         <el-button type="primary"
                    style="margin-top: 20px;"
-                   @click="printTransferCard">鎵撳嵃娴佽浆鍗�</el-button>
+                   @click="printTransferCard">鎵撳嵃娴佽浆鍗�
+        </el-button>
       </div>
     </el-dialog>
     <el-dialog v-model="reportDialogVisible"
                title="鎶ュ伐"
                width="500px">
-      <el-form :model="reportForm"
+      <el-form ref="reportFormRef"
+               :model="reportForm"
+               :rules="reportFormRules"
                label-width="120px">
         <el-form-item label="寰呯敓浜ф暟閲�">
           <el-input v-model="reportForm.planQuantity"
                     readonly
-                    style="width: 300px" />
+                    style="width: 300px"/>
         </el-form-item>
-        <el-form-item label="鏈鐢熶骇鏁伴噺">
+        <el-form-item label="鏈鐢熶骇鏁伴噺" prop="quantity">
           <el-input v-model.number="reportForm.quantity"
                     type="number"
                     min="1"
+                    step="1"
                     style="width: 300px"
-                    placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�" />
+                    placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�"
+                    @input="handleQuantityInput"/>
         </el-form-item>
-        <el-form-item label="鎶ュ簾鏁伴噺">
+        <el-form-item label="鎶ュ簾鏁伴噺" prop="scrapQty">
           <el-input v-model.number="reportForm.scrapQty"
                     type="number"
-                    min="1"
+                    min="0"
+                    step="1"
                     style="width: 300px"
-                    placeholder="璇疯緭鍏ユ姤搴熸暟閲�" />
+                    placeholder="璇疯緭鍏ユ姤搴熸暟閲�"
+                    @input="handleScrapQtyInput"/>
         </el-form-item>
         <el-form-item label="鐝粍淇℃伅">
           <el-select v-model="reportForm.userId"
@@ -197,9 +208,10 @@
             <el-option v-for="user in userOptions"
                        :key="user.userId"
                        :label="user.userName"
-                       :value="user.userId" />
+                       :value="user.userId"/>
           </el-select>
         </el-form-item>
+        <ProductionRecordForm ref="productionRecordFormRef" :list="processParamList"/>
       </el-form>
       <template #footer>
         <span class="dialog-footer">
@@ -209,192 +221,342 @@
         </span>
       </template>
     </el-dialog>
-    <FilesDia ref="workOrderFilesRef" />
+    <FilesDia ref="workOrderFilesRef"/>
+    <CopperPrintingForm
+        v-if="copperPrintingFormVisible"
+        v-model:isShow="copperPrintingFormVisible"
+        :isEdit="true"
+        :row="currentReportRowData"
+        @refreshData="getList"/>
+    <VoltageSortingForm
+        v-if="voltageSortingFormVisible"
+        v-model:isShow="voltageSortingFormVisible"
+        :isEdit="true"
+        :row="currentReportRowData"
+        @refreshData="getList"/>
+    <GranulationForm
+        v-if="granulationFormVisible"
+        v-model:isShow="granulationFormVisible"
+        :isEdit="true"
+        :row="currentReportRowData"
+        @refreshData="getList"/>
   </div>
 </template>
 
 <script setup>
-  import { onMounted, ref } from "vue";
-  import { ElMessageBox } from "element-plus";
-  import dayjs from "dayjs";
-  import {
-    productWorkOrderPage,
-    updateProductWorkOrder,
-    addProductMain,
-    downProductWorkOrder,
-  } from "@/api/productionManagement/workOrder.js";
-  import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
-  import QRCode from "qrcode";
-  import { getCurrentInstance, reactive, toRefs } from "vue";
-  import FilesDia from "./components/filesDia.vue";
-  const { proxy } = getCurrentInstance();
+import {onMounted, ref, nextTick} from "vue";
+import {ElMessageBox} from "element-plus";
+import dayjs from "dayjs";
+import {
+  productWorkOrderPage,
+  updateProductWorkOrder,
+  addProductMain,
+  downProductWorkOrder,
+} from "@/api/productionManagement/workOrder.js";
+import {getUserProfile, userListNoPageByTenantId} from "@/api/system/user.js";
+import QRCode from "qrcode";
+import {getCurrentInstance, reactive, toRefs} from "vue";
+import FilesDia from "./components/filesDia.vue";
+import {
+  listPage as listProcessParamPage,
+} from "@/api/productionManagement/productProcessParameter.js";
 
-  const tableColumn = ref([
-    {
-      label: "宸ュ崟缂栧彿",
-      prop: "workOrderNo",
-      width: "140",
-    },
-    {
-      label: "鐢熶骇璁㈠崟鍙�",
-      prop: "productOrderNpsNo",
-      width: "140",
-    },
-    {
-      label: "浜у搧鍚嶇О",
-      prop: "productName",
-      width: "140",
-    },
-    {
-      label: "瑙勬牸",
-      prop: "model",
-    },
-    {
-      label: "鍗曚綅",
-      prop: "unit",
-    },
-    {
-      label: "宸ュ簭鍚嶇О",
-      prop: "processName",
-    },
-    {
-      label: "闇�姹傛暟閲�",
-      prop: "planQuantity",
-      width: "140",
-    },
-    {
-      label: "瀹屾垚鏁伴噺",
-      prop: "completeQuantity",
-      width: "140",
-    },
-    {
-      label: "瀹屾垚杩涘害",
-      prop: "completionStatus",
-      dataType: "slot",
-      slot: "completionStatus",
-      width: "140",
-    },
-    {
-      label: "璁″垝寮�濮嬫椂闂�",
-      prop: "planStartTime",
-      width: "140",
-    },
-    {
-      label: "璁″垝缁撴潫鏃堕棿",
-      prop: "planEndTime",
-      width: "140",
-    },
-    {
-      label: "瀹為檯寮�濮嬫椂闂�",
-      prop: "actualStartTime",
-      width: "140",
-    },
-    {
-      label: "瀹為檯缁撴潫鏃堕棿",
-      prop: "actualEndTime",
-      width: "140",
-    },
-    {
-      label: "鎿嶄綔",
-      width: "200",
-      align: "center",
-      dataType: "action",
-      fixed: "right",
-      operation: [
-        {
-          name: "缂栬緫",
-          clickFun: row => {
-            handleEdit(row);
-          },
-        },
-        {
-          name: "娴佽浆鍗�",
-          clickFun: row => {
-            downloadAndPrintWorkOrder(row);
-          },
-        },
-        {
-          name: "闄勪欢",
-          clickFun: row => {
-            openWorkOrderFiles(row);
-          },
-        },
-        {
-          name: "鎶ュ伐",
-          clickFun: row => {
-            showReportDialog(row);
-          },
-          disabled: row => row.planQuantity <= 0,
-        },
-      ],
-    },
-  ]);
-  const tableData = ref([]);
-  const tableLoading = ref(false);
-  const qrCodeUrl = ref("");
-  const qrRowData = ref(null);
-  const editDialogVisible = ref(false);
-  const transferCardVisible = ref(false);
-  const transferCardData = ref([]);
-  const transferCardQrUrl = ref("");
-  const transferCardRowData = ref(null);
-  const reportDialogVisible = ref(false);
-  const workOrderFilesRef = ref(null);
-  const userOptions = ref([]);
-  const reportForm = reactive({
-    planQuantity: 0,
-    quantity: 0,
-    userName: "",
-    workOrderId: "",
-    reportWork: "",
-    productProcessRouteItemId: "",
-    userId: "",
-    productMainId: null,
-  });
-  const currentReportRowData = ref(null);
-  const page = reactive({
-    current: 1,
-    size: 100,
-    total: 0,
-  });
+const {proxy} = getCurrentInstance();
+const {priority_type} = proxy.useDict("priority_type");
 
-  const data = reactive({
-    searchForm: {
-      workOrderNo: "",
+const CopperPrintingForm = defineAsyncComponent(() => import("./components/CopperPrintingForm.vue"));
+const VoltageSortingForm = defineAsyncComponent(() => import("./components/VoltageSortingForm.vue"));
+const ProductionRecordForm = defineAsyncComponent(() => import("./components/ProductionRecordForm.vue"));
+const GranulationForm = defineAsyncComponent(() => import("./components/GranulationForm.vue"));
+const tableColumn = ref([
+  {
+    label: "浼樺厛绾�",
+    prop: "priority",
+    width: '100px',
+    dataType: "tag",
+    formatData: val => proxy.selectDictLabel(priority_type.value, val),
+    formatType: val => {
+      const v = Number(val);
+      if (v === 0) return "danger";   // 绾㈣壊
+      if (v === 1) return "warning";  // 榛勮壊
+      if (v === 2) return "success";  // 缁胯壊
+      return "";
     },
-  });
-  const { searchForm } = toRefs(data);
-  const toProgressPercentage = val => {
-    const n = Number(val);
-    if (!Number.isFinite(n)) return 0;
-    if (n <= 0) return 0;
-    if (n >= 100) return 100;
-    return Math.round(n);
-  };
-  const progressColor = percentage => {
-    const p = toProgressPercentage(percentage);
-    if (p < 30) return "#f56c6c";
-    if (p < 50) return "#e6a23c";
-    if (p < 80) return "#409eff";
-    return "#67c23a";
-  };
-  let editrow = ref(null);
+  },
+  // {
+  //   label: "宸ュ崟绫诲瀷",
+  //   prop: "workOrderType",
+  //   width: "80",
+  // },
+  {
+    label: "宸ュ崟缂栧彿",
+    prop: "workOrderNo",
+    width: "140",
+  },
+  {
+    label: "鐢熶骇璁㈠崟鍙�",
+    prop: "productOrderNpsNo",
+    width: "140",
+  },
+  {
+    label: "浜у搧鍚嶇О",
+    prop: "productName",
+    width: "140",
+  },
+  {
+    label: "瑙勬牸",
+    prop: "model",
+  },
+  {
+    label: "鍗曚綅",
+    prop: "unit",
+  },
+  {
+    label: "宸ュ簭鍚嶇О",
+    prop: "processName",
+  },
+  {
+    label: "闇�姹傛暟閲�",
+    prop: "planQuantity",
+    width: "140",
+  },
+  {
+    label: "瀹屾垚鏁伴噺",
+    prop: "completeQuantity",
+    width: "140",
+  },
+  {
+    label: "瀹屾垚杩涘害",
+    prop: "completionStatus",
+    dataType: "slot",
+    slot: "completionStatus",
+    width: "140",
+  },
+  {
+    label: "璁″垝寮�濮嬫椂闂�",
+    prop: "planStartTime",
+    width: "140",
+  },
+  {
+    label: "璁″垝缁撴潫鏃堕棿",
+    prop: "planEndTime",
+    width: "140",
+  },
+  {
+    label: "瀹為檯寮�濮嬫椂闂�",
+    prop: "actualStartTime",
+    width: "140",
+  },
+  {
+    label: "瀹為檯缁撴潫鏃堕棿",
+    prop: "actualEndTime",
+    width: "140",
+  },
+  {
+    label: "鎿嶄綔",
+    width: "200",
+    align: "center",
+    dataType: "action",
+    fixed: "right",
+    operation: [
+      {
+        name: "缂栬緫",
+        clickFun: row => {
+          handleEdit(row);
+          handleEdit(row);
+        },
+      },
+      {
+        name: "娴佽浆鍗�",
+        clickFun: row => {
+          downloadAndPrintWorkOrder(row);
+        },
+      },
+      {
+        name: "闄勪欢",
+        clickFun: row => {
+          openWorkOrderFiles(row);
+        },
+      },
+      {
+        name: "鎶ュ伐",
+        clickFun: row => {
+          showReportDialog(row);
+        },
+        disabled: row => !row.isCanReport || row.planQuantity <= 0,
+      },
+    ],
+  },
+]);
+const tableData = ref([]);
+const tableLoading = ref(false);
+const qrCodeUrl = ref("");
+const qrRowData = ref(null);
+const editDialogVisible = ref(false);
+const copperPrintingFormVisible = ref(false);
+const voltageSortingFormVisible = ref(false);
+const granulationFormVisible = ref(false);
+const transferCardVisible = ref(false);
+const transferCardData = ref([]);
+const transferCardQrUrl = ref("");
+const transferCardRowData = ref(null);
+const reportDialogVisible = ref(false);
+const workOrderFilesRef = ref(null);
+const reportFormRef = ref(null);
+const userOptions = ref([]);
+const reportForm = reactive({
+  planQuantity: 0,
+  quantity: null,
+  scrapQty: null,
+  userName: "",
+  workOrderId: "",
+  reportWork: "",
+  productProcessRouteItemId: "",
+  userId: "",
+  productMainId: null,
+  otherData: {
+    rows: [],
+  }
+});
+const productionRecordFormRef = ref();
 
-  // 鏌ヨ鍒楄〃
-  /** 鎼滅储鎸夐挳鎿嶄綔 */
-  const handleQuery = () => {
-    page.current = 1;
-    getList();
-  };
-  const pagination = obj => {
-    page.current = obj.page;
-    page.size = obj.limit;
-    getList();
-  };
-  const getList = () => {
-    tableLoading.value = true;
-    const params = { ...searchForm.value, ...page };
-    productWorkOrderPage(params)
+// 鏈鐢熶骇鏁伴噺楠岃瘉瑙勫垯
+const validateQuantity = (rule, value, callback) => {
+  if (value === null || value === undefined || value === '') {
+    callback(new Error('璇疯緭鍏ユ湰娆$敓浜ф暟閲�'));
+    return;
+  }
+  const num = Number(value);
+  // 鏁存暟涓斿ぇ浜庣瓑浜�1
+  if (isNaN(num) || !Number.isInteger(num) || num < 1) {
+    callback(new Error('鏈鐢熶骇鏁伴噺蹇呴』澶т簬绛変簬1'));
+    return;
+  }
+  callback();
+};
+
+// 鎶ュ簾鏁伴噺楠岃瘉瑙勫垯
+const validateScrapQty = (rule, value, callback) => {
+  if (value === null || value === undefined || value === '') {
+    callback();
+    return;
+  }
+  const num = Number(value);
+  // 鏁存暟涓斿ぇ浜庣瓑浜�0
+  if (isNaN(num) || !Number.isInteger(num) || num < 0) {
+    callback(new Error('鎶ュ簾鏁伴噺蹇呴』澶т簬绛変簬0'));
+    return;
+  }
+  callback();
+};
+
+// 楠岃瘉瑙勫垯
+const reportFormRules = {
+  quantity: [
+    {required: true, validator: validateQuantity, trigger: 'blur'}
+  ],
+  scrapQty: [
+    {validator: validateScrapQty, trigger: 'blur'}
+  ]
+};
+
+// 澶勭悊鏈鐢熶骇鏁伴噺杈撳叆锛岄檺鍒跺繀椤诲ぇ浜庣瓑浜�1
+const handleQuantityInput = (value) => {
+  if (value === '' || value === null || value === undefined) {
+    reportForm.quantity = null;
+    return;
+  }
+  const num = Number(value);
+  if (isNaN(num)) {
+    return;
+  }
+  // 濡傛灉灏忎簬1锛屾竻闄�
+  if (num < 1) {
+    reportForm.quantity = null;
+    return;
+  }
+  // 濡傛灉鏄皬鏁板彇鏁存暟閮ㄥ垎
+  if (!Number.isInteger(num)) {
+    const intValue = Math.floor(num);
+    // 濡傛灉鍙栨暣鍚庡皬浜�1锛屾竻闄�
+    if (intValue < 1) {
+      reportForm.quantity = null;
+      return;
+    }
+    reportForm.quantity = intValue;
+    return;
+  }
+  reportForm.quantity = num;
+};
+
+// 澶勭悊鎶ュ簾鏁伴噺
+const handleScrapQtyInput = (value) => {
+  if (value === '' || value === null || value === undefined) {
+    reportForm.scrapQty = null;
+    return;
+  }
+  const num = Number(value);
+  // 濡傛灉鏄疦aN锛屼繚鎸佸師鍊�
+  if (isNaN(num)) {
+    return;
+  }
+  // 濡傛灉鏄礋鏁帮紝娓呴櫎杈撳叆
+  if (num < 0) {
+    reportForm.scrapQty = null;
+    return;
+  }
+  // 濡傛灉鏄皬鏁帮紝鍙栨暣鏁伴儴鍒�
+  if (!Number.isInteger(num)) {
+    reportForm.scrapQty = Math.floor(num);
+    return;
+  }
+  // 鏈夋晥鐨勯潪璐熸暣鏁帮紙鍖呮嫭0锛�
+  reportForm.scrapQty = num;
+};
+const currentReportRowData = ref(null);
+const page = reactive({
+  current: 1,
+  size: 100,
+  total: 0,
+});
+
+const data = reactive({
+  searchForm: {
+    workOrderNo: "",
+  },
+});
+const {searchForm} = toRefs(data);
+const toProgressPercentage = val => {
+  const n = Number(val);
+  if (!Number.isFinite(n)) return 0;
+  if (n <= 0) return 0;
+  if (n >= 100) return 100;
+  return Math.round(n);
+};
+const progressColor = percentage => {
+  const p = toProgressPercentage(percentage);
+  if (p < 30) return "#f56c6c";
+  if (p < 50) return "#e6a23c";
+  if (p < 80) return "#409eff";
+  return "#67c23a";
+};
+let editrow = ref(null);
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = 1;
+  getList();
+};
+const pagination = obj => {
+  page.current = obj.page;
+  page.size = obj.limit;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  const params = {...searchForm.value, ...page};
+  productWorkOrderPage(params)
       .then(res => {
         tableLoading.value = false;
         tableData.value = res.data.records;
@@ -403,77 +565,77 @@
       .catch(() => {
         tableLoading.value = false;
       });
-  };
+};
 
-  // 涓嬭浇骞舵墦鍗板伐鍗曟祦杞崱锛堟枃浠舵祦锛�
-  const downloadAndPrintWorkOrder = async row => {
-    if (!row || !row.id) {
-      proxy.$modal.msgError("缂哄皯宸ュ崟ID锛屾棤娉曚笅杞芥祦杞崱");
-      return;
-    }
-    const fileName = row.workOrderNo
+// 涓嬭浇骞舵墦鍗板伐鍗曟祦杞崱锛堟枃浠舵祦锛�
+const downloadAndPrintWorkOrder = async row => {
+  if (!row || !row.id) {
+    proxy.$modal.msgError("缂哄皯宸ュ崟ID锛屾棤娉曚笅杞芥祦杞崱");
+    return;
+  }
+  const fileName = row.workOrderNo
       ? `宸ュ崟娴佽浆鍗${row.workOrderNo}.xlsx`
       : "宸ュ崟娴佽浆鍗�.xlsx";
-    try {
-      // 璋冪敤鎺ュ彛锛屼互 responseType: 'blob' 鑾峰彇鏂囦欢娴�
-      const blob = await downProductWorkOrder(row.id);
+  try {
+    // 璋冪敤鎺ュ彛锛屼互 responseType: 'blob' 鑾峰彇鏂囦欢娴�
+    const blob = await downProductWorkOrder(row.id);
 
-      if (!blob) {
-        proxy.$modal.msgError("鏈幏鍙栧埌娴佽浆鍗℃枃浠�");
-        return;
-      }
-
-      // 鍒涘缓 Blob URL
-      const fileBlob =
-        blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" });
-      const url = window.URL.createObjectURL(fileBlob);
-
-      // 鍒涘缓闅愯棌 iframe锛岀敤浜庤Е鍙戞祻瑙堝櫒鎵撳嵃
-      const iframe = document.createElement("iframe");
-      iframe.style.position = "fixed";
-      iframe.style.right = "0";
-      iframe.style.bottom = "0";
-      iframe.style.width = "0";
-      iframe.style.height = "0";
-      iframe.style.border = "0";
-      iframe.src = url;
-      document.body.appendChild(iframe);
-
-      iframe.onload = () => {
-        try {
-          iframe.contentWindow?.focus();
-          iframe.contentWindow?.print();
-        } catch (e) {
-          console.error("鑷姩璋冪敤鎵撳嵃澶辫触", e);
-          // 閫�鑰屾眰鍏舵锛屾墦寮�鏂扮獥鍙g敱鐢ㄦ埛鎵嬪姩鎵撳嵃
-          window.open(url);
-        }
-      };
-    } catch (e) {
-      console.error("涓嬭浇宸ュ崟娴佽浆鍗″け璐�", e);
-      proxy.$modal.msgError("涓嬭浇宸ュ崟娴佽浆鍗″け璐�");
+    if (!blob) {
+      proxy.$modal.msgError("鏈幏鍙栧埌娴佽浆鍗℃枃浠�");
+      return;
     }
-  };
 
-  const showTransferCard = async row => {
-    transferCardRowData.value = row;
-    const qrContent = String(row.id);
+    // 鍒涘缓 Blob URL
+    const fileBlob =
+        blob instanceof Blob ? blob : new Blob([blob], {type: blob.type || "application/octet-stream"});
+    const url = window.URL.createObjectURL(fileBlob);
 
-    transferCardQrUrl.value = await QRCode.toDataURL(qrContent);
-    transferCardVisible.value = true;
-  };
+    // 鍒涘缓闅愯棌 iframe锛岀敤浜庤Е鍙戞祻瑙堝櫒鎵撳嵃
+    const iframe = document.createElement("iframe");
+    iframe.style.position = "fixed";
+    iframe.style.right = "0";
+    iframe.style.bottom = "0";
+    iframe.style.width = "0";
+    iframe.style.height = "0";
+    iframe.style.border = "0";
+    iframe.src = url;
+    document.body.appendChild(iframe);
 
-  const printTransferCard = () => {
-    window.print();
-  };
+    iframe.onload = () => {
+      try {
+        iframe.contentWindow?.focus();
+        iframe.contentWindow?.print();
+      } catch (e) {
+        console.error("鑷姩璋冪敤鎵撳嵃澶辫触", e);
+        // 閫�鑰屾眰鍏舵锛屾墦寮�鏂扮獥鍙g敱鐢ㄦ埛鎵嬪姩鎵撳嵃
+        window.open(url);
+      }
+    };
+  } catch (e) {
+    console.error("涓嬭浇宸ュ崟娴佽浆鍗″け璐�", e);
+    proxy.$modal.msgError("涓嬭浇宸ュ崟娴佽浆鍗″け璐�");
+  }
+};
 
-  const handleEdit = row => {
-    editrow.value = JSON.parse(JSON.stringify(row));
-    editDialogVisible.value = true;
-  };
+const showTransferCard = async row => {
+  transferCardRowData.value = row;
+  const qrContent = String(row.id);
 
-  const handleUpdate = () => {
-    updateProductWorkOrder(editrow.value)
+  transferCardQrUrl.value = await QRCode.toDataURL(qrContent);
+  transferCardVisible.value = true;
+};
+
+const printTransferCard = () => {
+  window.print();
+};
+
+const handleEdit = row => {
+  editrow.value = JSON.parse(JSON.stringify(row));
+  editDialogVisible.value = true;
+};
+
+const handleUpdate = () => {
+  updateProductWorkOrder(editrow.value)
       .then(res => {
         proxy.$modal.msgSuccess("鎻愪氦鎴愬姛");
         editDialogVisible.value = false;
@@ -484,19 +646,50 @@
           confirmButtonText: "纭畾",
         });
       });
-  };
+};
 
-  const showReportDialog = row => {
-    currentReportRowData.value = row;
-    reportForm.planQuantity = row.planQuantity;
-    reportForm.quantity = row.quantity;
-    reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
-    reportForm.workOrderId = row.id;
-    reportForm.reportWork = row.reportWork;
-    reportForm.productMainId = row.productMainId;
-    reportForm.scrapQty = row.scrapQty;
-    // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
-    getUserProfile()
+const processParamPage = reactive({
+  current: 1,
+  size: 9999,
+  total: 0,
+});
+const getProcessParamList = async (row) => {
+  const params = {
+    processId: row.processId,
+    ...processParamPage,
+  };
+  const res = await listProcessParamPage(params)
+  return res.data.records
+};
+
+const processParamList = ref([])
+const showReportDialog = async row => {
+  currentReportRowData.value = row;
+  if (row.processName === '鍗伴摐' || row.processName === '鍗伴摱') {
+    copperPrintingFormVisible.value = true
+    return
+  }
+  if (row.processName === '鐢靛帇鍒嗛��') {
+    voltageSortingFormVisible.value = true
+    return;
+  }
+  if (row.processName === '閫犵矑') {
+    granulationFormVisible.value = true
+    return;
+  }
+  processParamList.value = await getProcessParamList(row)
+  reportForm.planQuantity = row.planQuantity;
+  reportForm.quantity = row.quantity !== undefined && row.quantity !== null ? row.quantity : null;
+  reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
+  reportForm.workOrderId = row.id;
+  reportForm.reportWork = row.reportWork;
+  reportForm.productMainId = row.productMainId;
+  reportForm.scrapQty = row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null;
+  nextTick(() => {
+    reportFormRef.value?.clearValidate();
+  });
+  // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
+  getUserProfile()
       .then(res => {
         if (res.code === 200) {
           reportForm.userId = res.data.userId;
@@ -507,34 +700,72 @@
         console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
       });
 
-    reportDialogVisible.value = true;
-  };
+  reportDialogVisible.value = true;
+};
 
-  const openWorkOrderFiles = row => {
-    workOrderFilesRef.value?.openDialog(row);
-  };
+const openWorkOrderFiles = row => {
+  workOrderFilesRef.value?.openDialog(row);
+};
 
-  const handleReport = () => {
+const handleReport = async () => {
+  const data = await productionRecordFormRef.value.submitData()
+  reportForm.otherData.rows = JSON.stringify(data || {});
+  reportFormRef.value?.validate((valid) => {
+    if (!valid) {
+      return false;
+    }
+
     if (reportForm.planQuantity <= 0) {
       ElMessageBox.alert("寰呯敓浜ф暟閲忎负0锛屾棤娉曟姤宸�", "鎻愮ず", {
         confirmButtonText: "纭畾",
       });
       return;
     }
-    if (!reportForm.quantity || reportForm.quantity <= 0) {
-      ElMessageBox.alert("璇疯緭鍏ユ湁鏁堢殑鏈鐢熶骇鏁伴噺", "鎻愮ず", {
+
+    // 楠岃瘉鏈鐢熶骇鏁伴噺
+    if (reportForm.quantity === null || reportForm.quantity === undefined || reportForm.quantity === '') {
+      ElMessageBox.alert("璇疯緭鍏ユ湰娆$敓浜ф暟閲�", "鎻愮ず", {
         confirmButtonText: "纭畾",
       });
       return;
     }
-    if (reportForm.quantity > reportForm.planQuantity) {
+
+    const quantity = Number(reportForm.quantity);
+    const scrapQty = reportForm.scrapQty === null || reportForm.scrapQty === undefined || reportForm.scrapQty === ''
+        ? 0
+        : Number(reportForm.scrapQty);
+
+    // 鏈鐢熶骇鏁伴噺
+    if (isNaN(quantity) || !Number.isInteger(quantity) || quantity < 1) {
+      ElMessageBox.alert("鏈鐢熶骇鏁伴噺蹇呴』澶т簬绛変簬1", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+      });
+      return;
+    }
+
+    // 鎶ュ簾鏁伴噺蹇呴』鏄暣鏁颁笖澶т簬绛変簬0
+    if (isNaN(scrapQty) || !Number.isInteger(scrapQty) || scrapQty < 0) {
+      ElMessageBox.alert("鎶ュ簾鏁伴噺蹇呴』澶т簬绛変簬0", "鎻愮ず", {
+        confirmButtonText: "纭畾",
+      });
+      return;
+    }
+
+    if (quantity > reportForm.planQuantity) {
       ElMessageBox.alert("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�", "鎻愮ず", {
         confirmButtonText: "纭畾",
       });
       return;
     }
-    // console.log(reportForm);
-    addProductMain(reportForm).then(res => {
+
+    const submitData = {
+      ...reportForm,
+      quantity: quantity,
+      scrapQty: scrapQty
+    };
+
+    // console.log(submitData);
+    addProductMain(submitData).then(res => {
       if (res.code === 200) {
         proxy.$modal.msgSuccess("鎶ュ伐鎴愬姛");
         reportDialogVisible.value = false;
@@ -545,11 +776,12 @@
         });
       }
     });
-  };
+  });
+};
 
-  // 鑾峰彇鐢ㄦ埛鍒楄〃
-  const getUserList = () => {
-    userListNoPageByTenantId()
+// 鑾峰彇鐢ㄦ埛鍒楄〃
+const getUserList = () => {
+  userListNoPageByTenantId()
       .then(res => {
         if (res.code === 200) {
           userOptions.value = res.data || [];
@@ -558,160 +790,172 @@
       .catch(err => {
         console.error("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触", err);
       });
-  };
+};
 
-  // 鐢ㄦ埛閫夋嫨鍙樺寲鏃舵洿鏂� userName
-  const handleUserChange = (userId) => {
-    if (userId) {
-      const selectedUser = userOptions.value.find(user => user.userId === userId);
-      if (selectedUser) {
-        reportForm.userName = selectedUser.userName;
-      }
-    } else {
-      reportForm.userName = "";
+// 鐢ㄦ埛閫夋嫨鍙樺寲鏃舵洿鏂� userName
+const handleUserChange = (userId) => {
+  if (userId) {
+    const selectedUser = userOptions.value.find(user => user.userId === userId);
+    if (selectedUser) {
+      reportForm.userName = selectedUser.userName;
     }
-  };
+  } else {
+    reportForm.userName = "";
+  }
+};
 
-  onMounted(() => {
-    getList();
-    getUserList();
-  });
+onMounted(() => {
+  getList();
+  getUserList();
+});
 </script>
 
 <style scoped lang="scss">
-  .search_form {
-    margin-bottom: 20px;
-    .search-row {
-      display: flex;
-      gap: 20px;
-      align-items: center;
-      .search-item {
-        display: flex;
-        align-items: center;
-        gap: 10px;
-      }
-    }
-  }
+.search_form {
+  margin-bottom: 20px;
 
-  .transfer-card-title {
-    font-size: 24px;
-    font-weight: bold;
-    text-align: center;
-    margin-bottom: 20px;
-  }
-
-  .transfer-card-container {
+  .search-row {
     display: flex;
     gap: 20px;
-    height: 350px;
-    .transfer-card-info {
-      flex: 1;
-      overflow: auto;
-      .info-group {
-        width: 50%;
-        float: left;
-      }
-      .info-item {
-        display: flex;
-        margin-bottom: 15px;
-        .info-label {
-          width: 120px;
-          font-weight: bold;
-          margin-right: 20px;
-        }
-        .info-value {
-          flex: 1;
-        }
-      }
-    }
-    .transfer-card-qr {
-      width: 240px;
+    align-items: center;
+
+    .search-item {
       display: flex;
-      flex-direction: column;
       align-items: center;
-      justify-content: flex-start;
+      gap: 10px;
     }
   }
+}
+
+.transfer-card-title {
+  font-size: 24px;
+  font-weight: bold;
+  text-align: center;
+  margin-bottom: 20px;
+}
+
+.transfer-card-container {
+  display: flex;
+  gap: 20px;
+  height: 350px;
+
+  .transfer-card-info {
+    flex: 1;
+    overflow: auto;
+
+    .info-group {
+      width: 50%;
+      float: left;
+    }
+
+    .info-item {
+      display: flex;
+      margin-bottom: 15px;
+
+      .info-label {
+        width: 120px;
+        font-weight: bold;
+        margin-right: 20px;
+      }
+
+      .info-value {
+        flex: 1;
+      }
+    }
+  }
+
+  .transfer-card-qr {
+    width: 240px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: flex-start;
+  }
+}
 </style>
 
-<style  lang="scss">
-  @media print {
-    @page {
-      size: landscape;
+<style lang="scss">
+@media print {
+  @page {
+    size: landscape;
+  }
+  body * {
+    visibility: hidden;
+  }
+  .el-dialog__wrapper,
+  .el-dialog,
+  .el-dialog__body,
+  .transfer-card-title,
+  .transfer-card-container,
+  .transfer-card-container *,
+  .info-item,
+  .info-label,
+  .info-value {
+    visibility: visible;
+  }
+  .print-button-container {
+    visibility: hidden;
+  }
+  .el-dialog__wrapper {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    margin: 0;
+  }
+  .el-dialog {
+    width: 100% !important;
+    max-width: 800px;
+    margin: 0 auto !important;
+  }
+  .el-dialog__header,
+  .el-dialog__footer {
+    display: none;
+  }
+  .el-dialog__body {
+    padding: 20px;
+  }
+  .transfer-card-container {
+    height: auto;
+    display: flex;
+    gap: 20px;
+  }
+  .transfer-card-info {
+    flex: 1;
+
+    .info-group {
+      width: 100%;
+      float: none;
+      margin-bottom: 20px;
     }
-    body * {
-      visibility: hidden;
-    }
-    .el-dialog__wrapper,
-    .el-dialog,
-    .el-dialog__body,
-    .transfer-card-title,
-    .transfer-card-container,
-    .transfer-card-container *,
-    .info-item,
-    .info-label,
-    .info-value {
-      visibility: visible;
-    }
-    .print-button-container {
-      visibility: hidden;
-    }
-    .el-dialog__wrapper {
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      margin: 0;
-    }
-    .el-dialog {
-      width: 100% !important;
-      max-width: 800px;
-      margin: 0 auto !important;
-    }
-    .el-dialog__header,
-    .el-dialog__footer {
-      display: none;
-    }
-    .el-dialog__body {
-      padding: 20px;
-    }
-    .transfer-card-container {
-      height: auto;
+
+    .info-item {
       display: flex;
-      gap: 20px;
-    }
-    .transfer-card-info {
-      flex: 1;
-      .info-group {
-        width: 100%;
-        float: none;
-        margin-bottom: 20px;
+      margin-bottom: 10px;
+
+      .info-label {
+        width: 100px;
+        font-weight: bold;
+        margin-right: 15px;
+        white-space: nowrap;
       }
-      .info-item {
-        display: flex;
-        margin-bottom: 10px;
-        .info-label {
-          width: 100px;
-          font-weight: bold;
-          margin-right: 15px;
-          white-space: nowrap;
-        }
-        .info-value {
-          flex: 1;
-          word-break: break-word;
-        }
+
+      .info-value {
+        flex: 1;
+        word-break: break-word;
       }
-    }
-    .transfer-card-qr {
-      width: 160px;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      justify-content: flex-start;
-    }
-    .qr-container img {
-      width: 140px !important;
-      height: 140px !important;
     }
   }
+  .transfer-card-qr {
+    width: 160px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: flex-start;
+  }
+  .qr-container img {
+    width: 140px !important;
+    height: 140px !important;
+  }
+}
 </style>

--
Gitblit v1.9.3