From 04b1a9cfde4049be9a38b9832d5289d4a192c883 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 15 五月 2026 16:29:33 +0800
Subject: [PATCH] 加班申请模块和审批流程公共组件

---
 src/views/productionManagement/processRoute/processRouteItem/index.vue |  218 +++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 167 insertions(+), 51 deletions(-)

diff --git a/src/views/productionManagement/processRoute/processRouteItem/index.vue b/src/views/productionManagement/processRoute/processRouteItem/index.vue
index 42fd4b2..99d4ab1 100644
--- a/src/views/productionManagement/processRoute/processRouteItem/index.vue
+++ b/src/views/productionManagement/processRoute/processRouteItem/index.vue
@@ -38,6 +38,15 @@
             <span class="info-value">{{ routeInfo.bomNo || '-' }}</span>
           </div>
         </div>
+        <div class="info-item"
+             v-if="routeInfo.quantity && routeInfo.quantity !== 0">
+          <div class="info-label-wrapper">
+            <span class="info-label">闇�姹傛暟閲�</span>
+          </div>
+          <div class="info-value-wrapper">
+            <span class="info-value">{{ routeInfo.quantity || '-' }}</span>
+          </div>
+        </div>
         <div class="info-item full-width"
              v-if="routeInfo.description">
           <div class="info-label-wrapper">
@@ -59,7 +68,8 @@
                    style="margin-right: 10px;">
           鍗$墖瑙嗗浘
         </el-button>
-        <el-button type="primary"
+        <el-button v-if="editable"
+                   type="primary"
                    @click="handleAdd">鏂板</el-button>
       </div>
     </div>
@@ -80,7 +90,7 @@
                        prop="technologyOperationId"
                        width="200">
         <template #default="scope">
-          {{ getProcessName(scope.row.technologyOperationId) || '-' }}
+          {{ scope.row.technologyOperationName || scope.row.operationName || '-' }}
         </template>
       </el-table-column>
       <el-table-column label="鍙傛暟鍒楄〃"
@@ -101,6 +111,13 @@
       <el-table-column label="鍗曚綅"
                        prop="unit"
                        width="100" />
+      <el-table-column label="璁¤垂绫诲瀷"
+                       prop="type"
+                       width="100">
+        <template #default="scope">
+          {{scope.row.type==0 ? "璁℃椂" : "璁′欢"}}
+        </template>
+      </el-table-column>
       <el-table-column label="鏄惁璐ㄦ"
                        prop="isQuality"
                        width="100">
@@ -124,12 +141,12 @@
                      link
                      size="small"
                      @click="handleEdit(scope.row)"
-                     :disabled="scope.row.isComplete">缂栬緫</el-button>
+                     :disabled="scope.row.isComplete || !editable">缂栬緫</el-button>
           <el-button type="danger"
                      link
                      size="small"
                      @click="handleDelete(scope.row)"
-                     :disabled="scope.row.isComplete">鍒犻櫎</el-button>
+                     :disabled="scope.row.isComplete || !editable">鍒犻櫎</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -143,7 +160,8 @@
                      style="margin-right: 10px;">
             琛ㄦ牸瑙嗗浘
           </el-button>
-          <el-button type="primary"
+          <el-button v-if="editable"
+                     type="primary"
                      @click="handleAdd">鏂板</el-button>
         </div>
       </div>
@@ -158,7 +176,7 @@
             <!-- 搴忓彿鍦嗗湀 -->
             <div class="card-header">
               <div class="card-number">{{ index + 1 }}</div>
-              <div class="card-process-name">{{ getProcessName(item.technologyOperationId) || '-' }}</div>
+              <div class="card-process-name">{{ item.technologyOperationName || item.operationName || '-' }}</div>
             </div>
             <!-- 浜у搧淇℃伅 -->
             <div class="card-content">
@@ -170,12 +188,16 @@
                   {{ item.model }}
                   <!-- <span v-if="item.unit" class="product-unit">{{ item.unit }}</span> -->
                 </div>
+                <el-tag class="product-tag"
+                        :type="item.type == 1 ? 'primary' : 'success'"
+                        style="margin-left: 8px;">{{ item.type==0?'璁℃椂':'璁′欢' }}</el-tag>
                 <el-tag type="primary"
                         class="product-tag"
