yuan
14 小时以前 5a96e6a94c982d413af29b9b2ee2a460bac121fd
src/views/procurementManagement/procurementLedger/index.vue
@@ -45,6 +45,7 @@
        <el-button @click="handleOut">导出</el-button>
        <el-button type="danger" plain @click="handleDelete">删除
        </el-button>
        <el-button type="warning" plain @click="handlePrint">打印单据</el-button>
      </div>
      <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange"
        :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable"
@@ -68,7 +69,7 @@
              <el-table-column label="可用数量" prop="availableQuality" />
              <el-table-column label="退货数量" prop="returnQuality" />
              <el-table-column label="税率(%)" prop="taxRate" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="unitPriceFormatter" />
              <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" />
              <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" />
              <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" />
            </el-table>
@@ -100,14 +101,14 @@
        <el-table-column label="录入人" prop="recorderName" width="120" show-overflow-tooltip />
        <el-table-column label="录入日期" prop="entryDate" width="100" show-overflow-tooltip />
        <el-table-column label="备注" prop="remarks" width="200" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" width="180" align="center">
        <el-table-column fixed="right" label="操作" width="220" align="center">
          <template #default="scope">
            <el-button link type="primary" @click="openForm('detail', scope.row)">详情
            </el-button>
            <el-button link type="primary" @click="openForm('edit', scope.row)"
              :disabled="scope.row.stockInStatus === '完全入库'">编辑
            </el-button>
            <el-button link type="primary" @click="openFileDialog(scope.row)">附件</el-button>
            <el-button link type="primary" @click="downloadOrder(scope.row.id)">下载</el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -161,7 +162,7 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="录入人:" prop="recorderId">
              <el-select v-model="form.recorderId" placeholder="请选择" clearable filterable>
              <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>
@@ -208,9 +209,9 @@
          <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="warnNum" width="120" show-overflow-tooltip />
<!--          <el-table-column label="库存预警数量" prop="warnNum" width="120" show-overflow-tooltip />-->
          <el-table-column label="税率(%)" prop="taxRate" width="80" />
          <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="unitPriceFormatter" width="150" />
          <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">
@@ -276,20 +277,22 @@
      @cancel="closeProductDia">
      <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" 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-col :span="12">
            <el-form-item label="产品大类:" prop="productCategory">
              <el-input v-model="productForm.productCategory"
                        placeholder="点击选择"
                        readonly
                        @click="showProductSelectDialog = true"
                        style="cursor:pointer" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="24">
          <el-col :span="12">
            <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>
              <el-input v-model="productForm.specificationModel"
                        placeholder="点击选择"
                        readonly
                        @click="showProductSelectDialog = true"
                        style="cursor:pointer" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -310,7 +313,7 @@
        <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.1" :min="0" clearable
              <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>
@@ -324,13 +327,13 @@
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice">
              <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" :min="0"
              <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="2" :step="0.1" :min="0"
              <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>
@@ -344,14 +347,12 @@
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="库存预警数量:" prop="warnNum">
              <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" :min="0" clearable
                style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
<!--          <el-col :span="12">-->
<!--            <el-form-item label="库存预警数量:" prop="warnNum">-->
<!--              <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" :min="0" clearable-->
<!--                style="width: 100%" />-->
<!--            </el-form-item>-->
<!--          </el-col>-->
          <el-col :span="12">
            <el-form-item label="是否质检:" prop="isChecked">
              <el-radio-group v-model="productForm.isChecked">
@@ -361,8 +362,21 @@
            </el-form-item>
          </el-col>
        </el-row>
<!--        <el-row :gutter="30">
          <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 />
    <FileList v-if="fileListDialogVisible" v-model:visible="fileListDialogVisible" record-type="purchase_ledger"
      :record-id="recordId" />
    <Detail ref="detailRef" />
