gongchunyi
2026-09-04 e57932740c39954cf0baa5d7eaa6c3eaeb313fb4
Merge branch 'dev_pro_河南鹤壁' of http://114.132.189.42:9002/r/product-inventory-management into dev_pro_河南鹤壁
已添加1个文件
已修改1个文件
896 ■■■■■ 文件已修改
src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/components/PurchaseLedgerAddDialog.vue 856 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue
@@ -6,12 +6,19 @@
               @close="handleClose">
      <div class="material-toolbar">
        <el-button type="primary"
                   plain
                   @click="handleAddPurchase">新增采购</el-button>
        <el-button type="primary"
                   @click="handleAddMaterialRow">新增</el-button>
      </div>
      <el-table v-loading="materialTableLoading"
                :data="materialTableData"
                border
                @selection-change="handleMaterialSelectionChange"
                row-key="tempId">
        <el-table-column align="center"
                         type="selection"
                         width="55" />
        <el-table-column label="工序名称"
                         min-width="100">
          <template #default="{ row }">
@@ -143,6 +150,8 @@
    <ProductSelectDialog v-model="materialProductDialogVisible"
                         @confirm="handleMaterialProductConfirm"
                         single />
    <PurchaseLedgerAddDialog ref="purchaseLedgerAddDialogRef"
                             v-model="purchaseLedgerDialogVisible" />
    <!-- request-url="/stockInventory/rawMaterials" -->
  </div>
