gaoluyang
6 小时以前 3501a6baef173d2333f48784d255035696bfbd03
fix(erp): 单据明细单价口径由「不含税单价」改为「含税单价」(前端)

明细公式改为:含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;
不含税金额 = 含税金额 − 税额。销售订单/采购订单/销售出库/采购入库/销售退货/采购退货
六张单据统一;采购申请补齐不含税金额、税额、含税合计三列。

已有单据的明细行(带 id)沿用后端返回值、不再重算,避免历史单据前端展示
按新口径算出与库中/列表页不一致的金额。

列顺序统一为 数量 | 含税单价(元) | 税率(%) | 不含税金额(元) | 税额(元) | 含税合计(元);
同步打印模板、详情页、选单弹窗、列表页与表头表单文案(金额合计→不含税金额合计、
优惠后金额→优惠后含税金额、税额合计→含税合计)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
已修改23个文件
504 ■■■■■ 文件已修改
src/api/erp/purchase/request/index.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/in/data.ts 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/in/modules/item-form.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/order/components/select-dialog.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/order/components/select.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/order/data.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/order/detail/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/order/modules/item-form.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/request/data.ts 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/request/detail/index.vue 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/request/modules/item-form.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/return/data.ts 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/purchase/return/modules/item-form.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/components/select-dialog.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/components/select.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/data.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/detail/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/modules/item-form.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/order/modules/print.vue 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/out/data.ts 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/out/modules/item-form.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/return/data.ts 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/erp/sale/return/modules/item-form.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/erp/purchase/request/index.ts
@@ -38,11 +38,15 @@
    productUnitId?: number; // 产品单位编号
    productUnitName?: string; // 产品单位名称
    productBarCode?: string; // 产品条码
    productPrice?: number; // 产品单价(参考价)
    productPrice?: number; // 含税单价(参考价)
    count: number; // 数量
    taxPercent?: number; // 税率
    totalPrice?: number; // 不含税金额
    taxPrice?: number; // 税额
    demandTime?: string; // 需求日期
    remark?: string; // 备注
    qcCheckFlag?: boolean; // 是否质检
    inCount?: number; // 入库数量
  }
}
src/views/erp/purchase/in/data.ts
@@ -132,11 +132,11 @@
    },
    {
      fieldName: 'discountedPrice',
      label: '优惠后金额',
      label: '优惠后含税金额',
      component: 'InputNumber',
      componentProps: {
        class: '!w-full',
        placeholder: '优惠后金额',
        placeholder: '优惠后含税金额',
        precision: 2,
        formatter: erpPriceInputFormatter,
        disabled: true,
@@ -256,17 +256,10 @@
    },
    {
      field: 'productPrice',
      title: '产品单价',
      title: '含税单价(元)',
      fixed: 'right',
      minWidth: 120,
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '产品金额',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
@@ -276,16 +269,23 @@
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '不含税金额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
      field: 'taxPrice',
      title: '税额',
      title: '税额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      field: 'totalPrice',
      fixed: 'right',
      title: '合计金额',
      title: '含税合计(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
@@ -603,7 +603,7 @@
    },
    {
      field: 'totalProductPrice',
      title: '金额合计',
      title: '不含税金额合计',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/purchase/in/modules/item-form.vue
@@ -152,6 +152,7 @@
/** 处理行数据变更 */
function handleRowChange(row: any) {
  // TODO 芋艿
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
@@ -161,13 +162,28 @@
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
function initRow(row: ErpPurchaseInApi.PurchaseInItem) {
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpPurchaseInApi.PurchaseInItem) {
  if (row.productPrice && row.count) {
    row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = row.totalProductPrice + row.taxPrice;
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalProductPrice = taxInclusivePrice - row.taxPrice;
    row.totalPrice = taxInclusivePrice;
  }
}
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpPurchaseInApi.PurchaseInItem) {
  if (!row.id) {
    recalcRow(row);
  }
}
@@ -280,11 +296,11 @@
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>
              金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
              不含税金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
            </span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>
              税额合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
              含税合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
            </span>
          </div>
        </div>
src/views/erp/purchase/order/components/select-dialog.vue
@@ -93,7 +93,7 @@
    { field: 'supplierName', title: '供应商', minWidth: 120 },
    { field: 'orderTime', title: '订单时间', width: 120, formatter: 'formatDate' },
    { field: 'totalCount', title: '合计数量', width: 100 },
    { field: 'totalPrice', title: '合计金额', width: 100 },
    { field: 'totalPrice', title: '含税合计', width: 100 },
  ];
}
src/views/erp/purchase/order/components/select.vue
@@ -116,7 +116,7 @@
          <div>订单号:{{ selectedItem.no || '-' }}</div>
          <div>供应商:{{ selectedItem.supplierName || '-' }}</div>
          <div>订单时间:{{ selectedItem.orderTime || '-' }}</div>
          <div>合计金额:{{ selectedItem.totalPrice || '-' }} 元</div>
          <div>含税合计:{{ selectedItem.totalPrice || '-' }} 元</div>
        </div>
      </template>
      <Input
