更新记录

1.0.0(2026-11-01)

首个版本:成本明细算报价。六类归集(材料/工时/外协/包装/运费/其他,主料、包材、委外、物流、杂费等叫法自动归一);报价链路为材料损耗 → 直接成本 → 管理费(基数 = 材料含损耗 + 工时 + 外协)→ 单件成本合计 → 利润 → 单件未税报价 → 阶梯折扣 → 单件折后未税 → 单件税额 → 含税单价 → 含税总价(单价 × 数量),每一步带计算基数说明;阶梯折扣按数量命中「下限 ≤ 数量」的最大一档,折扣率写 3、3%、0.03 都按 3% 处理;汇率作用在每一行单价上;默认逐行舍入后累加(可切整体一次舍入),并给出两种口径的尾差;缺单价、数量非数字、类别不认识、金额为零逐行提示;导出报价单 CSV(明细段 + 链路段,带 BOM)与链路纯文本。UTS→Kotlin 编译通过(index.kt 1430 行、classes.dex 65,372 字节),54 项回归测试全部通过;真机未执行(测试机未连接,adb devices 为空),市场截图为 H5 渲染并标注示例数据。


平台兼容性

uni-app

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× √ × × √ × √ × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

报价核算与阶梯折扣试算

给做报价、核价、成本核算的你:把一张成本明细算成一张能对得上的报价单。

不是「成本 × 1.3」那种拍脑袋加成。真到客户砍价那天,你需要的四件事,这里都有:

  1. 每一笔加成都有出处:材料损耗、管理费、利润率、税率分别按什么基数乘的,逐条写清楚,客户质疑时能当场解释;
  2. 阶梯折扣自动命中:报价数量落在哪一档、让了几个点、折后未税多少,不用翻 Excel 找行;
  3. 单据能逐行核加:每一步都用已舍入的值往下算,明细行金额之和 = 类别小计 = 成本合计,财务不会追着问那一分钱去哪了;
  4. 明细有问题先提示:缺单价、数量不是数字、类别不认识、金额为零,逐行点出来再算,不静默按 0 处理。

给谁用

  • 销售/业务:客户临时问「1000 个什么价」,改数量就出新的折扣价;
  • 工程/成本:把 BOM 展开后的用量清单换算成材料成本,加上工时与外协,看毛利还剩多少;
  • 财务/老板:核对报价单的成本构成,看利润点是不是被折扣吃掉了;
  • 外销:填个汇率,成本按本位币算,报价按外币出。

能做什么

能力 说明
六类归集 材料 / 工时 / 外协 / 包装 / 运费 / 其他,叫法自动归一(主料、包材、委外都认)
材料损耗 按材料小计的百分比补损耗,独立成行显示,不混进材料单价
管理费 基数 = 材料含损耗 + 工时 + 外协(包装/运费/其他不计,口径可在文档里核对)
利润 按成本合计的百分比加成
阶梯折扣 「数量,折扣率」多档,按报价数量自动命中最优档,写 3、3%、0.03 都当 3%
税率与汇率 税率按折后未税计;汇率作用在每一行单价上,外销直接填
单价与总价 明细按单件口径算,先出含税单价(保留四位,分位再多两位),再乘数量出总价,单据上乘得回去
明细提示 缺单价、数量非数字、类别不认识、金额为零,逐行给行号与文字说明
导出 报价单 CSV(明细 + 链路两段,带 BOM,Excel 双击不乱码)、链路纯文本(可直接贴邮件)

快速接入

import { quoteCalc, readCostTable, tierList, toText } from '@/uni_modules/szhzy-quote-cost'

// 1. 算报价:CSV 文本直接给,也可以传文件路径
const r = quoteCalc({
  csv: '类别,名称,数量,单价,单位\n材料,铝基板,1,18.5,块\n工时,贴片,1,6,小时\n…',
  materialLossRate: 3,   // 材料损耗 3%
  overheadRate: 12,      // 管理费 12%
  profitRate: 20,        // 利润 20%
  taxRate: 13,           // 增值税 13%
  qty: 1000,             // 报价数量
  tiersCsv: '1,0\n500,3\n1000,5',  // 1000 个命中 5% 档
  writeCsv: true,
  fileName: '报价单-1000个.csv'
})
// r.steps     [{ key, title, amount, basis }] 每一步的金额与计算基数(单件口径)
// r.unitPrice 含税单价;r.unitPriceNet 未税单价
// r.total     含税总价 = 单价 × 数量;r.totalNet 未税总价;r.taxTotal 税额合计
// r.tierIndex 命中的档位下标;r.discountRate 实际折扣率(0.05 = 5%)
// r.warnings  [{ kind, line, name, message }] 需要人确认的明细行

// 2. 只看解析结果,用于表格预览
const t = readCostTable({ csv: costText })
// t.rows [{ category, categoryText, name, qty, price, unit, amount, line }]

// 3. 试算不同数量的折扣
const g = tierList({ tiersCsv: '1,0\n500,3\n1000,5', qty: 800 })
// g.hitIndex 1;g.tiers [{ minQty, rate, percent, hit }]

// 4. 拿一段能直接贴进邮件的文本
const s = toText({ csv: costText, profitRate: 20, taxRate: 13 })