+                        style="margin-left: 8px;"
                         v-if="item.isQuality">璐ㄦ</el-tag>
                 <el-tag type="primary"
                         class="product-tag"
-                        :style="item.isQuality?'margin-left:8px':''"
+                        style="margin-left: 8px;"
                         v-if="item.isProduction">鐢熶骇</el-tag>
               </div>
               <div v-else
@@ -187,7 +209,7 @@
                          link
                          size="small"
                          @click="handleEdit(item)"
-                         :disabled="item.isComplete">缂栬緫</el-button>
+                         :disabled="item.isComplete || !editable">缂栬緫</el-button>
               <el-button type="info"
                          link
                          size="small"
@@ -196,7 +218,7 @@
                          link
                          size="small"
                          @click="handleDelete(item)"
-                         :disabled="item.isComplete">鍒犻櫎</el-button>
+                         :disabled="item.isComplete || !editable">鍒犻櫎</el-button>
             </div>
           </div>
         </div>
@@ -207,7 +229,7 @@
          style="margin-top: 20px;">
       <div class="section-title">BOM 缁撴瀯</div>
       <div class="section-actions"
-           v-if="pageType === 'order'">
+           v-if="pageType === 'order' && editable">
         <el-button v-if="!bomDataValue.isEdit"
                    type="primary"
                    @click="bomDataValue.isEdit = true">
@@ -232,7 +254,7 @@
               style="width: 100%">
       <el-table-column type="expand">
         <template #default>
-          <el-form ref="form"
+          <el-form ref="bomFormRef"
                    :model="bomDataValue">
             <el-table :data="bomDataValue.dataList"
                       row-key="tempId"
@@ -293,6 +315,7 @@
                                      :step="1"
                                      controls-position="right"
                                      style="width: 100%"
+                                     @change="handleUnitQuantityChange(row)"
                                      :disabled="!bomDataValue.isEdit || bomDataValue.dataList.some(item => (item).tempId === row.tempId)" />
                   </el-form-item>
                 </template>
@@ -356,7 +379,7 @@
                        prop="model" />
     </el-table>
     <ProductSelectDialog v-if="bomDataValue.showProductDialog"
-                         v-model:model-value="bomDataValue.showProductDialog"
+                         v-model="bomDataValue.showProductDialog"
                          :single="true"
                          @confirm="handleBomProduct" />
     <!-- 鏂板/缂栬緫寮圭獥 -->
@@ -369,6 +392,7 @@
                :rules="rules"
                label-width="120px">
         <el-form-item label="宸ュ簭"
+                      v-if="operationType === 'add' || pageType === 'route'"
                       prop="technologyOperationId">
           <el-select v-model="form.technologyOperationId"
                      placeholder="璇烽�夋嫨宸ュ簭"
@@ -381,33 +405,54 @@
                        :value="process.id" />
           </el-select>
         </el-form-item>
+        <el-form-item label="宸ュ簭"
+                      v-else>
+          <span>{{ getProcessName(form.technologyOperationId) }}</span>
+        </el-form-item>
         <el-form-item label="浜у搧鍚嶇О"
+                      v-if="operationType === 'add' || pageType === 'route'"
                       prop="productModelId">
           <el-button type="primary"
                      @click="showProductSelectDialog = true">
