电商场景
电商场景涉及大量价格计算,精度问题尤为重要。
价格计算
单品价格
javascript
import { calc } from 'a-calc'
// 计算商品总价
const total = calc('price * quantity | =2', {
price: 99.9,
quantity: 3
})
// '299.70'
// 带千分位的大额商品
const bigTotal = calc('price * quantity | =2,', {
price: 9999.99,
quantity: 10
})
// '99,999.90'Ctrl+D 选择词, Ctrl+/ 注释
购物车总价
javascript
import { calc_sum } from 'a-calc'
const cart = [
{ name: 'iPhone 15', price: 6999, quantity: 1 },
{ name: 'AirPods Pro', price: 1899, quantity: 2 },
{ name: '手机壳', price: 49.9, quantity: 3 }
]
// 计算购物车总价
const cartTotal = calc_sum('price * quantity | =2,', cart)
// '10,946.70'折扣计算
直接折扣
javascript
import { calc } from 'a-calc'
// 8折
const discounted = calc('price * 0.8 | =2', { price: 199 })
// '159.20'
// 指定折扣率
const withDiscount = calc('price * discount | =2', {
price: 199,
discount: 0.85 // 85折
})
// '169.15'满减优惠
javascript
import { calc } from 'a-calc'
function calcWithCoupon(subtotal, threshold, reduction) {
// 判断是否满足条件
const meetCondition = calc(`${subtotal} >= ${threshold} | !n`)
if (meetCondition) {
return calc('subtotal - reduction | =2', { subtotal, reduction })
}
return calc('subtotal | =2', { subtotal })
}
calcWithCoupon(299, 200, 30) // '269.00' (满200减30)
calcWithCoupon(150, 200, 30) // '150.00' (未满足条件)Ctrl+D 选择词, Ctrl+/ 注释
多重优惠
javascript
import { calc } from 'a-calc'
// 先折扣后满减
function calcMultiDiscount(price, discount, threshold, reduction) {
// 先打折
const afterDiscount = calc('price * discount', { price, discount })
// 再满减
const meetCondition = calc(`${afterDiscount} >= ${threshold} | !n`)
if (meetCondition) {
return calc('discounted - reduction | =2', {
discounted: afterDiscount,
reduction
})
}
return calc('discounted | =2', { discounted: afterDiscount })
}
// 原价500,8折后再满300减50
calcMultiDiscount(500, 0.8, 300, 50) // '350.00'运费计算
阶梯运费
javascript
import { calc } from 'a-calc'
function calcShipping(weight) {
// 首重3元/kg,续重2元/kg
const firstWeight = 1
const firstPrice = 3
const extraPrice = 2
if (calc(`${weight} <= ${firstWeight} | !n`)) {
return calc('firstPrice | =2', { firstPrice })
}
return calc('firstPrice + (weight - firstWeight) * extraPrice | =2', {
firstPrice,
weight,
firstWeight,
extraPrice
})
}
calcShipping(0.5) // '3.00'
calcShipping(1) // '3.00'
calcShipping(3.5) // '8.00'包邮判断
javascript
import { calc } from 'a-calc'
function calcWithShipping(subtotal, freeShippingThreshold, shippingFee) {
const needShipping = calc(`${subtotal} < ${freeShippingThreshold} | !n`)
if (needShipping) {
return {
subtotal: calc('subtotal | =2', { subtotal }),
shipping: calc('fee | =2', { fee: shippingFee }),
total: calc('subtotal + fee | =2', { subtotal, fee: shippingFee })
}
}
return {
subtotal: calc('subtotal | =2', { subtotal }),
shipping: '0.00',
total: calc('subtotal | =2', { subtotal })
}
}
calcWithShipping(88, 99, 8)
// { subtotal: '88.00', shipping: '8.00', total: '96.00' }
calcWithShipping(120, 99, 8)
// { subtotal: '120.00', shipping: '0.00', total: '120.00' }分摊计算
均摊优惠
javascript
import { calc, calc_sum } from 'a-calc'
const items = [
{ name: '商品A', price: 100 },
{ name: '商品B', price: 200 },
{ name: '商品C', price: 300 }
]
const totalDiscount = 60 // 总优惠60元
// 计算总价
const total = calc_sum('price', items) // '600'
// 按比例分摊优惠
const distributed = items.map(item => {
const ratio = calc('price / total', { price: item.price, total })
const itemDiscount = calc('discount * ratio | ~5=2', {
discount: totalDiscount,
ratio
})
const finalPrice = calc('price - itemDiscount | =2', {
price: item.price,
itemDiscount
})
return {
...item,
discount: itemDiscount,
finalPrice
}
})
// [
// { name: '商品A', price: 100, discount: '10.00', finalPrice: '90.00' },
// { name: '商品B', price: 200, discount: '20.00', finalPrice: '180.00' },
// { name: '商品C', price: 300, discount: '30.00', finalPrice: '270.00' }
// ]积分兑换
javascript
import { calc } from 'a-calc'
// 积分抵扣(100积分 = 1元)
function calcWithPoints(subtotal, points, pointsRatio = 100) {
const maxDeduction = calc('points / ratio', {
points,
ratio: pointsRatio
})
// 积分抵扣不能超过订单金额
const actualDeduction = calc(
`maxDeduction > subtotal ? subtotal : maxDeduction`,
{ maxDeduction, subtotal }
)
// 简化写法
const deduction = Math.min(
parseFloat(maxDeduction),
parseFloat(subtotal)
)
const usedPoints = calc('deduction * ratio | =0', {
deduction,
ratio: pointsRatio
})
return {
deduction: calc('deduction | =2', { deduction }),
usedPoints,
finalPrice: calc('subtotal - deduction | =2', { subtotal, deduction })
}
}
calcWithPoints(100, 5000)
// { deduction: '50.00', usedPoints: '5000', finalPrice: '50.00' }
calcWithPoints(30, 5000)
// { deduction: '30.00', usedPoints: '3000', finalPrice: '0.00' }价格展示
javascript
import { calc } from 'a-calc'
// 格式化价格展示
const formatPrice = (price) => calc('price | =2,', { price })
formatPrice(1234567.8) // '1,234,567.80'
formatPrice(99.9) // '99.90'
formatPrice(0.5) // '0.50'
// 带货币符号
const formatCNY = (price) => '¥' + calc('price | =2,', { price })
formatCNY(1234.56) // '¥1,234.56'Ctrl+D 选择词, Ctrl+/ 注释