src/views/erp/purchase/order/data.ts
@@ -81,7 +81,7 @@
            return z
              .number()
              .min(0, '订金不能小于0')
              .max(values.totalPrice, '订金不能大于优惠后金额');
              .max(values.totalPrice, '订金不能大于优惠后含税金额');
          }
          return z.number().min(0, '订金不能小于0');
        },
@@ -145,11 +145,11 @@
    },
    {
      fieldName: 'totalPrice',
      label: '优惠后金额',
      label: '优惠后含税金额',
      component: 'InputNumber',
      componentProps: {
        class: '!w-full',
        placeholder: '优惠后金额',
        placeholder: '优惠后含税金额',
        precision: 2,
        formatter: erpPriceInputFormatter,
        disabled: true,
@@ -210,17 +210,10 @@
    },
    {
      field: 'productPrice',
      title: '产品单价',
      title: '含税单价(元)',
      minWidth: 120,
      fixed: 'right',
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalProductPrice',
      title: '金额',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'taxPercent',
@@ -230,15 +223,22 @@
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalProductPrice',
      title: '不含税金额(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'taxPrice',
      title: '税额',
      title: '税额(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'totalPrice',
      title: '税额合计',
      title: '含税合计(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
@@ -404,7 +404,7 @@
    },
    {
      field: 'totalProductPrice',
      title: '金额合计',
      title: '不含税金额合计',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/purchase/order/detail/index.vue
@@ -60,7 +60,7 @@
      render: (val) => erpCountInputFormatter(val) || '-',
    },
    {
      label: '合计金额',
      label: '含税合计金额',
      field: 'totalPrice',
      render: (val) => erpPriceInputFormatter(val) || '-',
    },
src/views/erp/purchase/order/modules/item-form.vue
@@ -166,6 +166,7 @@
/** 处理行数据变更 */
function handleRowChange(row: any) {
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
@@ -175,13 +176,28 @@
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
function initRow(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
  if (row.productPrice && row.count) {
    row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = row.totalProductPrice + row.taxPrice;
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalProductPrice = taxInclusivePrice - row.taxPrice;
    row.totalPrice = taxInclusivePrice;
  }
}
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
  if (!row.id) {
    recalcRow(row);
  }
}
@@ -301,11 +317,11 @@
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>
              金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
              不含税金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
            </span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>
              税额合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
              含税合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
            </span>
          </div>
        </div>
src/views/erp/purchase/request/data.ts
@@ -167,17 +167,10 @@
    },
    {
      field: 'productPrice',
      title: '单价(参考价)',
      title: '含税单价(元)',
      minWidth: 120,
      fixed: 'right',
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalPrice',
      title: '预估金额',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'taxPercent',
@@ -185,6 +178,26 @@
      minWidth: 100,
      fixed: 'right',
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalPrice',
      title: '不含税金额(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'taxPrice',
      title: '税额(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      title: '含税合计(元)',
      minWidth: 120,
      fixed: 'right',
      slots: { default: 'totalTaxInclusivePrice' },
    },
    {
      field: 'demandTime',
@@ -339,7 +352,7 @@
    },
    {
      field: 'totalPrice',
      title: '预估金额',
      title: '含税金额',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/purchase/request/detail/index.vue
@@ -46,13 +46,7 @@
    },
    {
      field: 'productPrice',
      title: '单价(参考价)',
      minWidth: 120,
      formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-',
    },
    {
      field: 'totalPrice',
      title: '预估金额',
      title: '含税单价(元)',
      minWidth: 120,
      formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-',
    },