-            {{ form.productName && form.model 
-              ? `${form.productName} - ${form.model}` 
+            {{ form.productName
+              ? (form.model ? `${form.productName} - ${form.model}` : form.productName)
               : '閫夋嫨浜у搧' }}
           </el-button>
         </el-form-item>
+        <el-form-item label="浜у搧鍚嶇О"
+                      v-else>
+          <span>{{ form.productName }}{{ form.model ? ' - ' + form.model : '' }}</span>
+        </el-form-item>
         <el-form-item label="鍗曚綅"
+                      v-if="operationType === 'add' || pageType === 'route'"
                       prop="unit">
           <el-input v-model="form.unit"
                     :placeholder="form.productModelId ? '鏍规嵁閫夋嫨鐨勪骇鍝佽嚜鍔ㄥ甫鍑�' : '璇峰厛閫夋嫨浜у搧'"
                     clearable
                     :disabled="true" />
         </el-form-item>
+        <el-form-item label="鍗曚綅"
+                      v-else>
+          <span>{{ form.unit }}</span>
+        </el-form-item>
+        <el-form-item label="璁¤垂绫诲瀷"
+                      prop="type">
+          <el-radio-group v-model="form.type">
+            <el-radio :label="0">璁℃椂</el-radio>
+            <el-radio :label="1">璁′欢</el-radio>
+          </el-radio-group>
+        </el-form-item>
         <el-form-item label="鏄惁璐ㄦ"
                       prop="isQuality">
           <el-switch v-model="form.isQuality"
                      :active-value="true"
-                     inactive-value="false" />
+                     :inactive-value="false" />
         </el-form-item>
         <el-form-item label="鏄惁鐢熶骇"
                       prop="isProduction">
           <el-switch v-model="form.isProduction"
                      :active-value="true"
-                     inactive-value="false" />
+                     :inactive-value="false" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -422,14 +467,14 @@
                          @confirm="handleProductSelect"
                          single />
     <!-- 鍙傛暟鍒楄〃瀵硅瘽妗� -->
-    <!-- :editable="!routeInfo.status" -->
     <ProcessParamListDialog v-model="showParamListDialog"
-                            :title="`${currentProcess ? (currentProcess.processName || getProcessName(currentProcess.technologyOperationId)) : ''} - 鍙傛暟鍒楄〃`"
+                            :title="`${currentProcess ? (currentProcess.processName || currentProcess.technologyOperationName || currentProcess.operationName) : ''} - 鍙傛暟鍒楄〃`"
                             :route-id="routeId"
                             :order-id="orderId"
                             :process="currentProcess"
                             :page-type="pageType"
                             :param-list="paramList"
+                            :editable="editable"
                             @getsyncProcessParamItem="getsyncProcessParamItem"
                             @refresh="refreshParamList" />
   </div>
@@ -454,7 +499,10 @@
     batchDeleteProcessRouteItem,
     getProcessParamList,
   } from "@/api/productionManagement/processRouteItem.js";
-  import { syncProcessParamItem } from "@/api/productionManagement/processRouteItem.js";
+  import {
+    syncProcessParamItem,
+    syncProcessParamItemOrder,
+  } from "@/api/productionManagement/processRouteItem.js";
   import {
     findProductProcessRouteItemList,
     deleteRouteItem,
@@ -467,8 +515,10 @@
   import { listProcessBom } from "@/api/productionManagement/productionOrder.js";
   import {
     queryList,
-    addBomDetail,
+    queryList2,
+    add2,
   } from "@/api/productionManagement/productStructure.js";
+
   import { useRoute } from "vue-router";
   import { ElMessageBox, ElMessage } from "element-plus";
   import Sortable from "sortablejs";
@@ -479,12 +529,14 @@
   const routeId = computed(() => route.query.id);
   const orderId = computed(() => route.query.orderId);
   const pageType = computed(() => route.query.type);
+  const editable = computed(() => route.query.editable !== "false");
 
   const tableLoading = ref(false);
   const tableData = ref([]);
   const dialogVisible = ref(false);
   const operationType = ref("add"); // add | edit
   const formRef = ref(null);
+  const bomFormRef = ref(null);
   const submitLoading = ref(false);
   const cardsContainer = ref(null);
   const tableRef = ref(null);
@@ -495,6 +547,7 @@
     model: "",
     bomNo: "",
     description: "",
+    quantity: 0,
   });
 
   const processOptions = ref([]);
@@ -523,6 +576,7 @@
     model: "",
     unit: "",
     isQuality: false,
+    type: 0,
     isProduction: false,
   });
 
