You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

收银台JavaScript代码功能异常:无法正确拆分找零面额

收银台找零面额拆分问题修复

问题说明

这款简易收银台需要实现以下功能:

  • 计算顾客支付金额与商品价格的找零
  • 找零前判断:若应找零金额大于收银机抽屉(cid)内可用现金,状态为INSUFFICIENT_FUNDS;若足够则为OPEN
  • 状态为OPEN时,找零需按抽屉内面额从大到小拆分并显示

当前代码存在问题:当应找零8.25美元时,预期显示Status: OPEN Five: $5, One: $3, Quarter: $0.25,但实际无法正确拆分面额。

错误原因

原代码中计算可用面额数量的逻辑错误:使用抽屉内该面额的总金额而非单张面额值来计算可找零数量,导致无法正确拆分出对应面额的金额。

修复后的完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Manny Cash Register</title>
    <link rel="stylesheet" href="">
</head>
<body>
    <main>
        <form>
            <h1>Manny Cash Register</h1>
            <div id="change-due" class="result-div"></div>
            <div class="cash-input">
                <label for="cash">Enter Cash From Customer:</label>
                <input id="cash" type="number" step="0.01" />
                <button type="submit" id="purchase-btn">Purchase</button>
            </div>
            <div class="total">Total: $3.26</div>
        </form>
        <div class="cid">
            <h4>Change in Drawer</h4>
            <div id="cid-display"></div>
        </div>
    </main>
    <script>
const changeDue = document.getElementById("change-due");
const cash = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");

// 商品价格
let price = 3.26;
// 收银机抽屉初始现金,格式:[面额名称, 总金额]
let cid = [
  ["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90],
  ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]
];
// 定义各面额的单张价值
const denominationValues = {
  "PENNY": 0.01,
  "NICKEL": 0.05,
  "DIME": 0.1,
  "QUARTER": 0.25,
  "ONE": 1,
  "FIVE": 5,
  "TEN": 10,
  "TWENTY": 20,
  "ONE HUNDRED": 100
};

purchaseBtn.addEventListener("click", (e) => {
  e.preventDefault();
  
  // 计算应找零金额,转换为浮点数避免精度问题
  let change = parseFloat(cash.value) - price;
  let changeStatus = "";
  let changeArray = [];

  // 处理支付金额不足的情况
  if (parseFloat(cash.value) < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }
  
  // 处理刚好支付的情况
  if (parseFloat(cash.value) === price) {
    changeDue.textContent = "No change due - customer paid with exact cash";
    return;
  }

  // 计算抽屉内总现金
  let totalCid = parseFloat(cid.reduce((acc, curr) => acc + curr[1], 0).toFixed(2));

  // 判断抽屉现金是否足够找零
  if (change > totalCid) {
    changeStatus = "INSUFFICIENT_FUNDS";
  } else {
    changeStatus = "OPEN";
    let remainingChange = parseFloat(change.toFixed(2));

    // 从大到小遍历面额
    for (let i = cid.length - 1; i >= 0; i--) {
      const denomName = cid[i][0];
      const denomTotal = cid[i][1];
      const denomValue = denominationValues[denomName];
      
      // 计算该面额最多能找零的数量:不超过剩余找零所需,也不超过抽屉内现有数量
      const maxNeeded = Math.floor(remainingChange / denomValue);
      const maxAvailable = Math.floor(denomTotal / denomValue);
      const count = Math.min(maxNeeded, maxAvailable);

      if (count > 0) {
        const amountToGive = parseFloat((count * denomValue).toFixed(2));
        // 添加到找零数组
        changeArray.push([denomName, amountToGive]);
        // 更新剩余找零金额
        remainingChange = parseFloat((remainingChange - amountToGive).toFixed(2));
        // 更新抽屉内该面额的剩余金额
        cid[i][1] = parseFloat((denomTotal - amountToGive).toFixed(2));
      }

      // 剩余找零为0时提前退出循环
      if (remainingChange <= 0.001) break;
    }

    // 如果仍有剩余找零无法拆分,标记为资金不足
    if (remainingChange > 0.001) {
        changeStatus = "INSUFFICIENT_FUNDS";
        changeArray = [];
    }
  } 

  // 渲染找零结果
  let changeString = changeArray.map(item => `${item[0]}: $${item[1]}`).join(", ");
  if (changeStatus === "INSUFFICIENT_FUNDS") {
    changeDue.textContent = `Status: ${changeStatus}`;
  } else {
    changeDue.textContent = `Status: ${changeStatus} ${changeString}`;
  }

  cash.value = "";
});
    </script>
</body>
</html>

修复要点

  1. 新增面额单张值定义:创建denominationValues对象,明确每个面额的单张价值,用于正确计算可找零数量
  2. 修正找零数量计算逻辑:分别计算剩余找零所需的最大面额数量、抽屉内可用的最大面额数量,取两者最小值作为实际找零数量
  3. 优化精度处理:全程使用parseFloat(...toFixed(2))避免浮点数精度误差
  4. 提前终止循环:剩余找零为0时提前退出循环,提升性能
  5. 完善结果渲染:资金不足时仅显示状态,避免空字符串干扰

内容的提问来源于stack exchange,提问作者anoghena kanoba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 14:20:02