Kaynağa Gözat

first commit

root 2 gün önce
işleme
c84a55b460
8 değiştirilmiş dosya ile 804 ekleme ve 0 silme
  1. 8 0
      .gitignore
  2. 285 0
      admin.php
  3. 99 0
      besitz.php
  4. 9 0
      config.sample.php
  5. 16 0
      db_config.php
  6. 153 0
      gesamtliste.php
  7. 36 0
      gespielte_spiele.php
  8. 198 0
      index.php

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
+# Geheimnisse ignorieren
+config.php
+
+# Bilder-Cache ignorieren (optional)
+img/*
+
+# Temporäre Dateien
+.DS_Store

+ 285 - 0
admin.php

@@ -0,0 +1,285 @@
+<?php
+session_start();
+require_once 'config.php'; // Enthält ADMIN_PASSWORD und DB-Konstanten
+
+// --- 1. LOGOUT LOGIK ---
+if (isset($_GET['logout'])) {
+    session_destroy();
+    header("Location: admin.php");
+    exit;
+}
+
+// --- 2. LOGIN SCHUTZ ---
+$show_login = true;
+if (isset($_SESSION['admin_auth']) && $_SESSION['admin_auth'] === true) {
+    $show_login = false;
+}
+
+if (isset($_POST['login_auth'])) {
+    if ($_POST['pw'] === ADMIN_PASSWORD) {
+        $_SESSION['admin_auth'] = true;
+        $show_login = false;
+    } else {
+        $login_error = "Falsches Passwort!";
+    }
+}
+
+if ($show_login):
+?>
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <title>Admin Login</title>
+    <style>
+        body { font-family: 'Segoe UI', sans-serif; background: #121212; color: white; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
+        .login-box { background: #1e1e1e; padding: 40px; border-radius: 12px; border: 1px solid #e67e22; text-align: center; box-shadow: 0 10px 30px rgba(0,0,0,0.5); width: 300px; }
+        input { width: 100%; padding: 12px; margin: 15px 0; border-radius: 5px; border: 1px solid #444; background: #2a2a2a; color: white; box-sizing: border-box; }
+        button { background: #e67e22; color: white; border: none; padding: 12px; border-radius: 5px; cursor: pointer; width: 100%; font-weight: bold; }
+        .error { color: #e74c3c; margin-bottom: 10px; font-size: 0.9em; }
+        a { color: #888; text-decoration: none; font-size: 0.8em; margin-top: 15px; display: inline-block; }
+    </style>
+</head>
+<body>
+    <div class="login-box">
+        <h2>🔐 Admin Login</h2>
+        <?php if(isset($login_error)) echo "<div class='error'>$login_error</div>"; ?>
+        <form method="POST">
+            <input type="password" name="pw" placeholder="Passwort" autofocus required>
+            <button type="submit" name="login_auth">Einloggen</button>
+        </form>
+        <a href="index.php"> Zurück zum Dashboard</a>
+    </div>
+</body>
+</html>
+<?php
+    exit;
+endif;
+
+// --- 3. HAUPT-LOGIK (NUR ERREICHBAR WENN EINGELOGGT) ---
+require_once 'db_config.php';
+$msg = "";
+
+// Bild-Download Hilfsfunktion
+function downloadGameImage($ean, $url) {
+    if (!empty($ean) && filter_var($url, FILTER_VALIDATE_URL)) {
+        $content = @file_get_contents($url);
+        if ($content) {
+            if (!is_dir('img')) mkdir('img', 0777, true);
+            $path = "img/" . $ean . ".jpg";
+            file_put_contents($path, $content);
+            return $path;
+        }
+    }
+    return null;
+}
+
+// SPIEL HINZUFÜGEN
+if (isset($_POST['add_new_game'])) {
+    $ean = $_POST['new_ean'];
+    $bild_url = "https://via.placeholder.com/60";
+    if (!empty($_POST['new_bild_quelle'])) {
+        $downloaded = downloadGameImage($ean, $_POST['new_bild_quelle']);
+        if ($downloaded) $bild_url = $downloaded;
+    }
+    $stmt = $pdo->prepare("INSERT INTO spiele (titel, typ_id, ean, level, bild_url) VALUES (?, ?, ?, ?, ?)");
+    $stmt->execute([$_POST['new_titel'], (int)$_POST['new_typ_id'], $ean, $_POST['new_level'], $bild_url]);
+    $msg = "Spiel erfolgreich angelegt!";
+}
+
+// SPIEL AKTUALISIEREN
+if (isset($_POST['update_game'])) {
+    $spiel_id = (int)$_POST['spiel_id'];
+    $ean = $_POST['ean'];
+    if (!empty($_POST['update_bild_quelle'])) {
+        $new_path = downloadGameImage($ean, $_POST['update_bild_quelle']);
+        if ($new_path) $pdo->prepare("UPDATE spiele SET bild_url = ? WHERE id = ?")->execute([$new_path, $spiel_id]);
+    }
+    $stmt = $pdo->prepare("UPDATE spiele SET titel = ?, typ_id = ?, ean = ?, level = ? WHERE id = ?");
+    $stmt->execute([$_POST['titel'], (int)$_POST['typ_id'], $ean, $_POST['level'], $spiel_id]);
+    $msg = "Änderungen gespeichert!";
+}
+
+// SPIEL LÖSCHEN
+if (isset($_POST['delete_game'])) {
+    $pdo->prepare("DELETE FROM spiele WHERE id = ?")->execute([(int)$_POST['spiel_id']]);
+    $msg = "Spiel wurde gelöscht!";
+}
+
+// GRUPPEN & TYPEN LOGIK
+if (isset($_POST['add_player'])) { $pdo->prepare("INSERT INTO spieler (name) VALUES (?)")->execute([$_POST['player_name']]); }
+if (isset($_POST['delete_player'])) { $pdo->prepare("DELETE FROM spieler WHERE id = ?")->execute([(int)$_POST['player_id']]); }
+if (isset($_POST['add_type'])) { $pdo->prepare("INSERT INTO game_typen (bezeichnung) VALUES (?)")->execute([$_POST['type_name']]); }
+if (isset($_POST['delete_type'])) { $pdo->prepare("DELETE FROM game_typen WHERE id = ?")->execute([(int)$_POST['type_id']]); }
+
+// DATEN LADEN
+$spiele = $pdo->query("SELECT s.*, t.bezeichnung as typ_name FROM spiele s LEFT JOIN game_typen t ON s.typ_id = t.id ORDER BY s.id DESC")->fetchAll();
+$spieler = $pdo->query("SELECT * FROM spieler ORDER BY id ASC")->fetchAll();
+$typen = $pdo->query("SELECT * FROM game_typen ORDER BY bezeichnung ASC")->fetchAll();
+?>
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <title>EXIT Admin - Verwaltung</title>
+    <style>
+        body { font-family: 'Segoe UI', sans-serif; background: #f4f7f6; padding: 20px; color: #333; }
+        .container { max-width: 1200px; margin: 0 auto; }
+        .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
+        .alert { background: #27ae60; color: white; padding: 15px; border-radius: 8px; margin-bottom: 20px; text-align: center; font-weight: bold; }
+        
+        .tabs { display: flex; gap: 5px; }
+        .tab-button { padding: 12px 25px; cursor: pointer; background: #ddd; border: none; border-radius: 8px 8px 0 0; font-weight: bold; transition: 0.3s; }
+        .tab-button.active { background: #fff; border-top: 4px solid #e67e22; color: #e67e22; }
+        
+        .tab-content { background: #fff; padding: 25px; border-radius: 0 8px 8px 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.05); display: none; }
+        .tab-content.active { display: block; }
+
+        table { width: 100%; border-collapse: collapse; margin-top: 15px; }
+        th, td { padding: 12px; border-bottom: 1px solid #eee; text-align: left; }
+        input, select { padding: 8px; border: 1px solid #ddd; border-radius: 5px; width: 100%; box-sizing: border-box; }
+        
+        .btn { padding: 8px 15px; border: none; border-radius: 5px; color: white; cursor: pointer; font-weight: bold; text-decoration: none; display: inline-block; }
+        .btn-add { background: #27ae60; }
+        .btn-save { background: #2980b9; }
+        .btn-del { background: #e74c3c; }
+        .logout { background: #c0392b; font-size: 0.8em; }
+    </style>
+</head>
+<body>
+
+<div class="container">
+    <div class="header">
+        <h1>🛠 Stammdaten</h1>
+        <div>
+            <a href="index.php" class="btn btn-save">Dashboard</a>
+            <a href="admin.php?logout=1" class="btn logout">Abmelden 🚪</a>
+        </div>
+    </div>
+
+    <?php if ($msg): ?><div class="alert" id="msg-box"><?= $msg ?></div><?php endif; ?>
+
+    <div class="tabs">
+        <button class="tab-button active" onclick="openTab(event, 'tab-spiele')">🎮 Spiele</button>
+        <button class="tab-button" onclick="openTab(event, 'tab-gruppen')">👥 Gruppen</button>
+        <button class="tab-button" onclick="openTab(event, 'tab-typen')">🏷 Typen</button>
+    </div>
+
+    <div id="tab-spiele" class="tab-content active">
+        <div style="background:#f9f9f9; padding:20px; border-radius:8px; border:1px solid #eee; margin-bottom:30px;">
+            <h3>🆕 Neues Spiel erfassen</h3>
+            <form method="POST">
+                <div style="display:grid; grid-template-columns: 2fr 1fr 1fr 1fr 2fr; gap:10px;">
+                    <input type="text" name="new_titel" placeholder="Spieltitel" required>
+                    <select name="new_typ_id">
+                        <?php foreach($typen as $t): ?><option value="<?= $t['id'] ?>"><?= htmlspecialchars($t['bezeichnung']) ?></option><?php endforeach; ?>
+                    </select>
+                    <input type="text" name="new_ean" placeholder="EAN" required>
+                    <select name="new_level">
+                        <option value="Einsteiger">Einsteiger</option>
+                        <option value="Fortgeschrittene">Fortgeschrittene</option>
+                        <option value="Profi">Profi</option>
+                    </select>
+                    <input type="text" name="new_bild_quelle" placeholder="Bild-URL (Download)">
+                </div>
+                <button type="submit" name="add_new_game" class="btn btn-add" style="margin-top:15px; width:100%;">Spiel in Datenbank speichern</button>
+            </form>
+        </div>
+
+        <table>
+            <thead><tr><th>Bild</th><th>Titel & Typ</th><th>EAN</th><th>Level</th><th>Aktion</th></tr></thead>
+            <tbody>
+                <?php foreach ($spiele as $sp): ?>
+                <tr>
+                    <form method="POST">
+                        <input type="hidden" name="spiel_id" value="<?= $sp['id'] ?>">
+                        <td width="60"><img src="<?= $sp['bild_url'] ?>" width="50" style="border-radius:4px;"></td>
+                        <td>
+                            <input type="text" name="titel" value="<?= htmlspecialchars($sp['titel']) ?>" style="margin-bottom:5px;">
+                            <select name="typ_id">
+                                <?php foreach($typen as $t): ?>
+                                    <option value="<?= $t['id'] ?>" <?= $sp['typ_id']==$t['id']?'selected':'' ?>><?= htmlspecialchars($t['bezeichnung']) ?></option>
+                                <?php endforeach; ?>
+                            </select>
+                        </td>
+                        <td><input type="text" name="ean" value="<?= htmlspecialchars($sp['ean']) ?>"></td>
+                        <td>
+                            <select name="level">
+                                <option value="Einsteiger" <?= $sp['level']=='Einsteiger'?'selected':'' ?>>Einsteiger</option>
+                                <option value="Fortgeschrittene" <?= $sp['level']=='Fortgeschrittene'?'selected':'' ?>>Fortgeschrittene</option>
+                                <option value="Profi" <?= $sp['level']=='Profi'?'selected':'' ?>>Profi</option>
+                            </select>
+                        </td>
+                        <td style="white-space:nowrap;">
+                            <button type="submit" name="update_game" class="btn btn-save" title="Speichern">💾</button>
+                            <button type="submit" name="delete_game" class="btn btn-del" onclick="return confirm('Wirklich löschen?')" title="Löschen">🗑</button>
+                        </td>
+                    </form>
+                </tr>
+                <?php endforeach; ?>
+            </tbody>
+        </table>
+    </div>
+
+    <div id="tab-gruppen" class="tab-content">
+        <h3>👥 Teams / Spieler</h3>
+        <form method="POST" style="display:flex; gap:10px; margin-bottom:20px;">
+            <input type="text" name="player_name" placeholder="Name der Gruppe" required>
+            <button type="submit" name="add_player" class="btn btn-add">Anlegen</button>
+        </form>
+        <table>
+            <?php foreach ($spieler as $s): ?>
+            <tr>
+                <td><?= htmlspecialchars($s['name']) ?></td>
+                <td width="50">
+                    <form method="POST">
+                        <input type="hidden" name="player_id" value="<?= $s['id'] ?>">
+                        <button type="submit" name="delete_player" class="btn btn-del">🗑</button>
+                    </form>
+                </td>
+            </tr>
+            <?php endforeach; ?>
+        </table>
+    </div>
+
+    <div id="tab-typen" class="tab-content">
+        <h3>🏷 Spiel-Typen (z.B. EXIT, Adventure Games)</h3>
+        <form method="POST" style="display:flex; gap:10px; margin-bottom:20px;">
+            <input type="text" name="type_name" placeholder="Typ-Bezeichnung" required>
+            <button type="submit" name="add_type" class="btn btn-add">Anlegen</button>
+        </form>
+        <table>
+            <?php foreach ($typen as $t): ?>
+            <tr>
+                <td><?= htmlspecialchars($t['bezeichnung']) ?></td>
+                <td width="50">
+                    <form method="POST">
+                        <input type="hidden" name="type_id" value="<?= $t['id'] ?>">
+                        <button type="submit" name="delete_type" class="btn btn-del">🗑</button>
+                    </form>
+                </td>
+            </tr>
+            <?php endforeach; ?>
+        </table>
+    </div>
+</div>
+
+<script>
+    function openTab(evt, tabName) {
+        var i, tabcontent, tablinks;
+        tabcontent = document.getElementsByClassName("tab-content");
+        for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; }
+        tablinks = document.getElementsByClassName("tab-button");
+        for (i = 0; i < tablinks.length; i++) { tablinks[i].className = tablinks[i].className.replace(" active", ""); }
+        document.getElementById(tabName).style.display = "block";
+        evt.currentTarget.className += " active";
+    }
+
+    setTimeout(function() {
+        var msg = document.getElementById('msg-box');
+        if(msg) msg.style.display = 'none';
+    }, 3000);
+</script>
+
+</body>
+</html>

+ 99 - 0
besitz.php

@@ -0,0 +1,99 @@
+<?php
+require_once 'db_config.php';
+$msg = "";
+
+// Status-Update Logik
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_status'])) {
+    $stmt = $pdo->prepare("INSERT INTO besitzstatus (spieler_id, spiel_id, status) 
+                           VALUES (?, ?, ?) 
+                           ON DUPLICATE KEY UPDATE status = VALUES(status)");
+    $stmt->execute([(int)$_POST['spieler_id'], (int)$_POST['spiel_id'], $_POST['status']]);
+    $msg = "Status aktualisiert!";
+}
+
+$spieler = $pdo->query("SELECT * FROM spieler ORDER BY name ASC")->fetchAll();
+$spiele = $pdo->query("SELECT s.*, t.bezeichnung as typ_name FROM spiele s LEFT JOIN game_typen t ON s.typ_id = t.id ORDER BY s.titel ASC")->fetchAll();
+?>
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <title>EXIT - Bestandsverwaltung</title>
+    <style>
+        body { font-family: 'Segoe UI', sans-serif; background: #121212; color: #e0e0e0; padding: 20px; }
+        .container { max-width: 1200px; margin: auto; }
+        h1 { color: #e67e22; }
+        .alert { background: #27ae60; color: white; padding: 10px; border-radius: 5px; margin-bottom: 20px; text-align: center; }
+        table { width: 100%; border-collapse: collapse; background: #1e1e1e; border-radius: 8px; overflow: hidden; }
+        th, td { padding: 12px; border-bottom: 1px solid #333; text-align: left; }
+        th { background: #2a2a2a; color: #e67e22; text-transform: uppercase; font-size: 0.85em; }
+        .game-info { display: flex; align-items: center; gap: 15px; }
+        .game-info img { width: 40px; height: 40px; object-fit: cover; border-radius: 4px; border: 1px solid #444; }
+        select { background: #2a2a2a; color: white; border: 1px solid #444; padding: 5px; border-radius: 4px; width: 100%; cursor: pointer; }
+        select.besitzt { border-left: 4px solid #27ae60; }
+        select.verkauft { border-left: 4px solid #f39c12; }
+        select.nicht { border-left: 4px solid #7f8c8d; }
+        .back-link { color: #e67e22; text-decoration: none; font-weight: bold; margin-bottom: 20px; display: inline-block; }
+    </style>
+</head>
+<body>
+<div class="container">
+    <a href="index.php" class="back-link">← Zurück zum Dashboard</a>
+    <h1>📦 Bestandsverwaltung</h1>
+    
+    <?php if ($msg): ?><div class="alert" id="msg-box"><?= $msg ?></div><?php endif; ?>
+
+    <table>
+        <thead>
+            <tr>
+                <th>Spiel</th>
+                <?php foreach ($spieler as $s): ?>
+                    <th><?= htmlspecialchars($s['name']) ?></th>
+                <?php endforeach; ?>
+            </tr>
+        </thead>
+        <tbody>
+            <?php foreach ($spiele as $sp): ?>
+            <tr>
+                <td>
+                    <div class="game-info">
+                        <img src="<?= htmlspecialchars($sp['bild_url']) ?>">
+                        <div>
+                            <strong><?= htmlspecialchars($sp['titel']) ?></strong><br>
+                            <small style="color:#888"><?= htmlspecialchars($sp['typ_name']) ?></small>
+                        </div>
+                    </div>
+                </td>
+                <?php foreach ($spieler as $s): 
+                    $st_stmt = $pdo->prepare("SELECT status FROM besitzstatus WHERE spieler_id = ? AND spiel_id = ?");
+                    $st_stmt->execute([$s['id'], $sp['id']]);
+                    $current = $st_stmt->fetchColumn() ?: 'nicht besitzt';
+                    $class = ($current == 'besitzt') ? 'besitzt' : (($current == 'verkauft') ? 'verkauft' : 'nicht');
+                ?>
+                    <td>
+                        <form method="POST" style="margin:0;">
+                            <input type="hidden" name="update_status" value="1">
+                            <input type="hidden" name="spieler_id" value="<?= $s['id'] ?>">
+                            <input type="hidden" name="spiel_id" value="<?= $sp['id'] ?>">
+                            <select name="status" class="<?= $class ?>" onchange="this.form.submit()">
+                                <option value="besitzt" <?= $current == 'besitzt' ? 'selected' : '' ?>>Besitzt</option>
+                                <option value="nicht besitzt" <?= $current == 'nicht besitzt' ? 'selected' : '' ?>>Nicht</option>
+                                <option value="verkauft" <?= $current == 'verkauft' ? 'selected' : '' ?>>Verkauft</option>
+                            </select>
+                        </form>
+                    </td>
+                <?php endforeach; ?>
+            </tr>
+            <?php endforeach; ?>
+        </tbody>
+    </table>
+</div>
+
+<script>
+    setTimeout(function() { 
+        var msg = document.getElementById('msg-box'); 
+        if(msg) msg.style.opacity = '0'; 
+    }, 2000);
+</script>
+</body>
+</html>

+ 9 - 0
config.sample.php

@@ -0,0 +1,9 @@
+<?php
+// BEISPIEL-DATEI: Umbenennen in config.php und Daten ausfüllen
+define('DB_HOST', 'localhost');
+define('DB_NAME', 'datenbankname');
+define('DB_USER', 'benutzer');
+define('DB_PASS', 'passwort');
+define('DB_CHARSET', 'utf8mb4');
+define('ADMIN_PASSWORD', 'passwort123');
+?>

+ 16 - 0
db_config.php

@@ -0,0 +1,16 @@
+<?php
+require_once 'config.php';
+
+$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=" . DB_CHARSET;
+$options = [
+    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
+    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+    PDO::ATTR_EMULATE_PREPARES   => false,
+];
+
+try {
+    $pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
+} catch (\PDOException $e) {
+    die("Datenbankverbindung fehlgeschlagen: " . $e->getMessage());
+}
+?>

+ 153 - 0
gesamtliste.php

@@ -0,0 +1,153 @@
+<?php
+require_once 'db_config.php';
+
+$filterPlayerId = isset($_GET['team_filter']) ? (int)$_GET['team_filter'] : 0;
+
+// SQL-Abfrage: :fid wird für den Einzel-Status genutzt, :pid für den globalen Filter
+$sql = "SELECT sp.*, t.bezeichnung as typ_name, MAX(sc.sterne) as best_sterne, 
+               (SELECT status FROM besitzstatus WHERE spiel_id = sp.id AND spieler_id = :fid) as einzel_status,
+               (SELECT GROUP_CONCAT(CONCAT(p.name, ': ', b.status) SEPARATOR '||') 
+                FROM besitzstatus b JOIN spieler p ON b.spieler_id = p.id 
+                WHERE b.spiel_id = sp.id AND b.status != 'nicht besitzt') as besitz_info
+        FROM spiele sp
+        LEFT JOIN game_typen t ON sp.typ_id = t.id
+        LEFT JOIN scores sc ON sp.id = sc.spiel_id " . 
+        ($filterPlayerId > 0 ? " AND sc.spieler_id = :pid " : "") . "
+        GROUP BY sp.id ORDER BY sp.id DESC";
+
+$stmt = $pdo->prepare($sql);
+
+// Parameter-Array vorbereiten
+$params = ['fid' => $filterPlayerId]; // :fid wird immer benötigt für die Subquery
+if ($filterPlayerId > 0) {
+    $params['pid'] = $filterPlayerId; // :pid nur hinzufügen, wenn der Filter aktiv ist
+}
+
+$stmt->execute($params);
+$inventory = $stmt->fetchAll();
+
+$spieler = $pdo->query("SELECT * FROM spieler ORDER BY id ASC")->fetchAll();
+?>
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <title>EXIT Gesamtliste</title>
+    <style>
+        body { font-family: 'Segoe UI', sans-serif; background: #f8f9fa; padding: 20px; }
+        .container { max-width: 1400px; margin: 0 auto; }
+        table { width: 100%; border-collapse: collapse; background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
+        th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid #eee; }
+        th { background: #e67e22; color: white; cursor: pointer; font-size: 0.8em; text-transform: uppercase; }
+        .game-thumb { width: 50px; height: 50px; object-fit: cover; border-radius: 8px; }
+        .lvl-badge { padding: 4px 8px; border-radius: 4px; color: white; font-size: 0.7em; font-weight: bold; }
+        .lvl-Einsteiger { background: #27ae60; } .lvl-Fortgeschrittene { background: #2980b9; } .lvl-Profi { background: #c0392b; }
+        .st-badge { padding: 4px 8px; border-radius: 12px; font-size: 0.7em; font-weight: bold; display: inline-block; }
+        .st-besitzt { background: #d4edda; color: #155724; }
+        .st-verkauft { background: #fff3cd; color: #856404; }
+        .st-keins { background: #f8d7da; color: #721c24; }
+        .team-pill { display: inline-block; background: #eee; padding: 2px 6px; border-radius: 4px; font-size: 0.8em; margin: 2px; border: 1px solid #ddd; }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div style="display:flex; justify-content: space-between; align-items:center; margin-bottom:20px;">
+        <h1>📝 Sammlungs-Übersicht</h1>
+        <a href="index.php" style="color:#e67e22; font-weight:bold; text-decoration:none;">← Dashboard</a>
+    </div>
+
+    <div style="background:white; padding:15px; border-radius:10px; margin-bottom:20px; display:flex; gap:15px;">
+        <form method="GET">
+            <select name="team_filter" onchange="this.form.submit()" style="padding:10px; border-radius:5px;">
+                <option value="0">-- Alle Teams --</option>
+                <?php foreach ($spieler as $p): ?>
+                    <option value="<?= $p['id'] ?>" <?= $filterPlayerId == $p['id'] ? 'selected' : '' ?>><?= htmlspecialchars($p['name']) ?></option>
+                <?php endforeach; ?>
+            </select>
+        </form>
+        <input type="text" id="searchInput" placeholder="Suchen..." onkeyup="filterTable()" style="flex-grow:1; padding:10px; border:1px solid #ddd; border-radius:5px;">
+    </div>
+
+    <table id="exitTable">
+        <thead>
+            <tr>
+                <th onclick="sortTable(0)">ID</th>
+                <th>Bild</th>
+                <th onclick="sortTable(2)">Titel</th>
+                <th>Level</th>
+                <th>Bestwert</th>
+                <th>Besitzstatus</th>
+            </tr>
+        </thead>
+        <tbody>
+            <?php foreach ($inventory as $row): ?>
+            <tr>
+                <td>#<?= $row['id'] ?></td>
+                <td><img src="<?= $row['bild_url'] ?>" class="game-thumb" onerror="this.src='https://via.placeholder.com/50?text=?'"></td>
+                <td><strong><?= htmlspecialchars($row['titel']) ?></strong><br><small style="color:#666;"><?= htmlspecialchars($row['typ_name'] ?? 'Unbekannt') ?></small></td>
+                <td><span class="lvl-badge lvl-<?= $row['level'] ?>"><?= $row['level'] ?></span></td>
+                <td><?= $row['best_sterne'] ? "<b style='color:#e67e22'>{$row['best_sterne']} ★</b>" : "-" ?></td>
+                <td>
+                    <?php if ($filterPlayerId > 0): 
+                        $st = $row['einzel_status'] ?: 'nicht besitzt';
+                        $class = ($st == 'besitzt') ? 'st-besitzt' : (($st == 'verkauft') ? 'st-verkauft' : 'st-keins');
+                    ?>
+                        <span class="st-badge <?= $class ?>"><?= strtoupper($st) ?></span>
+                    <?php else: ?>
+                        <?php 
+                        if ($row['besitz_info']) {
+                            $teams = explode('||', $row['besitz_info']);
+                            foreach ($teams as $t) {
+                                $parts = explode(': ', $t);
+                                if(count($parts) < 2) continue;
+                                $tname = $parts[0]; $tstat = $parts[1];
+                                $color = ($tstat == 'besitzt') ? '#27ae60' : '#f39c12';
+                                echo "<span class='team-pill'><b style='color:$color'>●</b> " . htmlspecialchars($tname) . " (" . htmlspecialchars($tstat) . ")</span>";
+                            }
+                        } else { echo "<small style='color:#ccc'>Kein Team besitzt es</small>"; }
+                        ?>
+                    <?php endif; ?>
+                </td>
+            </tr>
+            <?php endforeach; ?>
+        </tbody>
+    </table>
+</div>
+
+<script>
+    function filterTable() {
+        let input = document.getElementById("searchInput"), 
+            filter = input.value.toUpperCase(), 
+            tr = document.getElementById("exitTable").getElementsByTagName("tr");
+        for (let i = 1; i < tr.length; i++) {
+            tr[i].style.display = tr[i].innerText.toUpperCase().includes(filter) ? "" : "none";
+        }
+    }
+
+    function sortTable(n) {
+        var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
+        table = document.getElementById("exitTable");
+        switching = true; dir = "asc";
+        while (switching) {
+            switching = false; rows = table.rows;
+            for (i = 1; i < (rows.length - 1); i++) {
+                shouldSwitch = false;
+                x = rows[i].getElementsByTagName("TD")[n];
+                y = rows[i + 1].getElementsByTagName("TD")[n];
+                var valX = x.innerText.toLowerCase().replace('#', '');
+                var valY = y.innerText.toLowerCase().replace('#', '');
+                if (n === 0) { valX = parseInt(valX); valY = parseInt(valY); }
+                if (dir == "asc") { if (valX > valY) { shouldSwitch = true; break; }
+                } else { if (valX < valY) { shouldSwitch = true; break; } }
+            }
+            if (shouldSwitch) {
+                rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
+                switching = true; switchcount ++;
+            } else {
+                if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; }
+            }
+        }
+    }
+</script>
+</body>
+</html>

+ 36 - 0
gespielte_spiele.php

@@ -0,0 +1,36 @@
+<?php
+include 'db_config.php'; // Falls du die Connection auslagerst, sonst Code von oben kopieren
+
+$sql = "SELECT DISTINCT sp.* FROM spiele sp
+        JOIN scores sc ON sp.id = sc.spiel_id
+        ORDER BY sp.titel ASC";
+$stmt = $pdo->query($sql);
+$playedGames = $stmt->fetchAll();
+?>
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <title>Gespielte Spiele</title>
+    <style>
+        body { font-family: sans-serif; background: #121212; color: white; padding: 20px; }
+        .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; }
+        .item { background: #1e1e1e; padding: 10px; border-radius: 8px; text-align: center; border: 1px solid #333; }
+        .item img { width: 100%; border-radius: 4px; height: 150px; object-fit: cover; }
+        h1 { color: #e67e22; }
+        .back { display: inline-block; margin-bottom: 20px; color: #e67e22; text-decoration: none; }
+    </style>
+</head>
+<body>
+    <a href="index.php" class="back">← Zurück zum Dashboard</a>
+    <h1>📂 Gelöste Abenteuer</h1>
+    <div class="grid">
+        <?php foreach ($playedGames as $game): ?>
+            <div class="item">
+                <img src="<?= htmlspecialchars($game['bild_url']) ?>">
+                <p><?= htmlspecialchars($game['titel']) ?></p>
+            </div>
+        <?php endforeach; ?>
+    </div>
+</body>
+</html>

+ 198 - 0
index.php

@@ -0,0 +1,198 @@
+<?php
+include 'db_config.php'; // Falls du die Connection auslagerst, sonst Code von oben kopieren
+
+
+// --- LOGIK: NEUEN SPIELER HINZUFÜGEN ---
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_player'])) {
+    $sql = "INSERT IGNORE INTO spieler (name) VALUES (?)";
+    $stmt = $pdo->prepare($sql);
+    $stmt->execute([$_POST['neuer_spieler_name']]);
+    header("Location: " . $_SERVER['PHP_SELF']);
+    exit;
+}
+
+// --- LOGIK: SCORE HINZUFÜGEN ---
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_score'])) {
+    $sql = "INSERT INTO scores (spieler_id, spiel_id, zeit, hilfe, sterne) VALUES (?, ?, ?, ?, ?)";
+    $stmt = $pdo->prepare($sql);
+    $stmt->execute([
+        $_POST['spieler_id'], 
+        $_POST['spiel_id'], 
+        (int)$_POST['zeit'], 
+        (int)$_POST['hilfe'], 
+        (int)$_POST['sterne']
+    ]);
+    header("Location: " . $_SERVER['PHP_SELF']);
+    exit;
+}
+
+// --- DATEN ABFRAGEN ---
+$stmtGames = $pdo->query("SELECT * FROM spiele ORDER BY id DESC");
+$exitGames = $stmtGames->fetchAll(PDO::FETCH_ASSOC);
+
+$stmtAllPlayers = $pdo->query("SELECT * FROM spieler ORDER BY name ASC");
+$playersList = $stmtAllPlayers->fetchAll();
+
+$sqlScores = "SELECT s.*, p.name as spieler_name 
+              FROM scores s 
+              JOIN spieler p ON s.spieler_id = p.id 
+              ORDER BY s.sterne DESC, s.zeit ASC";
+$allScores = $pdo->query($sqlScores)->fetchAll();
+?>
+
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>EXIT - Dashboard</title>
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
+    <style>
+        body { font-family: 'Segoe UI', sans-serif; background: #121212; color: #e0e0e0; margin: 0; padding-bottom: 100px; }
+        .container { max-width: 1200px; margin: auto; padding: 20px; }
+        
+        .swiper { width: 100%; padding-bottom: 40px; }
+        .swiper-slide { width: 320px; height: auto; }
+        
+        .card { background: #1e1e1e; border-radius: 12px; border: 1px solid #333; overflow: hidden; height: 100%; }
+        .card img { width: 100%; height: 180px; object-fit: cover; opacity: 0.7; }
+        .content { padding: 15px; }
+        
+        h2 { color: #e67e22; margin-top: 0; font-size: 1.2em; }
+        .stats { width: 100%; border-collapse: collapse; font-size: 0.85em; }
+        .stats td { padding: 6px 0; border-bottom: 1px solid #2a2a2a; }
+        
+        .badge { padding: 4px 8px; border-radius: 4px; font-size: 0.7em; font-weight: bold; text-transform: uppercase; }
+        .level-Einsteiger { background: #27ae60; } 
+        .level-Profi { background: #c0392b; } 
+        .level-Fortgeschrittene { background: #2980b9; }
+
+        .bottom-section { display: grid; grid-template-columns: 1fr 2fr; gap: 20px; margin-top: 20px; }
+        @media (max-width: 768px) { .bottom-section { grid-template-columns: 1fr; } }
+
+        .form-section, .info-section { background: #1e1e1e; padding: 20px; border-radius: 12px; border: 1px solid #444; }
+        .highlight-border { border-color: #e67e22; }
+        
+        input, select { width: 100%; padding: 10px; background: #2a2a2a; border: 1px solid #444; color: white; border-radius: 5px; box-sizing: border-box; margin-bottom: 10px; }
+        button { background: #e67e22; color: white; border: none; padding: 12px; border-radius: 5px; cursor: pointer; font-weight: bold; width: 100%; }
+
+        /* Footer Navigation */
+        .footer-nav { position: fixed; bottom: 0; left: 0; width: 100%; background: #1a1a1a; border-top: 2px solid #e67e22; padding: 15px 0; display: flex; justify-content: center; gap: 20px; z-index: 1000; flex-wrap: wrap; }
+        .footer-nav a { color: #e67e22; text-decoration: none; font-weight: bold; font-size: 0.85em; padding: 5px 10px; border: 1px solid transparent; transition: 0.3s; }
+        .footer-nav a:hover { border-color: #e67e22; border-radius: 5px; }
+        
+        .info-section a { color: #e67e22; text-decoration: none; display: block; padding: 10px; border: 1px dashed #444; border-radius: 8px; text-align: center; }
+        .info-section a:hover { background: #252525; }
+
+        #playerModal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #1e1e1e; padding: 30px; border-radius: 12px; border: 1px solid #e67e22; z-index: 2000; box-shadow: 0 0 50px rgba(0,0,0,0.8); }
+        .overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 1500; }
+    </style>
+</head>
+<body>
+
+<div class="container">
+    <h1>🏆 EXIT Highscores</h1>
+
+    <div class="swiper mySwiper">
+        <div class="swiper-wrapper">
+            <?php foreach ($exitGames as $game): ?>
+                <div class="swiper-slide">
+                    <div class="card">
+                        <img src="<?= htmlspecialchars($game['bild_url']) ?>" alt="Cover">
+                        <div class="content">
+                            <span class="badge level-<?= $game['level'] ?>"><?= $game['level'] ?></span>
+                            <h2><?= htmlspecialchars($game['titel']) ?></h2>
+                            <table class="stats">
+                                <?php 
+                                $found = false;
+                                foreach ($allScores as $entry): 
+                                    if ($entry['spiel_id'] == $game['id']): $found = true; ?>
+                                    <tr>
+                                        <td><strong><?= htmlspecialchars($entry['spieler_name']) ?></strong></td>
+                                        <td><?= $entry['zeit'] ?>'</td>
+                                        <td style="color:#f1c40f"><?= $entry['sterne'] ?>★</td>
+                                    </tr>
+                                <?php endif; endforeach; 
+                                if (!$found) echo "<tr><td colspan='3' style='color:#666'>Noch keine Scores.</td></tr>";
+                                ?>
+                            </table>
+                        </div>
+                    </div>
+                </div>
+            <?php endforeach; ?>
+        </div>
+        <div class="swiper-pagination"></div>
+    </div>
+
+    <div class="bottom-section">
+        <div class="info-section">
+            <h2>📜 Archiv</h2>
+            <p style="font-size: 0.8em; color: #888;">Hier findest du alle Details zu den bereits gelösten Abenteuern.</p>
+            <a href="gespielte_spiele.php">📂 Übersicht gespielte Spiele</a>
+        </div>
+
+        <div class="form-section highlight-border">
+            <h2>🎯 Ergebnis eintragen</h2>
+            <form method="POST">
+                <select name="spiel_id" required>
+                    <?php foreach ($exitGames as $game): ?>
+                        <option value="<?= $game['id'] ?>"><?= htmlspecialchars($game['titel']) ?></option>
+                    <?php endforeach; ?>
+                </select>
+                <select name="spieler_id" required>
+                    <option value="">-- Wer hat gespielt? --</option>
+                    <?php foreach ($playersList as $p): ?>
+                        <option value="<?= $p['id'] ?>"><?= htmlspecialchars($p['name']) ?></option>
+                    <?php endforeach; ?>
+                </select>
+                <div style="display: flex; gap: 10px;">
+                    <input type="number" name="zeit" placeholder="Min" required>
+                    <input type="number" name="sterne" min="1" max="10" placeholder="Sterne">
+                    <input type="number" name="hilfe" placeholder="Hilfe">
+                </div>
+                <button type="submit" name="add_score">Score speichern</button>
+            </form>
+        </div>
+    </div>
+</div>
+
+<div class="footer-nav">
+    <a href="javascript:void(0)" onclick="toggleModal()">👤 NEUER SPIELER</a>
+    <a href="besitz.php">📦 BESTAND PFLEGEN</a> <a href="gesamtliste.php">📝 GESAMTÜBERSICHT</a>
+    <a href="admin.php">🛠 ADMIN</a>
+</div>
+
+<div class="overlay" id="overlay" onclick="toggleModal()"></div>
+<div id="playerModal">
+    <h2>👤 Team/Spieler anlegen</h2>
+    <form method="POST">
+        <input type="text" name="neuer_spieler_name" placeholder="Name (z.B. Die Füchse)" required>
+        <button type="submit" name="add_player">Anlegen</button>
+        <button type="button" onclick="toggleModal()" style="background: #444; margin-top: 10px;">Abbrechen</button>
+    </form>
+</div>
+
+<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
+<script>
+    const swiper = new Swiper(".mySwiper", {
+        slidesPerView: "auto",
+        spaceBetween: 20,
+        centeredSlides: false,
+        grabCursor: true,
+        pagination: {
+            el: ".swiper-pagination",
+            clickable: true,
+        },
+    });
+
+    function toggleModal() {
+        const modal = document.getElementById('playerModal');
+        const overlay = document.getElementById('overlay');
+        const display = modal.style.display === 'block' ? 'none' : 'block';
+        modal.style.display = display;
+        overlay.style.display = display;
+    }
+</script>
+
+</body>
+</html>