@@ -542,17 +596,31 @@
       type: "warning",
     })
       .then(() => {
-        syncProcessParamItem({
-          replaceExisting: true,
-          technologyRoutingOperationId: currentProcess.value.id,
-        }).then(res => {
-          if (res.code === 200) {
-            ElMessage.success("鍚屾鎴愬姛");
-            refreshParamList();
-          } else {
-            ElMessage.error(res.msg || "鍚屾澶辫触");
-          }
-        });
+        if (pageType.value === "order") {
+          syncProcessParamItemOrder({
+            replaceExisting: true,
+            technologyRoutingOperationId: currentProcess.value.id,
+          }).then(res => {
+            if (res.code === 200) {
+              ElMessage.success("鍚屾鎴愬姛");
+              refreshParamList();
+            } else {
+              ElMessage.error(res.msg || "鍚屾澶辫触");
+            }
+          });
+        } else {
+          syncProcessParamItem({
+            replaceExisting: true,
+            technologyRoutingOperationId: currentProcess.value.id,
+          }).then(res => {
+            if (res.code === 200) {
+              ElMessage.success("鍚屾鎴愬姛");
+              refreshParamList();
+            } else {
+              ElMessage.error(res.msg || "鍚屾澶辫触");
+            }
+          });
+        }
       })
       .catch(() => {});
   };
@@ -611,6 +679,7 @@
       bomNo: route.query.bomNo || "",
       bomId: route.query.bomId || "",
       description: route.query.description || "",
+      quantity: route.query.quantity || 0,
       status: !(route.query.status == 1 || route.query.status === "false"),
     };
     bomTableData.value[0].productName = routeInfo.value.productName;
@@ -637,6 +706,7 @@
       model: row.model || "",
       unit: row.unit || "",
       isQuality: row.isQuality,
+      type: row.type || 0,
       isProduction: row.isProduction,
     };
     dialogVisible.value = true;
@@ -670,15 +740,20 @@
 
   // 浜у搧閫夋嫨
   const handleProductSelect = products => {
+    console.log(products, "===products===");
     if (products && products.length > 0) {
       const product = products[0];
-      form.value.productModelId = product.id;
-      form.value.productName = product.productName;
-      form.value.model = product.model;
-      form.value.unit = product.unit || "";
+      console.log(product, "product");
+      form.value = {
+        ...form.value,
+        productModelId: product.id,
+        productName: product.productName,
+        model: product.model,
+        unit: product.unit || "",
+      };
       showProductSelectDialog.value = false;
       // 瑙﹀彂琛ㄥ崟楠岃瘉
-      formRef.value?.validateField("productModelId");
+      // formRef.value?.validateField("productModelId");
     }
   };
 
@@ -696,11 +771,14 @@
 
           const addPromise = isOrderPage
             ? addRouteItem({
-                productOrderId: orderId.value,
-                productRouteId: routeId.value,
+                productionOrderId: Number(orderId.value),
+                orderRoutingId: Number(routeId.value),
                 technologyOperationId: form.value.technologyOperationId,
+                technologyRoutingId: Number(routeId.value),
+                operationName: getProcessName(form.value.technologyOperationId),
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
                 dragSort,
               })
@@ -709,6 +787,7 @@
                 technologyOperationId: form.value.technologyOperationId,
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
                 dragSort,
               });
@@ -733,8 +812,10 @@
             ? addOrUpdateProductProcessRouteItem({
                 id: form.value.id,
                 technologyOperationId: form.value.technologyOperationId,
+                operationName: getProcessName(form.value.technologyOperationId),
                 productModelId: form.value.productModelId,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
               })
             : addOrUpdateProcessRouteItem1({
@@ -743,6 +824,7 @@
                 productModelId: form.value.productModelId,
                 id: form.value.id,
                 isQuality: form.value.isQuality,
+                type: form.value.type,
                 isProduction: form.value.isProduction,
               });
 
@@ -773,6 +855,9 @@
       productName: "",
       model: "",
       unit: "",
+      isQuality: false,
+      type: 0,
+      isProduction: false,
     };
     formRef.value?.resetFields();
   };
