First Commit - sieht schon gut aus
This commit is contained in:
194
public/css/styles.css
Normal file
194
public/css/styles.css
Normal file
@@ -0,0 +1,194 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(180deg, #c8e6c9 0%, #81c784 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.checkbox-label input[type="checkbox"] {
|
||||
width: auto;
|
||||
margin-right: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
input, select {
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
input:focus, select:focus {
|
||||
outline: none;
|
||||
border-color: #43a047;
|
||||
}
|
||||
|
||||
button {
|
||||
background: linear-gradient(135deg, #43a047 0%, #1b5e20 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 30px;
|
||||
border-radius: 5px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(67, 160, 71, 0.4);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.results-container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: #e3f2fd;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
border-left: 4px solid #2196f3;
|
||||
}
|
||||
|
||||
.error-box {
|
||||
background: #ffebee;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 20px;
|
||||
border-left: 4px solid #f44336;
|
||||
color: #c62828;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
background: white;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
thead {
|
||||
background: linear-gradient(135deg, #43a047 0%, #1b5e20 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.number {
|
||||
text-align: right;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.summary {
|
||||
background: #f1f8e9;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin-top: 20px;
|
||||
border-left: 4px solid #8bc34a;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.summary-label {
|
||||
font-weight: 600;
|
||||
color: #558b2f;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
font-size: 1.5em;
|
||||
font-weight: 700;
|
||||
color: #33691e;
|
||||
}
|
||||
142
public/js/script.js
Normal file
142
public/js/script.js
Normal file
@@ -0,0 +1,142 @@
|
||||
// Datum auf heute und vor 7 Tagen setzen
|
||||
function initializeDates() {
|
||||
const today = new Date();
|
||||
const weekAgo = new Date();
|
||||
weekAgo.setDate(today.getDate() - 7);
|
||||
|
||||
document.getElementById('endDate').valueAsDate = today;
|
||||
document.getElementById('startDate').valueAsDate = weekAgo;
|
||||
}
|
||||
|
||||
// Datum formatieren
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleString('de-DE', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
|
||||
// Zahl formatieren
|
||||
function formatNumber(num) {
|
||||
return new Intl.NumberFormat('de-DE', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(num);
|
||||
}
|
||||
|
||||
// Formular absenden
|
||||
document.getElementById('verbrauchForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
// Ausgewählte Collections sammeln
|
||||
const checkboxes = document.querySelectorAll('.checkbox-group input[type="checkbox"]:checked');
|
||||
const selectedCollections = Array.from(checkboxes).map(cb => cb.value);
|
||||
|
||||
if (selectedCollections.length === 0) {
|
||||
alert('Bitte wählen Sie mindestens eine Collection aus.');
|
||||
return;
|
||||
}
|
||||
|
||||
const startDate = document.getElementById('startDate').value;
|
||||
const endDate = document.getElementById('endDate').value;
|
||||
|
||||
const resultsDiv = document.getElementById('results');
|
||||
resultsDiv.innerHTML = '<div class="loading">Lade Daten...</div>';
|
||||
|
||||
try {
|
||||
const collectionsParam = selectedCollections.join(',');
|
||||
const response = await fetch(
|
||||
`/api/verbrauch?collections=${collectionsParam}&startDate=${startDate}&endDate=${endDate}`
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Fehler beim Abrufen der Daten');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
displayResults(data);
|
||||
|
||||
} catch (error) {
|
||||
resultsDiv.innerHTML = `
|
||||
<div class="error-box">
|
||||
<strong>Fehler:</strong> ${error.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
// Ergebnisse anzeigen
|
||||
function displayResults(data) {
|
||||
const resultsDiv = document.getElementById('results');
|
||||
|
||||
if (data.verbraucher.length === 0) {
|
||||
resultsDiv.innerHTML = `
|
||||
<div class="info-box">
|
||||
Keine Daten für den gewählten Zeitraum gefunden.
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Gesamtverbrauch berechnen
|
||||
const gesamtVerbrauch = data.verbraucher.reduce((sum, v) => sum + v.verbrauch, 0);
|
||||
|
||||
let html = `
|
||||
<div class="info-box">
|
||||
<strong>Zeitraum:</strong> ${formatDate(data.zeitraum.von)} - ${formatDate(data.zeitraum.bis)}<br>
|
||||
<strong>Collections:</strong> ${data.collections.join(', ')}<br>
|
||||
<strong>Anzahl Verbraucher:</strong> ${data.verbraucher.length}
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Collection</th>
|
||||
<th>Verbraucher</th>
|
||||
<th class="number">Anfangswert (Wh)</th>
|
||||
<th>Anfangszeit</th>
|
||||
<th class="number">Endwert (Wh)</th>
|
||||
<th>Endzeit</th>
|
||||
<th class="number">Verbrauch (Wh)</th>
|
||||
<th class="number">Verbrauch (kWh)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
data.verbraucher.forEach(v => {
|
||||
html += `
|
||||
<tr>
|
||||
<td><strong>${v.collection}</strong></td>
|
||||
<td><strong>${v.verbraucher}</strong></td>
|
||||
<td class="number">${formatNumber(v.anfangsWert)}</td>
|
||||
<td>${formatDate(v.anfangsZeit)}</td>
|
||||
<td class="number">${formatNumber(v.endWert)}</td>
|
||||
<td>${formatDate(v.endZeit)}</td>
|
||||
<td class="number">${formatNumber(v.verbrauch)}</td>
|
||||
<td class="number">${formatNumber(v.verbrauch / 1000)}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="summary">
|
||||
<span class="summary-label">Gesamtverbrauch:</span>
|
||||
<span class="summary-value">${formatNumber(gesamtVerbrauch / 1000)} kWh</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
resultsDiv.innerHTML = html;
|
||||
}
|
||||
|
||||
// Beim Laden initialisieren
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
initializeDates();
|
||||
});
|
||||
Reference in New Issue
Block a user