ساخت ماشین‌حساب وام و پس‌انداز با HTML و CSS

آموزش ساخت یک ماشین‌حساب مالی پیشرفته برای محاسبه اقساط وام و سود پس‌انداز تنها با یک فایل HTML، بدون نیاز به نصب هیچ نرم‌افزار جانبی.

🎧 خلاصه صوتی مقاله (پادکست ۲ دقیقه‌ای):

فرصت مطالعه ندارید؟ چکیده این مطلب را همین‌جا گوش دهید:

مدیریت امور مالی شخصی، محاسبه دقیق سود تسهیلات بانکی و برنامه‌ریزی برای پس‌انداز هدفمند، از جمله دغدغه‌های روزمره بسیاری از افراد است. اگرچه اپلیکیشن‌های زیادی برای این منظور وجود دارند، اما داشتن یک ابزار اختصاصی، سبک و قابل دسترس در تمام دستگاه‌ها بدون نیاز به نصب نرم‌افزارهای پیچیده، مزیت بزرگی محسوب می‌شود. در این مقاله قصد داریم به سراغ ساخت یک ابزار کاربردی برویم که تمام این نیازمندی‌ها را پوشش می‌دهد. این پروژه شباهت زیادی به فرآیند توسعه ابزارهای شخصی کاربردی دارد؛ درست مانند زمانی که افراد به دنبال ساخت ابزار مدیریت لینک و بوکمارک خصوصی با HTML و CSS برای سازماندهی اطلاعات خود هستند.

در این آموزش جامع، کد کامل یک ماشین‌حساب مالی مدرن را آماده کرده‌ایم که در قالب یک تک‌فایل HTML پیاده‌سازی شده است. این ابزار به شما امکان می‌دهد مبلغ وام، نرخ سود سالانه و مدت زمان بازپرداخت را وارد کرده و بلافاصله مبلغ قسط ماهیانه، کل سود پرداختی و مجموع مبلغ بازپرداخت را به همراه یک جدول تفکیکی ماهانه مشاهده کنید. همچنین بخش مجزایی برای محاسبه سود پس‌انداز هدفمند در نظر گرفته شده است تا بتوانید رشد سرمایه خود را در طول زمان به صورت ترکیبی محاسبه کنید.

ویژگیمقدار / مشخصات
تکنولوژی‌های استفاده شدهHTML5, Tailwind CSS (از طریق CDN), Vanilla JavaScript
ساختار فایلتک‌فایل یکپارچه (Single File)
پشتیبانی از موبایلواکنش‌گرا (Responsive) و سازگار با تمام مرورگرها
هزینه۱۰۰٪ رایگان و متن‌باز
وضعیت دسترسی ایرانبدون محدودیت (Accessible)

درک منطق محاسباتی اقساط و پس‌انداز

پیش از بررسی کدهای برنامه، بهتر است نگاهی به فرمول‌های ریاضی پشت این ابزار بیندازیم. محاسبه اقساط وام بر اساس سیستم بازپرداخت پله‌ای یا ماهیانه ثابت (در سیستم بانکی متداول) از فرمول استاندارد قسط ماهیانه استفاده می‌کند. در این فرمول، نرخ سود سالانه به نرخ ماهیانه تبدیل شده و تعداد ماه‌های بازپرداخت به عنوان توان در فرمول اعمال می‌شود.

از سوی دیگر، محاسبه پس‌انداز هدفمند بر اساس فرمول سود مرکب انجام می‌شود که در آن مبالغ واریزی ماهیانه به همراه سود انباشته دوره قبل، محاسبه شده و سرمایه نهایی را شکل می‌دهد. ترکیب این دو قابلیت در یک صفحه ساده، به کاربران اجازه می‌دهد در کسری از ثانیه تصمیمات مالی خود را شبیه‌سازی کنند. پیاده‌سازی این فرمول‌ها در جاوااسکریپت بسیار ساده است و نیازی به کتابخانه‌های سنگین خارجی ندارد.

کد کامل و یکپارچه‌ی ماشین‌حساب مالی

برای استفاده از این ابزار، کافی است کد زیر را در یک فایل متنی با پسوند .html (مثلاً calculator.html) کپی کرده و آن را درون هر مرورگر وب دلخواهی باز کنید. این کد شامل بخش ظاهری با استایل‌های مدرن Tailwind و بخش منطقی با جاوااسکریپت خالص است.

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ماشین‌حساب هوشمند وام و پس‌انداز</title>
    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&tdisplay=swap" rel="stylesheet">
    <style>
        body { font-family: 'Vazirmatn', sans-serif; }
    </style>