所有接口返回统一信封 { ok, code, message, ... },不抛异常。code 取值:SUCCESS、EMPTY、NO_HEADER、TOO_LARGE、READ_FAILED、CHARSET_UNSUPPORTED 等。

输入格式

标准的五列,表头名可省(无表头时按列序读,缺数量列按 1 计):

列 表头可写 说明
类别 类别 / 分类 / 科目 / category 材料、工时、外协、包装、运费、其他;认不出按其他计并提示
名称 名称 / 项目 / 物料名称 / name 明细名称,为空的行跳过
数量 数量 / 用量 / qty 缺省 1;非数字按 1 计并提示
单价 单价 / price 空或非数字按 0 计并提示
单位 单位 / unit 缺省空
备注 备注 / remark 不参与计算,仅保留

分隔符支持逗号和制表符(从 Excel 直接复制粘贴过来就是制表符),字段可用双引号包裹,"" 表示引号本身。

参数

参数 类型 默认 说明
csv string — 成本明细文本,与 path 二选一
path string — 文件路径或 content:// URI
charset string UTF-8 读文件编码,老系统导出的 GBK 直接传 GBK
materialLossRate number 0 材料损耗百分比
overheadRate number 0 管理费百分比
profitRate number 0 利润百分比
taxRate number 13 税率百分比
exchangeRate number 1 汇率,作用在每一行单价上
freight number 0 额外运费(明细里已有运费行时在此基础上叠加)
qty number 1 报价数量,决定命中的折扣档与单价
decimals number 2 金额小数位(0–4)
currency string ¥ 货币符号,只影响文案与 CSV 展示
rounding string line line 逐行舍入后累加(财务口径)/ sum 汇总后一次舍入
tiersCsv string — 阶梯折扣表,「数量,折扣率」两列文本
writeCsv boolean false 是否把报价单写成 CSV
bom boolean true 写 CSV 时是否带 UTF-8 BOM

报价怎么算

明细是单件口径(做一支灯要多少料、多少工时),链路每一步都按单件算,最后一步才乘数量:

材料小计   = Σ 材料行金额(数量 × 单价 × 汇率)
材料损耗   = 材料小计 × 损耗率
直接成本   = 材料小计 + 材料损耗 + 工时 + 外协 + 包装 + 运费 + 其他
管理费     = (材料小计 + 材料损耗 + 工时 + 外协) × 管理费率
单件成本合计 = 直接成本 + 管理费
利润       = 单件成本合计 × 利润率
单件未税报价 = 单件成本合计 + 利润
阶梯折扣   = 单件未税报价 × 命中档位折扣率
单件折后未税 = 单件未税报价 − 阶梯折扣
单件税额   = 单件折后未税 × 税率
含税单价   = 单件折后未税 + 单件税额
含税总价   = 含税单价 × 报价数量

例:材料 100 元(损耗 3%)、工时 30 元、管理费 12%、利润 20%、税 13%、数量 1000 命中 5% 折扣 —— 直接成本 = 103 + 30 = 133,管理费 = (103 + 30) × 12% = 15.96,单件成本合计 148.96, 利润 29.79,单件未税报价 178.75,折扣 8.94,单件折后未税 169.81,单件税额 22.08, 含税单价 191.89,含税总价 191,890.00(未税单价 169.81)。

验证状态

  • UTS → Kotlin 编译:已执行,compiled successfully(详见 docs/quote-cost/测试记录.md);
  • 纯逻辑回归测试:54 项全部通过,覆盖解析、类别归一、折扣档位、链路计算、舍入口径、明细提示、CSV 与文本导出;
  • 真机运行:未执行。开发时测试机未连接(adb devices 为空),Android 平台层的文件读写需要你在自己的设备上跑一次;
  • iOS / 鸿蒙:未实现,仅支持 Android。

购买前必读

  1. 只算金额,不展开 BOM。需要「这个成品要备多少料」请用同门的《多级 BOM 展开与物料需求汇总》,两个插件可以串联:展开出用量 → 填上单价 → 本插件算报价;
  2. 明细填单件用量,不要填订单总量。一支灯用 72 颗灯珠就写 72,不要写 72×1000;订单总量由 qty 表达,插件负责乘上去。这条搞反了,报价会差一个数量级;
  3. 不做税率合规判断。税率是你填的,插件不判断该开 13% 还是 6%,也不生成发票;
  4. 管理费基数固定为「材料含损耗 + 工时 + 外协」。如果你们把包装也算进管理费基数,请自己把包装行改成「其他」类的处理方式,或直接把费率调高——插件不替你猜口径;
  5. 折扣是「按数量让点」,不是「阶梯单价」。如果你的报价单是「1–499 个每个 2 元、500 个以上每个 1.9 元」这种直接给单价的写法,请把数量分档各算一次;
  6. 单价与总价会有极小尾差。单价保留四位、总价保留两位,roundingDiff 会如实给出「单价 × 数量」与「整体一次算」的差额(摊到每件通常不到一分钱),对账时用它对齐。

更新日志

见 changelog.md。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无系统权限。读取调用方用系统文件选择器交过来的文件(路径或 content:// 授权),写出走应用外部私有目录。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集、不上传任何数据,不访问网络,不写日志。成本明细只在本机内存中解析与计算;报价单由调用方决定是否落盘,默认写应用外部私有目录。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。