huminmin
2026-06-01 a563ea879ef5fb6897e76d2df661e465dce2ab9b
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"
@@ -100,13 +103,34 @@
                               label="序号"
                               type="index"
                               width="60" />
              <el-table-column label="类型"
                               prop="productType"
                               width="100">
                <template #default="scope">
                  <el-tag :type="scope.row.productType === 2 ? 'warning' : 'success'" size="small">
                    {{ scope.row.productType === 2 ? '设备备件' : '产品' }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="产品大类"
                               prop="productCategory" />
              <el-table-column label="规格型号"
                               prop="specificationModel" />
                               prop="specificationModel"
                               width="120">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">/</span>
                  <span v-else>{{ scope.row.specificationModel || '--' }}</span>
                </template>
              </el-table-column>
              <el-table-column label="单位"
                               prop="unit" />
                               <el-table-column label="入库审核状态"
                               prop="unit"
                               width="100">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ scope.row.unit || '--' }}</span>
                </template>
              </el-table-column>
              <el-table-column label="入库审核状态"
                               prop="stockInApprovalStatus"
                               width="120">
                <template #default="scope">
@@ -117,22 +141,59 @@
                </template>
              </el-table-column>
              <el-table-column label="数量"
                               prop="quantity" />
                               prop="quantity"
                               width="100" />
              <el-table-column label="可用数量"
                               prop="availableQuality" />
                               prop="availableQuality"
                               width="100">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ scope.row.availableQuality }}</span>
                </template>
              </el-table-column>
              <el-table-column label="退货数量"
                               prop="returnQuality" />
                               prop="returnQuality"
                               width="100">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ scope.row.returnQuality }}</span>
                </template>
              </el-table-column>
              <el-table-column label="税率(%)"
                               prop="taxRate" />
                               prop="taxRate"
                               width="100">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ scope.row.taxRate }}</span>
                </template>
              </el-table-column>
              <el-table-column label="含税单价(元)"
                               prop="taxInclusiveUnitPrice"
                               :formatter="formattedNumber" />
                               :formatter="formattedNumber"
                               width="130">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="含税总价(元)"
                               prop="taxInclusiveTotalPrice"
                               :formatter="formattedNumber" />
                               :formatter="formattedNumber"
                               width="130">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveTotalPrice) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="不含税总价(元)"
                               prop="taxExclusiveTotalPrice"
                               :formatter="formattedNumber" />
                               :formatter="formattedNumber"
                               width="140">
                <template #default="scope">
                  <span v-if="scope.row.productType === 2">--</span>
                  <span v-else>{{ formattedNumber(null, null, scope.row.taxExclusiveTotalPrice) }}</span>
                </template>
              </el-table-column>
            </el-table>
          </template>
        </el-table-column>
@@ -210,8 +271,7 @@
          <template #default="scope">
            <el-button link
                       type="primary"
                       @click="openForm('edit', scope.row)"
                       :disabled="scope.row.stockInStatus === '完全入库'">编辑
                       @click="openForm('edit', scope.row)">编辑
            </el-button>
            <el-button link
                       type="primary"