</head>
<body class="bg-slate-50 text-slate-800 min-h-screen py-8 px-4">
    <div class="max-w-4xl mx-auto bg-white rounded-2xl shadow-xl overflow-hidden border border-slate-100">
        <header class="bg-indigo-600 text-white p-6 text-center">
            <h1 class="text-2xl font-bold">ماشین‌حساب پیشرفته وام و پس‌انداز</h1>
            <p class="text-indigo-100 text-sm mt-1">محاسبه سریع اقساط، سود تسهیلات و رشد سرمایه</p>
        </header>

        <div class="p-6 md:p-8">
            <!-- تب‌ها -->
            <div class="flex border-b border-slate-200 mb-6">
                <button onclick="switchTab('loan')" id="btn-loan" class="pb-3 px-4 font-semibold text-indigo-600 border-b-2 border-indigo-600 focus:outline-none transition-all">محاسبه وام و اقساط</button>
                <button onclick="switchTab('savings')" id="btn-savings" class="pb-3 px-4 font-semibold text-slate-500 hover:text-indigo-600 focus:outline-none transition-all">پس‌انداز هدفمند</button>
            </div>

            <!-- بخش وام -->
            <div id="tab-loan" class="space-y-6">
                <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                    <div>
                        <label class="block text-sm font-medium text-slate-700 mb-1">مبلغ وام (تومان)</label>
                        <input type="number" id="loan-amount" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" placeholder="مثلا ۱۰۰۰۰۰۰۰۰" value="100000000">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-slate-700 mb-1">نرخ سود سالانه (٪)</label>
                        <input type="number" id="loan-rate" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" placeholder="مثلا ۱۸" value="18">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-slate-700 mb-1">مدت بازپرداخت (ماه)</label>
                        <input type="number" id="loan-months" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" placeholder="مثلا ۲۴" value="24">
                    </div>
                </div>
                <button onclick="calculateLoan()" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2.5 rounded-lg transition-colors cursor-pointer">محاسبه اقساط وام</button>

                <div id="loan-results" class="hidden mt-6 space-y-6">
                    <div class="grid grid-cols-1 md:grid-cols-3 gap-4 bg-indigo-50 p-4 rounded-xl border border-indigo-100">
                        <div>
                            <span class="text-xs text-slate-500 block">قسط ماهیانه:</span>
                            <span id="res-monthly" class="text-lg font-bold text-indigo-700"></span>
                        </div>
                        <div>
                            <span class="text-xs text-slate-500 block">کل سود تسهیلات:</span>
                            <span id="res-total-interest" class="text-lg font-bold text-indigo-700"></span>
                        </div>
                        <div>
                            <span class="text-xs text-slate-500 block">مجموع بازپرداخت:</span>
                            <span id="res-total-payment" class="text-lg font-bold text-indigo-700"></span>
                        </div>
                    </div>

                    <div class="overflow-x-auto max-h-64 border border-slate-200 rounded-lg">
                        <table class="w-full text-right border-collapse">
                            <thead class="bg-slate-100 text-slate-700 text-xs sticky top-0">
                                <tr>
                                    <th class="p-3 border-b">ماه</th>
                                    <th class="p-3 border-b">قسط ماهیانه</th>
                                    <th class="p-3 border-b">سود ماه</th>
                                    <th class="p-3 border-b">اصل قسط</th>
                                    <th class="p-3 border-b">مانده بدهی</th>
                                </tr>
                            </thead>
                            <tbody id="loan-table-body" class="text-sm divide-y divide-slate-100"></tbody>
                        </table>
                    </div>
                </div>
            </div>

            <!-- بخش پس‌انداز -->
            <div id="tab-savings" class="space-y-6 hidden">
                <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                    <div>
                        <label class="block text-sm font-medium text-slate-700 mb-1">پس‌انداز اولیه (تومان)</label>
                        <input type="number" id="sav-initial" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" value="5000000">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-slate-700 mb-1">واریز ماهیانه (تومان)</label>
                        <input type="number" id="sav-monthly" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" value="2000000">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-slate-700 mb-1">سود سالانه (٪)</label>
                        <input type="number" id="sav-rate" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" value="20">
                    </div>
                    <div class="md:col-span-3">
                        <label class="block text-sm font-medium text-slate-700 mb-1">مدت زمان پس‌انداز (ماه)</label>
                        <input type="number" id="sav-months" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:outline-none" value="12">
                    </div>
                </div>
                <button onclick="calculateSavings()" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2.5 rounded-lg transition-colors cursor-pointer">محاسبه رشد پس‌انداز</button>

                <div id="savings-results" class="hidden mt-6 space-y-4">
                    <div class="grid grid-cols-1 md:grid-cols-3 gap-4 bg-emerald-50 p-4 rounded-xl border border-emerald-100">
                        <div>
                            <span class="text-xs text-slate-500 block">مجموع واریزی:</span>
                            <span id="res-sav-deposits" class="text-lg font-bold text-emerald-700"></span>
                        </div>
                        <div>
                            <span class="text-xs text-slate-500 block">سود حاصله:</span>
                            <span id="res-sav-interest" class="text-lg font-bold text-emerald-700"></span>
                        </div>
                        <div>
                            <span class="text-xs text-slate-500 block">موجودی نهایی:</span>
                            <span id="res-sav-total" class="text-lg font-bold text-emerald-700"></span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        function switchTab(tab) {
            const loanTab = document.getElementById('tab-loan');
            const savingsTab = document.getElementById('tab-savings');
            const btnLoan = document.getElementById('btn-loan');
            const btnSavings = document.getElementById('btn-savings');

            if(tab === 'loan') {
                loanTab.classList.remove('hidden');
                savingsTab.classList.add('hidden');
                btnLoan.className = "pb-3 px-4 font-semibold text-indigo-600 border-b-2 border-indigo-600 focus:outline-none transition-all";
                btnSavings.className = "pb-3 px-4 font-semibold text-slate-500 hover:text-indigo-600 focus:outline-none transition-all";
            } else {
                loanTab.classList.add('hidden');
                savingsTab.classList.remove('hidden');
                btnSavings.className = "pb-3 px-4 font-semibold text-indigo-600 border-b-2 border-indigo-600 focus:outline-none transition-all";
                btnLoan.className = "pb-3 px-4 font-semibold text-slate-500 hover:text-indigo-600 focus:outline-none transition-all";
            }
        }

        function formatNumber(num) {
            return num.toLocaleString('fa-IR');
        }

        function calculateLoan() {
            const amount = parseFloat(document.getElementById('loan-amount').value);
            const annualRate = parseFloat(document.getElementById('loan-rate').value) / 100;
            const months = parseInt(document.getElementById('loan-months').value);

            if(isNaN(amount) || isNaN(annualRate) || isNaN(months) || amount <= 0 || months <= 0) {
                alert('لطفاً مقادیر معتبری وارد کنید.');
                return;
            }

            const monthlyRate = annualRate / 12;
            let monthlyPayment = 0;

            if(monthlyRate === 0) {
                monthlyPayment = amount / months;
            } else {
                monthlyPayment = (amount * monthlyRate * Math.pow(1 + monthlyRate, months)) / (Math.pow(1 + monthlyRate, months) - 1);
            }

            let totalPayment = monthlyPayment * months;
            let totalInterest = totalPayment - amount;

            document.getElementById('res-monthly').innerText = formatNumber(Math.round(monthlyPayment)) + ' تومان';
            document.getElementById('res-total-interest').innerText = formatNumber(Math.round(totalInterest)) + ' تومان';
            document.getElementById('res-total-payment').innerText = formatNumber(Math.round(totalPayment)) + ' تومان';

            let tableBody = document.getElementById('loan-table-body');
            tableBody.innerHTML = '';

            let balance = amount;
            for(let i = 1; i <= months; i++) {
                let interestPayment = balance * monthlyRate;
                let principalPayment = monthlyPayment - interestPayment;
                balance -= principalPayment;
                if(balance < 0) balance = 0;

                let row = `<tr class="hover:bg-slate-50">
                    <td class="p-3 border-b">${i}</td>
                    <td class="p-3 border-b">${formatNumber(Math.round(monthlyPayment))}</td>
                    <td class="p-3 border-b text-amber-600">${formatNumber(Math.round(interestPayment))}</td>
                    <td class="p-3 border-b text-emerald-600">${formatNumber(Math.round(principalPayment))}</td>
                    <td class="p-3 border-b font-mono">${formatNumber(Math.round(balance))}</td>
                </tr>`;
                tableBody.innerHTML += row;
            }

            document.getElementById('loan-results').classList.remove('hidden');
        }

        function calculateSavings() {
            const initial = parseFloat(document.getElementById('sav-initial').value) || 0;
            const monthly = parseFloat(document.getElementById('sav-monthly').value) || 0;
            const annualRate = parseFloat(document.getElementById('sav-rate').value) / 100;
            const months = parseInt(document.getElementById('sav-months').value) || 0;

            const monthlyRate = annualRate / 12;
            let totalSavings = initial;
            let totalDeposits = initial;

            for(let i = 0; i < months; i++) {
                totalSavings = (totalSavings + monthly) * (1 + monthlyRate);
                totalDeposits += monthly;
            }

            let totalInterest = totalSavings - totalDeposits;

            document.getElementById('res-sav-deposits').innerText = formatNumber(Math.round(totalDeposits)) + ' تومان';
            document.getElementById('res-sav-interest').innerText = formatNumber(Math.round(totalInterest)) + ' تومان';
            document.getElementById('res-sav-total').innerText = formatNumber(Math.round(totalSavings)) + ' تومان';

            document.getElementById('savings-results').classList.remove('hidden');
        }
    </script>
