src/views/procurementManagement/procurementLedger/index.vue
@@ -66,6 +66,9 @@
    </div>
    <div class="table_list">
      <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;">
        <el-button type="success"
                   plain
                   @click="handleBatchGenerate">批量生成数据</el-button>
        <el-button type="primary"
                   @click="openForm('add')">新增台账</el-button>
        <el-button type="primary"
@@ -102,11 +105,13 @@
                               width="60" />
              <el-table-column label="产品大类"
                               prop="productCategory" />
              <el-table-column label="材质"
                               prop="material" />
              <el-table-column label="规格型号"
                               prop="specificationModel" />
              <el-table-column label="单位"
                               prop="unit" />
                               <el-table-column label="入库审核状态"
              <el-table-column label="入库审核状态"
                               prop="stockInApprovalStatus"
                               width="120">
                <template #default="scope">
@@ -118,10 +123,12 @@
              </el-table-column>
              <el-table-column label="数量"
                               prop="quantity" />
              <el-table-column label="销售发货数量"
                               prop="shippedQuantity" />
              <el-table-column label="可用数量"
                               prop="availableQuality" />
              <el-table-column label="退货数量"
                               prop="returnQuality" />
                               prop="returnQuantity" />
              <el-table-column label="税率(%)"
                               prop="taxRate" />
              <el-table-column label="含税单价(元)"
@@ -144,10 +151,10 @@
                         prop="purchaseContractNumber"
                         width="160"
                         show-overflow-tooltip />
        <el-table-column label="销售合同号"
                         prop="salesContractNo"
                         width="160"
                         show-overflow-tooltip />
<!--        <el-table-column label="销售合同号"-->
<!--                         prop="salesContractNo"-->
<!--                         width="160"-->
<!--                         show-overflow-tooltip />-->
        <el-table-column label="供应商名称"
                         prop="supplierName"
                         width="160"
@@ -191,6 +198,11 @@
                         width="200"
                         show-overflow-tooltip
                         :formatter="formattedNumber" />
        <el-table-column label="实际合同金额(元)"
                         prop="netContractAmount"
                         width="200"
                         show-overflow-tooltip
                         :formatter="(_, __, cellValue) => formatMoney(cellValue)" />
        <el-table-column label="录入人"
                         prop="recorderName"
                         width="120"
@@ -211,7 +223,7 @@
            <el-button link
                       type="primary"
                       @click="openForm('edit', scope.row)"
                       :disabled="scope.row.stockInStatus === '完全入库'">编辑
                       :disabled="scope.row.approvalStatus === 3">编辑
            </el-button>
            <el-button link
                       type="primary"
@@ -247,21 +259,21 @@
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="销售合同号:"
                          prop="salesLedgerId">
              <el-select v-model="form.salesLedgerId"
                         placeholder="请选择"
                         filterable
                         clearable
                         @change="salesLedgerChange">
                <el-option v-for="item in salesContractList"
                           :key="item.id"
                           :label="item.salesContractNo"
                           :value="item.id" />
              </el-select>
            </el-form-item>
          </el-col>
<!--          <el-col :span="12">-->
<!--            <el-form-item label="销售合同号:"-->
<!--                          prop="salesLedgerId">-->
<!--              <el-select v-model="form.salesLedgerId"-->
<!--                         placeholder="请选择"-->
<!--                         filterable-->
<!--                         clearable-->
<!--                         @change="salesLedgerChange">-->
<!--                <el-option v-for="item in salesContractList"-->
<!--                           :key="item.id"-->
<!--                           :label="item.salesContractNo"-->
<!--                           :value="item.id" />-->
<!--              </el-select>-->
<!--            </el-form-item>-->
<!--          </el-col>-->
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
@@ -402,6 +414,8 @@
                           width="60" />
          <el-table-column label="产品大类"
                           prop="productCategory" />
          <el-table-column label="材质"
                           prop="material" />
          <el-table-column label="规格型号"
                           prop="specificationModel" />
          <el-table-column label="单位"
@@ -530,34 +544,31 @@
               ref="productFormRef">
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="产品大类:"
                          prop="productId">
              <el-tree-select v-model="productForm.productId"
                              placeholder="请选择"
                              clearable
                              filterable
                              check-strictly
                              @change="getModels"
                              :data="productOptions"
                              :render-after-expand="false"
                              style="width: 100%" />
            <el-form-item label="品名:"
                          prop="productCategory">
              <el-input v-model="productForm.productCategory"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="材质:"
                          prop="material">
              <el-input v-model="productForm.material"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="规格型号:"
                          prop="productModelId">
              <el-select v-model="productForm.productModelId"
                         placeholder="请选择"
                         filterable
                         clearable
                         @change="getProductModel">
                <el-option v-for="item in modelOptions"
                           :key="item.id"
                           :label="item.model"
                           :value="item.id" />
              </el-select>
                          prop="specificationModel">
              <el-input v-model="productForm.specificationModel"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
        </el-row>
