AA制计算器

输入每个人花钱信息,直接计算出每个人应该付多少钱。

https://dataholdcn.cn/AAmoney

示例:

张三:32 # 买肉
李四:12 # 买土豆
张三:35 # 买番茄
王五:
这六:
展开/折叠结果
每人应交或返回的金额
王五: 19.75元(应交)
这六: 19.75元(应交)
李四: 7.75元(应交)
张三: 47.25元(应退)
支付分配情况
王五 应交 19.75元 给 张三
这六 应交 19.75元 给 张三
李四 应交 7.75元 给 张三

源代码:

<!DOCTYPE html>  
<html lang="zh">  
<head>  
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>AA制计算器</title>  
    <style>  
        body {  
            text-align: center;
            font-family: Arial, sans-serif;  
            margin: 20px;  
        }  
        textarea {  
            width: 100%;  
            height: 150px;  
        }  
        button {  
            margin-top: 10px;  
        }  
        .result {  
            margin-top: 20px;  
            border: 1px solid #ccc;  
            padding: 10px;  
        }  
    </style>  
</head>  
<body>  
    <h1>AA制计算器</h1>  
    <textarea id="input" placeholder="请输入信息,格式为:张三: 32 # 买肉"></textarea>  
    <button onclick="calculate()">计算</button>  
    <div class="result" id="result"></div> 

    <script>  
        function calculate() {  
            let input = document.getElementById('input').value.trim();  
            // 替换中文冒号为英文冒号  
            input = input.replace(/:/g, ':');  
            const lines = input.split('\n');  
            const expenses = {};  
            const contributions = {};  
            const allNames = new Set(); // 用于存储所有姓名  

            lines.forEach(line => {  
                const [info, note] = line.split('#').map(part => part.trim());  
                const [name, value] = info.split(':').map(part => part.trim());  

                // 添加姓名到集合中  
                allNames.add(name);  

                // 处理收入和支出  
                if (value.startsWith('+')) {  
                    const amount = parseFloat(value.slice(1));  
                    contributions[name] = (contributions[name] || 0) + amount; // 记录预收款  
                } else {  
                    const amount = parseFloat(value);  
                    if (!isNaN(amount)) {  
                        expenses[name] = (expenses[name] || 0) + amount; // 记录支出  
                    }  
                }  
            });  

            // 计算总支出  
            const totalExpense = Object.values(expenses).reduce((sum, val) => sum + val, 0);  
            const totalPeople = allNames.size; // 参与人数  
            const averageExpense = totalExpense / totalPeople; // 每人应负担的金额  

            // 计算每个人的应交或应退金额  
            const result = {};  
            allNames.forEach(name => {  
                const paid = contributions[name] || 0; // 个人预收款  
                const owed = expenses[name] || 0; // 个人支出  
                // 应交或应退金额 = 每人应负担的金额 - (支出 + 预收款)  
                result[name] = averageExpense - (owed + paid);   
            });  

            // 计算应交和应退的人  
            const payers = [];  
            const receivers = [];  

            allNames.forEach(name => {  
                if (result[name] > 0) {  
                    payers.push({ name, amount: result[name] }); // 应交的人  
                } else if (result[name] < 0) {  
                    receivers.push({ name, amount: -result[name] }); // 应退的人  
                }  
            });  

            // 按应退金额从高到低排序  
            receivers.sort((a, b) => b.amount - a.amount);  
            // 按应交金额从高到低排序  
            payers.sort((a, b) => b.amount - a.amount);  

            // 分配应交金额  
            let output = '<h3>每人应交或返回的金额</h3><ul>';  
            payers.forEach(payer => {  
                output += `<li>${payer.name}: ${payer.amount.toFixed(2)}元(应交)</li>`;  
            });  
            receivers.forEach(receiver => {  
                output += `<li>${receiver.name}: ${-result[receiver.name].toFixed(2)}元(应退)</li>`;  
            });  

            // 创建一个新的输出列表  
            let paymentOutput = '<h3>支付分配情况</h3><ul>';  

            // 分配应交金额给应退金额最多的人  
            payers.forEach(payer => {  
                let remaining = payer.amount;  
                for (let receiver of receivers) {  
                    if (remaining <= 0) break; // 如果没有剩余金额,退出  
                    if (receiver.amount > 0) {  
                        const payment = Math.min(remaining, receiver.amount);  
                        paymentOutput += `<li>${payer.name} 应交 ${payment.toFixed(2)}元 给 ${receiver.name}</li>`;  
                        remaining -= payment;  
                        receiver.amount -= payment; // 减少接收者的应退金额  
                    }  
                }  
            });  

            // 将支付分配情况添加到结果中  
            output += paymentOutput + '</ul>';  

            // output += '</ul>';  
            document.getElementById('result').innerHTML = output;  
        }  
    </script>  
</body>  
</html>

评论

发表回复