Technology
<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>व्यक्तिगत खर्च ट्रैकर</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css">
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f8f9fa;
}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>व्यक्तिगत खर्च ट्रैकर</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.0.0/css/all.min.css">
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f8f9fa;
}
.expense-card {
transition: all 0.3s ease;
}
.expense-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.chart-container {
height: 350px;
max-height: 350px;
}
@media print {
body {
width: 100%;
margin: 0;
padding: 0;
}
.no-print {
display: none;
}
.print-break-inside-avoid {
page-break-inside: avoid;
}
}
</style>
</head>
<body class="min-h-screen bg-gray-50">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<header class="mb-8 text-center">
<h1 class="text-3xl font-bold text-indigo-700 mb-2">💰 व्यक्तिगत खर्च ट्रैकर</h1>
<p class="text-gray-600">अपने दैनिक खर्चों को ट्रैक करें और अपने वित्त का बेहतर प्रबंधन करें</p>
</header>
<body class="min-h-screen bg-gray-50">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<header class="mb-8 text-center">
<h1 class="text-3xl font-bold text-indigo-700 mb-2">💰 व्यक्तिगत खर्च ट्रैकर</h1>
<p class="text-gray-600">अपने दैनिक खर्चों को ट्रैक करें और अपने वित्त का बेहतर प्रबंधन करें</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
<!-- Expense Form Card -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-plus-circle text-green-500 mr-2"></i>नया खर्च जोड़ें
</h2>
<div class="mb-4">
<label for="expenseName" class="block text-sm font-medium text-gray-700 mb-1">खर्च का नाम:</label>
<input type="text" id="expenseName" placeholder="जैसे: सब्ज़ी, पेट्रोल, आदि"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<div class="mb-4">
<label for="expenseAmount" class="block text-sm font-medium text-gray-700 mb-1">रकम (₹):</label>
<input type="number" id="expenseAmount" placeholder="जैसे: 500"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<div class="mb-4">
<label for="expenseCategory" class="block text-sm font-medium text-gray-700 mb-1">श्रेणी:</label>
<select id="expenseCategory"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
<option value="भोजन">भोजन</option>
<option value="परिवहन">परिवहन</option>
<option value="मनोरंजन">मनोरंजन</option>
<option value="घर">घर</option>
<option value="स्वास्थ्य">स्वास्थ्य</option>
<option value="शिक्षा">शिक्षा</option>
<option value="कपड़े">कपड़े</option>
<option value="बिजली">बिजली और पानी</option>
<option value="अन्य">अन्य</option>
</select>
</div>
<div class="mb-6">
<label for="expenseDate" class="block text-sm font-medium text-gray-700 mb-1">तारीख:</label>
<input type="date" id="expenseDate"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<div class="flex space-x-3">
<button onclick="addExpense()"
class="flex-1 bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2 px-4 rounded-md transition duration-200">
<i class="fas fa-plus-circle mr-2"></i>खर्च जोड़ें
</button>
<button onclick="clearAll()"
class="flex-1 bg-red-500 hover:bg-red-600 text-white font-medium py-2 px-4 rounded-md transition duration-200">
<i class="fas fa-trash mr-2"></i>सब साफ करें
</button>
</div>
</div>
<!-- Summary Card -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-chart-pie text-blue-500 mr-2"></i>खर्च सारांश
</h2>
<div id="summary" class="text-gray-700"></div>
<div id="monthly-trend" class="mt-4">
<h3 class="text-lg font-medium mb-2 text-gray-700">मासिक प्रवृत्ति</h3>
<div class="chart-container h-40">
<canvas id="trendChart"></canvas>
</div>
</div>
</div>
<!-- Chart Card -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-chart-pie text-purple-500 mr-2"></i>श्रेणी विश्लेषण
</h2>
<div class="chart-container">
<canvas id="expenseChart"></canvas>
</div>
</div>
</div>
<!-- Expense Table Card -->
<div class="bg-white rounded-lg shadow-md p-6 mb-8">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-list text-indigo-500 mr-2"></i>सभी खर्च
</h2>
<div class="mb-4">
<input type="text" id="searchExpense" placeholder="खर्च खोजें..."
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</div>
<div class="overflow-x-auto">
<table class="min-w-full bg-white border border-gray-200">
<thead>
<tr>
<th class="px-4 py-2 border-b border-gray-200 bg-gray-50 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
तारीख
</th>
<th class="px-4 py-2 border-b border-gray-200 bg-gray-50 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
नाम
</th>
<th class="px-4 py-2 border-b border-gray-200 bg-gray-50 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
श्रेणी
</th>
<th class="px-4 py-2 border-b border-gray-200 bg-gray-50 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
रकम (₹)
</th>
<th class="px-4 py-2 border-b border-gray-200 bg-gray-50 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">
क्रिया
</th>
</tr>
</thead>
<tbody id="expenseTableBody" class="divide-y divide-gray-200">
<!-- Expense rows will be inserted here -->
</tbody>
</table>
</div>
</div>
<!-- Statistics Dashboard -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<!-- Top Expenses Card -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-fire text-orange-500 mr-2"></i>शीर्ष खर्च
</h2>
<div id="topExpenses"></div>
</div>
<!-- Weekly Breakdown Card -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold mb-4 text-gray-800">
<i class="fas fa-calendar-week text-green-500 mr-2"></i>साप्ताहिक विश्लेषण
</h2>
<div class="chart-container h-60">
<canvas id="weeklyChart"></canvas>
</div>
</div>
</div>
</div>
<script>
let expenses = JSON.parse(localStorage.getItem('expenses')) || [];
let pieChart = null;
let trendChart = null;
let weeklyChart = null;
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('expenseDate').valueAsDate = new Date();
renderExpenses();
updateSummary();
renderCharts();
updateTopExpenses();
});
// Search functionality
document.getElementById('searchExpense').addEventListener('input', function() {
renderExpenses();
});
// Add new expense
function addExpense() {
const name = document.getElementById('expenseName').value.trim();
const amount = parseFloat(document.getElementById('expenseAmount').value);
const category = document.getElementById('expenseCategory').value;
const date = document.getElementById('expenseDate').value;
if (!name || isNaN(amount) || amount <= 0 || !date) {
showAlert('कृपया सभी फील्ड सही से भरें', 'error');
return;
}
const expense = {
id: Date.now(),
date,
name,
category,
amount
};
expenses.push(expense);
saveToLocalStorage();
renderExpenses();
updateSummary();
renderCharts();
updateTopExpenses();
// Reset form fields
document.getElementById('expenseName').value = '';
document.getElementById('expenseAmount').value = '';
showAlert('खर्च सफलतापूर्वक जोड़ा गया', 'success');
}
// Delete expense
function deleteExpense(id) {
if (confirm('क्या आप वाकई इस खर्च को हटाना चाहते हैं?')) {
expenses = expenses.filter(expense => expense.id !== id);
saveToLocalStorage();
renderExpenses();
updateSummary();
renderCharts();
updateTopExpenses();
showAlert('खर्च हटा दिया गया', 'success');
}
}
// Clear all expenses
function clearAll() {
if (confirm('क्या आप वाकई सभी खर्चे हटाना चाहते हैं? यह क्रिया अपरिवर्तनीय है।')) {
expenses = [];
saveToLocalStorage();
renderExpenses();
updateSummary();
renderCharts();
updateTopExpenses();
showAlert('सभी खर्चे हटा दिए गए', 'success');
}
}
// Save to local storage
function saveToLocalStorage() {
localStorage.setItem('expenses', JSON.stringify(expenses));
}
// Display alert message
function showAlert(message, type) {
const alertDiv = document.createElement('div');
alertDiv.className = type === 'error'
? 'fixed top-4 right-4 bg-red-500 text-white px-6 py-3 rounded-md shadow-lg z-50'
: 'fixed top-4 right-4 bg-green-500 text-white px-6 py-3 rounded-md shadow-lg z-50';
alertDiv.innerHTML = message;
document.body.appendChild(alertDiv);
setTimeout(() => {
alertDiv.style.opacity = '0';
alertDiv.style.transition = 'opacity 0.5s ease';
setTimeout(() => {
document.body.removeChild(alertDiv);
}, 500);
}, 3000);
}
// Render expenses table
function renderExpenses() {
const tbody = document.getElementById('expenseTableBody');
tbody.innerHTML = '';
const searchTerm = document.getElementById('searchExpense').value.toLowerCase();
let filteredExpenses = expenses;
if (searchTerm) {
filteredExpenses = expenses.filter(expense =>
expense.name.toLowerCase().includes(searchTerm) ||
expense.category.toLowerCase().includes(searchTerm)
);
}
if (filteredExpenses.length === 0) {
const row = document.createElement('tr');
row.innerHTML = '<td colspan="5" class="px-4 py-4 text-center text-gray-500">कोई खर्च नहीं मिला</td>';
tbody.appendChild(row);
return;
}
// Sort by date (newest first)
filteredExpenses.sort((a, b) => new Date(b.date) - new Date(a.date));
filteredExpenses.forEach(expense => {
const row = document.createElement('tr');
row.className = 'expense-card hover:bg-gray-50';
const date = new Date(expense.date);
const formattedDate = date.toLocaleDateString('hi-IN', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
const categoryClass = getCategoryColorClass(expense.category);
row.innerHTML = `
<td class="px-4 py-3">${formattedDate}</td>
<td class="px-4 py-3 font-medium">${expense.name}</td>
<td class="px-4 py-3">
<span class="inline-block px-2 py-1 text-xs font-semibold rounded-full ${categoryClass}">
${expense.category}
</span>
</td>
<td class="px-4 py-3 font-semibold">₹${expense.amount.toLocaleString('hi-IN')}</td>
<td class="px-4 py-3">
<button onclick="deleteExpense(${expense.id})"
class="text-red-500 hover:text-red-700 focus:outline-none">
<i class="fas fa-trash"></i>
</button>
</td>
`;
tbody.appendChild(row);
});
}
// Get category color class
function getCategoryColorClass(category) {
const categoryColors = {
'भोजन': 'bg-green-100 text-green-800',
'परिवहन': 'bg-blue-100 text-blue-800',
'मनोरंजन': 'bg-purple-100 text-purple-800',
'घर': 'bg-yellow-100 text-yellow-800',
'स्वास्थ्य': 'bg-red-100 text-red-800',
'शिक्षा': 'bg-indigo-100 text-indigo-800',
'कपड़े': 'bg-pink-100 text-pink-800',
'बिजली': 'bg-teal-100 text-teal-800'
};
return categoryColors[category] || 'bg-gray-100 text-gray-800';
}
// Update summary information
function updateSummary() {
const summaryDiv = document.getElementById('summary');
if (expenses.length === 0) {
summaryDiv.innerHTML = '<p class="text-gray-500">अभी तक कोई खर्च नहीं किया गया है</p>';
return;
}
const total = expenses.reduce((sum, expense) => sum + expense.amount, 0);
// Calculate category totals
const categorySummary = {};
expenses.forEach(expense => {
if (!categorySummary[expense.category]) {
categorySummary[expense.category] = 0;
}
categorySummary[expense.category] += expense.amount;
});
// Calculate monthly totals
const monthlyData = {};
expenses.forEach(expense => {
const yearMonth = expense.date.substring(0, 7); // YYYY-MM format
if (!monthlyData[yearMonth]) {
monthlyData[yearMonth] = 0;
}
monthlyData[yearMonth] += expense.amount;
});
// Calculate this month total
const currentDate = new Date();
const currentYearMonth = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}`;
const thisMonthTotal = monthlyData[currentYearMonth] || 0;
// Get today's expenses
const today = new Date().toISOString().split('T')[0];
const todayTotal = expenses
.filter(expense => expense.date === today)
.reduce((sum, expense) => sum + expense.amount, 0);
let summaryHTML = `
<div class="grid grid-cols-2 gap-4 mb-4">
<div class="bg-indigo-50 p-3 rounded-lg">
<p class="text-sm text-indigo-500">कुल खर्च</p>
<p class="text-xl font-bold">₹${total.toLocaleString('hi-IN')}</p>
</div>
<div class="bg-green-50 p-3 rounded-lg">
<p class="text-sm text-green-500">इस महीने</p>
<p class="text-xl font-bold">₹${thisMonthTotal.toLocaleString('hi-IN')}</p>
</div>
</div>
<div class="bg-blue-50 p-3 rounded-lg mb-4">
<p class="text-sm text-blue-500">आज का खर्च</p>
<p class="text-xl font-bold">₹${todayTotal.toLocaleString('hi-IN')}</p>
</div>
<h3 class="font-semibold mb-2 text-gray-700">श्रेणी के अनुसार खर्च:</h3>
<div class="space-y-2">
`;
// Sort categories by amount (highest first)
const sortedCategories = Object.keys(categorySummary).sort(
(a, b) => categorySummary[b] - categorySummary[a]
);
for (const category of sortedCategories) {
const amount = categorySummary[category];
const percentage = ((amount / total) * 100).toFixed(1);
const categoryColorClass = getCategoryColorClass(category);
summaryHTML += `
<div class="flex items-center justify-between">
<div class="flex items-center">
<span class="inline-block w-2 h-2 rounded-full ${categoryColorClass.split(' ')[0]} mr-2"></span>
<span>${category}</span>
</div>
<div class="text-right">
<span class="block font-semibold">₹${amount.toLocaleString('hi-IN')}</span>
<span class="text-xs text-gray-500">${percentage}%</span>
</div>
</div>
`;
}
summaryHTML += '</div>';
summaryDiv.innerHTML = summaryHTML;
// Update trend chart
updateTrendChart(monthlyData);
}
// Update monthly trend chart
function updateTrendChart(monthlyData) {
const ctx = document.getElementById('trendChart').getContext('2d');
if (trendChart) {
trendChart.destroy();
}
if (Object.keys(monthlyData).length === 0) {
return;
}
// Sort months chronologically
const sortedMonths = Object.keys(monthlyData).sort();
const monthLabels = sortedMonths.map(ym => {
const [year, month] = ym.split('-');
const monthNames = ['जन', 'फर', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुल', 'अग', 'सित', 'अक्ट', 'नव', 'दिस'];
return `${monthNames[parseInt(month) - 1]} ${year.substring(2)}`;
});
const monthValues = sortedMonths.map(ym => monthlyData[ym]);
trendChart = new Chart(ctx, {
type: 'line',
data: {
labels: monthLabels,
datasets: [{
label: 'मासिक खर्च',
data: monthValues,
backgroundColor: 'rgba(99, 102, 241, 0.2)',
borderColor: 'rgba(99, 102, 241, 1)',
borderWidth: 2,
tension: 0.3,
pointBackgroundColor: 'rgba(99, 102, 241, 1)',
pointRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: function(context) {
return `₹${context.raw.toLocaleString('hi-IN')}`;
}
}
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
if (value >= 1000) {
return '₹' + (value / 1000) + 'k';
}
return '₹' + value;
}
}
}
}
}
});
}
// Render all charts
function renderCharts() {
renderPieChart();
renderWeeklyChart();
}
// Render pie chart for category breakdown
function renderPieChart() {
const ctx = document.getElementById('expenseChart').getContext('2d');
if (pieChart) {
pieChart.destroy();
}
if (expenses.length === 0) {
return;
}
// Calculate category totals
const categoryData = {};
expenses.forEach(expense => {
if (!categoryData[expense.category]) {
categoryData[expense.category] = 0;
}
categoryData[expense.category] += expense.amount;
});
const categories = Object.keys(categoryData);
const amounts = Object.values(categoryData);
// Color palette
const backgroundColors = [
'rgba(99, 102, 241, 0.8)', // Indigo
'rgba(52, 211, 153, 0.8)', // Green
'rgba(251, 146, 60, 0.8)', // Orange
'rgba(239, 68, 68, 0.8)', // Red
'rgba(168, 85, 247, 0.8)', // Purple
'rgba(59, 130, 246, 0.8)', // Blue
'rgba(236, 72, 153, 0.8)', // Pink
'rgba(234, 179, 8, 0.8)', // Yellow
'rgba(20, 184, 166, 0.8)', // Teal
'rgba(107, 114, 128, 0.8)' // Gray
];
pieChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: categories,
datasets: [{
data: amounts,
backgroundColor: backgroundColors,
borderWidth: 1,
borderColor: '#ffffff'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
boxWidth: 15,
padding: 15
}
},
tooltip: {
callbacks: {
label: function(context) {
const label = context.label || '';
const value = context.raw || 0;
const total = context.dataset.data.reduce((a, b) => a + b, 0);
const percentage = Math.round((value / total) * 100);
return `${label}: ₹${value.toLocaleString('hi-IN')} (${percentage}%)`;
}
}
}
}
}
});
}
// Render weekly expense breakdown
function renderWeeklyChart() {
const ctx = document.getElementById('weeklyChart').getContext('2d');
if (weeklyChart) {
weeklyChart.destroy();
}
if (expenses.length === 0) {
return;
}
// Get the last 7 days
const dayNames = ['रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र', 'शनि'];
const today = new Date();
const last7Days = Array(7).fill().map((_, i) => {
const date = new Date();
date.setDate(today.getDate() - 6 + i);
return {
date: date.toISOString().split('T')[0],
dayName: dayNames[date.getDay()],
amount: 0
};
});
// Calculate daily totals
expenses.forEach(expense => {
const expenseDate = expense.date;
const dayIndex = last7Days.findIndex(day => day.date === expenseDate);
if (dayIndex !== -1) {
last7Days[dayIndex].amount += expense.amount;
}
});
const dayLabels = last7Days.map(day => day.dayName);
const dayAmounts = last7Days.map(day => day.amount);
weeklyChart = new Chart(ctx, {
type: 'bar',
data: {
labels: dayLabels,
datasets: [{
label: 'दैनिक खर्च',
data: dayAmounts,
backgroundColor: 'rgba(52, 211, 153, 0.7)',
borderColor: 'rgba(52, 211, 153, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: function(context) {
return `₹${context.raw.toLocaleString('hi-IN')}`;
}
}
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return '₹' + value;
}
}
}
}
}
});
}
// Update top expenses list
function updateTopExpenses() {
const topExpensesDiv = document.getElementById('topExpenses');
if (expenses.length === 0) {
topExpensesDiv.innerHTML = '<p class="text-gray-500">अभी तक कोई खर्च नहीं किया गया है</p>';
return;
}
// Get top 5 expenses
const sortedExpenses = [...expenses].sort((a, b) => b.amount - a.amount).slice(0, 5);
let topExpensesHTML = '<div class="space-y-3">';
sortedExpenses.forEach((expense, index) => {
const date = new Date(expense.date);
const formattedDate = date.toLocaleDateString('hi-IN', {
month: 'short',
day: 'numeric'
});
const categoryColorClass = getCategoryColorClass(expense.category);
topExpensesHTML += `
<div class="flex items-center p-2 rounded-lg ${index === 0 ? 'bg-yellow-50' : 'bg-gray-50'}">
<div class="flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center ${index === 0 ? 'bg-yellow-100 text-yellow-600' : 'bg-gray-200 text-gray-600'} mr-3">
${index + 1}
</div>
<div class="flex-1">
<div class="flex justify-between">
<span class="font-medium">${expense.name}</span>
<span class="font-bold">₹${expense.amount.toLocaleString('hi-IN')}</span>
</div>
<div class="flex justify-between text-xs text-gray-500">
<span>${formattedDate}</span>
<span class="inline-block px-2 py-1 rounded-full ${categoryColorClass}">
${expense.category}
</span>
</div>
</div>
</div>
`;
});
topExpensesHTML += '</div>';
topExpensesDiv.innerHTML = topExpensesHTML;
}
</script>
</body>
</html>
</html>
Comments
Post a Comment