{"id":895,"date":"2025-11-13T15:33:34","date_gmt":"2025-11-13T08:33:34","guid":{"rendered":"https:\/\/howdoi.id.vn\/?p=895"},"modified":"2025-11-13T15:33:34","modified_gmt":"2025-11-13T08:33:34","slug":"ngan-sach-thong-minh","status":"publish","type":"post","link":"https:\/\/howdoi.id.vn\/?p=895","title":{"rendered":"Ng\u00e2n s\u00e1ch th\u00f4ng minh"},"content":{"rendered":"\n<!doctype html>\n<html lang=\"vi\">\n<head>\n<meta charset=\"utf-8\" \/>\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" \/>\n<title>Ng\u00e2n s\u00e1ch th\u00f4ng minh<\/title>\n<style>\n  \/* ===== reset & base ===== *\/\n  *{box-sizing:border-box}\n  html,body{height:100%}\n  body{\n    margin:0;\n    font-family: \"Segoe UI\", Roboto, Arial, sans-serif;\n    background:#f5f7fa;\n    color:#223;\n    padding:20px;\n    display:flex;\n    justify-content:center;\n    align-items:flex-start;\n  }\n\n  \/* ===== container (matches previous neutral style) ===== *\/\n  .tool {\n    width:100%;\n    max-width:980px;\n    background:#fff;\n    border-radius:14px;\n    box-shadow:0 10px 30px rgba(12,30,50,0.08);\n    padding:22px;\n    transition:transform .18s ease;\n  }\n  .tool:active{transform:translateY(1px)}\n\n  header h1{margin:0;font-size:20px;color:#1f2d3d}\n  header p{margin:6px 0 16px;color:#667786;font-size:14px}\n\n  \/* ===== layout grid ===== *\/\n  .grid{\n    display:grid;\n    grid-template-columns: 1fr 360px;\n    gap:18px;\n  }\n  @media (max-width:980px){ .grid{grid-template-columns:1fr} }\n\n  \/* ===== left panel ===== *\/\n  .panel{\n    background:linear-gradient(0deg, rgba(250,251,253,1), #fff);\n    padding:14px;border-radius:12px;border:1px solid #eef3f7;\n  }\n\n  label{display:block;font-weight:600;color:#34495e;font-size:13px;margin-bottom:8px}\n  .row{display:flex;gap:10px;align-items:center;margin-bottom:12px}\n  .col{flex:1}\n\n  input[type=\"number\"], input[type=\"text\"], select{\n    width:100%;padding:10px;border-radius:8px;border:1px solid #d3dce6;font-size:14px;\n    background:#fff;color:#233;\n  }\n  input[type=\"number\"]:focus, input[type=\"text\"]:focus, select:focus{outline:none;border-color:#6ea8ff;box-shadow:0 6px 20px rgba(110,168,255,0.07)}\n\n  .btn {\n    display:inline-flex;align-items:center;justify-content:center;\n    padding:10px 12px;border-radius:9px;border:none;cursor:pointer;\n    background:linear-gradient(90deg,#6ea8ff,#7be0ff);color:#042433;font-weight:700;\n  }\n  .btn.ghost{background:transparent;border:1px solid #d8e6f7;color:#274552;font-weight:600}\n  .actions{display:flex;gap:8px;margin-top:8px}\n\n  \/* ===== expenses list ===== *\/\n  .expenses{\n    margin-top:8px;border-radius:10px;border:1px dashed #e6eef6;padding:10px;background:#fbfdff;\n  }\n  .expense-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}\n  .expense-row input{padding:8px;font-size:14px}\n  .expense-row .remove{background:#ffecec;border:1px solid #ffd6d6;color:#b33;padding:6px 8px;border-radius:8px;cursor:pointer}\n\n  .small{font-size:13px;color:#6b7886}\n\n  \/* ===== right panel visuals ===== *\/\n  .summary{\n    padding:14px;border-radius:12px;background:linear-gradient(180deg,#ffffff,#fbfdff);border:1px solid #eef3f7;\n    display:flex;flex-direction:column;gap:12px;\n  }\n  .metric{display:flex;justify-content:space-between;align-items:center;padding:6px 4px}\n  .metric .label{color:#526271}\n  .metric .value{font-weight:700;color:#123;}\n\n  .bars{display:flex;flex-direction:column;gap:10px;margin-top:8px}\n  .bar {\n    background:#eef4fb;border-radius:999px;padding:6px 8px;display:flex;align-items:center;gap:10px;\n  }\n  .bar .meta{flex:1}\n  .bar .track{height:12px;background:#e6eef7;border-radius:999px;overflow:hidden}\n  .bar .fill{height:100%;width:0;background:linear-gradient(90deg,#6ea8ff,#7be0ff);border-radius:999px;transition:width .9s cubic-bezier(.2,.9,.3,1)}\n  .bar .num{width:90px;text-align:right;font-weight:700;color:#123}\n\n  \/* ===== envelope panel ===== *\/\n  .envelopes{display:grid;grid-template-columns:1fr 1fr;gap:10px}\n  @media (max-width:480px){ .envelopes{grid-template-columns:1fr} }\n  .envelope{background:#fff;border-radius:10px;padding:10px;border:1px solid #eef6ff}\n  .envelope h5{margin:0;font-size:14px;color:#2b3f50}\n  .envelope .amt{font-weight:800;margin-top:6px}\n\n  \/* ===== analytics & definitions ===== *\/\n  .analytics{background:#fff;border-radius:10px;padding:12px;border:1px solid #eef4f9}\n  .analytics h4{margin:0 0 8px 0}\n  .definition{font-size:13px;color:#55666f;background:#fbfdff;padding:10px;border-radius:8px;border-left:4px solid #6ea8ff}\n\n  \/* ===== footer small ===== *\/\n  footer{margin-top:12px;font-size:13px;color:#65787f}\n\n  \/* subtle appear animation *\/\n  .fade-in{opacity:0;transform:translateY(8px);animation:fade .45s forwards}\n  @keyframes fade{to{opacity:1;transform:none}}\n<\/style>\n<\/head>\n<body>\n  <div class=\"tool fade-in\" role=\"application\" aria-label=\"Ng\u00e2n s\u00e1ch th\u00f4ng minh\">\n    <header>\n      <h1>Ng\u00e2n s\u00e1ch th\u00f4ng minh<\/h1>\n      <p>Thi\u1ebft l\u1eadp ng\u00e2n s\u00e1ch theo 50\/30\/20 (v\u00e0 bi\u1ebfn th\u1ec3), theo d\u00f5i chi ti\u00eau, t\u1ea1o phong b\u00ec v\u00e0 x\u00e2y qu\u1ef9 kh\u1ea9n c\u1ea5p \u2014 cho ng\u01b0\u1eddi Vi\u1ec7t.<\/p>\n    <\/header>\n\n    <div class=\"grid\" style=\"margin-top:12px\">\n      <!-- LEFT: inputs & expense tracker -->\n      <div class=\"panel\" aria-label=\"Inputs\">\n        <label for=\"salary\">L\u01b0\u01a1ng ch\u00ednh (\u20ab \/ th\u00e1ng)<\/label>\n        <div class=\"row\">\n          <input id=\"salary\" type=\"number\" placeholder=\"Nh\u1eadp l\u01b0\u01a1ng ch\u00ednh...\" \/>\n          <input id=\"extraIncome\" type=\"number\" placeholder=\"Thu nh\u1eadp ph\u1ee5 (n\u1ebfu c\u00f3)...\" \/>\n        <\/div>\n        <div class=\"small\">Nh\u1eadp t\u1ed5ng thu nh\u1eadp: l\u01b0\u01a1ng ch\u00ednh + c\u00e1c kho\u1ea3n th\u00eam<\/div>\n\n        <hr style=\"margin:12px 0;border:none;border-top:1px dashed #e8f0f8\" \/>\n\n        <label>Chi ti\u00eau h\u00e0ng th\u00e1ng (th\u00eam nh\u00f3m)<\/label>\n        <div class=\"expenses\" id=\"expensesList\" aria-live=\"polite\">\n          <!-- dynamic expense rows go here -->\n        <\/div>\n        <div style=\"display:flex;gap:8px;margin-top:8px\">\n          <button class=\"btn\" id=\"addExpenseBtn\" type=\"button\">+ Th\u00eam kho\u1ea3n chi<\/button>\n          <button class=\"btn ghost\" id=\"clearExpensesBtn\" type=\"button\">X\u00f3a to\u00e0n b\u1ed9<\/button>\n        <\/div>\n\n        <hr style=\"margin:12px 0;border:none;border-top:1px dashed #e8f0f8\" \/>\n\n        <label>Ch\u1ecdn quy t\u1eafc ph\u00e2n b\u1ed5<\/label>\n        <div class=\"row\" style=\"align-items:center\">\n          <select id=\"ruleSelect\">\n            <option value=\"50-30-20\">50% Nhu c\u1ea7u \/ 30% Gi\u1ea3i tr\u00ed \/ 20% Ti\u1ebft ki\u1ec7m<\/option>\n            <option value=\"debt-first\">30% Tr\u1ea3 n\u1ee3 \/ 20% Gi\u1ea3i tr\u00ed \/ 50% Nhu c\u1ea7u (\u01afu ti\u00ean tr\u1ea3 n\u1ee3)<\/option>\n            <option value=\"custom\">T\u00f9y ch\u1ec9nh<\/option>\n          <\/select>\n        <\/div>\n\n        <div id=\"customInputs\" style=\"display:none;margin-top:10px\">\n          <div class=\"row\">\n            <input id=\"cNeeds\" type=\"number\" placeholder=\"T\u1ef7 l\u1ec7 Nhu c\u1ea7u (%)\" \/>\n            <input id=\"cWants\" type=\"number\" placeholder=\"T\u1ef7 l\u1ec7 Gi\u1ea3i tr\u00ed (%)\" \/>\n            <input id=\"cSave\" type=\"number\" placeholder=\"T\u1ef7 l\u1ec7 Ti\u1ebft ki\u1ec7m (%)\" \/>\n          <\/div>\n          <div class=\"small\">Nh\u1eadp t\u1ef7 l\u1ec7 (%) \u2014 t\u1ed5ng ph\u1ea3i = 100%<\/div>\n        <\/div>\n\n        <div class=\"actions\" style=\"margin-top:12px\">\n          <button class=\"btn\" id=\"calcBtn\">T\u00ednh &#038; Ph\u00e2n t\u00edch<\/button>\n          <button class=\"btn ghost\" id=\"saveProfileBtn\">L\u01b0u profile<\/button>\n        <\/div>\n\n        <div style=\"margin-top:10px;display:flex;gap:8px\">\n          <input id=\"profileName\" type=\"text\" placeholder=\"T\u00ean profile (v\u00ed d\u1ee5: Th\u00e1ng 7)\" style=\"flex:1\" \/>\n          <button class=\"btn ghost\" id=\"loadProfileBtn\">T\u1ea3i<\/button>\n        <\/div>\n\n        <footer>\n          <div class=\"small\">M\u1eb9o: n\u1ebfu \u0111ang c\u00f3 n\u1ee3, ch\u1ecdn <strong>\u01afu ti\u00ean tr\u1ea3 n\u1ee3<\/strong> \u0111\u1ec3 t\u0103ng t\u1ef7 l\u1ec7 tr\u1ea3 n\u1ee3.<\/div>\n        <\/footer>\n      <\/div>\n\n      <!-- RIGHT: summary, bars, envelopes -->\n      <aside class=\"panel summary\" aria-live=\"polite\">\n        <div>\n          <div class=\"metric\"><div class=\"label\">T\u1ed5ng thu nh\u1eadp<\/div><div class=\"value\" id=\"totalIncome\">\u20ab0<\/div><\/div>\n          <div class=\"metric\"><div class=\"label\">T\u1ed5ng chi ti\u00eau<\/div><div class=\"value\" id=\"totalExpense\">\u20ab0<\/div><\/div>\n          <div class=\"metric\"><div class=\"label\">S\u1ed1 c\u00f2n l\u1ea1i<\/div><div class=\"value\" id=\"leftover\">\u20ab0<\/div><\/div>\n        <\/div>\n\n        <div style=\"margin-top:6px\">\n          <div class=\"small\">Ph\u00e2n b\u1ed5 \u0111\u1ec1 xu\u1ea5t<\/div>\n          <div class=\"bars\" id=\"allocBars\" style=\"margin-top:8px\">\n            <!-- bars: Needs \/ Wants \/ Save -->\n            <div class=\"bar\">\n              <div class=\"meta\"><div style=\"font-size:13px;color:#3a5566\">Nhu c\u1ea7u (Essentials)<\/div>\n                <div class=\"track\"><div class=\"fill\" id=\"fillNeeds\" style=\"width:0%\"><\/div><\/div>\n              <\/div>\n              <div class=\"num\" id=\"numNeeds\">0%<\/div>\n            <\/div>\n\n            <div class=\"bar\">\n              <div class=\"meta\"><div style=\"font-size:13px;color:#3a5566\">Gi\u1ea3i tr\u00ed (Wants)<\/div>\n                <div class=\"track\"><div class=\"fill\" id=\"fillWants\" style=\"width:0%\"><\/div><\/div>\n              <\/div>\n              <div class=\"num\" id=\"numWants\">0%<\/div>\n            <\/div>\n\n            <div class=\"bar\">\n              <div class=\"meta\"><div style=\"font-size:13px;color:#3a5566\">Ti\u1ebft ki\u1ec7m &#038; tr\u1ea3 n\u1ee3 (Save)<\/div>\n                <div class=\"track\"><div class=\"fill\" id=\"fillSave\" style=\"width:0%\"><\/div><\/div>\n              <\/div>\n              <div class=\"num\" id=\"numSave\">0%<\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n\n        <div style=\"margin-top:10px\">\n          <div class=\"small\">Phong b\u00ec chi ti\u00eau<\/div>\n          <div class=\"envelopes\" id=\"envelopeBox\" style=\"margin-top:8px\">\n            <!-- envelopes dynamically generated -->\n          <\/div>\n        <\/div>\n\n        <div style=\"margin-top:10px\">\n          <div class=\"small\">Qu\u1ef9 kh\u1ea9n c\u1ea5p \u0111\u1ec1 xu\u1ea5t<\/div>\n          <div style=\"display:flex;align-items:center;gap:10px;margin-top:6px\">\n            <div style=\"flex:1\">\n              <input id=\"emergencyMonthly\" type=\"number\" placeholder=\"S\u1ed1 ti\u1ec1n b\u1ea1n mu\u1ed1n \u0111\u1ec3 d\u00e0nh \/ th\u00e1ng (v\u00ed d\u1ee5 300000)\" \/>\n              <div class=\"small\" style=\"margin-top:6px\">G\u1ee3i \u00fd: 300.000 &#8211; 500.000 VN\u0110 \/ th\u00e1ng (t\u00f9y thu nh\u1eadp)<\/div>\n            <\/div>\n            <button class=\"btn ghost\" id=\"setEmergencyBtn\" style=\"height:40px\">\u0110\u1eb7t<\/button>\n          <\/div>\n        <\/div>\n\n        <div style=\"margin-top:12px\" class=\"analytics\">\n          <h4>Ph\u00e2n t\u00edch nhanh<\/h4>\n          <div id=\"quickInsights\" style=\"font-size:13px;color:#466372\">Ch\u01b0a c\u00f3 d\u1eef li\u1ec7u. Nh\u1eadp thu nh\u1eadp v\u00e0 chi ti\u00eau r\u1ed3i b\u1ea5m &#8220;T\u00ednh &#038; Ph\u00e2n t\u00edch&#8221;.<\/div>\n        <\/div>\n      <\/aside>\n    <\/div>\n\n  <\/div>\n\n<script>\n(function(){\n  \/\/ Helpers\n  const $ = id => document.getElementById(id);\n  const fmt = n => {\n    n = Number(n) || 0;\n    return '\u20ab' + n.toString().replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, '.');\n  };\n  const pct = v => (isFinite(v) ? v.toFixed(0) + '%' : '0%');\n\n  \/\/ initial expense categories (common VN groups)\n  const defaultExpenses = [\n    {cat:'Nh\u00e0 \u1edf (ti\u1ec1n thu\u00ea\/\u0111i\u1ec7n\/n\u01b0\u1edbc)', amount:0},\n    {cat:'\u0102n u\u1ed1ng', amount:0},\n    {cat:'Di chuy\u1ec3n', amount:0},\n    {cat:'Internet\/\u0111i\u1ec7n tho\u1ea1i', amount:0},\n    {cat:'Gi\u1ea3i tr\u00ed\/Mua s\u1eafm', amount:0},\n    {cat:'Kh\u00e1c', amount:0}\n  ];\n\n  \/\/ state\n  let expenses = JSON.parse(localStorage.getItem('smartBudget_expenses')) || defaultExpenses.slice();\n  let emergencyMonthly = Number(localStorage.getItem('smartBudget_emergency')) || 0;\n\n  \/\/ render expenses list\n  function renderExpenses(){\n    const list = $('expensesList');\n    list.innerHTML = '';\n    expenses.forEach((e,i)=>{\n      const row = document.createElement('div');\n      row.className = 'expense-row';\n      row.innerHTML = `\n        <input type=\"text\" class=\"col\" value=\"${escapeHtml(e.cat)}\" data-i=\"${i}\" data-type=\"name\" \/>\n        <input type=\"number\" style=\"width:150px\" value=\"${e.amount||0}\" data-i=\"${i}\" data-type=\"amt\" \/>\n        <button class=\"remove\" data-i=\"${i}\" title=\"X\u00f3a\">X<\/button>\n      `;\n      list.appendChild(row);\n    });\n    \/\/ attach handlers\n    list.querySelectorAll('input[data-type=\"name\"]').forEach(el=>{\n      el.addEventListener('change', (ev)=>{\n        const idx=+ev.target.dataset.i; expenses[idx].cat = ev.target.value.trim() || 'Kh\u00e1c';\n        saveState();\n      });\n    });\n    list.querySelectorAll('input[data-type=\"amt\"]').forEach(el=>{\n      el.addEventListener('input', (ev)=>{\n        const idx=+ev.target.dataset.i; expenses[idx].amount = Number(ev.target.value)||0;\n      });\n    });\n    list.querySelectorAll('.remove').forEach(btn=>{\n      btn.addEventListener('click', (ev)=>{\n        const idx=+btn.dataset.i; expenses.splice(idx,1); renderExpenses(); saveState();\n      });\n    });\n  }\n\n  \/\/ add expense\n  $('addExpenseBtn').addEventListener('click', ()=>{\n    expenses.push({cat:'Kho\u1ea3n m\u1edbi', amount:0}); renderExpenses(); saveState();\n  });\n  $('clearExpensesBtn').addEventListener('click', ()=>{\n    if(!confirm('X\u00f3a t\u1ea5t c\u1ea3 kho\u1ea3n chi?')) return;\n    expenses = []; renderExpenses(); saveState();\n  });\n\n  \/\/ rule select\n  $('ruleSelect').addEventListener('change', (e)=>{\n    if(e.target.value === 'custom') $('customInputs').style.display = 'block';\n    else $('customInputs').style.display = 'none';\n  });\n\n  \/\/ save\/load profile\n  $('saveProfileBtn').addEventListener('click', ()=>{\n    const name = $('profileName').value.trim();\n    if(!name){ alert('Nh\u1eadp t\u00ean profile \u0111\u1ec3 l\u01b0u (v\u00ed d\u1ee5: Th\u00e1ng 7)'); return; }\n    const payload = {\n      incomes:{ salary: Number($('salary').value)||0, extra: Number($('extraIncome').value)||0 },\n      expenses,\n      rule: $('ruleSelect').value,\n      custom: { needs: Number($('cNeeds').value)||0, wants: Number($('cWants').value)||0, save: Number($('cSave').value)||0 },\n      emergencyMonthly\n    };\n    localStorage.setItem('smartBudget_profile_' + name, JSON.stringify(payload));\n    alert('\u0110\u00e3 l\u01b0u profile: ' + name);\n  });\n\n  $('loadProfileBtn').addEventListener('click', ()=>{\n    const name = $('profileName').value.trim();\n    if(!name){ alert('Nh\u1eadp t\u00ean profile c\u1ea7n t\u1ea3i'); return; }\n    const raw = localStorage.getItem('smartBudget_profile_' + name);\n    if(!raw){ alert('Kh\u00f4ng t\u00ecm th\u1ea5y profile: ' + name); return; }\n    const p = JSON.parse(raw);\n    $('salary').value = p.incomes.salary || 0;\n    $('extraIncome').value = p.incomes.extra || 0;\n    expenses = p.expenses || [];\n    $('ruleSelect').value = p.rule || '50-30-20';\n    if(p.rule === 'custom'){ $('customInputs').style.display = 'block'; $('cNeeds').value = p.custom.needs; $('cWants').value = p.custom.wants; $('cSave').value = p.custom.save; }\n    emergencyMonthly = p.emergencyMonthly || 0;\n    $('emergencyMonthly').value = emergencyMonthly || '';\n    renderExpenses(); computeAndRender();\n    alert('\u0110\u00e3 t\u1ea3i profile: ' + name);\n  });\n\n  \/\/ set emergency\n  $('setEmergencyBtn').addEventListener('click', ()=>{\n    emergencyMonthly = Number($('emergencyMonthly').value) || 0;\n    localStorage.setItem('smartBudget_emergency', emergencyMonthly);\n    alert('\u0110\u00e3 \u0111\u1eb7t qu\u1ef9 kh\u1ea9n c\u1ea5p h\u00e0ng th\u00e1ng: ' + fmt(emergencyMonthly));\n  });\n\n  \/\/ compute & render allocations\n  $('calcBtn').addEventListener('click', computeAndRender);\n\n  function computeAndRender(){\n    \/\/ incomes\n    const salary = Number($('salary').value)||0;\n    const extra = Number($('extraIncome').value)||0;\n    const totalIncome = Math.max(0, salary + extra);\n\n    \/\/ totals expense\n    const totalExp = expenses.reduce((s,it)=> s + (Number(it.amount)||0), 0);\n\n    \/\/ determine allocation ratios\n    let needsPct = 50, wantsPct = 30, savePct = 20;\n    const rule = $('ruleSelect').value;\n    if(rule === 'debt-first'){ needsPct=50; wantsPct=20; savePct=30; } \/\/ user wanted reversed earlier (we keep labeling but allocate more to save\/debt)\n    if(rule === 'custom'){\n      const a = Number($('cNeeds').value)||0;\n      const b = Number($('cWants').value)||0;\n      const c = Number($('cSave').value)||0;\n      if(a + b + c === 100){ needsPct=a; wantsPct=b; savePct=c; }\n      else { alert('T\u1ed5ng % t\u00f9y ch\u1ec9nh ph\u1ea3i b\u1eb1ng 100%.'); return; }\n    }\n\n    \/\/ allocation amounts\n    const needAmt = Math.round(totalIncome * needsPct \/ 100);\n    const wantAmt = Math.round(totalIncome * wantsPct \/ 100);\n    const saveAmt = Math.round(totalIncome * savePct \/ 100);\n\n    \/\/ leftover\n    const leftover = totalIncome - totalExp;\n\n    \/\/ fill bars percentages (how much of allocation used by actual spending)\n    \/\/ For simplicity, map particular expense groups to Needs\/Wants heuristics by matching keywords\n    const needsKeywords = ['nh\u00e0','ti\u1ec1n thu\u00ea','\u0103n u\u1ed1ng','\u0111i\u1ec7n','n\u01b0\u1edbc','internet','\u0111i\u1ec7n tho\u1ea1i','\u0111i l\u1ea1i','di chuy\u1ec3n','x\u0103ng','thu\u00ea'];\n    const wantsKeywords = ['gi\u1ea3i tr\u00ed','mua s\u1eafm','qu\u00e0','shopping','cafe','\u0103n v\u1eb7t','tiktok','netflix'];\n    let needsSpent = 0, wantsSpent = 0, others = 0;\n    expenses.forEach(it=>{\n      const name = (it.cat || '').toLowerCase();\n      const amt = Number(it.amount)||0;\n      if(needsKeywords.some(k=> name.includes(k))){ needsSpent += amt; }\n      else if(wantsKeywords.some(k=> name.includes(k))){ wantsSpent += amt; }\n      else others += amt;\n    });\n    const totalMapped = needsSpent + wantsSpent + others;\n    \/\/ If user left groups empty, fallback: assume all expense -> needs\n    if(totalExp > 0 && totalMapped === 0) needsSpent = totalExp;\n\n    \/\/ perc used\n    const needsUsedPct = needAmt ? Math.min(100, Math.round((needsSpent \/ needAmt) * 100)) : 0;\n    const wantsUsedPct = wantAmt ? Math.min(100, Math.round((wantsSpent \/ wantAmt) * 100)) : 0;\n    const saveUsedPct = saveAmt ? Math.min(100, Math.round(((totalExp - (needsSpent + wantsSpent)) \/ saveAmt) * 100)) : 0;\n\n    \/\/ envelopes: create 4 envelopes (Essentials, Wants, Save, Emergency)\n    const envelopes = [\n      {name:'Nhu c\u1ea7u (Essentials)', amt: needAmt},\n      {name:'Gi\u1ea3i tr\u00ed (Wants)', amt: wantAmt},\n      {name:'Ti\u1ebft ki\u1ec7m\/Tr\u1ea3 n\u1ee3 (Save)', amt: saveAmt},\n      {name:'Qu\u1ef9 kh\u1ea9n c\u1ea5p (Emergency)', amt: emergencyMonthly || 0}\n    ];\n\n    \/\/ quick insights\n    let insights = [];\n    if(totalIncome === 0) insights.push('B\u1ea1n ch\u01b0a nh\u1eadp thu nh\u1eadp. H\u00e3y nh\u1eadp \u0111\u1ec3 nh\u1eadn g\u1ee3i \u00fd ph\u00e2n b\u1ed5.');\n    else {\n      insights.push(`T\u1ed5ng thu nh\u1eadp: ${fmt(totalIncome)}. T\u1ed5ng chi ti\u00eau \u0111\u00e3 nh\u1eadp: ${fmt(totalExp)}.`);\n      if(totalExp > totalIncome) insights.push('C\u1ea3nh b\u00e1o: chi ti\u00eau \u0111ang v\u01b0\u1ee3t thu nh\u1eadp \u2014 c\u1ea7n xem l\u1ea1i c\u00e1c kho\u1ea3n \"Gi\u1ea3i tr\u00ed\" ho\u1eb7c gi\u1ea3m chi ph\u00ed.');\n      else insights.push(`B\u1ea1n c\u00f2n l\u1ea1i sau chi ti\u00eau: ${fmt(leftover)}.`);\n\n      \/\/ advice about emergency\n      if((emergencyMonthly || 0) === 0) insights.push('G\u1ee3i \u00fd: \u0111\u1eb7t qu\u1ef9 kh\u1ea9n c\u1ea5p 300k\u2013500k \/ th\u00e1ng \u0111\u1ec3 d\u1ef1 ph\u00f2ng r\u1ee7i ro.');\n      else insights.push(`Qu\u1ef9 kh\u1ea9n c\u1ea5p hi\u1ec7n \u0111\u1eb7t: ${fmt(emergencyMonthly)} \/ th\u00e1ng.`);\n\n      \/\/ check needs coverage\n      if(needsUsedPct > 100) insights.push('L\u01b0u \u00fd: kho\u1ea3n \"Nhu c\u1ea7u\" \u0111\u00e3 v\u01b0\u1ee3t m\u1ee9c khuy\u1ebfn ngh\u1ecb \u2014 c\u00e2n nh\u1eafc gi\u1ea3m chi ho\u1eb7c t\u0103ng thu nh\u1eadp.');\n      if(wantsUsedPct > 100) insights.push('L\u01b0u \u00fd: kho\u1ea3n \"Gi\u1ea3i tr\u00ed\" v\u01b0\u1ee3t m\u1ee9c \u2014 th\u1eed gi\u1ea3m l\u1ea7n mua ngo\u00e0i \u00fd mu\u1ed1n.');\n      \/\/ small tip\n      if(leftover >= saveAmt) insights.push('T\u1ed1t \u2014 b\u1ea1n c\u00f3 th\u1ec3 \u0111\u1ea3m b\u1ea3o m\u1ee9c ti\u1ebft ki\u1ec7m d\u1ef1 ki\u1ebfn.');\n      else if(leftover > 0) insights.push('B\u1ea1n c\u00f2n d\u01b0 nh\u01b0ng ch\u01b0a \u0111\u1ee7 cho m\u1ee5c ti\u00eau ti\u1ebft ki\u1ec7m \u2014 \u01b0u ti\u00ean c\u1eaft gi\u1ea3m Gi\u1ea3i tr\u00ed.');\n    }\n\n    \/\/ render right panel summary\n    $('totalIncome').textContent = fmt(totalIncome);\n    $('totalExpense').textContent = fmt(totalExp);\n    $('leftover').textContent = fmt(leftover);\n\n    \/\/ render allocation bars\n    $('fillNeeds').style.width = (needsUsedPct) + '%';\n    $('fillWants').style.width = (wantsUsedPct) + '%';\n    $('fillSave').style.width = Math.min(100, Math.round(( (totalExp - (needsSpent + wantsSpent)) \/ (saveAmt || 1) ) * 100)) + '%';\n    $('numNeeds').textContent = needsPct + '% (' + fmt(needAmt) + ')';\n    $('numWants').textContent = wantsPct + '% (' + fmt(wantAmt) + ')';\n    $('numSave').textContent = savePct + '% (' + fmt(saveAmt) + ')';\n\n    \/\/ render envelopes\n    const envBox = $('envelopeBox'); envBox.innerHTML = '';\n    envelopes.forEach((en,idx)=>{\n      const el = document.createElement('div'); el.className='envelope';\n      el.innerHTML = `<h5>${escapeHtml(en.name)}<\/h5><div class=\"amt\">${fmt(en.amt)}<\/div><div class=\"small\">S\u1eed d\u1ee5ng: ${idx===0?fmt(needsSpent): idx===1?fmt(wantsSpent): idx===2?fmt(totalExp - (needsSpent + wantsSpent)):fmt(emergencyMonthly)}<\/div>`;\n      envBox.appendChild(el);\n    });\n\n    \/\/ show analytics \/ quick insights\n    const qi = $('quickInsights');\n    qi.innerHTML = insights.map(i=>'<div style=\"margin-bottom:6px\">'+escapeHtml(i)+'<\/div>').join('');\n\n    \/\/ show allocation detail & save to localStorage state\n    saveState();\n\n    \/\/ scroll to results\n    document.querySelector('.summary').scrollIntoView({behavior:'smooth', block:'center'});\n  }\n\n  \/\/ save state to localStorage\n  function saveState(){\n    try{\n      localStorage.setItem('smartBudget_expenses', JSON.stringify(expenses));\n      localStorage.setItem('smartBudget_emergency', emergencyMonthly||0);\n    }catch(e){ console.warn('Cannot save state', e) }\n  }\n\n  \/\/ helpers escapes\n  function escapeHtml(s){ return String(s||'').replace(\/[&<>\"']\/g, c=>({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;',\"'\":'&#39;'}[c])) }\n\n  \/\/ init render\n  renderExpenses();\n  if(emergencyMonthly) $('emergencyMonthly').value = emergencyMonthly;\n  \/\/ optional: prefill salary for demo\n  \/\/ $('salary').value = 12000000;\n\n  \/\/ allow pressing Enter on amount to compute\n  document.addEventListener('keydown', (e)=>{\n    if(e.key === 'Enter' && (document.activeElement.tagName === 'INPUT')) {\n      e.preventDefault();\n      computeAndRender();\n    }\n  });\n\n})();\n<\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>Ng\u00e2n s\u00e1ch th\u00f4ng minh Ng\u00e2n s\u00e1ch th\u00f4ng minh Thi\u1ebft l\u1eadp ng\u00e2n s\u00e1ch theo 50\/30\/20 (v\u00e0 bi\u1ebfn th\u1ec3), theo d\u00f5i chi ti\u00eau, t\u1ea1o phong b\u00ec v\u00e0 x\u00e2y qu\u1ef9 kh\u1ea9n c\u1ea5p \u2014 cho ng\u01b0\u1eddi Vi\u1ec7t. L\u01b0\u01a1ng ch\u00ednh (\u20ab \/ th\u00e1ng) Nh\u1eadp t\u1ed5ng thu nh\u1eadp: l\u01b0\u01a1ng ch\u00ednh + c\u00e1c kho\u1ea3n th\u00eam Chi ti\u00eau h\u00e0ng th\u00e1ng (th\u00eam nh\u00f3m) + [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[49],"tags":[],"class_list":["post-895","post","type-post","status-publish","format-standard","hentry","category-cong-cu-cua-toi"],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":719,"url":"https:\/\/howdoi.id.vn\/?p=719","url_meta":{"origin":895,"position":0},"title":"B\u1ea1n \u0111\u00e3 ti\u00eau bao nhi\u00eau tu\u1ed5i th\u1ecd?","author":"admin","date":"April 22, 2025","format":false,"excerpt":"M\u1ed7i m\u00f3n \u0111\u1ed3 b\u1ea1n mua kh\u00f4ng ch\u1ec9 l\u00e0 ti\u1ec1n \u2013 m\u00e0 c\u00f2n l\u00e0 th\u1eddi gian b\u1ea1n ph\u1ea3i lao \u0111\u1ed9ng \u0111\u1ec3 c\u00f3 \u0111\u01b0\u1ee3c. H\u00e3y d\u00f9ng c\u00f4ng c\u1ee5 n\u00e0y \u0111\u1ec3 xem b\u1ea1n \u0111ang \u201c\u0111\u00e1nh \u0111\u1ed5i\u201d bao nhi\u00eau gi\u1edd cu\u1ed9c \u0111\u1eddi cho m\u1ed7i m\u00f3n \u0111\u1ed3 m\u00ecnh chi ti\u00eau. M\u1ed9t c\u00e1ch c\u1ef1c hay \u0111\u1ec3\u2026","rel":"","context":"In &quot;C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I&quot;","block_context":{"text":"C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I","link":"https:\/\/howdoi.id.vn\/?cat=49"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/ban-da-ton-bao-nhieu-tuoi-tho.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/ban-da-ton-bao-nhieu-tuoi-tho.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/ban-da-ton-bao-nhieu-tuoi-tho.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/ban-da-ton-bao-nhieu-tuoi-tho.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/ban-da-ton-bao-nhieu-tuoi-tho.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/ban-da-ton-bao-nhieu-tuoi-tho.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":695,"url":"https:\/\/howdoi.id.vn\/?p=695","url_meta":{"origin":895,"position":1},"title":"Mu\u1ed1n mua th\u1ee9 n\u00e0y? B\u1ea1n ph\u1ea3i c\u00e0y bao nhi\u00eau gi\u1edd?","author":"admin","date":"April 22, 2025","format":false,"excerpt":"\ud83d\udcb0 C\u00e0y Bao Nhi\u00eau Gi\u1edd? l\u00e0 c\u00f4ng c\u1ee5 gi\u00fap b\u1ea1n quy \u0111\u1ed5i gi\u00e1 m\u00f3n \u0111\u1ed3 y\u00eau th\u00edch th\u00e0nh s\u1ed1 gi\u1edd b\u1ea1n ph\u1ea3i l\u00e0m vi\u1ec7c \u0111\u1ec3 mua \u0111\u01b0\u1ee3c n\u00f3. Kh\u00f4ng ch\u1ec9 l\u00e0 con s\u1ed1, m\u00e0 l\u00e0 c\u00e1ch \u0111\u1ec3 b\u1ea1n hi\u1ec3u r\u00f5 h\u01a1n gi\u00e1 tr\u1ecb th\u1eddi gian v\u00e0 ti\u1ec1n b\u1ea1c c\u1ee7a m\u00ecnh.\u2026","rel":"","context":"In &quot;C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I&quot;","block_context":{"text":"C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I","link":"https:\/\/howdoi.id.vn\/?cat=49"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":674,"url":"https:\/\/howdoi.id.vn\/?p=674","url_meta":{"origin":895,"position":2},"title":"C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I","author":"admin","date":"April 22, 2025","format":false,"excerpt":"\u0110\u00e2y l\u00e0 n\u01a1i t\u00f4i mu\u1ed1n chia s\u1ebd nh\u1eefng c\u00f4ng c\u1ee5 c\u00f3 \u00edch cho con \u0111\u01b0\u1eddng t\u00e0i ch\u00ednh c\u1ee7a b\u1ea1n Th\u1eddi gian \u0111\u1ec3 mua m\u00f3n \u0111\u1ed3 n\u00e0y Mu\u1ed1n mua th\u1ee9 n\u00e0y? B\u1ea1n ph\u1ea3i c\u00e0y bao nhi\u00eau gi\u1edd? M\u1ee9c l\u01b0\u01a1ng m\u1ed7i gi\u1edd c\u1ee7a b\u1ea1n (VND): Gi\u00e1 m\u00f3n \u0111\u1ed3 b\u1ea1n mu\u1ed1n mua (VND):\u2026","rel":"","context":"In &quot;N\u1ee2 C\u1ee6A T\u00d4I&quot;","block_context":{"text":"N\u1ee2 C\u1ee6A T\u00d4I","link":"https:\/\/howdoi.id.vn\/?cat=1"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":859,"url":"https:\/\/howdoi.id.vn\/?p=859","url_meta":{"origin":895,"position":3},"title":"B\u1ea3ng T\u00ednh L\u1ee3i Nhu\u1eadn Kinh Doanh C\u01a1 B\u1ea3n","author":"Alex Prosperity","date":"November 7, 2025","format":false,"excerpt":"C\u00f4ng C\u1ee5 T\u00ednh L\u1ee3i Nhu\u1eadn & Ph\u00e2n T\u00edch Kinh Doanh \ud83d\udcca C\u00f4ng C\u1ee5 T\u00ednh L\u1ee3i Nhu\u1eadn & Ph\u00e2n T\u00edch Kinh Doanh N\u00e2ng Cao Gi\u00fap b\u1ea1n hi\u1ec3u r\u00f5 l\u1ee3i nhu\u1eadn, hi\u1ec7u qu\u1ea3 \u0111\u1ea7u t\u01b0 v\u00e0 \u0111i\u1ec3m h\u00f2a v\u1ed1n cho t\u1eebng t\u00ecnh hu\u1ed1ng kinh doanh. Tr\u01b0\u1eddng h\u1ee3p A Doanh Thu (\u20ab): Chi\u2026","rel":"","context":"In &quot;C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I&quot;","block_context":{"text":"C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I","link":"https:\/\/howdoi.id.vn\/?cat=49"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":699,"url":"https:\/\/howdoi.id.vn\/?p=699","url_meta":{"origin":895,"position":4},"title":"Gi\u1ea5c m\u01a1 bao nhi\u00eau ti\u1ec1n?","author":"admin","date":"April 22, 2025","format":false,"excerpt":"B\u1ea1n c\u00f3 m\u1ed9t gi\u1ea5c m\u01a1 l\u1edbn nh\u01b0 mua nh\u00e0, \u0111i du l\u1ecbch hay h\u1ecdc th\u00eam k\u1ef9 n\u0103ng m\u1edbi? C\u00f4ng c\u1ee5 n\u00e0y s\u1ebd gi\u00fap b\u1ea1n bi\u1ebft ch\u00ednh x\u00e1c b\u1ea1n c\u1ea7n ti\u1ebft ki\u1ec7m bao nhi\u00eau l\u00e2u \u0111\u1ec3 bi\u1ebfn \u01b0\u1edbc m\u01a1 th\u00e0nh hi\u1ec7n th\u1ef1c. C\u1ef1c k\u1ef3 h\u1eefu \u00edch cho ng\u01b0\u1eddi m\u1edbi b\u1eaft \u0111\u1ea7u\u2026","rel":"","context":"In &quot;C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I&quot;","block_context":{"text":"C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I","link":"https:\/\/howdoi.id.vn\/?cat=49"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/uoc-mo-cua-ban-bao-nhieu-tien.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/uoc-mo-cua-ban-bao-nhieu-tien.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/uoc-mo-cua-ban-bao-nhieu-tien.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/uoc-mo-cua-ban-bao-nhieu-tien.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/uoc-mo-cua-ban-bao-nhieu-tien.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/uoc-mo-cua-ban-bao-nhieu-tien.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":723,"url":"https:\/\/howdoi.id.vn\/?p=723","url_meta":{"origin":895,"position":5},"title":"L\u00e3i K\u00e9p M\u1ed7i Ng\u00e0y","author":"admin","date":"April 22, 2025","format":false,"excerpt":"B\u1ea1n c\u00f3 bi\u1ebft ch\u1ec9 c\u1ea7n ti\u1ebft ki\u1ec7m m\u1ed9t \u00edt m\u1ed7i ng\u00e0y, t\u00e0i kho\u1ea3n b\u1ea1n c\u00f3 th\u1ec3 \"ph\u00ecnh to\" m\u1ed9t c\u00e1ch ngo\u1ea1n m\u1ee5c nh\u1edd l\u00e3i k\u00e9p?C\u00f4ng c\u1ee5 \u201cL\u00e3i K\u00e9p M\u1ed7i Ng\u00e0y\u201d gi\u00fap b\u1ea1n t\u00ednh to\u00e1n s\u1ed1 ti\u1ec1n s\u1ebd c\u00f3 \u0111\u01b0\u1ee3c n\u1ebfu ti\u1ebft ki\u1ec7m m\u1ed7i ng\u00e0y m\u1ed9t kho\u1ea3n nh\u1ecf v\u00e0 \u0111\u1ec3 n\u00f3\u2026","rel":"","context":"In &quot;C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I&quot;","block_context":{"text":"C\u00d4NG C\u1ee4 C\u1ee6A T\u00d4I","link":"https:\/\/howdoi.id.vn\/?cat=49"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/mini-lai-suat-kep.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/mini-lai-suat-kep.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/mini-lai-suat-kep.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/mini-lai-suat-kep.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/mini-lai-suat-kep.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/howdoi.id.vn\/wp-content\/uploads\/2025\/04\/mini-lai-suat-kep.png?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=\/wp\/v2\/posts\/895","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=895"}],"version-history":[{"count":3,"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=\/wp\/v2\/posts\/895\/revisions"}],"predecessor-version":[{"id":898,"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=\/wp\/v2\/posts\/895\/revisions\/898"}],"wp:attachment":[{"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=895"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=895"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/howdoi.id.vn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=895"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}