@@ -721,6 +732,7 @@
    getOptions,
    getPurchaseTemplateList,
    delPurchaseTemplate,
    batchGeneratePurchaseInboundSteps,
  } from "@/api/procurementManagement/procurementLedger.js";
  import useFormData from "@/hooks/useFormData.js";
  const FileList = defineAsyncComponent(() =>
@@ -733,9 +745,7 @@
  const productData = ref([]);
  const selectedRows = ref([]);
  const productSelectedRows = ref([]);
  const modelOptions = ref([]);
  const userList = ref([]);
  const productOptions = ref([]);
  const salesContractList = ref([]);
  const supplierList = ref([]);
  const tableLoading = ref(false);
@@ -748,7 +758,6 @@
  const total = ref(0);
  const fileList = ref([]);
  import useUserStore from "@/store/modules/user";
  import { modelList, productTreeList } from "@/api/basicData/product.js";
  import dayjs from "dayjs";
  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
@@ -776,9 +785,9 @@
  // 获取入库状态标签类型
  const getStockInStatusType = status => {
    const typeMap = {
      "待入库": "info", // 待入库 - 灰色
      "入库中": "warning", // 入库中 - 橙色
      "完全入库": "success", // 完全入库 - 绿色
      待入库: "info", // 待入库 - 灰色
      入库中: "warning", // 入库中 - 橙色
      完全入库: "success", // 完全入库 - 绿色
    };
    return typeMap[status] || "";
  };
@@ -786,9 +795,9 @@
  // 获取入库审核状态标签类型
  const getStockInApprovalStatusType = status => {
    const typeMap = {
      "待入库": "info", // 待入库 - 灰色
      "入库中": "warning", // 入库中 - 橙色
      "完全入库": "success", // 完全入库 - 绿色
      待入库: "info", // 待入库 - 灰色
      入库中: "warning", // 入库中 - 橙色
      完全入库: "success", // 完全入库 - 绿色
    };
    return typeMap[status] || "";
  };
@@ -923,7 +932,7 @@
    },
    rules: {
      purchaseContractNumber: [
        { required: true, message: "请输入", trigger: "blur" },
        { required: false, message: "请输入", trigger: "blur" },
      ],
      projectName: [
        { required: true, message: "请输入项目名称", trigger: "blur" },
@@ -934,16 +943,7 @@
    },
  });
  const { form, rules } = toRefs(data);
  const { form: searchForm } = useFormData({
    ...data.searchForm,
    // 设置录入日期范围为当天
    entryDate: [
      dayjs().startOf("day").format("YYYY-MM-DD"),
      dayjs().endOf("day").format("YYYY-MM-DD"),
    ],
    entryDateStart: dayjs().startOf("day").format("YYYY-MM-DD"),
    entryDateEnd: dayjs().endOf("day").format("YYYY-MM-DD"),
  });
  const { form: searchForm } = useFormData(data.searchForm);
  // 产品表单弹框数据
  const productFormVisible = ref(false);
