Fügt eine optisch abgesetzte Summenzeile unter der Dashboard-Tabelle hinzu, die die Beträge der aktuell sichtbaren (per Spaltenfilter gefilterten) Einträge summiert und live aktualisiert. Schließt #6 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
280 lines
9.2 KiB
PHP
280 lines
9.2 KiB
PHP
<?php
|
|
require 'config.php';
|
|
require_once 'lib/fscash.php';
|
|
error_log('Session user_id: ' . (isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 'nicht gesetzt'));
|
|
// 1. Session-Prüfung (nur für geschützte Seiten)
|
|
if (!isset($_SESSION['user_id'])) {
|
|
header('Location: index.php');
|
|
exit;
|
|
}
|
|
|
|
// Ab hier: Nur für angemeldete Benutzer
|
|
error_log($_SESSION['user_id']);
|
|
|
|
// Rollen des angemeldeten Benutzers ermitteln
|
|
$roles = fscash_user_roles((int)$_SESSION['user_id'], $admin_ids, $aktien_ids);
|
|
if ($roles['is_admin']) {
|
|
$is_admin = "true";
|
|
}
|
|
if ($roles['is_aktien']) {
|
|
$is_aktien = "true";
|
|
}
|
|
|
|
// Aktuelles Jahr und Monat ermitteln, ggf. aus GET-Parametern
|
|
$year = isset($_GET['year']) ? (int)$_GET['year'] : (int)date('Y');
|
|
$month = isset($_GET['month']) ? (int)$_GET['month'] : (int)date('m');
|
|
|
|
// Monats- und Jahresgrenzen prüfen und anpassen
|
|
['month' => $month, 'year' => $year] = fscash_normalize_month_year($month, $year);
|
|
|
|
// Daten abrufen
|
|
$sql="WITH user_names AS (
|
|
SELECT
|
|
p.id,
|
|
b_single.username AS zahler,
|
|
GROUP_CONCAT(b_array.username) AS personen
|
|
FROM
|
|
entries p
|
|
LEFT JOIN users b_single ON p.user_id = b_single.id
|
|
JOIN JSON_TABLE(p.person, '$[*]' COLUMNS(id INT PATH '$')) AS jt
|
|
LEFT JOIN users b_array ON jt.id = b_array.id
|
|
GROUP BY
|
|
p.id, b_single.username
|
|
)
|
|
SELECT
|
|
e.*,
|
|
un.zahler,
|
|
un.personen,
|
|
c.name AS kategorie,
|
|
pm.name AS zahlweise
|
|
FROM
|
|
entries e
|
|
JOIN user_names un ON e.id = un.id
|
|
LEFT JOIN categories c ON e.category = c.category_id
|
|
LEFT JOIN payment_methods pm ON e.payment_method = pm.payment_method_id
|
|
WHERE
|
|
EXTRACT(YEAR FROM e.date) = :year
|
|
AND EXTRACT(MONTH FROM e.date) = :month
|
|
ORDER BY
|
|
e.date DESC, id desc;
|
|
";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute([
|
|
'year' => $year,
|
|
'month' => $month
|
|
]);
|
|
$entries = $stmt->fetchAll();
|
|
|
|
// Eindeutige Werte für die Filter-Dropdowns ermitteln
|
|
$filterZahler = [];
|
|
$filterPersonen = [];
|
|
$filterKategorie = [];
|
|
$filterZahlweise = [];
|
|
foreach ($entries as $entry) {
|
|
if (!empty($entry['zahler'])) {
|
|
$filterZahler[$entry['zahler']] = true;
|
|
}
|
|
if (!empty($entry['personen'])) {
|
|
foreach (explode(',', $entry['personen']) as $person) {
|
|
$person = trim($person);
|
|
if ($person !== '') {
|
|
$filterPersonen[$person] = true;
|
|
}
|
|
}
|
|
}
|
|
if (!empty($entry['kategorie'])) {
|
|
$filterKategorie[$entry['kategorie']] = true;
|
|
}
|
|
if (!empty($entry['zahlweise'])) {
|
|
$filterZahlweise[$entry['zahlweise']] = true;
|
|
}
|
|
}
|
|
// Vorauswahl der Filter aus GET-Parametern (z. B. Link aus einem Report)
|
|
$presetZahler = isset($_GET['zahler']) ? $_GET['zahler'] : '';
|
|
$presetKategorie = isset($_GET['kategorie']) ? $_GET['kategorie'] : '';
|
|
$presetKategorien = isset($_GET['kategorien']) && is_array($_GET['kategorien']) ? $_GET['kategorien'] : [];
|
|
|
|
$filterZahler = array_keys($filterZahler);
|
|
$filterPersonen = array_keys($filterPersonen);
|
|
$filterKategorie = array_keys($filterKategorie);
|
|
$filterZahlweise = array_keys($filterZahlweise);
|
|
sort($filterZahler, SORT_STRING | SORT_FLAG_CASE);
|
|
sort($filterPersonen, SORT_STRING | SORT_FLAG_CASE);
|
|
sort($filterKategorie, SORT_STRING | SORT_FLAG_CASE);
|
|
sort($filterZahlweise, SORT_STRING | SORT_FLAG_CASE);
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
|
<title>FSCash - Dashboard</title>
|
|
<link rel="stylesheet" href="assets/css/style.css">
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<!-- Navigation -->
|
|
<nav class="nav">
|
|
<button class="hamburger">☰</button>
|
|
<ul class="nav-list">
|
|
<li><a href="dashboard.php">Start</a></li>
|
|
<?php if ($is_aktien === "true") echo '<li><a href="aktien.php">Aktien</a></li>'; ?>
|
|
<?php if ($is_admin === "true") echo '<li><a href="register.php">Neue User</a></li>'; ?>
|
|
<li><a href="rep-month.php">Report Monat</a></li>
|
|
<li><a href="rep-person.php">Report Personen</a></li>
|
|
<li><a href="menu5.php" style="display: none;">Menüpunkt 5</a></li>
|
|
</ul>
|
|
<!-- Container für die rechten Buttons -->
|
|
<div class="nav-right">
|
|
<a href="?year=<?= $year ?>&month=<?= $month - 1 ?>" class="nav-button"> < </a>
|
|
<a href="?year=<?= $year ?>&month=<?= $month + 1 ?>" class="nav-button"> > </a>
|
|
<a href="logout.php" class="logout">Logout</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<h2><?= strftime('%B %Y', mktime(0, 0, 0, $month, 1, $year)) ?></h2>
|
|
|
|
<!-- Tabelle -->
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Datum</th>
|
|
<th class="hide-on-mobile">Zahler</th>
|
|
<th class="hide-on-mobile">Person</th>
|
|
<th class="hide-on-mobile">Kategorie</th>
|
|
<th>Zahlweise</th>
|
|
<th>Betreff</th>
|
|
<th>Betrag</th>
|
|
<th class="hide-on-mobile">Hinweis</th>
|
|
<th> </th>
|
|
</tr>
|
|
<tr class="filter-row">
|
|
<th><input type="text" class="column-filter" data-col="0" placeholder="Filter…"></th>
|
|
<th class="hide-on-mobile">
|
|
<select class="column-filter" data-col="1">
|
|
<option value="">Alle</option>
|
|
<?php foreach ($filterZahler as $wert): ?>
|
|
<option value="<?= htmlspecialchars($wert) ?>" <?= $wert === $presetZahler ? 'selected' : '' ?>><?= htmlspecialchars($wert) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</th>
|
|
<th class="hide-on-mobile">
|
|
<select class="column-filter" data-col="2">
|
|
<option value="">Alle</option>
|
|
<?php foreach ($filterPersonen as $wert): ?>
|
|
<option value="<?= htmlspecialchars($wert) ?>"><?= htmlspecialchars($wert) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</th>
|
|
<th class="hide-on-mobile">
|
|
<select class="column-filter" data-col="3">
|
|
<option value="">Alle</option>
|
|
<?php foreach ($filterKategorie as $wert): ?>
|
|
<option value="<?= htmlspecialchars($wert) ?>" <?= $wert === $presetKategorie ? 'selected' : '' ?>><?= htmlspecialchars($wert) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</th>
|
|
<th>
|
|
<select class="column-filter" data-col="4">
|
|
<option value="">Alle</option>
|
|
<?php foreach ($filterZahlweise as $wert): ?>
|
|
<option value="<?= htmlspecialchars($wert) ?>"><?= htmlspecialchars($wert) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</th>
|
|
<th><input type="text" class="column-filter" data-col="5" placeholder="Filter…"></th>
|
|
<th><input type="text" class="column-filter" data-col="6" placeholder="Filter…"></th>
|
|
<th class="hide-on-mobile"><input type="text" class="column-filter" data-col="7" placeholder="Filter…"></th>
|
|
<th> </th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="entries-body">
|
|
<?php foreach ($entries as $entry): ?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($entry['date']) ?></td>
|
|
<td class="hide-on-mobile"><?= htmlspecialchars($entry['zahler'] ?? '') ?></td>
|
|
<td class="hide-on-mobile"><?= htmlspecialchars($entry['personen'] ?? '') ?></td>
|
|
<td class="hide-on-mobile"><?= htmlspecialchars($entry['kategorie'] ?? '') ?></td>
|
|
<td><?= htmlspecialchars($entry['zahlweise'] ?? '') ?></td>
|
|
<td><?= htmlspecialchars($entry['subject']) ?></td>
|
|
<td class="align-right" data-amount="<?= htmlspecialchars($entry['amount']) ?>"><?= htmlspecialchars( number_format($entry['amount'], 2, ',', '.')) ?></td>
|
|
<td class="hide-on-mobile"><?= htmlspecialchars($entry['note']) ?></td>
|
|
<td class="hide-on-mobile">
|
|
<a href="edit_entry.php?id=<?= $entry['id'] ?>">
|
|
<img class="pencil" src="/assets/img/pencil.png" width="20px" />
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
<tfoot>
|
|
<tr class="sum-row">
|
|
<td>Summe</td>
|
|
<td class="hide-on-mobile"></td>
|
|
<td class="hide-on-mobile"></td>
|
|
<td class="hide-on-mobile"></td>
|
|
<td></td>
|
|
<td></td>
|
|
<td class="align-right" id="sum-value">0,00</td>
|
|
<td class="hide-on-mobile"></td>
|
|
<td></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
|
|
<!-- Neu-Button -->
|
|
<a href="new_entry.php" class="btn-xr">+</a>
|
|
</div>
|
|
|
|
<script>
|
|
// Hamburger-Menü-Funktion
|
|
document.querySelector('.hamburger').addEventListener('click', function() {
|
|
document.querySelector('.nav-list').classList.toggle('show');
|
|
});
|
|
|
|
// Spaltenfilter für die Tabelle
|
|
(function() {
|
|
const filters = document.querySelectorAll('.column-filter');
|
|
const rows = document.querySelectorAll('#entries-body tr');
|
|
const sumValue = document.getElementById('sum-value');
|
|
// Mehrfach-Kategorie-Vorauswahl, z. B. per Link aus dem Personenreport (Kategorie-Select kann nur einen Wert anzeigen)
|
|
const presetKategorien = <?= json_encode(array_map('strtolower', $presetKategorien)) ?>;
|
|
|
|
function applyFilters() {
|
|
const activeFilters = Array.from(filters)
|
|
.map(f => ({ col: parseInt(f.dataset.col, 10), value: f.value.trim().toLowerCase() }))
|
|
.filter(f => f.value !== '');
|
|
|
|
let sum = 0;
|
|
rows.forEach(row => {
|
|
const cells = row.children;
|
|
const visible = activeFilters.every(f => {
|
|
const cell = cells[f.col];
|
|
if (!cell) return true;
|
|
return cell.textContent.trim().toLowerCase().includes(f.value);
|
|
}) && (presetKategorien.length === 0 || (cells[3] && presetKategorien.includes(cells[3].textContent.trim().toLowerCase())));
|
|
row.style.display = visible ? '' : 'none';
|
|
if (visible) {
|
|
const amountCell = cells[6];
|
|
if (amountCell) {
|
|
sum += parseFloat(amountCell.dataset.amount) || 0;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (sumValue) {
|
|
sumValue.textContent = sum.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
}
|
|
}
|
|
|
|
filters.forEach(f => {
|
|
f.addEventListener('input', applyFilters);
|
|
f.addEventListener('change', applyFilters);
|
|
});
|
|
|
|
applyFilters();
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|