src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -2,7 +2,7 @@
  <div>
    <el-dialog v-model="dialogVisible"
               title="领料台账"
               width="1200px"
               width="1400px"
               @close="handleClose">
      <div class="material-toolbar">
        <el-button type="primary"
@@ -65,10 +65,18 @@
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="库存数量"
                         min-width="120">
          <template #default="{ row }">
            <span :class="{ 'text-danger': isStockInsufficient(row) }">
              {{ row.stockQuantity ?? '-' }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="需求数量"
                         min-width="120">
          <template #default="{ row }">
            <span v-if="row.bom === true">{{ row.demandedQuantity ?? "-" }}</span>
            <span v-if="row.bom === true" :class="{ 'text-danger': isStockInsufficient(row) }">{{ row.demandedQuantity ?? "-" }}</span>
            <el-input-number v-else
                             v-model="row.demandedQuantity"
                             :min="0"
@@ -76,6 +84,7 @@
                             :step="1"
                             controls-position="right"
                             style="width: 100%;"
                             :class="{ 'is-stock-insufficient': isStockInsufficient(row) }"
                             @change="val => handleRequiredQtyChange(row, val)" />
          </template>
        </el-table-column>
@@ -109,6 +118,9 @@
      </el-table>
      <template #footer>
        <span class="dialog-footer">
          <el-button v-if="hasInsufficientStock"
                     type="warning"
                     @click="openPurchaseRequestDialog">采购申请</el-button>
          <el-button type="primary"
                     :loading="materialSaving"
                     :disabled="isSaveDisabled"
@@ -120,6 +132,10 @@
    <ProductSelectDialog v-model="materialProductDialogVisible"
                         @confirm="handleMaterialProductConfirm"
                         single />
    <PurchaseRequestDialog v-model="purchaseRequestDialogVisible"
                           :insufficient-items="insufficientStockItems"
                           :order-row="props.orderRow"
                           @saved="handlePurchaseRequestSaved" />
    <!-- request-url="/stockInventory/rawMaterials" -->
  </div>
</template>
@@ -128,18 +144,18 @@
  import { computed, ref, watch } from "vue";
  import { ElMessage } from "element-plus";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import PurchaseRequestDialog from "./PurchaseRequestDialog.vue";
  import {
    findProductProcessRouteItemList,
    listMain,
  } from "@/api/productionManagement/productProcessRoute.js";
  import {
    listMaterialPickingDetail,
    listMaterialPickingBom,
    listMaterialPickingLedger,
    saveMaterialPickingLedger,
    updateMaterialPickingLedger,
  } from "@/api/productionManagement/productionOrder.js";
  import { queryList2 } from "@/api/productionManagement/productStructure.js";
  const props = defineProps({
    modelValue: { type: Boolean, default: false },
@@ -156,6 +172,7 @@
  const materialTableLoading = ref(false);
  const materialSaving = ref(false);
  const materialTableData = ref([]);
  const purchaseRequestDialogVisible = ref(false);
  const isSaveDisabled = computed(() => {
    if (materialTableData.value.length === 0) return true;
@@ -183,6 +200,23 @@
    });
  });
  // 判断库存是否不足
  const isStockInsufficient = (row) => {
    const stockQuantity = Number(row.stockQuantity ?? 0);
    const demandedQty = Number(row.demandedQuantity ?? 0);
    return demandedQty > 0 && stockQuantity > 0 && demandedQty > stockQuantity;
  };
  // 库存不足的行
  const insufficientStockItems = computed(() => {
    return materialTableData.value.filter(row => isStockInsufficient(row));
  });
  // 是否有库存不足
  const hasInsufficientStock = computed(() => {
    return insufficientStockItems.value.length > 0;
  });
  const processOptions = ref([]);
  const currentMaterialSelectRowIndex = ref(-1);
  let materialTempId = 0;
@@ -206,6 +240,7 @@
        : row.batchNo
      : [],
    batchNoList: row.batchNoList || [],
    stockQuantity: row.stockQuantity ?? row.stockQty ?? null,
  });
  const getProcessOptions = async () => {
@@ -239,22 +274,14 @@
    materialTableData.value = [];
    await getProcessOptions();
    try {
      const detailRes = await listMaterialPickingDetail(props.orderRow.id);
      const detailList = Array.isArray(detailRes?.data)
        ? detailRes.data
        : detailRes?.data?.records || [];
      if (detailList.length > 0) {
        isDetail.value = true;
        materialTableData.value = detailList.map(item => createMaterialRow(item));
        return;
      } else {
      // 直接调用listMaterialPickingBom接口获取库存数量
      const bomRes = await listMaterialPickingBom(props.orderRow.id);
      const bomList = Array.isArray(bomRes?.data)
        ? bomRes.data
        : bomRes?.data?.records || [];
      if (bomList.length > 0) {
        isDetail.value = false;
        const bomRes = await listMaterialPickingBom(props.orderRow.id);
        const bomList = Array.isArray(bomRes?.data)
          ? bomRes.data
          : bomRes?.data?.records || [];
        materialTableData.value = bomList.map(item => createMaterialRow(item));
        return;
      }
    } finally {
      materialTableLoading.value = false;
@@ -305,7 +332,7 @@
    materialProductDialogVisible.value = true;
  };
  const handleMaterialProductConfirm = products => {
  const handleMaterialProductConfirm = async (products) => {
    console.log(products, "products");
    if (!products || products.length === 0) return;
@@ -417,6 +444,17 @@
      materialSaving.value = false;
    }
  };
  // 打开采购申请对话框
  const openPurchaseRequestDialog = () => {
    purchaseRequestDialogVisible.value = true;
  };
  // 采购申请保存回调
  const handlePurchaseRequestSaved = () => {
    // 采购申请保存成功后刷新数据
    loadMaterialData();
  };
</script>
<style scoped lang="scss">
@@ -424,4 +462,15 @@
    margin-bottom: 12px;
    text-align: right;
  }
  .text-danger {
    color: #f56c6c;
    font-weight: bold;
  }
  :deep(.is-stock-insufficient) {
    .el-input__wrapper {
      box-shadow: 0 0 0 1px #f56c6c inset;
    }
  }
</style>