zhangwencui
2026-06-08 9d2f568a86ab9ab212965de5c18681cc2bd21bb7
feat(采购管理,审批管理): 新增采购运费功能并完善审批详情展示

- 采购台账页面:新增运费单价、总运费表格列与搜索编辑字段,实现总运费自动计算,优化数字格式化函数处理空值与非法数值避免报错,完善表单字段绑定与初始化,调整数量变更回调触发运费计算
- 审批详情页面:补充采购、报价审批的运费字段展示,新增采购审批的车牌号与运输单位信息展示,优化模板代码排版格式
已修改3个文件
5503 ■■■■ 文件已修改
src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue 110 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 5278 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/officeProcessAutomation/ApproveManage/approve-list/components/ApproveDetailPanel.vue
@@ -40,12 +40,13 @@
                         :fields="formResolved.fields"
                         :form-payload="formResolved.formPayload"
                         readonly />
      <!-- å‘货审批详情 -->
      <template v-else-if="row.businessType === 7">
        <div v-if="detailData.shippingInfo" class="shipment-detail">
        <div v-if="detailData.shippingInfo"
             class="shipment-detail">
          <el-divider content-position="left">发货详情</el-divider>
          <el-descriptions :column="2" border>
          <el-descriptions :column="2"
                           border>
            <el-descriptions-item label="销售订单">{{ detailData.shippingInfo.salesContractNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货订单号">{{ detailData.shippingInfo.shippingNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{ detailData.shippingInfo.customerName || "--" }}</el-descriptions-item>
@@ -54,28 +55,43 @@
            <el-descriptions-item label="审核状态">{{ detailData.shippingInfo.status || "--" }}</el-descriptions-item>
            <el-descriptions-item label="发货车牌号">{{ detailData.shippingInfo.shippingCarNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递公司">{{ detailData.shippingInfo.expressCompany || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递单号" :span="2">{{ detailData.shippingInfo.expressNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="快递单号"
                                  :span="2">{{ detailData.shippingInfo.expressNumber || "--" }}</el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.shippingProductDetailDtoList.length" style="margin-top: 20px;">
          <div v-if="detailData.shippingProductDetailDtoList.length"
               style="margin-top: 20px;">
            <h4>产品明细</h4>
            <el-table :data="detailData.shippingProductDetailDtoList"
                      border
                      size="small"
                      style="width: 100%">
              <el-table-column label="批号" prop="batchNo" min-width="160" show-overflow-tooltip />
              <el-table-column label="产品名称" prop="productName" min-width="160" show-overflow-tooltip />
              <el-table-column label="规格型号" prop="specificationModel" min-width="160" show-overflow-tooltip />
              <el-table-column label="发货数量" prop="deliveryQuantity" min-width="120" align="center" />
              <el-table-column label="批号"
                               prop="batchNo"
                               min-width="160"
                               show-overflow-tooltip />
              <el-table-column label="产品名称"
                               prop="productName"
                               min-width="160"
                               show-overflow-tooltip />
              <el-table-column label="规格型号"
                               prop="specificationModel"
                               min-width="160"
                               show-overflow-tooltip />
              <el-table-column label="发货数量"
                               prop="deliveryQuantity"
                               min-width="120"
                               align="center" />
            </el-table>
          </div>
        </div>
      </template>
      <!-- é‡‡è´­å®¡æ‰¹è¯¦æƒ… -->
      <template v-else-if="row.businessType === 5">
        <div v-if="detailData" class="procurement-detail">
        <div v-if="detailData"
             class="procurement-detail">
          <el-divider content-position="left">采购详情</el-divider>
          <el-descriptions :column="2" border>
          <el-descriptions :column="2"
                           border>
            <el-descriptions-item label="采购合同号">{{ detailData.purchaseContractNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="供应商名称">{{ detailData.supplierName || "--" }}</el-descriptions-item>
            <el-descriptions-item label="项目名称">{{ detailData.projectName || "--" }}</el-descriptions-item>
@@ -83,63 +99,98 @@
            <el-descriptions-item label="签订日期">{{ detailData.executionDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="录入日期">{{ detailData.entryDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
            <el-descriptions-item label="车牌号">{{ detailData.carPlateNumber || "--" }}</el-descriptions-item>
            <el-descriptions-item label="运输单位/个人">{{ detailData.transportUnitOrPerson || "--" }}</el-descriptions-item>
            <el-descriptions-item label="合同金额" :span="2">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                Â¥{{ Number(detailData.contractAmount ?? 0).toFixed(2) }}
              </span>
            </el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.productData.length" style="margin-top: 20px;">
          <div v-if="detailData.productData.length"
               style="margin-top: 20px;">
            <h4>产品明细</h4>
            <el-table :data="detailData.productData"
                      border
                      style="width: 100%">
              <el-table-column prop="productCategory" label="产品名称" />
              <el-table-column prop="specificationModel" label="规格型号" />
              <el-table-column prop="unit" label="单位" />
              <el-table-column prop="quantity" label="数量" />
              <el-table-column prop="taxInclusiveUnitPrice" label="含税单价">
              <el-table-column prop="productCategory"
                               label="产品名称" />
              <el-table-column prop="specificationModel"
                               label="规格型号" />
              <el-table-column prop="unit"
                               label="单位" />
              <el-table-column prop="quantity"
                               label="数量" />
              <el-table-column prop="freightUnitPrice"
                               label="运费单价">
                <template #default="scope">Â¥{{ Number(scope.row.freightUnitPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
              <el-table-column prop="totalFreight"
                               label="运费总价">
                <template #default="scope">Â¥{{ Number(scope.row.totalFreight ?? 0).toFixed(2) }}</template>
              </el-table-column>
              <el-table-column prop="taxInclusiveUnitPrice"
                               label="含税单价">
                <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
              <el-table-column prop="taxInclusiveTotalPrice" label="含税总价">
              <el-table-column prop="taxInclusiveTotalPrice"
                               label="含税总价">
                <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
            </el-table>
          </div>
        </div>
      </template>
      <!-- æŠ¥ä»·å®¡æ‰¹è¯¦æƒ… -->
      <template v-else-if="row.businessType === 6">
        <div v-if="detailData" class="quotation-detail">
        <div v-if="detailData"
             class="quotation-detail">
          <el-divider content-position="left">报价详情</el-divider>
          <el-descriptions :column="2" border>
          <el-descriptions :column="2"
                           border>
            <el-descriptions-item label="报价单号">{{ detailData.quotationNo || "--" }}</el-descriptions-item>
            <el-descriptions-item label="客户名称">{{ detailData.customer || "--" }}</el-descriptions-item>
            <el-descriptions-item label="业务员">{{ detailData.salesperson || "--" }}</el-descriptions-item>
            <el-descriptions-item label="报价日期">{{ detailData.quotationDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="有效期至">{{ detailData.validDate || "--" }}</el-descriptions-item>
            <el-descriptions-item label="付款方式">{{ detailData.paymentMethod || "--" }}</el-descriptions-item>
            <el-descriptions-item label="报价总额" :span="2">
            <el-descriptions-item label="报价总额"
                                  :span="2">
              <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">
                Â¥{{ Number(detailData.totalAmount ?? 0).toFixed(2) }}
              </span>
            </el-descriptions-item>
          </el-descriptions>
          <div v-if="detailData.products.length" style="margin-top: 20px;">
          <div v-if="detailData.products.length"
               style="margin-top: 20px;">
            <h4>产品明细</h4>
            <el-table :data="detailData.products"
                      border
                      style="width: 100%">
              <el-table-column prop="product" label="产品名称" />
              <el-table-column prop="specification" label="规格型号" />
              <el-table-column prop="unit" label="单位" />
              <el-table-column prop="unitPrice" label="单价">
              <el-table-column prop="product"
                               label="产品名称" />
              <el-table-column prop="specification"
                               label="规格型号" />
              <el-table-column prop="unit"
                               label="单位" />
              <el-table-column prop="quantity"
                               label="数量" />
              <el-table-column prop="freightUnitPrice"
                               label="运费单价">
                <template #default="scope">Â¥{{ Number(scope.row.freightUnitPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
              <el-table-column prop="totalFreight"
                               label="运费总价">
                <template #default="scope">Â¥{{ Number(scope.row.totalFreight ?? 0).toFixed(2) }}</template>
              </el-table-column>
              <el-table-column prop="unitPrice"
                               label="单价">
                <template #default="scope">Â¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template>
              </el-table-column>
            </el-table>
          </div>
          <div v-if="detailData.remark" style="margin-top: 20px;">
          <div v-if="detailData.remark"
               style="margin-top: 20px;">
            <h4>备注</h4>
            <p>{{ detailData.remark }}</p>
          </div>
@@ -197,7 +248,6 @@
  });
  const formResolved = computed(() => resolveInstanceFormFields(props.row));
  // æ˜¯å¦ä¸ºç‰¹æ®Šå®¡æ‰¹ç±»åž‹ï¼ˆé‡‡è´­ã€å‘货、报价)
  const isSpecialApprovalType = computed(() => {
src/views/procurementManagement/procurementLedger/index.vue
@@ -125,6 +125,12 @@
                               prop="availableQuality" />
              <el-table-column label="退货数量"
                               prop="returnQuality" />
              <el-table-column label="运费单价(元)"
                               prop="freightUnitPrice"
                               :formatter="formattedNumber" />
              <el-table-column label="总运费(元)"
                               prop="totalFreight"
                               :formatter="formattedNumber" />
              <el-table-column label="税率(%)"
                               prop="taxRate" />
              <el-table-column label="含税单价(元)"
@@ -188,6 +194,14 @@
        <el-table-column label="付款方式"
                         width="100"
                         prop="paymentMethod"
                         show-overflow-tooltip />
        <el-table-column label="车牌号"
                         prop="carPlateNumber"
                         width="140"
                         show-overflow-tooltip />
        <el-table-column label="运输单位/个人"
                         prop="transportUnitOrPerson"
                         width="180"
                         show-overflow-tooltip />
        <el-table-column label="合同金额(元)"
                         prop="contractAmount"
@@ -319,6 +333,24 @@
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="车牌号:"
                          prop="carPlateNumber">
              <el-input v-model="form.carPlateNumber"
                        placeholder="请输入"
                        clearable />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="运输单位/个人:"
                          prop="transportUnitOrPerson">
              <el-input v-model="form.transportUnitOrPerson"
                        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"
@@ -418,6 +450,14 @@
          <el-table-column label="数量"
                           prop="quantity"
                           width="70" />
          <el-table-column label="运费单价(元)"
                           prop="freightUnitPrice"
                           :formatter="formattedNumber"
                           width="150" />
          <el-table-column label="总运费(元)"
                           prop="totalFreight"
                           :formatter="formattedNumber"
                           width="150" />
          <el-table-column label="库存预警数量"
                           prop="warnNum"
                           width="120"
@@ -616,7 +656,32 @@
                               style="width: 100%"
                               v-model="productForm.quantity"
                               placeholder="请输入"
                               @change="mathNum" />
                               @change="handleQuantityChange" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="30">
          <el-col :span="12">
            <el-form-item label="运费单价(元):"
                          prop="freightUnitPrice">
              <el-input-number v-model="productForm.freightUnitPrice"
                               :precision="2"
                               :step="0.1"
                               :min="0"
                               clearable
                               style="width: 100%"
                               @change="handleFreightUnitPriceChange" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="总运费(元):"
                          prop="totalFreight">
              <el-input-number v-model="productForm.totalFreight"
                               :precision="2"
                               :step="0.1"
                               :min="0"
                               clearable
                               style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>
@@ -1013,6 +1078,8 @@
      supplierName: "",
      supplierId: "",
      paymentMethod: "",
      carPlateNumber: "",
      transportUnitOrPerson: "",
      executionDate: "",
      isChecked: false,
    },
@@ -1053,6 +1120,8 @@
      specificationModel: "",
      unit: "",
      quantity: "",
      freightUnitPrice: "",
      totalFreight: "",
      taxInclusiveUnitPrice: "",
      taxRate: "",
      taxInclusiveTotalPrice: "",
@@ -1170,7 +1239,12 @@
  };
  const formattedNumber = (row, column, cellValue) => {
    return parseFloat(cellValue).toFixed(2);
    if (cellValue === undefined || cellValue === null || cellValue === "") {
      return "0.00";
    }
    const num = Number(cellValue);
    if (Number.isNaN(num)) return "0.00";
    return num.toFixed(2);
  };
  // æŸ¥è¯¢åˆ—表
  /** æœç´¢æŒ‰é’®æ“ä½œ */
@@ -1281,6 +1355,8 @@
    return proxy.summarizeTable(
      param,
      [
        "freightUnitPrice",
        "totalFreight",
        "taxInclusiveUnitPrice",
        "taxInclusiveTotalPrice",
        "taxExclusiveTotalPrice",
@@ -1463,6 +1539,7 @@
      "taxInclusiveUnitPrice",
      "taxInclusiveTotalPrice",
      "taxExclusiveTotalPrice",
      "totalFreight",
    ]);
  };
  // æ‰“开弹框
@@ -1669,6 +1746,12 @@
    if (type === "edit") {
      // å¤åˆ¶è¡Œæ•°æ®
      productForm.value = { ...row };
      if (productForm.value.freightUnitPrice === undefined) {
        productForm.value.freightUnitPrice = "";
      }
      if (productForm.value.totalFreight === undefined) {
        productForm.value.totalFreight = "";
      }
      // å¦‚果是从模板加载的数据,可能没有 productId å’Œ productModelId
      // éœ€è¦æ ¹æ® productCategory å’Œ specificationModel æ¥æŸ¥æ‰¾å¯¹åº”çš„ ID
@@ -1733,6 +1816,34 @@
      // æœ€åŽå†ç­‰å¾…一次 DOM æ›´æ–°ï¼Œç¡®ä¿æ‰€æœ‰æ•°æ®éƒ½å·²è®¾ç½®
      await nextTick();
    }
    computeTotalFreight();
  };
  const computeTotalFreight = () => {
    const hasQuantity =
      productForm.value.quantity !== "" &&
      productForm.value.quantity !== null &&
      productForm.value.quantity !== undefined;
    const hasFreightUnitPrice =
      productForm.value.freightUnitPrice !== "" &&
      productForm.value.freightUnitPrice !== null &&
      productForm.value.freightUnitPrice !== undefined;
    if (!hasQuantity || !hasFreightUnitPrice) return;
    const quantity = Number(productForm.value.quantity);
    const freightUnitPrice = Number(productForm.value.freightUnitPrice);
    if (!Number.isFinite(quantity) || !Number.isFinite(freightUnitPrice)) return;
    productForm.value.totalFreight = (quantity * freightUnitPrice).toFixed(2);
  };
  const handleQuantityChange = () => {
    mathNum();
    computeTotalFreight();
  };
  const handleFreightUnitPriceChange = () => {
    computeTotalFreight();
  };
  const getProductOptions = () => {
    return productTreeList().then(res => {
src/views/salesManagement/salesLedger/index.vue
ÎļþÌ«´ó