let accounts = []; let retainedEarnings = null; let isLocked = false; function formatNumber(n) { return Number(n || 0).toLocaleString(); } function recalcTotals() { let debit = 0; let credit = 0; // 先算:不含繰越利益 accounts.forEach((a) => { if (a.account_name === "繰越利益") return; debit += Number(a.opening_debit || 0); credit += Number(a.opening_credit || 0); }); const diff = debit - credit; // 自动计算 繰越利益 if (retainedEarnings) { if (diff > 0) { retainedEarnings.opening_debit = 0; retainedEarnings.opening_credit = diff; } else { retainedEarnings.opening_debit = -diff; retainedEarnings.opening_credit = 0; } } // 再算一次(包含繰越利益) let finalDebit = 0; let finalCredit = 0; accounts.forEach((a) => { finalDebit += Number(a.opening_debit || 0); finalCredit += Number(a.opening_credit || 0); }); document.getElementById("totalDebit").innerText = formatNumber(finalDebit); document.getElementById("totalCredit").innerText = formatNumber(finalCredit); document.getElementById("diff").innerText = formatNumber( finalDebit - finalCredit ); } async function loadOpeningBalances() { const year = document.getElementById("fiscalYear").value; const data = await apiGet("/opening-balances", { fiscal_year: year }); accounts = data; retainedEarnings = accounts.find((a) => a.account_name === "繰越利益"); const tbody = document.querySelector("#balanceTable tbody"); tbody.innerHTML = ""; GROUPS.forEach((group) => { // 分组标题行 const headerTr = document.createElement("tr"); headerTr.innerHTML = `