first commit

This commit is contained in:
Matthias Hinrichs
2025-08-26 03:17:49 +02:00
commit 189e7a2329
34 changed files with 8835 additions and 0 deletions
View File
+316
View File
@@ -0,0 +1,316 @@
// Dashboard Charts JavaScript - Mit echten Daten aus der API
document.addEventListener('DOMContentLoaded', function() {
console.log('Dashboard charts initializing...');
// Prüfe ob Chart.js geladen ist
if (typeof Chart === 'undefined') {
console.error('Chart.js not loaded!');
return;
}
console.log('Chart.js loaded, version:', Chart.version);
// Dashboard-Daten über API laden
fetch('/api/dashboard-data')
.then(response => {
console.log('API Response status:', response.status);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Dashboard data loaded:', data);
initializeCharts(data);
})
.catch(error => {
console.error('Error loading dashboard data:', error);
// Fallback mit Demo-Daten
console.log('Using fallback demo data...');
initializeChartsWithDemoData();
});
});
function initializeChartsWithDemoData() {
console.log('Initializing charts with demo data...');
const demoData = {
monthly_stats: [
{ month: '2024-01', income: 3000, expenses: 2200, net_change: 800, balance: 5000 },
{ month: '2024-02', income: 3200, expenses: 2400, net_change: 800, balance: 5800 },
{ month: '2024-03', income: 2800, expenses: 2100, net_change: 700, balance: 6500 }
],
category_stats: [
{ category_name: 'Lebensmittel', total_amount: 600, percentage: 27.3 },
{ category_name: 'Transport', total_amount: 250, percentage: 11.4 },
{ category_name: 'Unterhaltung', total_amount: 180, percentage: 8.2 },
{ category_name: 'Sonstiges', total_amount: 170, percentage: 7.7 }
],
transaction_trend: [
{ date: '2024-03-01T00:00:00Z', income: 100, expense: 50, balance: 5000 },
{ date: '2024-03-02T00:00:00Z', income: 0, expense: 80, balance: 4920 },
{ date: '2024-03-03T00:00:00Z', income: 200, expense: 120, balance: 5000 },
{ date: '2024-03-04T00:00:00Z', income: 50, expense: 90, balance: 4960 },
{ date: '2024-03-05T00:00:00Z', income: 0, expense: 70, balance: 4890 }
],
asset_overview: {
total_bank_balance: 15000,
total_depot_value: 25000
}
};
initializeCharts(demoData);
}
function initializeCharts(data) {
console.log('Initializing charts with data:', data);
// Chart 1: Monatliche Statistiken
createMonthlyChart(data);
// Chart 2: Einnahmen vs Ausgaben
createIncomeExpenseChart(data);
// Chart 3: Trend-Chart
createTrendChart(data);
console.log('All charts initialized');
}
function createMonthlyChart(data) {
const ctx = document.getElementById('monthlyChart');
if (!ctx) {
console.warn('Monthly chart canvas not found');
return;
}
try {
// Echte Datenstruktur aus der API verwenden
const monthlyStats = data.monthly_stats || data.monthlyStats || [];
console.log('Monthly stats data:', monthlyStats);
new Chart(ctx.getContext('2d'), {
type: 'bar',
data: {
labels: monthlyStats.map(d => {
// Month aus "2024-01" Format zu "Januar 2024" konvertieren
const [year, month] = d.month.split('-');
const monthNames = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'];
return `${monthNames[parseInt(month) - 1]} ${year}`;
}),
datasets: [{
label: 'Einnahmen',
data: monthlyStats.map(d => parseFloat(d.income || 0)),
backgroundColor: 'rgba(34, 197, 94, 0.7)',
borderColor: 'rgba(34, 197, 94, 1)',
borderWidth: 1
}, {
label: 'Ausgaben',
data: monthlyStats.map(d => parseFloat(d.expenses || 0)),
backgroundColor: 'rgba(239, 68, 68, 0.7)',
borderColor: 'rgba(239, 68, 68, 1)',
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return '€' + value.toLocaleString();
}
}
}
},
plugins: {
title: {
display: true,
text: 'Monatliche Ein- und Ausgaben'
}
}
}
});
console.log('Monthly chart created');
} catch (error) {
console.error('Error creating monthly chart:', error);
}
}
function createIncomeExpenseChart(data) {
const ctx = document.getElementById('incomeExpenseChart');
if (!ctx) {
console.warn('Income/Expense chart canvas not found');
return;
}
try {
// Echte Datenstruktur verwenden
const monthlyStats = data.monthly_stats || data.monthlyStats || [];
console.log('Income/Expense stats data:', monthlyStats);
const totalIncome = monthlyStats.reduce((sum, d) => sum + parseFloat(d.income || 0), 0);
const totalExpenses = monthlyStats.reduce((sum, d) => sum + parseFloat(d.expenses || 0), 0);
new Chart(ctx.getContext('2d'), {
type: 'pie',
data: {
labels: ['Einnahmen', 'Ausgaben'],
datasets: [{
data: [totalIncome, totalExpenses],
backgroundColor: ['#22c55e', '#ef4444'],
borderWidth: 2,
borderColor: '#ffffff'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: 'Einnahmen vs. Ausgaben'
},
legend: {
position: 'bottom'
},
tooltip: {
callbacks: {
label: function(context) {
return context.label + ': €' + context.parsed.toLocaleString();
}
}
}
}
}
});
console.log('Income/Expense chart created');
} catch (error) {
console.error('Error creating income/expense chart:', error);
}
}
function createTrendChart(data) {
const ctx = document.getElementById('trendChart');
if (!ctx) {
console.warn('Trend chart canvas not found');
return;
}
try {
// Echte Datenstruktur verwenden
const trendData = data.transaction_trend || data.transactionTrend || [];
console.log('Trend data:', trendData);
new Chart(ctx.getContext('2d'), {
type: 'bar', // Basis-Typ für Balken
data: {
labels: trendData.map(d => {
// Datum als Monat/Jahr formatieren für 12-Monats-Ansicht
const date = new Date(d.date);
return date.toLocaleDateString('de-DE', { month: 'short', year: 'numeric' });
}),
datasets: [{
label: 'Einnahmen',
type: 'bar', // Explizit als Bar definieren
data: trendData.map(d => parseFloat(d.income || 0)),
backgroundColor: 'rgba(34, 197, 94, 0.7)',
borderColor: 'rgba(34, 197, 94, 1)',
borderWidth: 1,
yAxisID: 'y'
}, {
label: 'Ausgaben',
type: 'bar', // Explizit als Bar definieren
data: trendData.map(d => parseFloat(d.expense || 0)),
backgroundColor: 'rgba(239, 68, 68, 0.7)',
borderColor: 'rgba(239, 68, 68, 1)',
borderWidth: 1,
yAxisID: 'y'
}, {
label: 'Saldo',
type: 'line', // Explizit als Linie definieren
data: trendData.map(d => parseFloat(d.balance || 0)),
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 3,
fill: false,
tension: 0.1,
yAxisID: 'y1',
pointRadius: 3,
pointHoverRadius: 5
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false,
},
scales: {
x: {
display: true,
title: {
display: true,
text: 'Datum'
}
},
y: {
type: 'linear',
display: true,
position: 'left',
title: {
display: true,
text: 'Einnahmen/Ausgaben (€)'
},
beginAtZero: true,
ticks: {
callback: function(value) {
return '€' + value.toLocaleString();
}
}
},
y1: {
type: 'linear',
display: true,
position: 'right',
title: {
display: true,
text: 'Saldo (€)'
},
grid: {
drawOnChartArea: false,
},
ticks: {
callback: function(value) {
return '€' + value.toLocaleString();
}
}
}
},
plugins: {
title: {
display: true,
text: '90-Tage Trend'
},
legend: {
position: 'top'
},
tooltip: {
callbacks: {
label: function(context) {
return context.dataset.label + ': €' + context.parsed.y.toLocaleString();
}
}
}
}
}
});
console.log('Trend chart created');
} catch (error) {
console.error('Error creating trend chart:', error);
}
}