10 次代碼提交 3d99dc87f8 ... 0158008293

作者 SHA1 備註 提交日期
  zhangcl 0158008293 Merge branch 'materials' into test 1 周之前
  zhangcl 69f126b949 pms 物料消耗 保养工单 保存手工新增的物料 1 周之前
  zhangcl 3ca8992f65 pms 物料消耗 保养工单 物料回显。 1 周之前
  zhangcl e75f61f849 pms 物料消耗 保养工单 删除物料 1 周之前
  zhangcl c52c5e85bb pms 物料消耗 保养工单 校验必填项 1 周之前
  zhangcl ca12fed863 pms 物料消耗 保养工单 修复bug 1 周之前
  zhangcl 9ec59e82ed pms 物料消耗 保养工单 不消耗物料 或保养完成时 选择物料 设置 新增物料按钮 为失效状态 1 周之前
  zhangcl 8f54de2bf7 pms 物料消耗 保养工单 保存后回显数据 1 周之前
  zhangcl 02f5d4c315 pms 物料消耗 立即刷新当前显示的物料列表 1 周之前
  zhangcl d20be30e4a pms 物料消耗 功能优化 保养状态 1 周之前
共有 4 個文件被更改,包括 405 次插入83 次删除
  1. 2 1
      src/locales/en.ts
  2. 2 1
      src/locales/ru.ts
  3. 2 1
      src/locales/zh-CN.ts
  4. 399 80
      src/views/pms/iotmainworkorder/IotMainWorkOrderOptimize.vue

+ 2 - 1
src/locales/en.ts

