更新记录
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」那种拍脑袋加成。真到客户砍价那天,你需要的四件事,这里都有:
- 每一笔加成都有出处:材料损耗、管理费、利润率、税率分别按什么基数乘的,逐条写清楚,客户质疑时能当场解释;
- 阶梯折扣自动命中:报价数量落在哪一档、让了几个点、折后未税多少,不用翻 Excel 找行;
- 单据能逐行核加:每一步都用已舍入的值往下算,明细行金额之和 = 类别小计 = 成本合计,财务不会追着问那一分钱去哪了;
- 明细有问题先提示:缺单价、数量不是数字、类别不认识、金额为零,逐行点出来再算,不静默按 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。
购买前必读
- 只算金额,不展开 BOM。需要「这个成品要备多少料」请用同门的《多级 BOM 展开与物料需求汇总》,两个插件可以串联:展开出用量 → 填上单价 → 本插件算报价;
- 明细填单件用量,不要填订单总量。一支灯用 72 颗灯珠就写 72,不要写 72×1000;订单总量由
qty表达,插件负责乘上去。这条搞反了,报价会差一个数量级; - 不做税率合规判断。税率是你填的,插件不判断该开 13% 还是 6%,也不生成发票;
- 管理费基数固定为「材料含损耗 + 工时 + 外协」。如果你们把包装也算进管理费基数,请自己把包装行改成「其他」类的处理方式,或直接把费率调高——插件不替你猜口径;
- 折扣是「按数量让点」,不是「阶梯单价」。如果你的报价单是「1–499 个每个 2 元、500 个以上每个 1.9 元」这种直接给单价的写法,请把数量分档各算一次;
- 单价与总价会有极小尾差。单价保留四位、总价保留两位,
roundingDiff会如实给出「单价 × 数量」与「整体一次算」的差额(摊到每件通常不到一分钱),对账时用它对齐。
更新日志
见 changelog.md。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 13
赞赏 0
下载 12731775
赞赏 1959
赞赏
京公网安备:11010802035340号