@@ -61,6 +55,25 @@
      title: '税率(%)',
      minWidth: 90,
      formatter: ({ cellValue }) => (cellValue ? `${cellValue}%` : '-'),
    },
    {
      field: 'totalPrice',
      title: '不含税金额(元)',
      minWidth: 120,
      formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-',
    },
    {
      field: 'taxPrice',
      title: '税额(元)',
      minWidth: 120,
      formatter: ({ cellValue }) => erpPriceInputFormatter(cellValue) || '-',
    },
    {
      field: 'totalTaxInclusivePrice',
      title: '含税合计(元)',
      minWidth: 120,
      formatter: ({ row }) =>
        erpPriceInputFormatter((row.totalPrice || 0) + (row.taxPrice || 0)) || '-',
    },
    { field: 'demandTime', title: '需求日期', minWidth: 110 },
    {
@@ -123,7 +136,7 @@
      render: (val) => erpCountInputFormatter(val) || '-',
    },
    {
      label: '合计金额',
      label: '含税合计金额',
      field: 'totalPrice',
      render: (val) => erpPriceInputFormatter(val) || '-',
    },
src/views/erp/purchase/request/modules/item-form.vue
@@ -30,19 +30,22 @@
const tableData = ref<ErpPurchaseRequestApi.PurchaseRequestItem[]>([]);
/** 获取表格合计数据 */
/** 获取表格合计数据(行上 totalPrice 为不含税金额,含税合计需加上税额) */
const summaries = computed(() => {
  return {
    count: tableData.value.reduce((sum, item) => sum + (item.count || 0), 0),
    totalPrice: tableData.value.reduce(
      (sum, item) => {
        const price = erpPriceMultiply(item.productPrice || 0, item.count || 0) ?? 0;
        return sum + price;
      },
      (sum, item) => sum + (item.totalPrice || 0),
      0,
    ),
    taxPrice: tableData.value.reduce((sum, item) => sum + (item.taxPrice || 0), 0),
  };
});
/** 含税合计 = 不含税金额 + 税额 */
const totalTaxInclusivePrice = computed(
  () => summaries.value.totalPrice + summaries.value.taxPrice,
);
/** 表格配置 */
const [Grid, gridApi] = useVbenVxeGrid({
@@ -126,25 +129,39 @@
  handleRowChange(row);
}
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpPurchaseRequestApi.PurchaseRequestItem) {
  if (row.productPrice && row.count) {
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = taxInclusivePrice - row.taxPrice;
  }
}
/** 处理行数据变更 */
function handleRowChange(row: any) {
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
  } else {
    tableData.value[index] = row;
  }
  // 计算预估金额
  if (row.productPrice && row.count) {
    row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
  }
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpPurchaseRequestApi.PurchaseRequestItem) {
  if (row.productPrice && row.count) {
    row.totalPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
  if (!row.id) {
    recalcRow(row);
  }
}
@@ -218,6 +235,9 @@
      />
      <span v-else>{{ row.taxPercent ? `${row.taxPercent}%` : '-' }}</span>
    </template>
    <template #totalTaxInclusivePrice="{ row }">
      <span>{{ erpPriceInputFormatter((row.totalPrice || 0) + (row.taxPrice || 0)) }}</span>
    </template>
    <template #demandTime="{ row }">
      <DatePicker
        v-if="!disabled"
@@ -264,7 +284,9 @@
          <span class="font-medium text-foreground">合计:</span>
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>预估金额:{{ erpPriceInputFormatter(summaries.totalPrice) }}</span>
            <span>不含税金额:{{ erpPriceInputFormatter(summaries.totalPrice) }}</span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>含税合计:{{ erpPriceInputFormatter(totalTaxInclusivePrice) }}</span>
          </div>
        </div>
      </div>
src/views/erp/purchase/return/data.ts
@@ -131,11 +131,11 @@
    },
    {
      fieldName: 'discountedPrice',
      label: '优惠后金额',
      label: '优惠后含税金额',
      component: 'InputNumber',
      componentProps: {
        class: '!w-full',
        placeholder: '优惠后金额',
        placeholder: '优惠后含税金额',
        precision: 2,
        formatter: erpPriceInputFormatter,
        disabled: true,
@@ -256,17 +256,10 @@
    },
    {
      field: 'productPrice',
      title: '产品单价',
      title: '含税单价(元)',
      fixed: 'right',
      minWidth: 120,
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '产品金额',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
@@ -276,16 +269,23 @@
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '不含税金额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
      field: 'taxPrice',
      title: '税额',
      title: '税额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      field: 'totalPrice',
      fixed: 'right',
      title: '合计金额',
      title: '含税合计(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
@@ -590,7 +590,7 @@
    },
    {
      field: 'totalProductPrice',
      title: '金额合计',
      title: '不含税金额合计',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/purchase/return/modules/item-form.vue
@@ -155,6 +155,7 @@
/** 处理行数据变更 */
function handleRowChange(row: any) {
  // TODO 芋艿
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
@@ -164,13 +165,28 @@
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
function initRow(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
  if (row.productPrice && row.count) {
    row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = row.totalProductPrice + row.taxPrice;
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalProductPrice = taxInclusivePrice - row.taxPrice;
    row.totalPrice = taxInclusivePrice;
  }
}
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
  if (!row.id) {
    recalcRow(row);
  }
}
@@ -283,11 +299,11 @@
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>
              金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
              不含税金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
            </span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>
              税额合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
              含税合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
            </span>
          </div>
        </div>
src/views/erp/sale/order/components/select-dialog.vue
@@ -95,7 +95,7 @@
    { field: 'customerName', title: '客户', minWidth: 120 },
    { field: 'orderTime', title: '订单时间', width: 120, formatter: 'formatDate' },
    { field: 'totalCount', title: '合计数量', width: 100 },
    { field: 'totalPrice', title: '合计金额', width: 100 },
    { field: 'totalPrice', title: '含税合计', width: 100 },
  ];
}
src/views/erp/sale/order/components/select.vue
@@ -119,7 +119,7 @@
          <div>订单号:{{ selectedItem.no || '-' }}</div>
          <div>客户:{{ selectedItem.customerName || '-' }}</div>
          <div>订单时间:{{ selectedItem.orderTime || '-' }}</div>
          <div>合计金额:{{ selectedItem.totalPrice || '-' }} 元</div>
          <div>含税合计:{{ selectedItem.totalPrice || '-' }} 元</div>
        </div>
      </template>
      <Input