@@ -1084,7 +1084,8 @@ export default {
     maintenanceQuery: 'Maintenance Query',
     notGenerated: "Not Generated",
     generatedNotExecuted: "Not Executed",
-    consumeMaterials: "Consumables"
+    consumeMaterials: "Consumables",
+    mainStatus: "Upkeep Status"
   },
   inspect:{
     InspectionItems:'InspectionItems',

+ 2 - 1
src/locales/ru.ts

@@ -997,7 +997,8 @@ export default {
     maintenanceQuery: '保养查询',
     notGenerated: "未生成工单",
     generatedNotExecuted: "已生成工单未执行",
-    consumeMaterials: "消耗物料"
+    consumeMaterials: "消耗物料",
+    mainStatus: "保养状态"
   },
   inspect:{
     InspectionItems:'巡检项',

+ 2 - 1
src/locales/zh-CN.ts

@@ -1080,7 +1080,8 @@ export default {
     maintenanceQuery: '保养查询',
     notGenerated: "未生成工单",
     generatedNotExecuted: "已生成工单未执行",
-    consumeMaterials: "消耗物料"
+    consumeMaterials: "消耗物料",
+    mainStatus: "保养状态"
   },
   inspect:{
     InspectionItems:'巡检项',

+ 399 - 80
src/views/pms/iotmainworkorder/IotMainWorkOrderOptimize.vue

@@ -152,6 +152,24 @@
           </template>
         </el-table-column>
 
+        <el-table-column :label="t('mainPlan.mainStatus')" align="center" width="140">
+          <template #default="scope">
+            <div class="status-container">
+              <el-switch
+                v-model="scope.row.status"
+                :active-value="1"
+                :inactive-value="0"
+                :disabled="scope.row.initialStatus === 1"
+                @change="handleStatusChange(scope.row)"
+                class="status-switch"
+              />
+              <span class="status-text">
+                {{ getStatusText(scope.row) }}
+              </span>
+            </div>
+          </template>
+        </el-table-column>
+
         <el-table-column :label="t('main.mileage')" key="mileageRule" align="center"
                          :width="columnWidths.mileageRule" v-if="false">
           <template #default="scope">
@@ -294,11 +312,6 @@
           </el-table-column>
         </el-table-column>
 
-        <el-table-column :label="t('common.status')" align="center" width="100">
-          <template #default="scope">
-            {{ getStatusText(scope.row) }}
-          </template>
-        </el-table-column>
         <!--
         <el-table-column :label="t('iotMaintain.numberOfMaterials')" align="center" width="90">
           <template #default="scope">
@@ -403,7 +416,7 @@
           type="primary"
           :icon="Box"
           @click="handleSelectMaterial"
-          :disabled="!currentBomItem"
+          :disabled="!currentBomItem || isButtonsDisabled"
         >
           {{ t('stock.selectMaterial') }}
         </el-button>
@@ -420,7 +433,7 @@
           type="primary"
           :icon="Plus"
           @click="handleAddMaterial"
-          :disabled="!currentBomItem"
+          :disabled="!currentBomItem || isButtonsDisabled"
         >
           新增物料
         </el-button>
@@ -468,7 +481,7 @@
               placeholder="请输入物料名称(必填)"
               style="width: 100%"
               :class="{ 'is-required-input': row.isNew && !row.materialName?.trim() }"
-            :disabled="isMaterialDisabled(row)"
+              :disabled="isMaterialDisabled(row)"
             />
             </el-tooltip>
             <!-- 非新增行:正常显示 -->
@@ -904,8 +917,13 @@ const displayedMaterialList = computed(() => {
 const isMaterialDisabled = (material) => {
   // 根据物料的bomNodeId找到对应的保养项
   const bomItem = list.value.find(item => item.bomNodeId === material.bomNodeId);
-  // 如果保养项存在且rule=1(不消耗物料),则禁用
-  return bomItem && bomItem.rule === 1;
+  // 如果保养项不存在,默认不禁用
+  if (!bomItem) return false;
+  // 如果保养项状态为已完成(status=1),则禁用该物料
+  if (bomItem.status === 1) return true;
+  // 如果保养项rule=1(不消耗物料),则禁用
+  if (bomItem.rule === 1) return true;
+  return false;
 };
 
 // 物料表格行类名 - 用于设置灰色背景
@@ -919,15 +937,27 @@ const getMaterialRowClassName = ({ row }) => {
   return '';
 };
 
+// 计算属性:判断按钮是否应该禁用
+const isButtonsDisabled = computed(() => {
+  if (!currentBomItem.value) return true;
+
+  // 条件1:保养状态为已完成(status=1)
+  if (currentBomItem.value.status === 1) return true;
+
+  // 条件2:消耗物料字段为不消耗物料(rule=1)
+  if (currentBomItem.value.rule === 1) return true;
+
+  return false;
+});
+
 // 切换显示所有物料/当前保养项物料
 const toggleShowAllMaterials = () => {
   showAllMaterials.value = !showAllMaterials.value;
 
   // 切换显示模式时,需要同步更新 materialList
   if (!showAllMaterials.value && currentBomItem.value) {
-    // 切换到显示当前保养项物料
-    const uniqueKey = `${currentBomItem.value.deviceId}${currentBomItem.value.bomNodeId}`;
-    materialList.value = bomMaterialsMap.value[uniqueKey] || [];
+    // 切换到显示当前保养项物料时,使用新的刷新方法
+    refreshCurrentBomItemMaterials();
   } else if (showAllMaterials.value) {
     // 切换到显示所有物料
     const allMaterials = [];
@@ -936,6 +966,10 @@ const toggleShowAllMaterials = () => {
     }
     materialList.value = allMaterials;
   }
+  console.log('切换显示模式:', {
+    showAllMaterials: showAllMaterials.value,
+    materialCount: materialList.value.length
+  });
 };
 
 // 为表格行添加类名,实现高亮效果
@@ -1228,6 +1262,43 @@ const handleSizeChange = (newSize: number) => {
   currentPage.value = 1 // 重置到第一页
 }
 
+// 处理状态变化
+const handleStatusChange = (row: IotMainWorkOrderBomVO) => {
+  // 如果是从未完成(0)切换到完成(1)
+  if (row.status === 1 && row.initialStatus === 0) {
+    // 检查消耗物料规则:如果设置为不消耗物料(rule=1),则跳过物料校验
+    if (row.rule === 1) {
+      console.log(`保养项 ${row.name} 设置为不消耗物料,跳过物料校验`);
+      message.success(`${row.deviceCode}-${formatMaintItemName(row.name)} 已标记为完成`);
+      return;
+    }
+
+    // 校验物料数据
+    const isValid = validateBomItemMaterials(row.bomNodeId);
+
+    if (!isValid) {
+      // 获取无效物料信息用于提示
+      const invalidMaterials = getInvalidMaterialsInfo(row.bomNodeId);
+      const errorMessage = `请填写物料必填项\n无效物料:\n${invalidMaterials.join('\n')}`;
+
+      message.error(errorMessage);
+
+      // 重置状态为未完成
+      row.status = 0;
+      return;
+    }
+  }
+
+  console.log(`保养项 ${row.name} 状态改为: ${row.status === 1 ? '完成' : '未完成'}`);
+
+  // 这里可以添加状态变化后的业务逻辑
+  // 例如:如果状态变为完成,可以自动填充完成时间等
+  if (row.status === 1) {
+    // 保养完成时的逻辑
+    message.success(`${row.deviceCode}-${formatMaintItemName(row.name)} 已标记为完成`);
+  }
+};
+
 // 运行时间周期 全局校验方法(在submitForm中调用)
 const validateAllRunningTimes = (): boolean => {
   let isValid = true;
@@ -1277,11 +1348,11 @@ const handleAddMaterial = () => {
 
     // 临时标识(用于区分新记录)
     isNew: true,
-    tempId: Date.now() // 临时ID用于唯一标识
+    tempId: Date.now() + Math.random() // 临时ID用于唯一标识
   };
 
   // 生成唯一键
-  const uniqueKey = `${currentBomItem.value.deviceId}${currentBomItem.value.bomNodeId}`;
+  const uniqueKey = `${currentBomItem.value.bomNodeId}`;
 
   // 更新 bomMaterialsMap
   if (!bomMaterialsMap.value[uniqueKey]) {
@@ -1322,20 +1393,56 @@ const openDeviceBomMaterials = (row: any) => {
   deviceBomMaterialsRef.value.open(formData.value.deptId, bomNodeId.value, row, type)
 }
 
+// 刷新当前保养项的物料列表显示
+const refreshCurrentBomItemMaterials = () => {
+  if (!currentBomItem.value) {
+    materialList.value = [];
+    return;
+  }
+
+  const uniqueKey = `${currentBomItem.value.bomNodeId}`;
+
+  // 确保从映射中获取最新数据
+  const currentMaterials = bomMaterialsMap.value[uniqueKey] || [];
+
+  // 强制更新 materialList 的引用,确保响应式更新
+  materialList.value = [...currentMaterials];
+
+  console.log('刷新物料列表:', {
+    currentBomItem: currentBomItem.value.name,
+    materialCount: materialList.value.length,
+    uniqueKey: uniqueKey,
+    showAllMaterials: showAllMaterials.value
+  });
+}
+
 const selectChoose = (selectedMaterial) => {
+  // 检查当前是否有选中的保养项
+  if (!currentBomItem.value) {
+    message.warning('请先选择一个保养项');
+    return;
+  }
+
+  const targetBomNodeId = currentBomItem.value.bomNodeId;
+  const targetDeviceId = currentBomItem.value.deviceId;
+
   selectedMaterial.bomNodeId = bomNodeId.value
   // 关联 bomNodeId
   const processedMaterials = selectedMaterial.map(material => ({
     ...material,
-    bomNodeId: bomNodeId.value // 统一关联当前行的 bomNodeId
+    bomNodeId: targetBomNodeId, // 统一关联当前行的 bomNodeId
+    deviceId: targetDeviceId // 确保 deviceId 也正确关联
   }));
 
+  // 生成唯一键
+  const uniqueKey = `${targetBomNodeId}`;
+  // 初始化物料映射(如果不存在)
+  if (!bomMaterialsMap.value[uniqueKey]) {
+    bomMaterialsMap.value[uniqueKey] = [];
+  }
+
   // 避免重复添加
   processedMaterials.forEach(newMaterial => {
-    const uniqueKey = `${newMaterial.deviceId}${bomNodeId.value}`;
-    if (!bomMaterialsMap.value[uniqueKey]) {
-      bomMaterialsMap.value[uniqueKey] = [];
-    }
     // 检查是否已存在相同 工厂+成本中心+库存地点+bomNodeId + materialCode 的条目
     const isExist = bomMaterialsMap.value[uniqueKey].some(item =>
       item.bomNodeId === bomNodeId.value &&
@@ -1350,10 +1457,8 @@ const selectChoose = (selectedMaterial) => {
     }
   });
 
-  // 同步到当前显示的 materialList(如果当前选中了该保养项)
-  if (currentBomItem.value && currentBomItem.value.bomNodeId === bomNodeId.value) {
-    materialList.value = bomMaterialsMap.value[`${currentBomItem.value.deviceId}${bomNodeId.value}`] || [];
-  }
+  // 关键修复:立即更新当前显示的物料列表
+  refreshCurrentBomItemMaterials();
 
   // 选择物料后立即计算费用
   nextTick(() => {
@@ -1514,51 +1619,115 @@ const queryParams = reactive({
 
 // 获取指定bomNodeId的物料数量
 const getMaterialCount = (bomNodeId: number) => {
-  console.log('当前BOM节点:' + bomNodeId)
-  return materialList.value.filter(item => item.bomNodeId === bomNodeId).length
-}
+  const uniqueKey = `${bomNodeId}`;
+  const materials = bomMaterialsMap.value[uniqueKey] || [];
+
+  // 只计算有效的物料数量
+  return materials.filter(material =>
+    !isMaterialDisabled(material) &&
+    material.materialName &&
+    material.unit &&
+    (material.unitPrice || 0) > 0 &&
+    (material.quantity || 0) > 0
+  ).length;
+}
+
+// 校验保养项下物料数据的方法
+const validateBomItemMaterials = (bomNodeId: number): boolean => {
+  const uniqueKey = `${bomNodeId}`;
+  const materials = bomMaterialsMap.value[uniqueKey] || [];
+
+  // 如果没有物料数据,直接返回true(允许完成)
+  if (materials.length === 0) {
+    return true;
+  }
+
+  // 检查所有物料的单价和消耗数量是否都大于0
+  const hasInvalidMaterial = materials.some(material => {
+    const unitPrice = Number(material.unitPrice) || 0;
+    const quantity = Number(material.quantity) || 0;
+
+    return unitPrice <= 0 || quantity <= 0;
+  });
+
+  return !hasInvalidMaterial;
+};
+
+// 获取校验失败的物料信息(用于错误提示)
+const getInvalidMaterialsInfo = (bomNodeId: number): string[] => {
+  const uniqueKey = `${bomNodeId}`;
+  const materials = bomMaterialsMap.value[uniqueKey] || [];
+  const invalidMaterials = [];
+
+  materials.forEach(material => {
+    const unitPrice = Number(material.unitPrice) || 0;
+    const quantity = Number(material.quantity) || 0;
+
+    if (unitPrice <= 0 || quantity <= 0) {
+      invalidMaterials.push(`${material.materialName || material.materialCode} (单价: ${unitPrice}, 数量: ${quantity})`);
+    }
+  });
+
+  return invalidMaterials;
+};
 
-// 删除物料(在表格中)
 const handleDeleteMaterialInTable = (material) => {
   // 确认删除对话框
   message.confirm('确认删除该物料吗?', { title: '提示' }).then(() => {
     const targetBomNodeId = material.bomNodeId;
-    const uniqueKey = `${material.deviceId}${targetBomNodeId}`;
+
+    // 修复:统一使用 bomNodeId 作为键(与新增物料保持一致)
+    const uniqueKey = `${targetBomNodeId}`;
+
+    console.log('删除物料调试信息:', {
+      material,
+      uniqueKey,
+      bomMaterialsMapKeys: Object.keys(bomMaterialsMap.value),
+      currentMaterials: bomMaterialsMap.value[uniqueKey] || []
+    });
 
     // 从 bomMaterialsMap 中删除
     if (bomMaterialsMap.value[uniqueKey]) {
-      const mapIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
-        (item.isNew && item.tempId === material.tempId) ||
-        (!item.isNew &&
+      let mapIndex = -1;
+
+      // 简化查找逻辑
+      if (material.isNew && material.tempId) {
+        // 新增物料:通过 tempId 查找
+        mapIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
+          item.isNew && item.tempId === material.tempId
+        );
+      } else {
+        // 已有物料:通过关键字段查找
+        mapIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
+          !item.isNew &&
           item.factoryId === material.factoryId &&
           item.costCenterId === material.costCenterId &&
           item.storageLocationId === material.storageLocationId &&
-          item.materialCode === material.materialCode)
-      );
+          item.materialCode === material.materialCode
+        );
+      }
 
       if (mapIndex !== -1) {
+        // 执行删除
         bomMaterialsMap.value[uniqueKey].splice(mapIndex, 1);
-      }
-    }
+        message.success('物料删除成功');
 
-    // 从 materialList 中删除
-    const index = materialList.value.findIndex(item =>
-      (item.isNew && item.tempId === material.tempId) ||
-      (!item.isNew &&
-        item.bomNodeId === targetBomNodeId &&
-        item.factoryId === material.factoryId &&
-        item.costCenterId === material.costCenterId &&
-        item.storageLocationId === material.storageLocationId &&
-        item.materialCode === material.materialCode)
-    );
+        console.log('删除成功后的物料列表:', bomMaterialsMap.value[uniqueKey]);
 
-    if (index !== -1) {
-      materialList.value.splice(index, 1);
+        // 关键修复:立即更新当前显示的物料列表
+        refreshCurrentBomItemMaterials();
+
+        // 删除物料后重新计算费用
+        nextTick(() => {
+          calculateTotalCost();
+        });
+      } else {
+        message.warning('未找到要删除的物料记录');
+        console.error('未找到匹配的物料记录:', material);
+      }
+    } else {
+      message.warning('未找到对应的物料列表');
     }
-    // 删除物料后重新计算费用
-    nextTick(() => {
-      calculateTotalCost();
-    });
   }).catch(() => {
     // 用户取消删除
   });
@@ -1604,6 +1773,38 @@ const submitForm = async () => {
     return; // 校验失败则终止提交
   }
 
+  // 校验所有设置为完成状态的保养项的物料数据
+  const invalidBomItems = [];
+
+  list.value.forEach(row => {
+    // 只校验状态为完成(1)且消耗物料规则为消耗(0)的保养项
+    if (row.status === 1 && row.rule === '0') {
+      const isValid = validateBomItemMaterials(row.bomNodeId);
+      if (!isValid) {
+        invalidBomItems.push({
+          name: `${row.deviceCode}-${formatMaintItemName(row.name)}`,
+          invalidMaterials: getInvalidMaterialsInfo(row.bomNodeId)
+        });
+      }
+    }
+  });
+
+  // 如果有校验失败的保养项,显示错误信息并终止提交
+  if (invalidBomItems.length > 0) {
+    let errorMessage = '请填写物料必填项\n\n';
+
+    invalidBomItems.forEach((item, index) => {
+      errorMessage += `${index + 1}. ${item.name}:\n`;
+      item.invalidMaterials.forEach(material => {
+        errorMessage += `   - ${material}\n`;
+      });
+      errorMessage += '\n';
+    });
+
+    message.error(errorMessage);
+    return;
+  }
+
   // 校验表格数据
   const isValid = validateTableData()
   if (!isValid) return
@@ -1616,10 +1817,17 @@ const submitForm = async () => {
         ? item.lastNaturalDate
         : (item.lastNaturalDate ? dayjs(item.lastNaturalDate).valueOf() : null)
     }));
+
+    // 从 bomMaterialsMap 获取所有物料数据,而不是 materialList
+    const allMaterials = [];
+    for (const key in bomMaterialsMap.value) {
+      allMaterials.push(...bomMaterialsMap.value[key]);
+    }
+
     const data = {
       mainWorkOrder: formData.value,
       mainWorkOrderBom: convertedList,
-      mainWorkOrderMaterials: materialList.value
+      mainWorkOrderMaterials: allMaterials
     }
     await IotMainWorkOrderApi.fillWorkOrder(data)
     message.success(t('common.createSuccess'))
@@ -2066,7 +2274,7 @@ const validateTableData = (): boolean => {
   if (formData.value.outsourcingFlag !== 1) {
     list.value.forEach((row, index) => {
       const rowNumber = index + 1;
-      const deviceIdentifier = `${row.deviceCode}-${row.name}`;
+      const deviceIdentifier = `${row.deviceCode}-${formatMaintItemName(row.name)}`;
 
       // 检查消耗物料规则,如果为1(不消耗物料)则跳过校验
       if (row.rule === 1) {
@@ -2079,10 +2287,24 @@ const validateTableData = (): boolean => {
         (row.delayNaturalDate || 0) > 0 ||
         (row.delayDuration || 0) > 0;
 
-      // 未设置推迟保养且未选择物料
-      if (!hasDelay && getMaterialCount(row.bomNodeId) === 0) {
-        materialRequiredErrors.push(`第${rowNumber}行【${deviceIdentifier}】未添加物料`);
-        isValid = false;
+      // 未设置推迟保养时,需要校验物料
+      if (!hasDelay) {
+        // 使用 bomMaterialsMap 获取物料,更可靠
+        const uniqueKey = `${row.bomNodeId}`;
+        const materials = bomMaterialsMap.value[uniqueKey] || [];
+
+        // 过滤有效的物料(非禁用、非无效状态)
+        const validMaterials = materials.filter(material =>
+          material.materialName && // 物料名称不为空
+          material.unit && // 单位不为空
+          (material.unitPrice || 0) > 0 && // 单价大于0
+          (material.quantity || 0) > 0 // 数量大于0
+        );
+
+        if (validMaterials.length === 0) {
+          materialRequiredErrors.push(`第${rowNumber}行【${deviceIdentifier}】未添加有效物料`);
+          isValid = false;
+        }
       }
     });
   }
@@ -2174,15 +2396,18 @@ onMounted(async () => {
     list.value = []
     if (Array.isArray(data)) {
       list.value = data.map(item => {
+          // 记录初始状态,用于判断是否可编辑
+          const initialStatus = item.status;
+
           // 提取分组名称
           const group = item.name && item.name.includes('->')
             ? item.name.split('->')[0].trim()
             : '';
 
           // 处理物料数据映射
-          if (item.deviceBomMaterials && item.deviceBomMaterials.length > 0) {
+          /* if (item.deviceBomMaterials && item.deviceBomMaterials.length > 0) {
             // 生成唯一键
-            const uniqueKey = `${item.deviceId}${item.bomNodeId}`;
+            const uniqueKey = `${item.bomNodeId}`;
 
             // 转换物料字段映射
             const mappedMaterials = item.deviceBomMaterials.map(material => ({
@@ -2190,11 +2415,12 @@ onMounted(async () => {
               materialName: material.name, // name -> materialName
               materialCode: material.code, // code -> materialCode
               projectDepartment: material.storageLocation, // storageLocation -> projectDepartment
-              totalInventoryQuantity: material.stockQuantity // stockQuantity -> totalInventoryQuantity
+              totalInventoryQuantity: material.stockQuantity, // stockQuantity -> totalInventoryQuantity
+              deviceId: item.deviceId // 添加 deviceId,从保养项中获取
             }));
             // 存储到映射表中
             bomMaterialsMap.value[uniqueKey] = mappedMaterials;
-          }
+          } */
 
           if (item.mileageRule === 0) {
             item.nextMaintenanceKm = calculateNextMaintenanceKm(item);
@@ -2212,6 +2438,7 @@ onMounted(async () => {
           return {
             ...item,
             group,
+            initialStatus, // 保存初始状态
             lastNaturalDate: item.lastNaturalDate,
             lastMaintenanceDate: item.lastMaintenanceDate
               ? dayjs(item.lastMaintenanceDate).format("YYYY-MM-DD")  // 时间戳 → 日期字符串
@@ -2229,34 +2456,74 @@ onMounted(async () => {
     }
     // 查询当前保养工单已经关联的所有物料
     const materials = await IotMainWorkOrderBomMaterialApi.getWorkOrderBomMaterials(queryParams);
-    materialList.value = []
-    // 修改:如果有已关联的物料,使用接口返回的数据覆盖默认数据
+    // 重新初始化物料映射,确保接口数据完全覆盖
+    const tempBomMaterialsMap = {};
+    // 首先,用 getWorkOrderBomMaterials 返回的数据初始化映射(主数据源)
     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 uniqueKey = `${material.bomNodeId}`;
+        if (!tempBomMaterialsMap[uniqueKey]) {
+          tempBomMaterialsMap[uniqueKey] = [];
         }
+
+        // 通过 bomNodeId 在 list 中查找对应的保养项,获取 deviceId
+        const correspondingItem = list.value.find(item => item.bomNodeId === material.bomNodeId);
+        const deviceId = correspondingItem ? correspondingItem.deviceId : null;
+
+        const materialWithDeviceId = {
+          ...material,
+          deviceId: deviceId
+        };
+
         // 避免重复添加
-        const existingIndex = bomMaterialsMap.value[uniqueKey].findIndex(item =>
+        const existingIndex = tempBomMaterialsMap[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);
+          tempBomMaterialsMap[uniqueKey].push(materialWithDeviceId);
         } else {
-          // 如果已存在,更新数据(使用接口返回的最新数据)
-          bomMaterialsMap.value[uniqueKey][existingIndex] = material;
+          tempBomMaterialsMap[uniqueKey][existingIndex] = materialWithDeviceId;
         }
       });
     }
+    // 其次,对于 getWorkOrderBOMs 接口返回的 deviceBomMaterials,
+    // 只有当 getWorkOrderBomMaterials 中没有对应保养项的物料时,才使用 deviceBomMaterials 作为备用
+    list.value.forEach(item => {
+      const uniqueKey = `${item.bomNodeId}`;
+
+      // 如果 getWorkOrderBomMaterials 中没有这个保养项的物料,且 deviceBomMaterials 有值,则使用备用数据
+      if ((!tempBomMaterialsMap[uniqueKey] || tempBomMaterialsMap[uniqueKey].length === 0) &&
+        item.deviceBomMaterials && item.deviceBomMaterials.length > 0) {
+
+        tempBomMaterialsMap[uniqueKey] = item.deviceBomMaterials.map(material => ({
+          ...material,
+          materialName: material.name,
+          materialCode: material.code,
+          projectDepartment: material.storageLocation,
+          totalInventoryQuantity: material.stockQuantity,
+          deviceId: item.deviceId
+        }));
+      } else if (!tempBomMaterialsMap[uniqueKey]) {
+        // 确保每个保养项在映射中都有对应的数组(即使是空的)
+        tempBomMaterialsMap[uniqueKey] = [];
+      }
+    });
+
+    // 更新响应式映射
+    bomMaterialsMap.value = tempBomMaterialsMap;
+
+    // 如果有数据,选中第一个保养项并显示其物料
     if (list.value.length > 0) {
-      handleBomItemClick(list.value[0]);
+      // 确保第一个保养项的物料正确显示
+      const firstItem = list.value[0];
+      const uniqueKey = `${firstItem.bomNodeId}`;
+      materialList.value = bomMaterialsMap.value[uniqueKey] || [];
+
+      handleBomItemClick(firstItem);
     }
     // 页面初始化完成后立即计算费用
     nextTick(() => {
@@ -2291,11 +2558,9 @@ const handleBomItemClick = (item) => {
   currentBomItem.value = item;
   // 切换到当前保养项物料视图
   showAllMaterials.value = false;
-  // 生成唯一键
-  const uniqueKey = `${item.deviceId}${item.bomNodeId}`;
 
-  // 更新物料列表
-  materialList.value = bomMaterialsMap.value[uniqueKey] || [];
+  // 使用新的刷新方法
+  refreshCurrentBomItemMaterials();
 
   // 切换保养项时重新计算费用
   nextTick(() => {
@@ -2503,19 +2768,27 @@ const handleRowClick = (row) => {
 :deep(.disabled-material-row) {
   background-color: #f5f7fa !important;
   color: #c0c4cc !important;
+  cursor: not-allowed !important;
 }
 
 :deep(.disabled-material-row:hover>td) {
   background-color: #f5f7fa !important;
 }
 
+:deep(.disabled-material-row .el-input.is-disabled .el-input__inner) {
+  background-color: #f5f7fa !important;
+  color: #c0c4cc !important;
+  cursor: not-allowed !important;
+}
+
 :deep(.disabled-material-row .el-input-number.is-disabled) {
   opacity: 0.6;
+  cursor: not-allowed !important;
 }
 
 :deep(.disabled-material-row .el-button.is-disabled) {
   opacity: 0.6;
-  cursor: not-allowed;
+  cursor: not-allowed !important;
 }
 
 /* 新增物料行的样式 */
@@ -2567,4 +2840,50 @@ const handleRowClick = (row) => {
   border-bottom-color: #ffeeba !important;
 }
 
+/* 状态列容器样式 - 水平排列 */
+.status-container {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px; /* 设置开关和文本之间的间距 */
+  white-space: nowrap; /* 防止换行 */
+}
+
+/* 状态开关样式 */
+.status-switch {
+  flex-shrink: 0; /* 防止开关被压缩 */
+}
+
+/* 状态列样式优化 */
+.status-text {
+  font-size: 12px;
+  color: #666;
+  min-width: 40px; /* 为文本设置最小宽度,确保对齐 */
+  text-align: left;
+  flex-shrink: 0; /* 防止文本被压缩 */
+}
+
+/* 禁用状态的switch样式 */
+:deep(.el-switch.is-disabled) {
+  opacity: 0.6;
+}
+
+/* 已完成状态的特殊样式 */
+:deep(.status-completed .el-switch__core) {
+  background-color: #67c23a;
+  border-color: #67c23a;
+}
+
+/* 保养中状态的样式 */
+:deep(.status-maintaining .el-switch__core) {
+  background-color: #409eff;
+  border-color: #409eff;
+}
+
+/* 延迟状态的样式 */
+:deep(.status-delayed .el-switch__core) {
+  background-color: #e6a23c;
+  border-color: #e6a23c;
+}
+
 </style>