Skip to content

电商场景

电商场景涉及大量价格计算,精度问题尤为重要。

价格计算

单品价格

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+/ 注释

基于 MIT 许可发布