src/views/erp/sale/order/data.ts
@@ -156,11 +156,11 @@
    },
    {
      fieldName: 'totalPrice',
      label: '优惠后金额',
      label: '优惠后含税金额',
      component: 'InputNumber',
      componentProps: {
        class: '!w-full',
        placeholder: '优惠后金额',
        placeholder: '优惠后含税金额',
        precision: 2,
        formatter: erpPriceInputFormatter,
        disabled: true,
@@ -197,7 +197,7 @@
            return z
              .number()
              .min(0, '订金不能小于0')
              .max(values.totalPrice, '收取订金不能大于优惠后金额');
              .max(values.totalPrice, '收取订金不能大于优惠后含税金额');
          }
          return z.number().min(0, '订金不能小于0').optional();
        },
@@ -270,17 +270,10 @@
    },
    {
      field: 'productPrice',
      title: '产品单价',
      title: '含税单价(元)',
      minWidth: 120,
      fixed: 'right',
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalProductPrice',
      title: '金额',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'taxPercent',
@@ -290,15 +283,22 @@
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalProductPrice',
      title: '不含税金额(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'taxPrice',
      title: '税额',
      title: '税额(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
    },
    {
      field: 'totalPrice',
      title: '税额合计',
      title: '含税合计(元)',
      minWidth: 120,
      fixed: 'right',
      formatter: 'formatAmount2',
@@ -482,7 +482,7 @@
    },
    {
      field: 'totalProductPrice',
      title: '金额合计',
      title: '不含税金额合计',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/sale/order/detail/index.vue
@@ -75,7 +75,7 @@
      render: (val) => erpCountInputFormatter(val) || '-',
    },
    {
      label: '合计金额',
      label: '含税合计金额',
      field: 'totalPrice',
      render: (val) => erpPriceInputFormatter(val) || '-',
    },
