This commit is contained in:
ninortbrgr
2025-10-10 13:45:59 +02:00
parent edde9f07fc
commit fa830f892e
16 changed files with 748 additions and 0 deletions

63
admin.html Normal file
View File

@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<title>Admin Dashboard</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="container">
<h2>Admin Dashboard</h2>
<a href="backend/logout.php">Logout</a>
<div id="ticket-container">Tickets werden geladen...</div>
</div>
<script>
// einfache Escaping-Funktion gegen XSS
function escapeHtml(str) {
return String(str)
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
async function ladeTickets() {
try {
const response = await fetch('backend/tickets.json');
if (!response.ok) throw new Error("Fehler beim Laden der Datei");
const tickets = await response.json();
const container = document.getElementById('ticket-container');
container.innerHTML = '';
if (!Array.isArray(tickets) || tickets.length === 0) {
container.innerHTML = '<p>Aktuell keine Tickets vorhanden.</p>';
return;
}
tickets.forEach(ticket => {
const div = document.createElement('div');
div.className = 'ticket';
const date = ticket.created_at || ticket.date || '';
const room = ticket.room || ticket.raum || '';
div.innerHTML = `
<h3>${escapeHtml(ticket.title || '')}</h3>
<p><strong>Kategorie:</strong> ${escapeHtml(ticket.category || '')}</p>
${room ? `<p><strong>Raum:</strong> ${escapeHtml(room)}</p>` : ""}
<p>${escapeHtml(ticket.description || '')}</p>
<p><em>${escapeHtml(date)}</em></p>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('ticket-container').innerHTML = 'Fehler beim Laden der Tickets: ' + error.message;
console.error(error);
}
}
ladeTickets();
</script>
</body>
</html>

130
admin.php Normal file
View File

@@ -0,0 +1,130 @@
<?php
session_start();
if (!isset($_SESSION["loggedIn"])) {
header("Location: login.html");
exit;
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Admin Dashboard</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container-dashboard">
<div class="header-with-image">
<h2>Admin Dashboard</h2>
<img src="img/csg.png" width="100" />
</div>
<a href="backend/logout.php" class="logout-btn">Logout</a>
<div class="dashboard">
<!-- Linke Ticket-Übersicht -->
<div id="ticket-list" class="ticket-list">
<h3>Tickets Übersicht</h3>
<ul id="tickets-ul"></ul>
</div>
<!-- Rechte Ticket-Details -->
<div id="ticket-details" class="ticket-details">
<p>Wähle ein Ticket aus der Liste links aus.</p>
</div>
</div>
</div>
<script>
let tickets = [];
async function ladeTickets() {
try {
const response = await fetch('backend/tickets.json?ts=' + Date.now(), {cache:"no-store"});
tickets = await response.json();
const ul = document.getElementById('tickets-ul');
ul.innerHTML = '';
if (!Array.isArray(tickets) || tickets.length === 0) {
ul.innerHTML = '<li>Keine Tickets vorhanden</li>';
return;
}
tickets.forEach((ticket, index) => {
const li = document.createElement('li');
li.textContent = ticket.title ?? "Kein Titel";
li.className = 'ticket-item';
li.addEventListener('click', () => showTicketDetails(index));
ul.appendChild(li);
});
} catch (error) {
console.error(error);
document.getElementById('ticket-details').innerHTML = 'Fehler beim Laden der Tickets.';
}
}
function showTicketDetails(index) {
const ticket = tickets[index];
const details = document.getElementById('ticket-details');
details.innerHTML = `
<h3>${ticket.title ?? "Kein Titel"}</h3>
<p><strong>Kategorie:</strong> ${ticket.category ?? "-"}</p>
<p><strong>Raum:</strong> ${ticket.room ?? "-"}</p>
<p><strong>Name:</strong> ${ticket.name ?? "-"}</p>
<p>${ticket.description ?? "-"}</p>
<p><em>${ticket.date ?? "-"}</em></p>
<label>Status ändern:</label>
<select id="status-select">
<option value="To-Do" ${ticket.status==="To-Do"?"selected":""}>To-Do</option>
<option value="InProgress" ${ticket.status==="InProgress"?"selected":""}>InProgress</option>
<option value="Done" ${ticket.status==="Done"?"selected":""}>Done</option>
</select>
<button id="save-status">Speichern</button>
<button id="delete-ticket" class="delete-btn">Löschen</button>
`;
document.getElementById('save-status').addEventListener('click', async () => {
const newStatus = document.getElementById('status-select').value;
ticket.status = newStatus;
const res = await fetch('backend/update_ticket.php', {
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({index, ticket})
});
const data = await res.json();
if(data.success){
alert("Status aktualisiert!");
ladeTickets();
} else {
alert("Fehler beim Aktualisieren!");
}
});
document.getElementById('delete-ticket').addEventListener('click', async () => {
if(!confirm("Ticket wirklich löschen?")) return;
const res = await fetch('backend/delete_ticket.php', {
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({index})
});
const data = await res.json();
if(data.success){
alert("Ticket gelöscht!");
details.innerHTML = "<p>Wähle ein Ticket aus der Liste links aus.</p>";
ladeTickets();
} else {
alert("Fehler beim Löschen!");
}
});
}
ladeTickets();
</script>
</body>
</html>

32
backend/delete_ticket.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
session_start();
if(!isset($_SESSION["loggedIn"])){
echo json_encode(["success"=>false,"message"=>"Nicht eingeloggt"]);
exit;
}
$input = json_decode(file_get_contents("php://input"), true);
$index = $input['index'] ?? null;
if($index === null){
echo json_encode(["success"=>false,"message"=>"Kein Index angegeben"]);
exit;
}
$ticketsPath = __DIR__ . '/tickets.json';
$tickets = [];
if(file_exists($ticketsPath)){
$tickets = json_decode(file_get_contents($ticketsPath), true);
}
if(!isset($tickets[$index])){
echo json_encode(["success"=>false,"message"=>"Ticket existiert nicht"]);
exit;
}
// Ticket löschen
array_splice($tickets, $index, 1);
file_put_contents($ticketsPath, json_encode($tickets, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
echo json_encode(["success"=>true]);

32
backend/login.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
session_start();
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$usersFile = __DIR__ . "/users.json";
if (!file_exists($usersFile)) {
die("Benutzerdaten fehlen!");
}
$users = json_decode(file_get_contents($usersFile), true);
$loginOk = false;
if (is_array($users)) {
foreach ($users as $user) {
if ($user['username'] === $username && $user['password'] === $password) {
$loginOk = true;
break;
}
}
}
if ($loginOk) {
$_SESSION['loggedIn'] = true;
$_SESSION['username'] = $username;
header("Location: ../admin.php");
exit;
} else {
header("Location: ../login.html?error=1");
exit;
}

6
backend/logout.php Normal file
View File

@@ -0,0 +1,6 @@
<?php
session_start();
session_destroy();
header("Location: login.html");
exit;
?>

40
backend/save_ticket.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo "Method not allowed";
exit;
}
$title = trim($_POST['title'] ?? '');
$description = trim($_POST['description'] ?? '');
$category = $_POST['category'] ?? 'Sonstiges';
$room = trim($_POST['room'] ?? '');
$name = trim($_POST['name'] ?? '');
$date = date("Y-m-d H:i:s");
$newTicket = [
'title' => $title,
'description' => $description,
'category' => $category,
'room' => $room,
'name' => $name,
'status' => 'To-Do',
'date' => $date
];
$ticketsPath = __DIR__ . '/tickets.json';
$tickets = [];
if (file_exists($ticketsPath)) {
$json = file_get_contents($ticketsPath);
$tickets = json_decode($json, true);
if (!is_array($tickets)) $tickets = [];
}
$tickets[] = $newTicket;
file_put_contents($ticketsPath, json_encode($tickets, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
// Redirect zurück ins Dashboard oder zur Hauptseite
header('Location: ../index.html?success=1');
exit;

1
backend/tickets.json Normal file
View File

@@ -0,0 +1 @@
[]

33
backend/update_ticket.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
session_start();
if(!isset($_SESSION["loggedIn"])){
echo json_encode(["success"=>false,"message"=>"Nicht eingeloggt"]);
exit;
}
$input = json_decode(file_get_contents("php://input"), true);
$index = $input['index'] ?? null;
$ticket = $input['ticket'] ?? null;
if($index === null || $ticket === null){
echo json_encode(["success"=>false,"message"=>"Keine Daten"]);
exit;
}
$ticketsPath = __DIR__ . '/tickets.json';
$tickets = [];
if(file_exists($ticketsPath)){
$tickets = json_decode(file_get_contents($ticketsPath), true);
}
if(!isset($tickets[$index])){
echo json_encode(["success"=>false,"message"=>"Ticket existiert nicht"]);
exit;
}
// Ticket aktualisieren
$tickets[$index] = $ticket;
file_put_contents($ticketsPath, json_encode($tickets, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), LOCK_EX);
echo json_encode(["success"=>true]);

9
backend/users.json Normal file
View File

@@ -0,0 +1,9 @@
[
{ "username": "rtbrgr",
"password": "tNafets_9i"
},
{
"username": "admin",
"password": "1234"
}
]

168
css/style.css Normal file
View File

@@ -0,0 +1,168 @@
/* Grundstyles */
body {
font-family: Arial, sans-serif;
background: #f0f2f5;
padding: 2rem;
margin: 0;
}
.container {
max-width: 900px;
margin: auto;
background: #fff;
padding: 2rem;
border-radius: 1rem;
box-shadow: 0 0 15px rgba(0,0,0,0.1);
}
.header-with-image {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.header-with-image img {
height: 60px;
}
/* Formular Styles */
input, textarea, select, button {
width: 100%;
margin-top: 1rem;
padding: 0.75rem;
font-size: 1rem;
border-radius: 0.5rem;
border: 1px solid #ccc;
box-sizing: border-box;
}
button {
background-color: #2b79c2;
color: white;
border: none;
cursor: pointer;
}
button:hover {
background-color: #1d5fa0;
}
/* Login Button (Index-Seite) */
.login-btn {
display: inline-block;
padding: 12px 400px;
background: #2b79c2;
color: white;
border-radius: 10px;
text-decoration: none;
font-weight: bold;
font-size: 1rem;
cursor: pointer;
border: none;
transition: all 0.2s ease-in-out;
}
.login-btn:hover {
background: #1d5fa0;
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
/* Logout Button */
.logout-btn {
display: inline-block;
padding: 10px 20px;
background: #ff4d4d;
color: white;
border-radius: 10px;
text-decoration: none;
font-weight: bold;
transition: 0.2s ease-in-out;
margin-bottom: 20px;
}
.logout-btn:hover {
background: #e60000;
transform: scale(1.05);
}
/* Tickets */
.ticket {
border: 1px solid #ccc;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 10px;
background: #fff;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.ticket h3 {
margin-top: 0;
color: #2b79c2;
}
.ticket p {
margin: 0.3rem 0;
}
/* Status Labels */
.status {
display: inline-block;
padding: 4px 10px;
border-radius: 8px;
font-size: 0.8rem;
font-weight: bold;
margin-top: 8px;
}
/* Logout Button */
.logout-btn {
display: inline-block;
padding: 10px 20px;
background: #ff4d4d;
color: white;
border-radius: 10px;
text-decoration: none;
font-weight: bold;
transition: 0.2s ease-in-out;
margin-bottom: 20px;
}
.logout-btn:hover {
background: #e60000;
transform: scale(1.05);
}
/* Tickets */
.ticket {
border: 1px solid #ccc;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 10px;
background: #fff;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.ticket h3 {
margin-top: 0;
color: #2b79c2;
}
.ticket p {
margin: 0.3rem 0;
}
/* Status Labels */
.status {
display: inline-block;
padding: 4px 10px;
border-radius: 8px;
font-size: 0.8rem;
font-weight: bold;
margin-top: 8px;
}
.status.To-Do { background: #ffcccc; color: #a00; }
.status.InProgress { background: #fff3cd; color: #856404; }
.status.Done { background: #d4edda; color: #155724; }

141
dashboard.php Normal file
View File

@@ -0,0 +1,141 @@
<?php
session_start();
if(!isset($_SESSION['user_id'])){
header("Location: login.html");
exit;
}
echo "Willkommen im Dashboard, ".$_SESSION['role']."!";
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Dashboard</title>
<link rel="stylesheet" href="../css/style.css"> <!-- Pfad zu CSS anpassen -->
<style>
body {
display: flex;
margin: 0;
font-family: Arial, sans-serif;
}
/* Sidebar */
.sidebar {
width: 220px;
background-color: #2b79c2;
color: white;
height: 100vh;
padding-top: 2rem;
display: flex;
flex-direction: column;
}
.sidebar a {
color: white;
text-decoration: none;
padding: 1rem 1.5rem;
display: block;
transition: background 0.3s;
}
.sidebar a:hover, .sidebar a.active {
background-color: #1d5fa0;
}
/* Content */
.content {
flex: 1;
padding: 2rem;
background: #f0f2f5;
min-height: 100vh;
}
h2 {
margin-top: 0;
}
.button-panel {
display: flex;
gap: 1rem;
flex-wrap: wrap;
margin-top: 1rem;
}
.button-panel button {
padding: 1rem 1.5rem;
font-size: 1rem;
border: none;
border-radius: 6px;
cursor: pointer;
background-color: #2b79c2;
color: white;
transition: background 0.3s;
}
.button-panel button:hover {
background-color: #1d5fa0;
}
</style>
</head>
<body>
<div class="sidebar">
<a href="#" class="active" data-section="welcome">Willkommen</a>
<a href="#" data-section="tickets">Tickets</a>
<a href="#" data-section="users">Benutzer</a>
<a href="#" data-section="settings">Persönliche Einstellungen</a>
<a href="backend/logout.php">Logout</a>
</div>
<div class="content" id="main-content">
<!-- Start: Welcome -->
<div class="welcome-box">
<h2>Admin Dashboard</h2>
<p>Angemeldet als: <?= htmlspecialchars($_SESSION["username"]) ?></p>
<a href="backend/logout.php">Logout</a>
</div>
</div>
<script>
const username = "<?php echo $username; ?>"; // Variable aus PHP ins JS
const links = document.querySelectorAll('.sidebar a');
const content = document.getElementById('main-content');
links.forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
links.forEach(l => l.classList.remove('active'));
this.classList.add('active');
const section = this.dataset.section;
switch(section) {
case 'welcome':
content.innerHTML = `
<div class="welcome-box">
<h2>Willkommen, ${username}!</h2>
<p>Hier siehst du eine Übersicht und kannst über die Buttons neue Bereiche öffnen:</p>
<div class="button-panel">
<button onclick="window.location.href='users.php'">Benutzer erstellen</button>
<button onclick="window.location.href='admin.php'">Tickets verwalten</button>
<button onclick="window.location.href='deleted_tickets.php'">Gelöschte Tickets</button>
<button onclick="window.location.href='settings.php'">Persönliche Einstellungen</button>
</div>
</div>`;
break;
case 'tickets':
content.innerHTML = '<h2>Tickets</h2><p>Tickets-Panel wird hier geladen...</p>';
break;
case 'users':
content.innerHTML = '<h2>Benutzerverwaltung</h2><p>Hier kannst du Benutzer hinzufügen, bearbeiten oder löschen.</p>';
break;
case 'settings':
content.innerHTML = '<h2>Persönliche Einstellungen</h2><p>Hier kannst du dein Passwort oder andere Einstellungen ändern.</p>';
break;
default:
content.innerHTML = '<p>Unbekannte Sektion</p>';
}
});
});
</script>
</body>
</html>

BIN
img/csg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
img/dsc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

46
index.html Normal file
View File

@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Schul-IT Ticketsystem</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<div class="container">
<div class="header-with-image">
<h2>CSG IT Ticket System</h2>
<img src="img/csg.png" width="100" />
</div>
<form action="backend/save_ticket.php" method="post">
<label for="title">Betreff</label>
<input type="text" id="title" name="title" required />
<label for="description">Problem-Beschreibung</label>
<textarea id="description" name="description" rows="5" required></textarea>
<label for="room">Raum</label>
<input type="number" id="room" name="room" required />
<label for="name">Name, Vorname</label>
<input type="text" id="name" name="name" required>
<label for="category">Kategorie</label>
<select id="category" name="category">
<option value="Whiteboard">Whiteboard</option>
<option value="Internet">Internet</option>
<option value="Schülerportal">Schülerportal</option>
<option value="Ipad(Koffer)">Ipad(Koffer)</option>
<option value="Apple TV">Apple TV</option>
<option value="DocuCam">Docu Kamera</option>
<option value="Sonstiges">Sonstiges</option>
</select>
<button type="submit">Ticket absenden</button>
<a href="login.html" class="login-btn">Admin Login</a>
</form>
</div>
</body>
</html>

21
js/login.js Normal file
View File

@@ -0,0 +1,21 @@
document.getElementById("loginForm").addEventListener("submit", async function (e) {
e.preventDefault();
const username = document.getElementById("username").value;
const password = document.getElementById("password").value;
const formData = new FormData();
formData.append("username", username);
formData.append("password", password);
const response = await fetch("backend/login.php", {
method: "POST",
body: formData
});
const result = await response.json();
if (result.success) {
window.location.href = "admin.php";
} else {
document.getElementById("errorMsg").innerText = "Login fehlgeschlagen!";
}
});

26
login.html Normal file
View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login</title>
<link rel="stylesheet" href="./css/style.css" />
</head>
<body>
<div class="container">
<div class="header-with-image">
<h2>Admin Login</h2>
<img src="img/csg.png" width="100" />
</div>
<form id="loginForm">
<label for="username">Benutzername</label>
<input type="text" id="username" name="username" required />
<label for="password">Passwort</label>
<input type="password" id="password" name="password" required />
<button type="submit">Einloggen</button>
</form>
<p id="errorMsg" style="color: red;"></p>
</div>
<script src="./js/login.js"></script>
</body>
</html>