@@ -403,6 +417,7 @@
  productList,
  getPurchaseById,
  getOptions,
  getPrintData,
  getPurchaseTemplateList,
  delPurchaseTemplate,
} from "@/api/procurementManagement/procurementLedger.js";
@@ -435,8 +450,11 @@
const fileList = ref([]);
import useUserStore from "@/store/modules/user";
import { modelList, productTreeList } from "@/api/basicData/product.js";
import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue";
import dayjs from "dayjs";
import FileUpload from "@/components/AttachmentUpload/file/index.vue";
import { tableAmountFormatter, formatDecimal, buildAmountSummaryFormat } from '@/utils/numberFormat';
import { downloadPurchaseJpg, printPurchaseMulti } from "@/utils/documentPrint.js";
const userStore = useUserStore();
@@ -632,17 +650,11 @@
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 productFormVisible = ref(false);
const showProductSelectDialog = ref(false);
const productOperationType = ref("");
const productOperationIndex = ref("");
const currentId = ref("");
@@ -663,15 +675,15 @@
    isChecked: false,
  },
  productRules: {
    productId: [{ required: true, message: "请选择", trigger: "change" }],
    productModelId: [{ required: true, message: "请选择", trigger: "change" }],
    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" }],
    warnNum: [{ required: true, message: "请选择", trigger: "change" }],
    // warnNum: [{ required: true, message: "请选择", trigger: "change" }],
    taxInclusiveTotalPrice: [
      { required: true, message: "请输入", trigger: "blur" },
    ],
@@ -770,12 +782,7 @@
  handleQuery();
};
const formattedNumber = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(2);
};
const unitPriceFormatter = (row, column, cellValue) => {
  return parseFloat(cellValue).toFixed(6);
};
const formattedNumber = tableAmountFormatter;
// 查询列表
/** 搜索按钮操作 */
const handleQuery = () => {
@@ -893,10 +900,19 @@
      "futureTickets",
      "futureTicketsAmount",
    ],
    {
      ticketsNum: { noDecimal: true }, // 不保留小数
      futureTickets: { noDecimal: true }, // 不保留小数
    }
    buildAmountSummaryFormat(
      [
        "taxInclusiveUnitPrice",
        "taxInclusiveTotalPrice",
        "taxExclusiveTotalPrice",
        "ticketsAmount",
        "futureTicketsAmount",
      ],
      {
        ticketsNum: { noDecimal: true },
        futureTickets: { noDecimal: true },
      }
    )
  );
};
const paginationChange = obj => {
@@ -959,15 +975,27 @@
};
// 主表合计方法
const summarizeMainTable = param => {
  return proxy.summarizeTable(param, ["contractAmount"]);
  return proxy.summarizeTable(
    param,
    ["contractAmount"],
    buildAmountSummaryFormat(["contractAmount"])
  );
};
// 子表合计方法
const summarizeProTable = param => {
  return proxy.summarizeTable(param, [
    "taxInclusiveUnitPrice",
    "taxInclusiveTotalPrice",
    "taxExclusiveTotalPrice",
  ]);
  return proxy.summarizeTable(
    param,
    [
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
    ],
    buildAmountSummaryFormat([
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
    ])
  );
};
// 打开弹框
const openForm = async (type, row) => {
@@ -1008,6 +1036,7 @@
    );
    form.value.entryDate = getCurrentDate();
    form.value.recorderId = userStore.id;
    if (type === "add") {
      // 新增时生成采购合同号
@@ -1235,6 +1264,19 @@
    await nextTick();
  }
};
// ProductSelectDialog 选中回调
const handleProductSelect = (products) => {
  if (!products || !products.length) return;
  const p = products[0];
  productForm.value.productId = p.productId;
  productForm.value.productCategory = p.productName || '';
  productForm.value.productModelId = p.id;
  productForm.value.specificationModel = p.model || '';
  productForm.value.unit = p.unit || '';
  showProductSelectDialog.value = false;
};
const getProductOptions = () => {
  return productTreeList().then(res => {
    productOptions.value = convertIdToValue(res);
@@ -1417,6 +1459,31 @@
    });
};
// 批量打印采购单 - 多选合并预览
const handlePrint = async () => {
  if (selectedRows.value.length === 0) {
    proxy.$modal.msgWarning("请选择要打印的数据");
    return;
  }
  proxy.$modal.loading("正在加载打印数据...");
  try {
    const orders = [];
    let companyName = '';
    for (const row of selectedRows.value) {
      const res = await getPrintData(row.id);
      const data = res.data || res;
      companyName = data.companyName || companyName;
      orders.push({ ledger: data.ledger, products: data.products });
    }
    printPurchaseMulti(companyName, orders);
  } catch (e) {
    console.error('打印失败:', e);
    proxy.$modal.msgError("打印失败");
  } finally {
    proxy.$modal.closeLoading();
  }
};
// 获取当前日期并格式化为 YYYY-MM-DD
function getCurrentDate() {
  const today = new Date();
@@ -1476,10 +1543,10 @@
  if (field === "taxInclusiveTotalPrice") {
    // 已知含税总价和数量,反算含税单价
    if (productForm.value.quantity) {
      productForm.value.taxInclusiveUnitPrice = (
      productForm.value.taxInclusiveUnitPrice = formatDecimal(
        Number(productForm.value.taxInclusiveTotalPrice) /
        Number(productForm.value.quantity)
      ).toFixed(6);
      );
      // 确保结果不为负数
      if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
        productForm.value.taxInclusiveUnitPrice = "0";
@@ -1497,30 +1564,30 @@
      }
    }
    // 反算不含税总价
    productForm.value.taxExclusiveTotalPrice = (
    productForm.value.taxExclusiveTotalPrice = formatDecimal(
      Number(productForm.value.taxInclusiveTotalPrice) /
      (1 + taxRate / 100)
    ).toFixed(2);
    );
    // 确保结果不为负数
    if (Number(productForm.value.taxExclusiveTotalPrice) < 0) {
      productForm.value.taxExclusiveTotalPrice = "0";
    }
  } else if (field === "taxExclusiveTotalPrice") {
    // 反算含税总价
    productForm.value.taxInclusiveTotalPrice = (
    productForm.value.taxInclusiveTotalPrice = formatDecimal(
      Number(productForm.value.taxExclusiveTotalPrice) *
      (1 + taxRate / 100)
    ).toFixed(2);
    );
    // 确保结果不为负数
    if (Number(productForm.value.taxInclusiveTotalPrice) < 0) {
      productForm.value.taxInclusiveTotalPrice = "0";
    }
    // 已知数量,反算含税单价
    if (productForm.value.quantity) {
      productForm.value.taxInclusiveUnitPrice = (
      productForm.value.taxInclusiveUnitPrice = formatDecimal(
        Number(productForm.value.taxInclusiveTotalPrice) /
        Number(productForm.value.quantity)
      ).toFixed(6);
      );
      // 确保结果不为负数
      if (Number(productForm.value.taxInclusiveUnitPrice) < 0) {
        productForm.value.taxInclusiveUnitPrice = "0";
@@ -1570,6 +1637,28 @@
  fileListDialogVisible.value = true;
};
// 下载采购单
const downloadOrder = async (id) => {
  try {
    const res = await getPrintData(id);
    const data = res.data || res;
    downloadPurchaseJpg(data.companyName, data.ledger, data.products, '采购单_' + (data.ledger.purchaseContractNumber || id) + '.jpg');
  } catch (e) {
    console.error('下载失败:', e);
  }
};
// 打印采购单
const printOrder = async (id) => {
  try {
    const res = await getPrintData(id);
    const data = res.data || res;
    printPurchase(data.companyName, data.ledger, data.products);
  } catch (e) {
    console.error('打印失败:', e);
  }
};
// 删除模板
const handleDeleteTemplate = async item => {
  if (!item.id) {