@@ -786,15 +871,19 @@
   // 鏌ョ湅鍙傛暟鍒楄〃
   const handleViewParams = row => {
     currentProcess.value = row;
-    const query = {
+    const param = {
+      productionOrderRoutingOperationId: row.id,
+      productionOrderId: orderId.value,
+    };
+    const param1 = {
       technologyRoutingOperationId: row.id,
-      orderId: orderId.value,
+      productionOrderId: orderId.value,
     };
 
     const apiPromise =
       pageType.value === "order"
-        ? findProcessParamListOrder(query)
-        : getProcessParamList(query);
+        ? findProcessParamListOrder(param)
+        : getProcessParamList(param1);
 
     apiPromise
       .then(res => {
@@ -817,6 +906,7 @@
   // 鍒濆鍖栨嫋鎷芥帓搴�
   const initSortable = () => {
     destroySortable();
+    if (!editable.value) return;
 
     if (viewMode.value === "table") {
       // 琛ㄦ牸瑙嗗浘鐨勬嫋鎷芥帓搴�
@@ -968,7 +1058,8 @@
   });
 
   const syncProcessOperationFields = item => {
-    const processId = item.processId ?? item.operationId ?? "";
+    const processId =
+      item.processId ?? item.operationId ?? item.technologyOperationId ?? "";
     if (!processId) {
       item.processId = "";
       return;
@@ -980,7 +1071,11 @@
       option?.name || item.processName || item.operationName || "";
 
     item.processId = processId;
-    item.operationId = processId;
+    if (pageType.value === "order") {
+      item.technologyOperationId = processId;
+    } else {
+      item.operationId = processId;
+    }
     item.processName = processName;
     item.operationName = processName;
   };
@@ -998,6 +1093,7 @@
     processOptions.value.forEach(item => {
       if (item.id == value) {
         form.value.isQuality = item.isQuality;
+        form.value.type = item.type || 0;
         form.value.isProduction = item.isProduction;
       }
     });
@@ -1015,7 +1111,10 @@
 
   const fetchBomData = async () => {
     try {
-      const { data } = await queryList(routeInfo.value.bomId);
+      const isOrderPage = pageType.value === "order";
+      const { data } = await (isOrderPage ? queryList2 : queryList)(
+        routeInfo.value.bomId
+      );
       bomDataValue.value.dataList = data || [];
       normalizeTreeData(bomDataValue.value.dataList);
     } catch (err) {
@@ -1113,6 +1212,12 @@
     });
   };
 
+  const handleUnitQuantityChange = row => {
+    if (routeInfo.value.quantity && routeInfo.value.quantity !== 0) {
+      row.demandedQuantity = (row.unitQuantity || 0) * routeInfo.value.quantity;
+    }
+  };
+
   const addchildItem = (item, tempId) => {
     if (item.tempId === tempId) {
       if (!item.children) {
@@ -1127,10 +1232,14 @@
         productModelId: undefined,
         processId: "",
         processName: "",
-        operationId: "",
+        [pageType.value === "order" ? "technologyOperationId" : "operationId"]:
+          "",
         operationName: "",
         unitQuantity: 1,
-        demandedQuantity: 0,
+        demandedQuantity:
+          routeInfo.value.quantity && routeInfo.value.quantity !== 0
+            ? 1 * routeInfo.value.quantity
+            : 0,
         children: [],
         unit: "",
         tempId: new Date().getTime(),
@@ -1162,10 +1271,14 @@
           productModelId: undefined,
           processId: "",
           processName: "",
-          operationId: "",
+          [pageType.value === "order" ? "technologyOperationId" : "operationId"]:
+            "",
           operationName: "",
           unitQuantity: 1,
-          demandedQuantity: 0,
+          demandedQuantity:
+            routeInfo.value.quantity && routeInfo.value.quantity !== 0
+              ? 1 * routeInfo.value.quantity
+              : 0,
           unit: "",
           children: [],
           tempId: new Date().getTime(),
@@ -1234,12 +1347,15 @@
 
   const handleSaveBom = () => {
     bomDataValue.value.loading = true;
+    console.log(bomDataValue.value.dataList, "bomDataValue.value.dataList");
+
     normalizeTreeData(bomDataValue.value.dataList);
 
     const valid = validateAllBom();
     if (valid) {
-      addBomDetail({
-        bomId: routeInfo.value.bomId,
+      add2({
+        // bomId: Number(routeInfo.value.bomId),
+        productionOrderBomId: Number(routeInfo.value.bomId) || null,
         children: buildSubmitTree(bomDataValue.value.dataList || []),
       })
         .then(() => {

--
Gitblit v1.9.3