src/views/erp/sale/order/modules/item-form.vue
@@ -172,6 +172,7 @@
/** 处理行数据变更 */
function handleRowChange(row: any) {
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
@@ -181,13 +182,28 @@
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
function initRow(row: ErpSaleOrderApi.SaleOrderItem) {
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpSaleOrderApi.SaleOrderItem) {
  if (row.productPrice && row.count) {
    row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = row.totalProductPrice + row.taxPrice;
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalProductPrice = taxInclusivePrice - row.taxPrice;
    row.totalPrice = taxInclusivePrice;
  }
}
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpSaleOrderApi.SaleOrderItem) {
  if (!row.id) {
    recalcRow(row);
  }
  // 默认需要生产
  if (row.needProduction === undefined) {
@@ -311,11 +327,11 @@
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>
              金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
              不含税金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
            </span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>
              税额合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
              含税合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
            </span>
          </div>
        </div>
src/views/erp/sale/order/modules/print.vue
@@ -99,21 +99,21 @@
}
/**
 * 明细行(后端不返回明细行的 totalProductPrice/totalPrice,需按单价×数量计算:
 * 金额 = 单价 × 数量;税额 = 金额 × 税率;含税金额 = 金额 + 税额)
 * 明细行(优先用后端返回值;缺省时按「单价为含税单价」计算:
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额)
 */
const printRows = computed(() =>
  (printData.value.items || []).map((item) => {
    const totalProductPrice =
      item.totalProductPrice ?? multiplyPrice(item.productPrice, item.count) ?? 0;
    const taxInclusivePrice = multiplyPrice(item.productPrice, item.count);
    const taxPrice =
      item.taxPrice ?? multiplyPrice(totalProductPrice, (item.taxPercent ?? 0) / 100) ?? 0;
    const totalPrice = item.totalPrice ?? totalProductPrice + taxPrice;
      item.taxPrice ?? multiplyPrice(taxInclusivePrice, (item.taxPercent ?? 0) / 100) ?? 0;
    const totalPrice = item.totalPrice ?? taxInclusivePrice ?? 0;
    const totalProductPrice = item.totalProductPrice ?? totalPrice - taxPrice;
    return { ...item, totalProductPrice, taxPrice, totalPrice };
  }),
);
/** 明细合计:数量/金额优先取订单头(后端权威值),税额与含税金额按明细累加(订单头 totalPrice 为优惠后金额,另在金额信息区展示) */
/** 明细合计:数量/金额优先取订单头(后端权威值),税额与含税金额按明细累加(订单头 totalPrice 为优惠后含税金额,另在金额信息区展示) */
const summaries = computed(() => {
  const rows = printRows.value;
  const count = rows.reduce((sum, item) => sum + (item.count || 0), 0);
@@ -262,17 +262,17 @@
            <th
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold"
            >
              产品单价(元)
            </th>
            <th
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold"
            >
              金额(元)
              含税单价(元)
            </th>
            <th
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold"
            >
              税率(%)
            </th>
            <th
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold"
            >
              不含税金额(元)
            </th>
            <th
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right font-bold"
@@ -312,10 +312,10 @@
              {{ formatPrice(item.productPrice) }}
            </td>
            <td class="border border-solid border-[#dcdfe6] p-2 text-right">
              {{ formatPrice(item.totalProductPrice) }}
              {{ formatPrice(item.taxPercent) }}
            </td>
            <td class="border border-solid border-[#dcdfe6] p-2 text-right">
              {{ formatPrice(item.taxPercent) }}
              {{ formatPrice(item.totalProductPrice) }}
            </td>
            <td class="border border-solid border-[#dcdfe6] p-2 text-right">
              {{ formatPrice(item.taxPrice) }}
@@ -348,13 +348,13 @@
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2"
            ></td>
            <td
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2"
            ></td>
            <td
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right"
            >
              {{ formatPrice(summaries.totalProductPrice) }}
            </td>
            <td
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2"
            ></td>
            <td
              class="border border-solid border-[#dcdfe6] bg-[#f5f7fa] p-2 text-right"
            >
@@ -386,7 +386,7 @@
      >
        <div>优惠率(%):{{ formatPrice(printData.discountPercent) }}</div>
        <div>付款优惠(元):{{ formatPrice(printData.discountPrice) }}</div>
        <div>优惠后金额(元):{{ formatPrice(printData.totalPrice) }}</div>
        <div>优惠后含税金额(元):{{ formatPrice(printData.totalPrice) }}</div>
        <div>收取订金(元):{{ formatPrice(printData.depositPrice) }}</div>
      </div>
src/views/erp/sale/out/data.ts
@@ -149,11 +149,11 @@
    },
    {
      fieldName: 'discountedPrice',
      label: '优惠后金额',
      label: '优惠后含税金额',
      component: 'InputNumber',
      componentProps: {
        class: '!w-full',
        placeholder: '优惠后金额',
        placeholder: '优惠后含税金额',
        precision: 2,
        formatter: erpPriceInputFormatter,
        disabled: true,
@@ -277,17 +277,10 @@
    },
    {
      field: 'productPrice',
      title: '产品单价',
      title: '含税单价(元)',
      fixed: 'right',
      minWidth: 120,
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '产品金额',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
@@ -297,16 +290,23 @@
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '不含税金额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
      field: 'taxPrice',
      title: '税额',
      title: '税额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      field: 'totalPrice',
      fixed: 'right',
      title: '合计金额',
      title: '含税合计(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
@@ -617,7 +617,7 @@
    },
    {
      field: 'totalProductPrice',
      title: '金额合计',
      title: '不含税金额合计',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/sale/out/modules/item-form.vue
@@ -153,6 +153,7 @@
/** 处理行数据变更 */
function handleRowChange(row: any) {
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
@@ -162,13 +163,28 @@
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
function initRow(row: ErpSaleOutApi.SaleOutItem) {
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpSaleOutApi.SaleOutItem) {
  if (row.productPrice && row.count) {
    row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = row.totalProductPrice + row.taxPrice;
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalProductPrice = taxInclusivePrice - row.taxPrice;
    row.totalPrice = taxInclusivePrice;
  }
}
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpSaleOutApi.SaleOutItem) {
  if (!row.id) {
    recalcRow(row);
  }
}
@@ -282,11 +298,11 @@
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>
              金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
              不含税金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
            </span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>
              税额合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
              含税合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
            </span>
          </div>
        </div>
src/views/erp/sale/return/data.ts
@@ -144,11 +144,11 @@
    },
    {
      fieldName: 'discountedPrice',
      label: '优惠后金额',
      label: '优惠后含税金额',
      component: 'InputNumber',
      componentProps: {
        class: '!w-full',
        placeholder: '优惠后金额',
        placeholder: '优惠后含税金额',
        precision: 2,
        formatter: erpPriceInputFormatter,
        disabled: true,
@@ -270,17 +270,10 @@
    },
    {
      field: 'productPrice',
      title: '产品单价',
      title: '含税单价(元)',
      fixed: 'right',
      minWidth: 120,
      slots: { default: 'productPrice' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '产品金额',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
@@ -290,16 +283,23 @@
      slots: { default: 'taxPercent' },
    },
    {
      field: 'totalProductPrice',
      fixed: 'right',
      title: '不含税金额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      fixed: 'right',
      field: 'taxPrice',
      title: '税额',
      title: '税额(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
    {
      field: 'totalPrice',
      fixed: 'right',
      title: '合计金额',
      title: '含税合计(元)',
      minWidth: 120,
      formatter: 'formatAmount2',
    },
@@ -604,7 +604,7 @@
    },
    {
      field: 'totalProductPrice',
      title: '金额合计',
      title: '不含税金额合计',
      formatter: 'formatAmount2',
      minWidth: 120,
    },
src/views/erp/sale/return/modules/item-form.vue
@@ -207,6 +207,7 @@
/** 处理行数据变更 */
function handleRowChange(row: any) {
  recalcRow(row);
  const index = tableData.value.findIndex((item) => item.seq === row.seq);
  if (index === -1) {
    tableData.value.push(row);
@@ -216,13 +217,28 @@
  emit('update:items', [...tableData.value]);
}
/** 初始化行数据 */
function initRow(row: ErpSaleReturnApi.SaleReturnItem) {
/**
 * 重算行金额(单价为**含税**单价)
 * 含税金额 = 含税单价 × 数量;税额 = 含税金额 × 税率;不含税金额 = 含税金额 - 税额
 */
function recalcRow(row: ErpSaleReturnApi.SaleReturnItem) {
  if (row.productPrice && row.count) {
    row.totalProductPrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    const taxInclusivePrice = erpPriceMultiply(row.productPrice, row.count) ?? 0;
    row.taxPrice =
      erpPriceMultiply(row.totalProductPrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalPrice = row.totalProductPrice + row.taxPrice;
      erpPriceMultiply(taxInclusivePrice, (row.taxPercent || 0) / 100) ?? 0;
    row.totalProductPrice = taxInclusivePrice - row.taxPrice;
    row.totalPrice = taxInclusivePrice;
  }
}
/**
 * 初始化行数据
 * 已有单据的明细行(带 id)沿用后端返回的金额,避免历史单据被新口径覆盖;
 * 只有未保存的新增行才按新口径重算。
 */
function initRow(row: ErpSaleReturnApi.SaleReturnItem) {
  if (!row.id) {
    recalcRow(row);
  }
}
@@ -340,11 +356,11 @@
          <div class="flex space-x-4">
            <span>数量:{{ erpCountInputFormatter(summaries.count) }}</span>
            <span>
              金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
              不含税金额:{{ erpPriceInputFormatter(summaries.totalProductPrice) }}
            </span>
            <span>税额:{{ erpPriceInputFormatter(summaries.taxPrice) }}</span>
            <span>
              税额合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
              含税合计:{{ erpPriceInputFormatter(summaries.totalPrice) }}
            </span>
          </div>
        </div>