소스 검색

pms 保养工单 消耗物料 自动计算保养费用

zhangcl 1 주 전
부모
커밋
fafd1f04a6
1개의 변경된 파일133개의 추가작업 그리고 74개의 파일을 삭제
  1. 133 74
      src/views/pms/iotmainworkorder/IotMainWorkOrderOptimize.vue

+ 133 - 74
src/views/pms/iotmainworkorder/IotMainWorkOrderOptimize.vue

@@ -448,6 +448,7 @@
               v-model="row.materialCode"
               placeholder="请输入物料编码"
               style="width: 100%"
+              :disabled="isMaterialDisabled(row)"
             />
             <span v-else>{{ row.materialCode }}</span>
           </template>
@@ -499,29 +500,18 @@
         <el-table-column label="单价(CNY/元)" align="center" prop="unitPrice" :formatter="erpPriceTableColumnFormatter" width="120px">
           <template #default="{ row }">
             <div class="unit-price-container">
-              <!--
-              <el-tooltip
-                v-if="row.isNew || !row.unitPrice || row.unitPrice === 0"
-                effect=""
-                content=""
-                placement=""
-                :disabled="row.unitPrice > 0"
-              > -->
-                <el-input-number
-                  v-if="row.isNew || !row.unitPrice || row.unitPrice === 0"
-                  v-model="row.unitPrice"
-                  :precision="2"
-                  :min="0"
-                  :controls="false"
-                  style="width: 100%"
-                  class="unit-price-input"
-                  :class="{
-                    'is-required-input': (row.isNew || !row.unitPrice || row.unitPrice === 0) && row.unitPrice <= 0
-                  }"
-                  :disabled="isMaterialDisabled(row)"
-                />
-              <!-- </el-tooltip> -->
-              <span v-else class="unit-price-text">{{ row.unitPrice }}</span>
+              <el-input-number
+                v-model="row.unitPrice"
+                :precision="2"
+                :min="0"
+                :controls="false"
+                style="width: 100%"
+                class="unit-price-input"
+                :class="{
+                  'is-required-input': row.unitPrice <= 0
+                }"
+                :disabled="isMaterialDisabled(row)"
+              />
             </div>
           </template>
         </el-table-column>
@@ -1311,6 +1301,11 @@ const handleAddMaterial = () => {
   }
 
   message.success('已新增空白物料记录,请填写相关信息');
