Initial commit
This commit is contained in:
35
templates/base.html
Normal file
35
templates/base.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Expense Tracker - Home Assistant</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<i class="fas fa-cash-register"></i>
|
||||
<h2>Expense Tracker</h2>
|
||||
</div>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('index') }}"><i class="fas fa-home"></i> Dashboard</a></li>
|
||||
<li><a href="{{ url_for('expenses') }}"><i class="fas fa-receipt"></i> Ausgaben</a></li>
|
||||
<li><a href="{{ url_for('categories') }}"><i class="fas fa-tags"></i> Kategorien</a></li>
|
||||
<!--<li><a href="{{ url_for('reports') }}"><i class="fas fa-chart-pie"></i> Berichte</a></li>-->
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="content-wrapper">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/scripts.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
53
templates/categories.html
Normal file
53
templates/categories.html
Normal file
@ -0,0 +1,53 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="categories-page">
|
||||
<h1>Kategorien verwalten</h1>
|
||||
|
||||
<div class="form-container">
|
||||
<h2>Neue Kategorie hinzufügen</h2>
|
||||
{% if error %}
|
||||
<div class="error-message">{{ error }}</div>
|
||||
{% endif %}
|
||||
<form action="{{ url_for('categories') }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Beschreibung:</label>
|
||||
<input type="text" id="description" name="description">
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="button primary">Kategorie speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="categories-list">
|
||||
<h2>Alle Kategorien</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in categories %}
|
||||
<tr>
|
||||
<td>{{ category.name }}</td>
|
||||
<td>{{ category.description }}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="2" class="no-data">Keine Kategorien vorhanden</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
69
templates/expenses.html
Normal file
69
templates/expenses.html
Normal file
@ -0,0 +1,69 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="expenses-page">
|
||||
<h1>Ausgaben verwalten</h1>
|
||||
|
||||
<div class="form-container">
|
||||
<h2>Neue Ausgabe hinzufügen</h2>
|
||||
<form action="{{ url_for('expenses') }}" method="post">
|
||||
<div class="form-group">
|
||||
<label for="amount">Betrag (€):</label>
|
||||
<input type="number" id="amount" name="amount" step="0.01" min="0.01" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Beschreibung:</label>
|
||||
<input type="text" id="description" name="description" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="category_id">Kategorie:</label>
|
||||
<select id="category_id" name="category_id" required>
|
||||
<option value="">-- Kategorie wählen --</option>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category.id }}">{{ category.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="date">Datum:</label>
|
||||
<input type="date" id="date" name="date" value="{{ today }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="button primary">Ausgabe speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="expenses-list">
|
||||
<h2>Alle Ausgaben</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Beschreibung</th>
|
||||
<th>Kategorie</th>
|
||||
<th>Betrag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for expense in expenses %}
|
||||
<tr>
|
||||
<td>{{ expense.date.strftime('%d.%m.%Y') }}</td>
|
||||
<td>{{ expense.description }}</td>
|
||||
<td>{{ expense.category.name }}</td>
|
||||
<td class="amount">{{ "%.2f"|format(expense.amount) }} €</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="no-data">Keine Ausgaben vorhanden</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
110
templates/index.html
Normal file
110
templates/index.html
Normal file
@ -0,0 +1,110 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="dashboard">
|
||||
<h1>Dashboard</h1>
|
||||
|
||||
<div class="dashboard-summary">
|
||||
<div class="summary-card">
|
||||
<div class="card-icon">
|
||||
<i class="fas fa-euro-sign"></i>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>Gesamtausgaben</h3>
|
||||
<p class="amount">{{ "%.2f"|format(total_expenses) }} €</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="card-icon">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>Aktuelle Periode</h3>
|
||||
<p>{{ now.strftime('%B %Y') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="summary-card">
|
||||
<div class="card-icon">
|
||||
<i class="fas fa-tags"></i>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<h3>Kategorien</h3>
|
||||
<p>{{ categories|length }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-charts">
|
||||
<div class="chart-container">
|
||||
<h2>Ausgaben nach Kategorie</h2>
|
||||
<div id="category-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="recent-expenses">
|
||||
<h2>Neueste Ausgaben</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datum</th>
|
||||
<th>Beschreibung</th>
|
||||
<th>Kategorie</th>
|
||||
<th>Betrag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for expense in expenses %}
|
||||
<tr>
|
||||
<td>{{ expense.date.strftime('%d.%m.%Y') }}</td>
|
||||
<td>{{ expense.description }}</td>
|
||||
<td>{{ expense.category.name }}</td>
|
||||
<td class="amount">{{ "%.2f"|format(expense.amount) }} €</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="no-data">Keine Ausgaben vorhanden</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="action-button">
|
||||
<a href="{{ url_for('expenses') }}" class="button">Alle Ausgaben anzeigen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Category pie chart
|
||||
const categoryNames = {{ category_names|safe }};
|
||||
const categoryAmounts = {{ category_amounts|safe }};
|
||||
|
||||
if (categoryNames.length > 0) {
|
||||
const data = [{
|
||||
values: categoryAmounts,
|
||||
labels: categoryNames,
|
||||
type: 'pie',
|
||||
marker: {
|
||||
colors: [
|
||||
'#4e79a7', '#f28e2c', '#e15759', '#76b7b2',
|
||||
'#59a14f', '#edc949', '#af7aa1', '#ff9da7',
|
||||
'#9c755f', '#bab0ab'
|
||||
]
|
||||
}
|
||||
}];
|
||||
|
||||
const layout = {
|
||||
height: 400,
|
||||
margin: { t: 0, b: 0, l: 0, r: 0 },
|
||||
showlegend: true
|
||||
};
|
||||
|
||||
Plotly.newPlot('category-chart', data, layout);
|
||||
} else {
|
||||
document.getElementById('category-chart').innerHTML = '<p class="no-data">Keine Daten verfügbar</p>';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
43
templates/reports.html
Normal file
43
templates/reports.html
Normal file
@ -0,0 +1,43 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="reports-page">
|
||||
<h1>Ausgabenberichte</h1>
|
||||
|
||||
<div class="filter-container">
|
||||
<h2>Zeitraum filtern</h2>
|
||||
<form action="{{ url_for('reports') }}" method="get">
|
||||
<div class="form-group inline">
|
||||
<label for="start_date">Von:</label>
|
||||
<input type="date" id="start_date" name="start_date" value="{{ start_date }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group inline">
|
||||
<label for="end_date">Bis:</label>
|
||||
<input type="date" id="end_date" name="end_date" value="{{ end_date }}">
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="button primary">Filter anwenden</button>
|
||||
<a href="{{ url_for('reports') }}" class="button secondary">Zurücksetzen</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="charts-container">
|
||||
<div class="chart-box">
|
||||
<h2>Ausgaben nach Kategorie</h2>
|
||||
<div class="chart">
|
||||
{{ category_chart|safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-box">
|
||||
<h2>Ausgaben im Zeitverlauf</h2>
|
||||
<div class="chart">
|
||||
{{ timeline_chart|safe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user