From 3a63dff0d98c148c6b915cd762a50ed87aa6c3a5 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期四, 26 三月 2026 11:20:55 +0800
Subject: [PATCH] feat:1.生产订单增加清场记录弹框

---
 src/views/productionManagement/productionOrder/ClearanceRecordDialog.vue |  400 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/views/productionManagement/productionOrder/index.vue                 |   47 +++++
 src/api/productionManagement/productionOrder.js                          |    9 +
 3 files changed, 456 insertions(+), 0 deletions(-)

diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index 9441544..72cdb10 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -136,4 +136,13 @@
     url: `/productOrder/${id}`,
     method: "patch",
   });
+}
+
+// 淇濆瓨娓呭満璁板綍
+export function saveCleanRecord(id, data) {
+  return request({
+    url: `/productOrder/cleanRecord/${id}`,
+    method: "patch",
+    data: data,
+  });
 }
\ No newline at end of file
diff --git a/src/views/productionManagement/productionOrder/ClearanceRecordDialog.vue b/src/views/productionManagement/productionOrder/ClearanceRecordDialog.vue
new file mode 100644
index 0000000..0b8d3af
--- /dev/null
+++ b/src/views/productionManagement/productionOrder/ClearanceRecordDialog.vue
@@ -0,0 +1,400 @@
+<template>
+  <el-dialog
+    v-model="visible"
+    title="娓呭満璁板綍"
+    width="900px"
+    :close-on-click-modal="false"
+    destroy-on-close
+  >
+    <div class="clearance-record-form">
+      <!-- 鍩烘湰淇℃伅鍖哄煙 -->
+      <div class="basic-info">
+        <table class="info-table">
+          <tr>
+            <td class="label">浜у搧鍚嶇О</td>
+            <td class="value" colspan="3">{{ formData.productName }}</td>
+            <td class="label">鐢熶骇鏃ユ湡</td>
+            <td class="value">{{ formData.productionDate }}</td>
+          </tr>
+          <tr>
+            <td class="label">瑙勬牸</td>
+            <td class="value">{{ formData.spec }}</td>
+            <td class="label">鎵瑰彿</td>
+            <td class="value">{{ formData.batchNo }}</td>
+            <td class="label">鐢熶骇杞﹂棿</td>
+            <td class="value">{{ formData.workshop }}</td>
+          </tr>
+        </table>
+      </div>
+
+      <!-- 娓呭満妫�鏌ラ」鐩〃鏍� -->
+      <div class="check-items-section">
+        <table class="check-table">
+          <thead>
+            <tr>
+              <th class="item-no">搴忓彿</th>
+              <th class="content">娓呭満鍐呭鍙婅姹�</th>
+              <th class="result" colspan="2">妫�鏌ョ粨鏋�</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr v-for="(item, index) in formData.checkItems" :key="index">
+              <td class="item-no">{{ item.itemNo }}</td>
+              <td class="content">{{ item.content }}</td>
+              <td class="result-option">
+                <el-radio-group v-model="item.result">
+                  <el-radio label="绗﹀悎瑙勫畾">绗﹀悎瑙勫畾</el-radio>
+                </el-radio-group>
+              </td>
+              <td class="result-option">
+                <el-radio-group v-model="item.result">
+                  <el-radio label="涓嶇鍚堣瀹�">涓嶇鍚堣瀹�</el-radio>
+                </el-radio-group>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+
+      <!-- 绛惧悕鍖哄煙 -->
+      <div class="signature-section">
+        <table class="signature-table">
+          <tr>
+            <td class="label">娓呭満浜�</td>
+            <td class="value">
+              <el-input v-model="formData.cleaner" placeholder="璇疯緭鍏ユ竻鍦轰汉" clearable />
+            </td>
+            <td class="label">鏃ユ湡</td>
+            <td class="value">
+              <el-date-picker
+                v-model="formData.cleanDate"
+                type="datetime"
+                placeholder="閫夋嫨鏃ユ湡鏃堕棿"
+                format="YYYY-MM-DD HH:mm:ss"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                style="width: 100%"
+              />
+            </td>
+            <td class="label">妫�鏌ヤ汉</td>
+            <td class="value">
+              <el-input v-model="formData.inspector" placeholder="璇疯緭鍏ユ鏌ヤ汉" clearable />
+            </td>
+            <td class="label">鏃ユ湡</td>
+            <td class="value">
+              <el-date-picker
+                v-model="formData.inspectDate"
+                type="datetime"
+                placeholder="閫夋嫨鏃ユ湡鏃堕棿"
+                format="YYYY-MM-DD HH:mm:ss"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                style="width: 100%"
+              />
+            </td>
+          </tr>
+        </table>
+      </div>
+    </div>
+
+    <template #footer>
+      <span class="dialog-footer">
+        <el-button @click="handleCancel">鍙� 娑�</el-button>
+        <el-button type="primary" :loading="saving" @click="handleSave">淇� 瀛�</el-button>
+      </span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, watch, computed } from 'vue';
+import dayjs from 'dayjs';
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false
+  },
+  orderData: {
+    type: Object,
+    default: () => ({})
+  }
+});
+
+const emit = defineEmits(['update:modelValue', 'save']);
+
+const visible = computed({
+  get: () => props.modelValue,
+  set: (val) => emit('update:modelValue', val)
+});
+
+const saving = ref(false);
+
+// 榛樿妫�鏌ラ」鐩�
+const defaultCheckItems = [
+  { itemNo: 1, content: '杞﹂棿鍐呮棤鍓嶆壒閬楃暀鐗┿�佸簾寮冪墿銆�', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 2, content: '杞﹂棿鍐呮棤鏃犲叧鎸囦护銆佽绋嬨�佽褰曠瓑銆�', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 3, content: '妗岄潰銆佸伐浣滃彴搴旀竻娲侊紝鏃犲皹銆佹棤鍨€��', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 4, content: '鍦伴潰娓呮磥锛屾棤绉皹銆佹潅鐗┿��', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 5, content: '璁惧鍙婇儴浠跺唴銆佸搴旀竻娲侊紝鏃犲紓鐗┿��', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 6, content: '瀹瑰櫒鍏峰簲娓呮磥鏃犲紓鐗╋紝骞剁疆鎸囧畾浣嶇疆', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 7, content: '鍗敓娲佸叿娓呮磥锛屽苟缃寚瀹氫綅缃�', result: '绗﹀悎瑙勫畾', remark: '' },
+  { itemNo: 8, content: '鍏跺畠', result: '绗﹀悎瑙勫畾', remark: '' }
+];
+
+const formData = reactive({
+  orderId: '',
+  productName: '',
+  productionDate: '',
+  spec: '',
+  batchNo: '',
+  workshop: '',
+  checkItems: JSON.parse(JSON.stringify(defaultCheckItems)),
+  cleaner: '',
+  cleanDate: '',
+  inspector: '',
+  inspectDate: ''
+});
+
+// 鐩戝惉寮规鎵撳紑锛屽垵濮嬪寲鏁版嵁
+watch(() => props.modelValue, (val) => {
+  if (val && props.orderData) {
+    initFormData();
+  }
+});
+
+const initFormData = () => {
+  const order = props.orderData;
+
+  const cleanRecord = order.cleanRecord || order.clearanceRecord;
+  if (cleanRecord) {
+    try {
+      const record = typeof cleanRecord === 'string'
+        ? JSON.parse(cleanRecord)
+        : cleanRecord;
+
+      // 鍔犺浇鍩烘湰瀛楁
+      formData.orderId = record.orderId || order.npsNo || '';
+      formData.productName = record.productName || order.productCategory || '';
+      formData.productionDate = record.productionDate || (order.startTime ? dayjs(order.startTime).format('YYYY-MM-DD') : dayjs().format('YYYY-MM-DD'));
+      formData.spec = record.spec || order.specificationModel || '';
+      formData.batchNo = record.batchNo || order.batchNo || order.uidNo || '';
+      formData.workshop = record.workshop || order.workshop || order.manufacturingTeam || '';
+
+      // 鍔犺浇妫�鏌ラ」鐩紝淇濇寔榛樿缁撴瀯浣嗘洿鏂扮粨鏋�
+      if (record.checkItems && Array.isArray(record.checkItems)) {
+        formData.checkItems = defaultCheckItems.map((defaultItem, index) => {
+          const savedItem = record.checkItems.find(item => item.itemNo === defaultItem.itemNo);
+          return {
+            ...defaultItem,
+            result: savedItem?.result || '绗﹀悎瑙勫畾',
+            remark: savedItem?.remark || ''
+          };
+        });
+      } else {
+        formData.checkItems = JSON.parse(JSON.stringify(defaultCheckItems));
+      }
+
+      // 鍔犺浇绛惧悕淇℃伅
+      formData.cleaner = record.cleaner || '';
+      formData.cleanDate = record.cleanDate || dayjs().format('YYYY-MM-DD HH:mm:ss');
+      formData.inspector = record.inspector || '';
+      formData.inspectDate = record.inspectDate || dayjs().format('YYYY-MM-DD HH:mm:ss');
+    } catch (e) {
+      console.error('瑙f瀽娓呭満璁板綍鏁版嵁澶辫触:', e);
+      resetFormData(order);
+    }
+  } else {
+    resetFormData(order);
+  }
+};
+
+const resetFormData = (order) => {
+  // 閲嶇疆妫�鏌ラ」鐩�
+  formData.checkItems = JSON.parse(JSON.stringify(defaultCheckItems));
+
+  // 鑷姩甯﹀叆璁㈠崟鏁版嵁
+  formData.orderId = order.npsNo || '';
+  formData.productName = order.productCategory || '';
+  formData.productionDate = order.startTime ? dayjs(order.startTime).format('YYYY-MM-DD') : dayjs().format('YYYY-MM-DD');
+  formData.spec = order.specificationModel || '';
+  formData.batchNo = order.batchNo || order.uidNo || '';
+  formData.workshop = order.workshop || order.manufacturingTeam || '';
+
+  // 娓呭満浜哄拰妫�鏌ヤ汉榛樿涓虹┖锛屾棩鏈熼粯璁や负褰撳墠鏃堕棿
+  formData.cleaner = '';
+  formData.cleanDate = dayjs().format('YYYY-MM-DD HH:mm:ss');
+  formData.inspector = '';
+  formData.inspectDate = dayjs().format('YYYY-MM-DD HH:mm:ss');
+};
+
+const handleCancel = () => {
+  visible.value = false;
+};
+
+const handleSave = () => {
+  // 楠岃瘉蹇呭~椤�
+  if (!formData.cleaner) {
+    ElMessage.warning('璇疯緭鍏ユ竻鍦轰汉');
+    return;
+  }
+  if (!formData.cleanDate) {
+    ElMessage.warning('璇烽�夋嫨娓呭満鏃ユ湡');
+    return;
+  }
+  if (!formData.inspector) {
+    ElMessage.warning('璇疯緭鍏ユ鏌ヤ汉');
+    return;
+  }
+  if (!formData.inspectDate) {
+    ElMessage.warning('璇烽�夋嫨妫�鏌ユ棩鏈�');
+    return;
+  }
+  
+  // 鏋勯�犱繚瀛樼殑JSON鏁版嵁
+  const saveData = {
+    orderId: formData.orderId,
+    productName: formData.productName,
+    productionDate: formData.productionDate,
+    spec: formData.spec,
+    batchNo: formData.batchNo,
+    workshop: formData.workshop,
+    checkItems: formData.checkItems.map(item => ({
+      itemNo: item.itemNo,
+      content: item.content,
+      result: item.result,
+      remark: item.remark || undefined
+    })),
+    cleaner: formData.cleaner,
+    cleanDate: formData.cleanDate,
+    inspector: formData.inspector,
+    inspectDate: formData.inspectDate
+  };
+  
+  // 绉婚櫎undefined瀛楁
+  saveData.checkItems = saveData.checkItems.map(item => {
+    if (!item.remark) delete item.remark;
+    return item;
+  });
+  
+  saving.value = true;
+  emit('save', saveData, () => {
+    saving.value = false;
+    visible.value = false;
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.clearance-record-form {
+  .basic-info {
+    margin-bottom: 20px;
+  }
+
+  .info-table {
+    width: 100%;
+    border-collapse: collapse;
+    border: 1px solid #dcdfe6;
+
+    td {
+      border: 1px solid #dcdfe6;
+      padding: 10px;
+      font-size: 14px;
+    }
+
+    .label {
+      background-color: #f5f7fa;
+      width: 100px;
+      text-align: center;
+      font-weight: 500;
+    }
+
+    .value {
+      background-color: #fff;
+      min-width: 150px;
+    }
+  }
+
+  .check-items-section {
+    margin-bottom: 10px;
+
+    .check-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #dcdfe6;
+
+      th, td {
+        border: 1px solid #dcdfe6;
+        padding: 12px 10px;
+        font-size: 14px;
+      }
+
+      th {
+        background-color: #f5f7fa;
+        font-weight: 500;
+        text-align: center;
+      }
+
+      .item-no {
+        width: 60px;
+        text-align: center;
+      }
+
+      .content {
+        text-align: left;
+        padding-left: 15px;
+      }
+
+      .result {
+        width: 200px;
+        text-align: center;
+      }
+
+      .result-option {
+        width: 150px;
+        text-align: center;
+
+        :deep(.el-radio-group) {
+          display: flex;
+          justify-content: center;
+        }
+      }
+    }
+  }
+
+  .remark-section {
+    margin-bottom: 20px;
+    padding: 0 10px;
+  }
+
+  .signature-section {
+    .signature-table {
+      width: 100%;
+      border-collapse: collapse;
+      border: 1px solid #dcdfe6;
+
+      td {
+        border: 1px solid #dcdfe6;
+        padding: 10px;
+        font-size: 14px;
+      }
+
+      .label {
+        background-color: #f5f7fa;
+        width: 80px;
+        text-align: center;
+        font-weight: 500;
+      }
+
+      .value {
+        background-color: #fff;
+        min-width: 150px;
+      }
+    }
+  }
+}
+
+.dialog-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>
diff --git a/src/views/productionManagement/productionOrder/index.vue b/src/views/productionManagement/productionOrder/index.vue
index 829f7ab..8c254da 100644
--- a/src/views/productionManagement/productionOrder/index.vue
+++ b/src/views/productionManagement/productionOrder/index.vue
@@ -95,6 +95,13 @@
     <new-product-order v-if="isShowNewModal"
                        v-model:visible="isShowNewModal"
                        @completed="handleQuery"/>
+
+    <!-- 娓呭満璁板綍寮规 -->
+    <clearance-record-dialog
+      v-model="clearanceDialogVisible"
+      :order-data="currentOrderData"
+      @save="handleSaveClearanceRecord"
+    />
   </div>
 </template>
 
@@ -108,12 +115,14 @@
   listProcessRoute,
   bindingRoute,
   delProductOrder, finishOrder,
+  saveCleanRecord,
 } from "@/api/productionManagement/productionOrder.js";
 import {listMain as getOrderProcessRouteMain} from "@/api/productionManagement/productProcessRoute.js";
 import {fileDel} from "@/api/financialManagement/revenueManagement.js";
 import PIMTable from "@/components/PIMTable/PIMTable.vue";
 
 const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue"));
+const ClearanceRecordDialog = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/ClearanceRecordDialog.vue"));
 
 const {proxy} = getCurrentInstance();
 
@@ -227,6 +236,14 @@
           handleFinishOrder(row);
         },
       },