+
+  // 新增物料后重新计算费用
+  nextTick(() => {
+    calculateTotalCost();
+  });
 };
 
 const openMaterialForm = (row: any) => {
@@ -1337,8 +1332,12 @@ const selectChoose = (selectedMaterial) => {
 
   // 避免重复添加
   processedMaterials.forEach(newMaterial => {
+    const uniqueKey = `${newMaterial.deviceId}${bomNodeId.value}`;
+    if (!bomMaterialsMap.value[uniqueKey]) {
+      bomMaterialsMap.value[uniqueKey] = [];
+    }
     // 检查是否已存在相同 工厂+成本中心+库存地点+bomNodeId + materialCode 的条目
-    const isExist = materialList.value.some(item =>
+    const isExist = bomMaterialsMap.value[uniqueKey].some(item =>
       item.bomNodeId === bomNodeId.value &&
       item.materialCode === newMaterial.materialCode &&
       item.factoryId === newMaterial.factoryId &&
@@ -1347,9 +1346,19 @@ const selectChoose = (selectedMaterial) => {
     );
 
     if (!isExist) {
-      materialList.value.push(newMaterial);
+      bomMaterialsMap.value[uniqueKey].push(newMaterial);
     }
   });
+
+  // 同步到当前显示的 materialList(如果当前选中了该保养项)
+  if (currentBomItem.value && currentBomItem.value.bomNodeId === bomNodeId.value) {
+    materialList.value = bomMaterialsMap.value[`${currentBomItem.value.deviceId}${bomNodeId.value}`] || [];
+  }
+
+  // 选择物料后立即计算费用
+  nextTick(() => {
+    calculateTotalCost();
+  });
 }
 
 // 计算属性:判断是否需要显示运行时间周期列
@@ -1368,25 +1377,57 @@ const handleView = (row: IotMainWorkOrderBomVO) => {
 
 // 计算保养金额
 const calculateTotalCost = () => {
-  // 物料总金额 = ∑(单价 * 消耗数量)
-  const materialTotal = materialList.value.reduce((sum, item) => {
-    const price = Number(item.unitPrice) || 0
-    const quantity = Number(item.quantity) || 0
-    return sum + (price * quantity)
-  }, 0)
+  try {
+    // 创建保养项ID到消耗规则的映射
+    const ruleMap = new Map<number, number>();
+    list.value.forEach(item => {
+      ruleMap.set(item.bomNodeId, item.rule);
+    });
 
-  // 保养 = 物料总金额
-  formData.value.cost = (materialTotal).toFixed(2)
+    // 从 bomMaterialsMap 中获取所有保养项的所有物料
+    let allMaterials = [];
+    for (const key in bomMaterialsMap.value) {
+      allMaterials = allMaterials.concat(bomMaterialsMap.value[key]);
+    }
+
+    // 物料总金额 = ∑(单价 * 消耗数量)
+    const materialTotal = allMaterials.reduce((sum, item) => {
+      // 获取物料所属保养项的消耗规则
+      const rule = ruleMap.get(item.bomNodeId);
+
+      // 如果保养项设置为不消耗物料(rule=1),跳过计算
+      if (rule === 1) return sum;
+
+      const price = Number(item.unitPrice) || 0
+      const quantity = Number(item.quantity) || 0
+      return sum + (price * quantity)
+    }, 0)
+
+    // 保养费用 = 物料总金额
+    formData.value.cost = (materialTotal).toFixed(2)
+
+    console.log('计算保养费用:', {
+      物料总数: allMaterials.length,
+      参与计算的物料数: allMaterials.filter(item => {
+        const rule = ruleMap.get(item.bomNodeId);
+        return rule !== 1; // 过滤掉不消耗物料的项
+      }).length,
+      总金额: materialTotal
+    });
+  } catch (error) {
+    console.error('计算保养费用错误:', error);
+    formData.value.cost = '0.00';
+  }
 }
 
-// 监听物料列表变化
+// 同时监听物料列表和保养项列表变化
 watch(
-  () => materialList.value,
+  [() => materialList.value, () => list.value],
   () => {
-    calculateTotalCost()
+    calculateTotalCost();
   },
   { deep: true }
-)
+);
 
 const handleInput = (value, obj) => {
   // 1. 过滤非法字符(只允许数字和小数点)
@@ -1481,20 +1522,27 @@ const getMaterialCount = (bomNodeId: number) => {
 const handleDeleteMaterialInTable = (material) => {
   // 确认删除对话框
   message.confirm('确认删除该物料吗?', { title: '提示' }).then(() => {
-    let targetBomNodeId = material.bomNodeId;
-
-    // 如果没有选中保养项(显示所有物料),需要根据物料信息找到对应的bomNodeId
-    if (showAllMaterials.value && !currentBomItem.value) {
-      // 从物料中提取bomNodeId
-      targetBomNodeId = material.bomNodeId;
-    } else if (currentBomItem.value) {
-      // 使用当前选中保养项的bomNodeId
-      targetBomNodeId = currentBomItem.value.bomNodeId;
+    const targetBomNodeId = material.bomNodeId;
+    const uniqueKey = `${material.deviceId}${targetBomNodeId}`;
+
+    // 从 bomMaterialsMap 中删除
+    if (bomMaterialsMap.value[uniqueKey]) {
+      const mapIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
+        (item.isNew && item.tempId === material.tempId) ||
+        (!item.isNew &&
+          item.factoryId === material.factoryId &&
+          item.costCenterId === material.costCenterId &&
+          item.storageLocationId === material.storageLocationId &&
+          item.materialCode === material.materialCode)
+      );
+
+      if (mapIndex !== -1) {
+        bomMaterialsMap.value[uniqueKey].splice(mapIndex, 1);
+      }
     }
 
-    // 从materialList中删除
+    // 从 materialList 中删除
     const index = materialList.value.findIndex(item =>
-      // 对于新记录,使用tempId进行比较;对于已有记录,使用原有逻辑
       (item.isNew && item.tempId === material.tempId) ||
       (!item.isNew &&
         item.bomNodeId === targetBomNodeId &&
@@ -1506,27 +1554,11 @@ const handleDeleteMaterialInTable = (material) => {
 
     if (index !== -1) {
       materialList.value.splice(index, 1);
-
-      // 同时从bomMaterialsMap中删除
-      const uniqueKey = `${material.deviceId}${targetBomNodeId}`;
-      if (bomMaterialsMap.value[uniqueKey]) {
-        const mapIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
-          (item.isNew && item.tempId === material.tempId) ||
-          (!item.isNew &&
-            item.factoryId === material.factoryId &&
-            item.costCenterId === material.costCenterId &&
-            item.storageLocationId === material.storageLocationId &&
-            item.materialCode === material.materialCode)
-        );
-        if (mapIndex !== -1) {
-          bomMaterialsMap.value[uniqueKey].splice(mapIndex, 1);
-        }
-      }
-
-      message.success('物料删除成功');
-    } else {
-      message.error('未找到要删除的物料');
     }
+    // 删除物料后重新计算费用
+    nextTick(() => {
+      calculateTotalCost();
+    });
   }).catch(() => {
     // 用户取消删除
   });
@@ -2160,7 +2192,6 @@ onMounted(async () => {
               projectDepartment: material.storageLocation, // storageLocation -> projectDepartment
               totalInventoryQuantity: material.stockQuantity // stockQuantity -> totalInventoryQuantity
             }));
-
             // 存储到映射表中
             bomMaterialsMap.value[uniqueKey] = mappedMaterials;
           }
@@ -2199,15 +2230,38 @@ onMounted(async () => {
     // 查询当前保养工单已经关联的所有物料
     const materials = await IotMainWorkOrderBomMaterialApi.getWorkOrderBomMaterials(queryParams);
     materialList.value = []
-    if (Array.isArray(materials)) {
-      materialList.value = materials
-        .map(item => ({
-          ...item,
-        }))
+    // 修改:如果有已关联的物料,使用接口返回的数据覆盖默认数据
+    if (Array.isArray(materials) && materials.length > 0) {
+      // materialList.value = materials;
+
+      // 同时更新 bomMaterialsMap
+      materials.forEach(material => {
+        const uniqueKey = `${material.deviceId}${material.bomNodeId}`;
+        if (!bomMaterialsMap.value[uniqueKey]) {
+          bomMaterialsMap.value[uniqueKey] = [];
+        }
+        // 避免重复添加
+        const existingIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
+          item.materialCode === material.materialCode &&
+          item.factoryId === material.factoryId &&
+          item.costCenterId === material.costCenterId &&
+          item.storageLocationId === material.storageLocationId
+        );
+        if (existingIndex === -1) {
+          bomMaterialsMap.value[uniqueKey].push(material);
+        } else {
+          // 如果已存在,更新数据(使用接口返回的最新数据)
+          bomMaterialsMap.value[uniqueKey][existingIndex] = material;
+        }
+      });
     }
     if (list.value.length > 0) {
       handleBomItemClick(list.value[0]);
     }
+    // 页面初始化完成后立即计算费用
+    nextTick(() => {
+      calculateTotalCost();
+    });
   } catch (error) {
     console.error('数据加载失败:', error)
     message.error('数据加载失败,请重试')
@@ -2242,6 +2296,11 @@ const handleBomItemClick = (item) => {
 
   // 更新物料列表
   materialList.value = bomMaterialsMap.value[uniqueKey] || [];
+
+  // 切换保养项时重新计算费用
+  nextTick(() => {
+    calculateTotalCost();
+  });
 }
 
 // 为表格行添加点击事件处理