</template>
@@ -151,6 +160,7 @@
  import { computed, ref, watch } from "vue";
  import { ElMessage } from "element-plus";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import PurchaseLedgerAddDialog from "./PurchaseLedgerAddDialog.vue";
  import { findProductProcessRouteItemList } from "@/api/productionManagement/productProcessRoute.js";
  import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory.js";
  import {
@@ -174,6 +184,9 @@
  const materialTableLoading = ref(false);
  const materialSaving = ref(false);
  const materialTableData = ref([]);
  const selectedMaterialRows = ref([]);
  const purchaseLedgerDialogVisible = ref(false);
  const purchaseLedgerAddDialogRef = ref(null);
  const isSaveDisabled = computed(() => {
    if (materialTableLoading.value) return true;
@@ -378,6 +391,7 @@
  const handleClose = () => {
    materialTableData.value = [];
    selectedMaterialRows.value = [];
    currentMaterialSelectRowIndex.value = -1;
  };
@@ -419,6 +433,32 @@
    materialTableData.value.push(createMaterialRow());
  };
  const handleMaterialSelectionChange = selection => {
    selectedMaterialRows.value = selection;
  };
  const handleAddPurchase = () => {
    if (selectedMaterialRows.value.length === 0) {
      ElMessage.warning("请选择需要新增采购的原料行");
      return;
    }
    const rowsWithModel = selectedMaterialRows.value.filter(
      row => row.materialModelId
    );
    if (rowsWithModel.length === 0) {
      ElMessage.warning("所选行缺少原料型号,请先选择原料后再新增采购");
      return;
    }
    const productRows = rowsWithModel.map(row => ({
      productModelId: row.materialModelId,
      productCategory: row.materialName,
      specificationModel: row.materialModel,
      unit: row.unit,
      isChecked: false,
    }));
    purchaseLedgerAddDialogRef.value?.open(productRows);
  };
  const handleDeleteMaterialRow = index => {
    materialTableData.value.splice(index, 1);
  };
src/views/productionManagement/productionOrder/components/PurchaseLedgerAddDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,856 @@
<template>
  <div>
    <FormDialog v-model="dialogVisible"
                title="新增采购台账页面"
                :width="'70%'"
                operation-type="add"
                @close="closeDia"
                @confirm="submitForm"
                @cancel="closeDia">
      <el-form :model="form"
               label-width="140px"
               label-position="top"
               :rules="rules"
               ref="formRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="采购合同号:" prop="purchaseContractNumber">
              <el-input v-model="form.purchaseContractNumber" placeholder="请输入" clearable />
            </el-form-item>
          </el-col>
          <el-col v-if="showSalesContractBinding" :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">
            <el-form-item label="供应商名称:" prop="supplierId">
              <el-select v-model="form.supplierId" placeholder="请选择" filterable clearable>
                <el-option v-for="item in supplierList"
                           :key="item.id"
                           :label="item.supplierName"
                           :value="item.id">
                  {{ item.supplierName }}
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="项目名称" prop="projectName">
              <el-input v-model="form.projectName" placeholder="请输入" clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="付款方式">
              <el-input v-model="form.paymentMethod" placeholder="请输入" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="签订日期:" prop="executionDate">
              <el-date-picker v-model="form.executionDate"
                              style="width: 100%"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              type="date"
                              placeholder="请选择"
                              clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="录入人:" prop="recorderId">
              <el-select v-model="form.recorderId"
                         placeholder="请选择"
                         clearable
                         filterable
                         disabled>
                <el-option v-for="item in userList"
                           :key="item.userId"
                           :label="item.nickName"
                           :value="item.userId" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="录入日期:" prop="entryDate">
              <el-date-picker v-model="form.entryDate"
                              style="width: 100%"
                              value-format="YYYY-MM-DD"
                              format="YYYY-MM-DD"
                              type="date"
                              placeholder="请选择"
                              clearable />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-form-item label="产品信息:">
            <el-button type="primary" @click="openProductForm('add')">添加</el-button>
            <el-button plain type="danger" @click="deleteProduct">删除</el-button>
          </el-form-item>
          <div class="select-button-group">
            <el-select v-model="templateName"
                       filterable
                       allow-create
                       :reserve-keyword="true"
                       :default-first-option="false"
                       clearable
                       :input-value="filterInputValue"
                       @filter-change="onTemplateFilterChange"
                       @change="onTemplateChange"
                       @focus="getTemplateList"
                       placeholder="请选择模版或者输入新的模版名称后选择"
                       class="no-arrow-select template-select">
              <el-option v-for="item in templateList"
                         :key="item.id || item.value"
                         :label="item.templateName"
                         :value="item.templateName">
                <div class="template-option">
                  <span>{{ item.templateName }}</span>
                  <el-icon v-if="item.id"
                           class="delete-icon"
                           @click.stop="handleDeleteTemplate(item)">
                    <Delete />
                  </el-icon>
                </div>
              </el-option>
            </el-select>
            <el-button size="small"
                       class="template-save-button"
                       :disabled="!templateName || templateName.trim() === '' || (!currentTemplateId && isTemplateNameDuplicate)"
                       @click="handleButtonClick">
              ä¿å­˜
            </el-button>
          </div>
        </el-row>
        <el-table :data="productData"
                  border
                  show-summary
                  :summary-method="summarizeProTable"
                  @selection-change="productSelected">
          <el-table-column align="center" type="selection" width="55" />
          <el-table-column align="center" label="序号" type="index" width="60" />
          <el-table-column label="产品大类" prop="productCategory" />
          <el-table-column label="规格型号" prop="specificationModel" />
          <el-table-column label="单位" prop="unit" width="70" />
          <el-table-column label="数量" prop="quantity" width="70" />
          <el-table-column label="税率(%)" prop="taxRate" width="80" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="150" />
          <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150" />
          <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" />
          <el-table-column label="是否质检" prop="isChecked" width="150">
            <template #default="{ row }">
              <el-tag :type="row.isChecked ? 'success' : 'info'">
                {{ row.isChecked ? '是' : '否' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column fixed="right" label="操作" min-width="60" align="center">
            <template #default="{ row, $index }">
              <el-button link type="primary" @click="openProductForm('edit', row, $index)">编辑</el-button>
            </template>
          </el-table-column>
        </el-table>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="备注·:" prop="remarks">
              <el-input v-model="form.remarks" placeholder="请输入" clearable type="textarea" :rows="2" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
            <el-form-item label="附件材料:" prop="purchaseLedgerFiles">
              <FileUpload v-model:file-list="fileList" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </FormDialog>
    <FormDialog v-model="productFormVisible"
                :title="productOperationType === 'add' ? '新增产品' : '编辑产品'"
                :width="'40%'"
                :operation-type="productOperationType"
                @close="closeProductDia"
                @confirm="submitProduct"
                @cancel="closeProductDia">
      <el-form :model="productForm"
               label-width="140px"
               label-position="top"
               :rules="productRules"
               ref="productFormRef">
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="产品大类:" prop="productCategory">
              <el-input v-model="productForm.productCategory"
                        placeholder="点击选择"
                        readonly
                        style="cursor:pointer"
                        @click="showProductSelectDialog = true" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="规格型号:" prop="productModelId">
              <el-input v-model="productForm.specificationModel"
                        placeholder="点击选择"
                        readonly
                        style="cursor:pointer"
                        @click="showProductSelectDialog = true" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="单位:" prop="unit">
              <el-input v-model="productForm.unit" placeholder="请输入" clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="税率(%):" prop="taxRate">
              <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="mathNum">
                <el-option v-for="dict in tax_rate"
                           :key="dict.value"
                           :label="dict.label"
                           :value="dict.value" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice">
              <el-input-number v-model="productForm.taxInclusiveUnitPrice"
                               :precision="6"
                               :step="0.000001"
                               :min="0"
                               clearable
                               style="width: 100%"
                               @change="mathNum" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数量:" prop="quantity">
              <el-input-number v-model="productForm.quantity"
                               :step="0.1"
                               clearable
                               :precision="2"
                               :min="0"
                               style="width: 100%"
                               placeholder="请输入"
                               @change="mathNum" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
              <el-input-number v-model="productForm.taxInclusiveTotalPrice"
                               :precision="6"
                               :step="0.000001"
                               :min="0"
                               clearable
                               style="width: 100%"
                               @change="reverseMathNum('taxInclusiveTotalPrice')" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice">
              <el-input-number v-model="productForm.taxExclusiveTotalPrice"
                               :precision="6"
                               :step="0.000001"
                               :min="0"
                               clearable
                               style="width: 100%"
                               @change="reverseMathNum('taxExclusiveTotalPrice')" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="发票类型:" prop="invoiceType">
              <el-select v-model="productForm.invoiceType" placeholder="请选择" clearable>
                <el-option label="增普票" value="增普票" />
                <el-option label="增专票" value="增专票" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="是否质检:" prop="isChecked">
              <el-radio-group v-model="productForm.isChecked">
                <el-radio label="是" :value="true" />
                <el-radio label="否" :value="false" />
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </FormDialog>
    <ProductSelectDialog v-model="showProductSelectDialog"
                         @confirm="handleProductSelect"
                         single />
  </div>
</template>
<script setup>
  import { computed, getCurrentInstance, nextTick, reactive, ref, toRefs } from "vue";
  import { Delete } from "@element-plus/icons-vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import FormDialog from "@/components/Dialog/FormDialog.vue";
  import FileUpload from "@/components/AttachmentUpload/file/index.vue";
  import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
  import useUserStore from "@/store/modules/user";
  import { userListNoPage } from "@/api/system/user.js";
  import { getProductInfoByContractNo } from "@/api/salesManagement/salesLedger.js";
  import {
    addOrEditPurchase,
    addPurchaseTemplate,
    createPurchaseNo,
    delPurchaseTemplate,
    getOptions,
    getPurchaseTemplateList,
    getSalesNo,
    updatePurchaseTemplate,
  } from "@/api/procurementManagement/procurementLedger.js";
  import { tableAmountFormatter, formatDecimal, buildAmountSummaryFormat } from "@/utils/numberFormat";
  const props = defineProps({
    modelValue: { type: Boolean, default: false },
    initialProducts: { type: Array, default: () => [] },
  });
  const emit = defineEmits(["update:modelValue", "saved"]);
  const dialogVisible = computed({
    get: () => props.modelValue,
    set: val => emit("update:modelValue", val),
  });
  const { proxy } = getCurrentInstance();
  const { tax_rate } = proxy.useDict("tax_rate");
  const userStore = useUserStore();
  const showSalesContractBinding = false;
  const productData = ref([]);
  const productSelectedRows = ref([]);
  const userList = ref([]);
  const salesContractList = ref([]);
  const supplierList = ref([]);
  const fileList = ref([]);
  const productFormVisible = ref(false);
  const showProductSelectDialog = ref(false);
  const productOperationType = ref("");
  const productOperationIndex = ref(-1);
  const templateName = ref("");
  const filterInputValue = ref("");
  const templateList = ref([]);
  const isTemplateNameDuplicate = ref(false);
  const currentTemplateId = ref(null);
  let duplicateCheckTimer = null;
  const data = reactive({
    form: {
      purchaseContractNumber: "",
      salesLedgerId: "",
      projectName: "",
      recorderId: "",
      entryDate: "",
      productData: [],
      supplierName: "",
      supplierId: "",
      paymentMethod: "",
      executionDate: "",
      isChecked: false,
    },
    rules: {
      purchaseContractNumber: [{ required: true, message: "请输入", trigger: "blur" }],
      projectName: [{ required: true, message: "请输入项目名称", trigger: "blur" }],
      supplierId: [{ required: true, message: "请输入", trigger: "blur" }],
      entryDate: [{ required: true, message: "请选择", trigger: "change" }],
      executionDate: [{ required: true, message: "请选择", trigger: "change" }],
    },
  });
  const { form, rules } = toRefs(data);
  const productFormData = reactive({
    productForm: {
      productId: "",
      productCategory: "",
      productModelId: "",
      specificationModel: "",
      unit: "",
      quantity: "",
      taxInclusiveUnitPrice: "",
      taxRate: "",
      taxInclusiveTotalPrice: "",
      taxExclusiveTotalPrice: "",
      invoiceType: "",
      warnNum: "",
      isChecked: false,
    },
    productRules: {
      productCategory: [{ required: true, message: "请选择产品大类", trigger: "change" }],
      productModelId: [{ required: true, message: "请选择规格型号", trigger: "change" }],
      unit: [{ required: true, message: "请输入", trigger: "blur" }],
      quantity: [{ required: true, message: "请输入", trigger: "blur" }],
      taxInclusiveUnitPrice: [{ required: true, message: "请输入", trigger: "blur" }],
      taxRate: [{ required: true, message: "请选择", trigger: "change" }],
      taxInclusiveTotalPrice: [{ required: true, message: "请输入", trigger: "blur" }],
      taxExclusiveTotalPrice: [{ required: true, message: "请输入", trigger: "blur" }],
      invoiceType: [{ required: true, message: "请选择", trigger: "change" }],
      isChecked: [{ required: true, message: "请选择", trigger: "change" }],
    },
  });
  const { productForm, productRules } = toRefs(productFormData);
  const formattedNumber = tableAmountFormatter;
  const getCurrentDate = () => {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    const day = String(today.getDate()).padStart(2, "0");
    return `${year}-${month}-${day}`;
  };
  const normalizeProductRow = row => ({
    productId: row.productId || "",
    productCategory: row.productCategory || row.materialName || row.productName || "",
    productModelId: row.productModelId || row.materialModelId || row.modelId || "",
    specificationModel: row.specificationModel || row.materialModel || row.model || "",
    unit: row.unit || "",
    quantity: row.quantity || "",
    taxInclusiveUnitPrice: row.taxInclusiveUnitPrice || "",
    taxRate: row.taxRate || "",
    taxInclusiveTotalPrice: row.taxInclusiveTotalPrice || "",
    taxExclusiveTotalPrice: row.taxExclusiveTotalPrice || "",
    invoiceType: row.invoiceType || "",
    warnNum: row.warnNum || "",
    isChecked: row.isChecked ?? false,
  });
  const resetDialogState = () => {
    form.value = {
      purchaseContractNumber: "",
      salesLedgerId: "",
      projectName: "",
      recorderId: "",
      entryDate: "",
      productData: [],
      supplierName: "",
      supplierId: "",
      paymentMethod: "",
      executionDate: "",
      isChecked: false,
    };
    productData.value = [];
    productSelectedRows.value = [];
    fileList.value = [];
    templateName.value = "";
    filterInputValue.value = "";
    isTemplateNameDuplicate.value = false;
    currentTemplateId.value = null;
  };
  const open = async products => {
    resetDialogState();
    await Promise.all([
      getTemplateList(),
      userListNoPage().then(res => {
        userList.value = res.data || [];
      }),
      getSalesNo().then(res => {
        salesContractList.value = res || [];
      }),
      getOptions().then(res => {
        supplierList.value = (res.data || []).filter(item => item.isWhite === 0);
      }),
    ]);
    form.value.entryDate = getCurrentDate();
    form.value.recorderId = userStore.id;
    try {
      const purchaseNoRes = await createPurchaseNo();
      if (purchaseNoRes?.data) {
        form.value.purchaseContractNumber = purchaseNoRes.data;
      }
    } catch (error) {
      console.error("生成采购合同号失败:", error);
      proxy.$modal.msgWarning("生成采购合同号失败");
    }
    const sourceProducts = Array.isArray(products) ? products : props.initialProducts;
    productData.value = sourceProducts.map(normalizeProductRow);
    dialogVisible.value = true;
    await nextTick();
    if (productData.value.length > 0) {
      ElMessage.warning("已按所选领料行生成产品信息,请编辑补全数量、税率、单价、发票类型等必填项后再提交采购台账");
    }
  };
  defineExpose({ open });
  const checkTemplateNameDuplicate = name => {
    if (!name || name.trim() === "") {
      isTemplateNameDuplicate.value = false;
      return false;
    }
    const isDuplicate = templateList.value.some(item => item.templateName === name.trim());
    isTemplateNameDuplicate.value = isDuplicate;
    return isDuplicate;
  };
  const onTemplateFilterChange = val => {
    filterInputValue.value = val ?? "";
    if (duplicateCheckTimer) {
      clearTimeout(duplicateCheckTimer);
    }
    if (val && val.trim()) {
      duplicateCheckTimer = setTimeout(() => {
        if (checkTemplateNameDuplicate(val)) {
          ElMessage.warning("模板名称已存在,请更换模板名称");
        }
      }, 300);
    } else {
      isTemplateNameDuplicate.value = false;
    }
  };
  const onTemplateChange = async val => {
    if (typeof val === "string") {
      filterInputValue.value = val;
      checkTemplateNameDuplicate(val);
    }
    const matchedTemplate = templateList.value.find(item => item.templateName === val);
    if (matchedTemplate?.id) {
      currentTemplateId.value = matchedTemplate.id;
      isTemplateNameDuplicate.value = false;
      form.value.supplierId = matchedTemplate.supplierId || form.value.supplierId;
      form.value.supplierName = matchedTemplate.supplierName || form.value.supplierName;
      form.value.projectName = matchedTemplate.projectName || form.value.projectName;
      form.value.paymentMethod = matchedTemplate.paymentMethod || form.value.paymentMethod;
      productData.value = matchedTemplate.productList || matchedTemplate.productData || [];
    } else {
      currentTemplateId.value = null;
    }
  };
  const getTemplateList = async () => {
    const res = await getPurchaseTemplateList();
    if (res && res.code === 200 && Array.isArray(res.data)) {
      templateList.value = res.data;
    }
  };
  const handleButtonClick = async () => {
    if (!templateName.value || templateName.value.trim() === "") {
      ElMessage.warning("请输入模板名称");
      return;
    }
    if (!currentTemplateId.value && checkTemplateNameDuplicate(templateName.value)) {
      ElMessage.warning("模板名称已存在,请更换模板名称");
      return;
    }
    if (!form.value.supplierId) {
      ElMessage.warning("请先选择供应商");
      return;
    }
    if (!productData.value || productData.value.length === 0) {
      ElMessage.warning("请先添加产品信息");
      return;
    }
    const params = {
      productData: proxy.HaveJson(productData.value),
      supplierId: form.value.supplierId,
      paymentMethod: form.value.paymentMethod,
      recorderId: form.value.recorderId,
      projectName: form.value.projectName,
      templateName: templateName.value.trim(),
    };
    const res = currentTemplateId.value
      ? await updatePurchaseTemplate({ id: currentTemplateId.value, ...params })
      : await addPurchaseTemplate(params);
    if (res && res.code === 200) {
      ElMessage.success(currentTemplateId.value ? "模板更新成功" : "模板保存成功");
      await getTemplateList();
      templateName.value = "";
      filterInputValue.value = "";
      isTemplateNameDuplicate.value = false;
      currentTemplateId.value = null;
    } else {
      ElMessage.error(res?.msg || "模板保存失败");
    }
  };
  const productSelected = selectedRows => {
    productSelectedRows.value = selectedRows;
  };
  const openProductForm = (type, row, index) => {
    productOperationType.value = type;
    productOperationIndex.value = index ?? -1;
    proxy.resetForm("productFormRef");
    productForm.value = type === "edit" ? { ...row } : { isChecked: false };
    productFormVisible.value = true;
  };
  const handleProductSelect = products => {
    if (!products || !products.length) return;
    const p = products[0];
    productForm.value.productId = p.productId || "";
    productForm.value.productCategory = p.productName || p.topProductName || "";
    productForm.value.productModelId = p.id;
    productForm.value.specificationModel = p.model || "";
    productForm.value.unit = p.unit || "";
    showProductSelectDialog.value = false;
  };
  const closeProductDia = () => {
    proxy.resetForm("productFormRef");
    productFormVisible.value = false;
  };
  const submitProduct = () => {
    proxy.$refs["productFormRef"].validate(valid => {
      if (!valid) return;
      if (productOperationType.value === "add") {
        productData.value.push({ ...productForm.value });
      } else if (productOperationIndex.value > -1) {
        productData.value[productOperationIndex.value] = { ...productForm.value };
      }
      closeProductDia();
    });
  };
  const deleteProduct = () => {
    if (productSelectedRows.value.length === 0) {
      proxy.$modal.msgWarning("请选择数据");
      return;
    }
    productData.value = productData.value.filter(item => !productSelectedRows.value.includes(item));
    productSelectedRows.value = [];
  };
  const summarizeProTable = param => proxy.summarizeTable(
    param,
    ["taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice"],
    buildAmountSummaryFormat(["taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice"])
  );
  const mathNum = () => {
    if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
    }
    if (!productForm.value.taxInclusiveUnitPrice || !productForm.value.quantity) return;
    productForm.value.taxInclusiveTotalPrice = proxy.calculateTaxIncludeTotalPrice(
      productForm.value.taxInclusiveUnitPrice,
      productForm.value.quantity
    );
    productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(
      productForm.value.taxInclusiveTotalPrice,
      productForm.value.taxRate
    );
  };
  const reverseMathNum = field => {
    if (!productForm.value.taxRate) {
      proxy.$modal.msgWarning("请先选择税率");
      return;
    }
    const taxRate = Number(productForm.value.taxRate);
    if (!taxRate) return;
    if (field === "taxInclusiveTotalPrice") {
      if (productForm.value.quantity) {
        productForm.value.taxInclusiveUnitPrice = formatDecimal(
          Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)
        );
      } else if (productForm.value.taxInclusiveUnitPrice) {
        productForm.value.quantity = (
          Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)
        ).toFixed(2);
      }
      productForm.value.taxExclusiveTotalPrice = formatDecimal(
        Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100)
      );
    } else if (field === "taxExclusiveTotalPrice") {
      productForm.value.taxInclusiveTotalPrice = formatDecimal(
        Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100)
      );
      if (productForm.value.quantity) {
        productForm.value.taxInclusiveUnitPrice = formatDecimal(
          Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)
        );
      } else if (productForm.value.taxInclusiveUnitPrice) {
        productForm.value.quantity = (
          Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)
        ).toFixed(2);
      }
    }
  };
  const salesLedgerChange = async () => {
    await querygProductInfoByContractNo();
  };
  const querygProductInfoByContractNo = async () => {
    const { code, data } = await getProductInfoByContractNo({
      contractNo: form.value.salesLedgerId,
    });
    if (code === 200) {
      productData.value = data;
    }
  };
  const validateProductRows = () => {
    if (productData.value.length === 0) {
      return "请添加产品信息";
    }
    const requiredFields = [
      ["productCategory", "产品大类"],
      ["productModelId", "规格型号"],
      ["unit", "单位"],
      ["quantity", "数量"],
      ["taxRate", "税率"],
      ["taxInclusiveUnitPrice", "含税单价"],
      ["taxInclusiveTotalPrice", "含税总价"],
      ["taxExclusiveTotalPrice", "不含税总价"],
      ["invoiceType", "发票类型"],
    ];
    for (let i = 0; i < productData.value.length; i++) {
      const row = productData.value[i];
      const missing = requiredFields.find(([field]) => row[field] === "" || row[field] === null || row[field] === undefined);
      if (missing) {
        return `第${i + 1}行产品信息缺少${missing[1]},请编辑完再提交`;
      }
    }
    return "";
  };
  const submitForm = () => {
    proxy.$refs["formRef"].validate(valid => {
      if (!valid) return;
      const productMessage = validateProductRows();
      if (productMessage) {
        proxy.$modal.msgWarning(productMessage);
        return;
      }
      const processedProductData = productData.value.map(product => {
        const { id, ...rest } = product;
        return rest;
      });
      const submitData = {
        ...form.value,
        productData: proxy.HaveJson(processedProductData),
        storageBlobDTOS: fileList.value,
        type: 2,
      };
      if (!submitData.salesLedgerId) {
        submitData.salesContractNo = "";
      }
      delete submitData.id;
      addOrEditPurchase(submitData).then(() => {
        proxy.$modal.msgSuccess("提交成功");
        closeDia();
        emit("saved");
      });
    });
  };
  const closeDia = () => {
    proxy.resetForm("formRef");
    dialogVisible.value = false;
  };
  const handleDeleteTemplate = async item => {
    if (!item.id) {
      proxy.$modal.msgWarning("无法删除该模板");
      return;
    }
    try {
      await ElMessageBox.confirm(`确定要删除模板"${item.templateName}"吗?`, "删除确认", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      });
      const res = await delPurchaseTemplate([item.id]);
      if (res && res.code === 200) {
        ElMessage.success("删除成功");
        if (templateName.value === item.templateName) {
          templateName.value = "";
          filterInputValue.value = "";
        }
        await getTemplateList();
      } else {
        ElMessage.error(res?.msg || "删除失败");
      }
    } catch (error) {
      if (error !== "cancel") {
        ElMessage.error("删除失败,请稍后重试");
      }
    }
  };
</script>
<style scoped lang="scss">
  .el-row {
    justify-content: space-between;
    align-items: center;
  }
  .select-button-group {
    display: flex;
    align-items: center;
    width: 500px;
    margin: 20px 0;
  }
  .template-select {
    width: 500px;
  }
  .template-save-button {
    height: 32px;
    margin-left: 8px;
  }
  .template-option {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .no-arrow-select {
    --el-select-suffix-icon-color: transparent;
  }
  .delete-icon {
    cursor: pointer;
    color: #f56c6c;
    font-size: 14px;
    margin-left: 8px;
    transition: all 0.3s;
    &:hover {
      color: #f56c6c !important;
      transform: scale(1.2);
    }
  }
</style>