</body>
</html>

بررسی ساختار و بخش‌های کد

این اسکریپت و ساختار HTML به چند بخش کلیدی تقسیم شده است که درک آن‌ها به توسعه‌دهندگان کمک می‌کند:

  • کتابخانه Tailwind CSS: از نسخه جدید پکیج CDN برای استایل‌دهی سریع استفاده شده که بدون نیاز به تنظیمات پکیج‌منیجر، کلاس‌های آماده‌ای مانند bg-indigo-600 و طراحی شبکه‌ای (Grid) را فراهم می‌کند.
  • سیستم تب‌بندی (Tabs): تابعی ساده به نام switchTab وظیفه جابجایی بین پنل «وام» و «پس‌انداز» را بدون بارگذاری مجدد صفحه بر عهده دارد.
  • منطقی محاسباتی وام: تابع calculateLoan با دریافت نرخ سود و تعداد ماه‌ها، فرمول استاندارد اقساط مساوی را اعمال کرده و مقادیر را حساب می‌کند.
  • جدول تفکیکی (Amortization Schedule): یک حلقه for در جاوااسکریپت ایجاد شده که به ازای هر ماه، میزان سود پرداختی و کسر از اصل وام را محاسبه کرده و در جدول درج می‌کند.

نکات مهم، محدودیت‌ها و خطاهای رایج