+      {
+        name: "娓呭満璁板綍",
+        type: "text",
+        showHide: row => !row.isEnd,
+        clickFun: row => {
+          handleClearanceRecord(row);
+        },
+      },
     ],
   },
 ]);
@@ -289,6 +306,10 @@
 const bindRouteLoading = ref(false);
 const bindRouteSaving = ref(false);
 const routeOptions = ref([]);
+
+// 娓呭満璁板綍寮规
+const clearanceDialogVisible = ref(false);
+const currentOrderData = ref({});
 const bindForm = reactive({
   orderId: null,
   routeId: null,
@@ -478,6 +499,32 @@
         proxy.$modal.msg("宸插彇娑�");
       });
 };
+
+// 鎵撳紑娓呭満璁板綍寮规
+const handleClearanceRecord = (row) => {
+  currentOrderData.value = row;
+  clearanceDialogVisible.value = true;
+};
+
+// 淇濆瓨娓呭満璁板綍
+const handleSaveClearanceRecord = async (saveData, callback) => {
+  const orderId = currentOrderData.value?.id;
+  if (!orderId) {
+    proxy.$modal.msgError("璁㈠崟ID涓嶅瓨鍦�");
+    return;
+  }
+
+  try {
+    await saveCleanRecord(orderId, saveData);
+    proxy.$modal.msgSuccess("娓呭満璁板綍淇濆瓨鎴愬姛");
+    currentOrderData.value.cleanRecord = saveData;
+    if (callback) callback();
+    getList();
+  } catch (error) {
+    console.error('淇濆瓨娓呭満璁板綍澶辫触:', error);
+    proxy.$modal.msgError("娓呭満璁板綍淇濆瓨澶辫触");
+  }
+};
 onMounted(() => {
   getList();
 });

--
Gitblit v1.9.3