@@ -952,9 +952,8 @@
  const currentId = ref("");
  const productFormData = reactive({
    productForm: {
      productId: "",
      productCategory: "",
      productModelId: "",
      material: "",
      specificationModel: "",
      unit: "",
      quantity: "",
@@ -967,8 +966,11 @@
      isChecked: false,
    },
    productRules: {
      productId: [{ required: true, message: "请选择", trigger: "change" }],
      productModelId: [{ required: true, message: "请选择", trigger: "change" }],
      productCategory: [{ required: true, message: "请输入", trigger: "blur" }],
      material: [{ required: true, message: "请输入", trigger: "blur" }],
      specificationModel: [
        { required: true, message: "请输入", trigger: "blur" },
      ],
      unit: [{ required: true, message: "请输入", trigger: "blur" }],
      quantity: [{ required: true, message: "请输入", trigger: "blur" }],
      taxInclusiveUnitPrice: [
@@ -1260,7 +1262,14 @@
  };
  // 主表合计方法
  const summarizeMainTable = param => {
    return proxy.summarizeTable(param, ["contractAmount"]);
    return proxy.summarizeTable(param, ["contractAmount", "netContractAmount"]);
  };
  const formatMoney = value => {
    if (value === null || value === undefined || value === "") {
      return "--";
    }
    const num = Number(value);
    return Number.isFinite(num) ? num.toFixed(2) : "--";
  };
  // 子表合计方法
  const summarizeProTable = param => {
@@ -1274,7 +1283,7 @@
  const openForm = async (type, row) => {
    // 编辑时检查入库状态,完全入库时不能编辑
    if (type === "edit" && row) {
      if (row.stockInStatus === '完全入库') {
      if (row.stockInStatus === "完全入库") {
        proxy.$modal.msgWarning("完全入库状态的记录不能编辑");
        return;
      }
@@ -1306,18 +1315,7 @@
      form.value.entryDate = getCurrentDate();
      if (type === "add") {
        // 新增时生成采购合同号
        try {
          const purchaseNoRes = await createPurchaseNo();
          if (purchaseNoRes?.data) {
            form.value.purchaseContractNumber = purchaseNoRes.data;
          }
        } catch (error) {
          console.error("生成采购合同号失败:", error);
          proxy.$modal.msgWarning("生成采购合同号失败");
        }
      } else if (type === "edit" && row?.id) {
      if (type === "edit" && row?.id) {
        // 编辑时加载数据
        currentId.value = row.id;
        try {
@@ -1325,7 +1323,10 @@
          form.value = { ...purchaseRes, stockInStatus: row.stockInStatus };
          fileList.value = purchaseRes.storageBlobVOS || [];
          // 使用 productList 接口获取产品列表,以获取入库审核状态
          const productRes = await productList({ salesLedgerId: row.id, type: 2 });
          const productRes = await productList({
            salesLedgerId: row.id,
            type: 2,
          });
          productData.value = productRes.data || [];
        } catch (error) {
          console.error("加载采购台账数据失败:", error);
@@ -1398,7 +1399,7 @@
  // 提交表单
  const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
    proxy.$refs["formRef"].validate(async valid => {
      if (valid) {
        if (productData.value.length > 0) {
          // 新增时,需要从每个产品对象中删除 id 字段
@@ -1428,6 +1429,20 @@
          delete submitData.id;
        }
        // 如果采购合同号为空,则根据录入日期自动生成
        if (!submitData.purchaseContractNumber) {
          try {
            const purchaseNoRes = await createPurchaseNo(submitData.entryDate);
            if (purchaseNoRes?.data) {
              submitData.purchaseContractNumber = purchaseNoRes.data;
            }
          } catch (error) {
            console.error("生成采购合同号失败:", error);
            proxy.$modal.msgWarning("生成采购合同号失败");
            return;
          }
        }
        addOrEditPurchase(submitData).then(res => {
          proxy.$modal.msgSuccess("提交成功");
          closeDia();
@@ -1442,9 +1457,9 @@
    dialogFormVisible.value = false;
  };
  // 打开产品弹框
  const openProductForm = async (type, row, index) => {
  const openProductForm = (type, row, index) => {
    // 编辑时检查产品入库审核状态,完全入库时不能编辑
    if (type === "edit" && row && row.stockInApprovalStatus === '完全入库') {
    if (type === "edit" && row && row.stockInApprovalStatus === "完全入库") {
      proxy.$modal.msgWarning("完全入库状态的产品不能编辑");
      return;
    }
@@ -1455,12 +1470,6 @@
    proxy.resetForm("productFormRef");
    productFormVisible.value = true;
    // 先获取产品选项,确保数据加载完成
    await getProductOptions();
    // 等待 DOM 更新
    await nextTick();
    if (type === "add") {
      productForm.value.isChecked = false;
    }
@@ -1468,130 +1477,8 @@
    if (type === "edit") {
      // 复制行数据
      productForm.value = { ...row };
      // 如果是从模板加载的数据,可能没有 productId 和 productModelId
      // 需要根据 productCategory 和 specificationModel 来查找对应的 ID
      if (!productForm.value.productId && productForm.value.productCategory) {
        // 根据 productCategory 查找 productId
        const findProductIdByCategory = (nodes, categoryName) => {
          for (let i = 0; i < nodes.length; i++) {
            if (nodes[i].label === categoryName) {
              return nodes[i].value;
            }
            if (nodes[i].children && nodes[i].children.length > 0) {
              const found = findProductIdByCategory(
                nodes[i].children,
                categoryName
              );
              if (found) return found;
            }
          }
          return null;
        };
        const productId = findProductIdByCategory(
          productOptions.value,
          productForm.value.productCategory
        );
        if (productId) {
          productForm.value.productId = productId;
          // 获取型号列表并等待完成
          const modelRes = await modelList({ id: productId });
          modelOptions.value = modelRes;
          // 等待 DOM 更新
          await nextTick();
          // 根据 specificationModel 查找 productModelId
          if (
            productForm.value.specificationModel &&
            modelOptions.value.length > 0
          ) {
            const modelItem = modelOptions.value.find(
              item => item.model === productForm.value.specificationModel
            );
            if (modelItem) {
              productForm.value.productModelId = modelItem.id;
              // 设置规格型号和单位
              getProductModel(modelItem.id);
            }
          }
        }
      } else if (productForm.value.productId) {
        // 如果有 productId,正常加载型号列表
        await getModels(productForm.value.productId);
        // 等待 DOM 更新
        await nextTick();
        if (productForm.value.productModelId) {
          getProductModel(productForm.value.productModelId);
        }
      }
      // 最后再等待一次 DOM 更新,确保所有数据都已设置
      await nextTick();
    }
  };
  const getProductOptions = () => {
    return productTreeList().then(res => {
      productOptions.value = convertIdToValue(res);
      return res;
    });
  };
  const getModels = value => {
    if (value) {
      productForm.value.productCategory =
        findNodeById(productOptions.value, value) || "";
      return modelList({ id: value }).then(res => {
        modelOptions.value = res;
        return res;
      });
    } else {
      productForm.value.productCategory = "";
      modelOptions.value = [];
      return Promise.resolve([]);
    }
  };
  const getProductModel = value => {
    const index = modelOptions.value.findIndex(item => item.id === value);
    if (index !== -1) {
      productForm.value.specificationModel = modelOptions.value[index].model;
      productForm.value.unit = modelOptions.value[index].unit;
    } else {
      productForm.value.specificationModel = null;
      productForm.value.unit = null;
    }
  };
  const findNodeById = (nodes, productId) => {
    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].value === productId) {
        return nodes[i].label; // 找到节点,返回该节点的label
      }
      if (nodes[i].children && nodes[i].children.length > 0) {
        const foundNode = findNodeById(nodes[i].children, productId);
        if (foundNode) {
          return foundNode; // 在子节点中找到,直接返回(已经是label字符串)
        }
      }
    }
    return null; // 没有找到节点,返回null
  };
  function convertIdToValue(data) {
    return data.map(item => {
      const { id, children, ...rest } = item;
      const newItem = {
        ...rest,
        value: id, // 将 id 改为 value
      };
      if (children && children.length > 0) {
        newItem.children = convertIdToValue(children);
      }
      return newItem;
    });
  }
  // 提交产品表单
  const submitProduct = () => {
@@ -1627,13 +1514,17 @@
  };
  // 删除产品
  const deleteProduct = () => {
    if (productData.value.length <= 1) {
      proxy.$modal.msgWarning("采购台账至少需要保留一条产品数据");
      return;
    }
    if (productSelectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    // 检查选中的产品中是否有完全入库的
    const hasFullyStocked = productSelectedRows.value.some(
      row => row.stockInApprovalStatus === '完全入库'
      row => row.stockInApprovalStatus === "完全入库"
    );
    if (hasFullyStocked) {
      proxy.$modal.msgWarning("选中的产品中包含完全入库的产品,无法删除");
@@ -1709,6 +1600,37 @@
          proxy.$modal.msgSuccess("删除成功");
          getList();
        });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
  };
  const handleBatchGenerate = async () => {
    if (selectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    const ids = selectedRows.value.map((item) => item.id);
    ElMessageBox.confirm("确认批量生成数据?", "批量生成", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "info",
    })
      .then(() => {
        proxy.$modal.loading("正在批量生成数据,请稍候...");
        batchGeneratePurchaseInboundSteps({ ids })
          .then((res) => {
            proxy.$modal.msgSuccess("批量生成成功");
            getList();
          })
          .catch(() => {
            proxy.$modal.msgError("批量生成失败");
          })
          .finally(() => {
            proxy.$modal.closeLoading();
          });
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
@@ -1852,7 +1774,7 @@
      contractNo: form.value.salesLedgerId,
    });
    if (code == 200) {
      productData.value = data;
      productData.value = data || [];
    }
  };