@@ -400,40 +460,86 @@
                           label="序号"
                           type="index"
                           width="60" />
          <el-table-column label="类型"
                           prop="productType"
                           width="100">
            <template #default="scope">
              <el-tag :type="scope.row.productType === 2 ? 'warning' : 'success'" size="small">
                {{ scope.row.productType === 2 ? '设备备件' : '产品' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column label="产品大类"
                           prop="productCategory" />
          <el-table-column label="规格型号"
                           prop="specificationModel" />
                           prop="specificationModel"
                           width="120">
            <template #default="scope">
              <span v-if="scope.row.productType === 2">/</span>
              <span v-else>{{ scope.row.specificationModel || '--' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="单位"
                           prop="unit"
                           width="70" />
                           width="70">
            <template #default="scope">
              <span v-if="scope.row.productType === 2">--</span>
              <span v-else>{{ scope.row.unit || '--' }}</span>
            </template>
          </el-table-column>
          <el-table-column label="数量"
                           prop="quantity"
                           width="70" />
          <el-table-column label="库存预警数量"
                           prop="warnNum"
                           width="120"
                           show-overflow-tooltip />
                           show-overflow-tooltip>
            <template #default="scope">
              <span v-if="scope.row.productType === 2">--</span>
              <span v-else>{{ scope.row.warnNum }}</span>
            </template>
          </el-table-column>
          <el-table-column label="税率(%)"
                           prop="taxRate"
                           width="80" />
                           width="80">
            <template #default="scope">
              <span v-if="scope.row.productType === 2">--</span>
              <span v-else>{{ scope.row.taxRate }}</span>
            </template>
          </el-table-column>
          <el-table-column label="含税单价(元)"
                           prop="taxInclusiveUnitPrice"
                           :formatter="formattedNumber"
                           width="150" />
                           width="130">
            <template #default="scope">
              <span v-if="scope.row.productType === 2">--</span>
              <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="含税总价(元)"
                           prop="taxInclusiveTotalPrice"
                           :formatter="formattedNumber"
                           width="150" />
                           width="130">
            <template #default="scope">
              <span v-if="scope.row.productType === 2">--</span>
              <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveTotalPrice) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="不含税总价(元)"
                           prop="taxExclusiveTotalPrice"
                           :formatter="formattedNumber"
                           width="150" />
                           width="140">
            <template #default="scope">
              <span v-if="scope.row.productType === 2">--</span>
              <span v-else>{{ formattedNumber(null, null, scope.row.taxExclusiveTotalPrice) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="是否质检"
                           prop="isChecked"
                           width="150">
                           width="100">
            <template #default="scope">
              <el-tag :type="scope.row.isChecked ? 'success' : 'info'">
              <span v-if="scope.row.productType === 2">--</span>
              <el-tag v-else :type="scope.row.isChecked ? 'success' : 'info'">
                {{ scope.row.isChecked ? '是' : '否' }}
              </el-tag>
            </template>
@@ -530,9 +636,21 @@
               ref="productFormRef">
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="类型:"
                          prop="productType">
              <el-radio-group v-model="productForm.productType" @change="handleProductTypeChange">
                <el-radio :label="1">产品</el-radio>
                <el-radio :label="2">设备备件</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="产品大类:"
                          prop="productId">
              <el-tree-select v-model="productForm.productId"
              <el-tree-select v-if="productForm.productType !== 2"
                              v-model="productForm.productId"
                              placeholder="请选择"
                              clearable
                              filterable
@@ -541,10 +659,22 @@
                              :data="productOptions"
                              :render-after-expand="false"
                              style="width: 100%" />
              <el-select v-else
                         v-model="productForm.productId"
                         placeholder="请选择设备备件"
                         filterable
                         clearable
                         @change="handleSparePartsChange"
                         style="width: 100%">
                <el-option v-for="item in sparePartsOptions"
                           :key="item.id"
                           :label="item.name"
                           :value="item.id" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
        <el-row :gutter="30" v-if="productForm.productType !== 2">
          <el-col :span="24">
            <el-form-item label="规格型号:"
                          prop="productModelId">
@@ -561,7 +691,7 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
        <el-row :gutter="30" v-if="productForm.productType !== 2">
          <el-col :span="12">
            <el-form-item label="单位:"
                          prop="unit">
@@ -585,7 +715,7 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
        <el-row :gutter="30" v-if="productForm.productType !== 2">
          <el-col :span="12">
            <el-form-item label="含税单价(元):"
                          prop="taxInclusiveUnitPrice">
@@ -612,7 +742,21 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
        <el-row :gutter="30" v-if="productForm.productType === 2">
          <el-col :span="24">
            <el-form-item label="数量:"
                          prop="quantity">
              <el-input-number :step="0.1"
                               clearable
                               :precision="2"
                               :min="0"
                               style="width: 100%"
                               v-model="productForm.quantity"
                               placeholder="请输入" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30" v-if="productForm.productType !== 2">
          <el-col :span="12">
            <el-form-item label="含税总价(元):"
                          prop="taxInclusiveTotalPrice">
@@ -652,7 +796,7 @@
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
          <el-col :span="12" v-if="productForm.productType !== 2">
            <el-form-item label="库存预警数量:"
                          prop="warnNum">
              <el-input-number v-model="productForm.warnNum"
@@ -664,7 +808,7 @@
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
        <el-row :gutter="30" v-if="productForm.productType !== 2">
          <el-col :span="12">
            <el-form-item label="是否质检:"
                          prop="isChecked">
@@ -721,6 +865,7 @@
    getOptions,
    getPurchaseTemplateList,
    delPurchaseTemplate,
    batchGeneratePurchaseInboundSteps,
  } from "@/api/procurementManagement/procurementLedger.js";
  import useFormData from "@/hooks/useFormData.js";
  const FileList = defineAsyncComponent(() =>
@@ -736,6 +881,7 @@
  const modelOptions = ref([]);
  const userList = ref([]);
  const productOptions = ref([]);
  const sparePartsOptions = ref([]);
  const salesContractList = ref([]);
  const supplierList = ref([]);
  const tableLoading = ref(false);
@@ -749,6 +895,7 @@
  const fileList = ref([]);
  import useUserStore from "@/store/modules/user";
  import { modelList, productTreeList } from "@/api/basicData/product.js";
  import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js";
  import dayjs from "dayjs";
  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
@@ -776,9 +923,9 @@
  // 获取入库状态标签类型
  const getStockInStatusType = status => {
    const typeMap = {
      "待入库": "info", // 待入库 - 灰色
      "入库中": "warning", // 入库中 - 橙色
      "完全入库": "success", // 完全入库 - 绿色
      待入库: "info", // 待入库 - 灰色
      入库中: "warning", // 入库中 - 橙色
      完全入库: "success", // 完全入库 - 绿色
    };
    return typeMap[status] || "";
  };
@@ -786,9 +933,9 @@
  // 获取入库审核状态标签类型
  const getStockInApprovalStatusType = status => {
    const typeMap = {
      "待入库": "info", // 待入库 - 灰色
      "入库中": "warning", // 入库中 - 橙色
      "完全入库": "success", // 完全入库 - 绿色
      待入库: "info", // 待入库 - 灰色
      入库中: "warning", // 入库中 - 橙色
      完全入库: "success", // 完全入库 - 绿色
    };
    return typeMap[status] || "";
  };
@@ -923,7 +1070,7 @@
    },
    rules: {
      purchaseContractNumber: [
        { required: true, message: "请输入", trigger: "blur" },
        { required: false, message: "请输入", trigger: "blur" },
      ],
      projectName: [
        { required: true, message: "请输入项目名称", trigger: "blur" },
@@ -952,6 +1099,7 @@
  const currentId = ref("");
  const productFormData = reactive({
    productForm: {
      productType: 1,
      productId: "",
      productCategory: "",
      productModelId: "",
@@ -983,10 +1131,27 @@
        { required: true, message: "请输入", trigger: "blur" },
      ],
      invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
      isChecked: [{ required: true, message: "请选择", trigger: "change" }],
      // isChecked 默认传否,不需要验证
    },
  });
  const { productForm, productRules } = toRefs(productFormData);
  const { productForm } = toRefs(productFormData);
  // 动态计算验证规则
  const productRules = computed(() => {
    const isSpareParts = productForm.value.productType === 2;
    return {
      productId: [{ required: true, message: "请选择", trigger: "change" }],
      productModelId: isSpareParts ? [] : [{ required: true, message: "请选择", trigger: "change" }],
      unit: isSpareParts ? [] : [{ required: true, message: "请输入", trigger: "blur" }],
      quantity: [{ required: true, message: "请输入", trigger: "blur" }],
      taxInclusiveUnitPrice: isSpareParts ? [] : [{ required: true, message: "请输入", trigger: "blur" }],
      taxRate: isSpareParts ? [] : [{ required: true, message: "请选择", trigger: "change" }],
      warnNum: isSpareParts ? [] : [{ required: true, message: "请选择", trigger: "change" }],
      taxInclusiveTotalPrice: isSpareParts ? [] : [{ required: true, message: "请输入", trigger: "blur" }],
      taxExclusiveTotalPrice: isSpareParts ? [] : [{ required: true, message: "请输入", trigger: "blur" }],
      invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
    };
  });
  const upload = reactive({
    // 上传的地址
    url: import.meta.env.VITE_APP_BASE_API + "/file/upload",
@@ -1274,7 +1439,7 @@
  const openForm = async (type, row) => {
    // 编辑时检查入库状态,完全入库时不能编辑
    if (type === "edit" && row) {
      if (row.stockInStatus === '完全入库') {
      if (row.stockInStatus === "完全入库") {
        proxy.$modal.msgWarning("完全入库状态的记录不能编辑");
        return;
      }
@@ -1306,18 +1471,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 +1479,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 +1555,7 @@
  // 提交表单
  const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
    proxy.$refs["formRef"].validate(async valid => {
      if (valid) {
        if (productData.value.length > 0) {
          // 新增时,需要从每个产品对象中删除 id 字段
@@ -1428,6 +1585,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();
@@ -1444,7 +1615,7 @@
  // 打开产品弹框
  const openProductForm = async (type, row, index) => {
    // 编辑时检查产品入库审核状态,完全入库时不能编辑
    if (type === "edit" && row && row.stockInApprovalStatus === '完全入库') {
    if (type === "edit" && row && row.stockInApprovalStatus === "完全入库") {
      proxy.$modal.msgWarning("完全入库状态的产品不能编辑");
      return;
    }
@@ -1462,16 +1633,27 @@
    await nextTick();
    if (type === "add") {
      productForm.value.isChecked = false;
      productForm.value.isChecked = false; // 是否质检默认传否
      productForm.value.productType = "product";
    }
    if (type === "edit") {
      // 复制行数据
      productForm.value = { ...row };
      // 如果没有 productType,默认为 product (1)
      if (!productForm.value.productType) {
        productForm.value.productType = 1;
      }
      // 如果是设备备件类型,加载设备备件列表
      if (productForm.value.productType === 2) {
        await getSparePartsOptions();
      }
      // 如果是从模板加载的数据,可能没有 productId 和 productModelId
      // 需要根据 productCategory 和 specificationModel 来查找对应的 ID
      if (!productForm.value.productId && productForm.value.productCategory) {
      if (!productForm.value.productId && productForm.value.productCategory && productForm.value.productType !== 2) {
        // 根据 productCategory 查找 productId
        const findProductIdByCategory = (nodes, categoryName) => {
          for (let i = 0; i < nodes.length; i++) {
@@ -1539,6 +1721,45 @@
      return res;
    });
  };
  // 获取设备备件列表
  const getSparePartsOptions = () => {
    return getSparePartsList({ current: -1, size: -1 }).then(res => {
      if (res.data && Array.isArray(res.data.rows)) {
        sparePartsOptions.value = res.data.rows;
      } else if (res.data && Array.isArray(res.data.records)) {
        sparePartsOptions.value = res.data.records;
      } else {
        sparePartsOptions.value = [];
      }
      return res;
    });
  };
  // 处理类型变化
  const handleProductTypeChange = (type) => {
    productForm.value.productId = "";
    productForm.value.productCategory = "";
    productForm.value.productModelId = "";
    productForm.value.specificationModel = "";
    modelOptions.value = [];
    if (type === 2) {
      getSparePartsOptions();
    }
  };
  // 处理设备备件选择
  const handleSparePartsChange = (value) => {
    const selectedSparePart = sparePartsOptions.value.find(item => item.id === value);
    if (selectedSparePart) {
      productForm.value.productCategory = selectedSparePart.name;
      productForm.value.specificationModel = "/";
    } else {
      productForm.value.productCategory = "";
      productForm.value.specificationModel = "";
    }
  };
  const getModels = value => {
    if (value) {
      productForm.value.productCategory =
@@ -1595,6 +1816,19 @@
  // 提交产品表单
  const submitProduct = () => {
    // 如果是设备备件,先设置默认值,再验证
    if (productForm.value.productType === 2) {
      productForm.value.specificationModel = "/";
      productForm.value.productModelId = null;
      productForm.value.unit = "";
      productForm.value.taxRate = "";
      productForm.value.taxInclusiveUnitPrice = 0;
      productForm.value.taxInclusiveTotalPrice = 0;
      productForm.value.taxExclusiveTotalPrice = 0;
      productForm.value.warnNum = 0;
      productForm.value.isChecked = false; // 是否质检默认传否
    }
    proxy.$refs["productFormRef"].validate(valid => {
      if (valid) {
        if (operationType.value === "edit") {
@@ -1633,7 +1867,7 @@
    }
    // 检查选中的产品中是否有完全入库的
    const hasFullyStocked = productSelectedRows.value.some(
      row => row.stockInApprovalStatus === '完全入库'
      row => row.stockInApprovalStatus === "完全入库"
    );
    if (hasFullyStocked) {
      proxy.$modal.msgWarning("选中的产品中包含完全入库的产品,无法删除");
@@ -1709,6 +1943,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 +2117,7 @@
      contractNo: form.value.salesLedgerId,
    });
    if (code == 200) {
      productData.value = data;
      productData.value = data || [];
    }
  };