هنگام کار با ابزارهای مالی تحت وب، توجه به چند نکته فنی حائز اهمیت است. فرمول‌های پیاده‌سازی شده در این ابزار بر اساس سود ماهیانه ساده و مرکب استاندارد هستند، اما برخی بانک‌ها ممکن است کارمزدها، بیمه تسهیلات یا روش‌های محاسبه روزشمار متفاوتی را اعمال کنند. بنابراین، این ابزار به عنوان یک شبیه‌ساز سریع و دقیق برای ارزیابی‌های اولیه طراحی شده است.

از جمله خطاهای رایج کاربران می‌توان به وارد کردن نرخ سود به صورت اعشاری به جای درصد کامل (مثلا ورود 0.18 به جای 18) اشاره کرد که در این کد با دریافت عدد صحیح و تقسیم آن بر 100 برطرف شده است. همچنین اعداد بزرگ باید به تومان یا ریال یکپارچه وارد شوند تا تناقضی در خروجی محاسبات ایجاد نگردد.

پرسش‌های متداول

چگونه می‌توانم این ابزار را روی هاست شخصی خودم آپلود کنم؟

کافی است کدهای بالا را درون یک فایل با نام دلخواه مثلا index.html ذخیره کنید و آن را روی هر هاست وب یا سرویس میزبانی استاتیک (مانند گیت‌هاب پیجز) بارگذاری کنید؛ چون این ابزار از هیچ سمت سروری استفاده نمی‌کند، به هیچ پایگاه داده‌ای نیاز ندارد.

آیا فرمول محاسبه سود وام برای تمام بانک‌ها یکسان است؟

اکثر بانک‌ها و موسسات مالی از فرمول بازپرداخت اقساط ماهیانه مساوی (Annuity) استفاده می‌کنند که دقیقا در این اسکریپت پیاده‌سازی شده است. با این حال، تفاوت در نحوه محاسبه روزهای تقویم یا کارمزدهای جانبی ممکن است اختلافات جزئی ایجاد کند.

چگونه می‌توان فونت پیش‌فرض صفحه را تغییر داد؟

در بخش هد (Head) سند، از فونت وزیرمتن (Vazirmatn) از طریق گوگل فونتس استفاده شده است. شما می‌توانید با تغییر لینک گوگل فونت و کلاس font-family در استایل داخلی، هر فونت فارسی دیگری را جایگزین کنید.

جمع‌بندی

در این مقاله یک ماشین‌حساب مالی کاربردی، مدرن و ۱۰۰٪ رایگان را با استفاده از HTML، Tailwind CSS و جاوااسکریپت پیاده‌سازی کردیم. این ابزار نه تنها به شما در محاسبه دقیق اقساط تسهیلات و تحلیل سود پرداختی کمک می‌کند، بلکه به عنوان یک پروژه فرانت‌اند تمیز، قابل توسعه و سبد پروژه‌های شخصی شما نیز قابل استفاده است. با کپی کردن این کد می‌توانید در کمتر از یک دقیقه مالک یک ابزار محاسباتی قدرتمند در مرورگر خود باشید.

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *