All checks were successful
Docker Build & Push / build-and-push (push) Successful in 1m36s
80 lines
20 KiB
PHP
80 lines
20 KiB
PHP
<?php
|
|
require_once 'includes/auth_check.php';
|
|
require_once 'includes/db_connect.php';
|
|
|
|
$plant_id = $_GET['id'] ?? null;
|
|
if (!$plant_id || !is_numeric($plant_id)) { header("location: plants.php"); exit; }
|
|
$plant_id = (int)$plant_id;
|
|
$user_id = $_SESSION['user_id'];
|
|
|
|
// Lade Pflanzendaten
|
|
$plant = null;
|
|
$sql = "SELECT p.*, s.strain_name, s.internal_name, z.name AS zone_name, c.name AS container_name, (SELECT file_path FROM plant_images WHERE plant_id = p.id ORDER BY uploaded_at DESC LIMIT 1) as latest_image, (SELECT MAX(hm.height_cm) FROM plant_height_measurements hm WHERE hm.plant_id = p.id) AS current_height, (SELECT MAX(pa.activity_date) FROM plant_activities pa WHERE pa.plant_id = p.id AND pa.activity_type = 'Wässern') AS last_watering, (SELECT MAX(pa.activity_date) FROM plant_activities pa WHERE pa.plant_id = p.id AND pa.activity_type = 'Düngen') AS last_fertilizing FROM plants p JOIN seeds s ON p.seed_id = s.id JOIN zones z ON p.zone_id = z.id JOIN containers c ON p.container_id = c.id WHERE p.id = ? AND p.user_id = ?";
|
|
if ($stmt = $mysqli->prepare($sql)) { $stmt->bind_param("ii", $plant_id, $user_id); $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows === 1) { $plant = $result->fetch_assoc(); } $stmt->close(); }
|
|
if ($plant === null) { header("location: plants.php"); exit; }
|
|
|
|
// KORREKTUR: Fehlende Abfrage für Benutzerdaten (API-Key) hinzugefügt
|
|
$user_data = null;
|
|
$sql_user = "SELECT api_key FROM users WHERE id = ?";
|
|
if ($stmt_user = $mysqli->prepare($sql_user)) {
|
|
$stmt_user->bind_param("i", $user_id);
|
|
$stmt_user->execute();
|
|
$user_data = $stmt_user->get_result()->fetch_assoc();
|
|
$stmt_user->close();
|
|
}
|
|
|
|
// Lade alle weiteren Daten für die Tabs
|
|
$gallery_images = []; $sql_gallery = "SELECT id, file_path, uploaded_at FROM plant_images WHERE plant_id = ? ORDER BY uploaded_at DESC";
|
|
if($stmt_gallery = $mysqli->prepare($sql_gallery)){ $stmt_gallery->bind_param("i", $plant_id); $stmt_gallery->execute(); $result_gallery = $stmt_gallery->get_result(); while($row = $result_gallery->fetch_assoc()){ $gallery_images[] = $row; } $stmt_gallery->close(); }
|
|
$plant_activities = []; $sql_activities = "SELECT activity_type, note, activity_date FROM plant_activities WHERE plant_id = ? ORDER BY activity_date DESC";
|
|
if($stmt_activities = $mysqli->prepare($sql_activities)){ $stmt_activities->bind_param("i", $plant_id); $stmt_activities->execute(); $result_activities = $stmt_activities->get_result(); while($row = $result_activities->fetch_assoc()){ $plant_activities[] = $row; } $stmt_activities->close(); }
|
|
$plant_measurements = []; $sql_measurements = "SELECT height_cm, measurement_date FROM plant_height_measurements WHERE plant_id = ? ORDER BY measurement_date DESC";
|
|
if($stmt_measurements = $mysqli->prepare($sql_measurements)){ $stmt_measurements->bind_param("i", $plant_id); $stmt_measurements->execute(); $result_measurements = $stmt_measurements->get_result(); while($row = $result_measurements->fetch_assoc()){ $plant_measurements[] = $row; } $stmt_measurements->close(); }
|
|
$zones = []; $sql_zones = "SELECT id, name FROM zones WHERE user_id = ? ORDER BY name ASC";
|
|
if ($stmt_zones = $mysqli->prepare($sql_zones)) { $stmt_zones->bind_param("i", $user_id); $stmt_zones->execute(); $result_zones = $stmt_zones->get_result(); while ($row = $result_zones->fetch_assoc()) { $zones[] = $row; } $stmt_zones->close(); }
|
|
|
|
require_once 'includes/header.php';
|
|
?>
|
|
|
|
<div class="card header-card mb-4"><div class="card-body"><h1 class="mb-0"><?php echo htmlspecialchars($plant['strain_name']); ?></h1><p class="card-text text-white-50 mt-2">Detailansicht deiner Pflanze</p></div></div>
|
|
<div class="row">
|
|
<div class="col-lg-4 mb-4"><div class="plant-image-frame"><img src="<?php echo !empty($plant['latest_image']) ? htmlspecialchars($plant['latest_image']) : 'assets/dummy_plant.png'; ?>" class="img-fluid w-100" style="object-fit: contain;"></div></div>
|
|
<div class="col-lg-8 mb-4">
|
|
<table class="table table-hover cazubu-table-frameless">
|
|
<thead class="table-dark"><tr><th colspan="2">Stammdaten & Zustand</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="fw-bold" style="width: 40%;">Status</td><td><span class='badge <?php if ($plant['status'] == 'Eingepflanzt') echo 'text-bg-success'; elseif ($plant['status'] == 'Trocknend') echo 'text-bg-info'; else echo 'text-bg-dark'; ?>'><?php echo htmlspecialchars($plant['status']); ?></span></td></tr>
|
|
<tr><td class="fw-bold">Phase</td><td><?php $phase = $plant['phase']; $phase_badge_class = 'text-bg-secondary'; if ($phase == 'Keimend') $phase_badge_class = 'text-bg-light'; if ($phase == 'Setzling') $phase_badge_class = 'text-bg-success'; if ($phase == 'Wachstum') $phase_badge_class = 'text-bg-primary'; if ($phase == 'Blütenphase') $phase_badge_class = 'text-bg-warning'; if ($phase == 'Ernte' || $phase == 'Getrocknet') $phase_badge_class = 'text-bg-dark'; echo "<span class='badge {$phase_badge_class}'>".htmlspecialchars($phase)."</span>"; ?></td></tr>
|
|
<tr><td class="fw-bold">Sorte</td><td><?php echo htmlspecialchars($plant['strain_name']); ?></td></tr>
|
|
<tr><td class="fw-bold">Zone / Gefäß</td><td><?php echo htmlspecialchars($plant['zone_name']); ?> / <?php echo htmlspecialchars($plant['container_name']); ?></td></tr>
|
|
<tr><td class="fw-bold">Gepflanzt am</td><td><?php echo date('d.m.Y', strtotime($plant['plant_date'])); ?> (vor <?php echo (new DateTime())->diff(new DateTime($plant['plant_date']))->days; ?> Tagen)</td></tr>
|
|
<tr><td class="fw-bold">Aktuelle Höhe</td><td><?php echo $plant['current_height'] ? htmlspecialchars($plant['current_height']) . ' cm' : '<i>Keine Messung</i>'; ?></td></tr>
|
|
<tr><td class="fw-bold">Letzte Bewässerung</td><td><?php echo $plant['last_watering'] ? date('d.m.Y H:i', strtotime($plant['last_watering'])) . ' Uhr' : '<i>Nie</i>'; ?></td></tr>
|
|
<tr><td class="fw-bold">Letzte Düngung</td><td><?php echo $plant['last_fertilizing'] ? date('d.m.Y H:i', strtotime($plant['last_fertilizing'])) . ' Uhr' : '<i>Nie</i>'; ?></td></tr>
|
|
</tbody>
|
|
</table>
|
|
<table class="table cazubu-table-frameless mt-3">
|
|
<thead class="table-dark"><tr><th>Aktionen</th></tr></thead>
|
|
<tbody><tr><td class="p-3"><div class="d-flex flex-wrap gap-2"><button class="btn btn-sm btn-danger delete-btn" data-bs-toggle="modal" data-bs-target="#deleteConfirmModal" data-id="<?php echo $plant['id']; ?>" data-name="<?php echo htmlspecialchars($plant['strain_name']); ?>" data-type="plant">Pflanze löschen</button><button class="btn btn-sm btn-secondary edit-plant-btn" data-bs-toggle="modal" data-bs-target="#editPlantModal" data-plant-info='<?php echo json_encode($plant, JSON_HEX_APOS | JSON_HEX_QUOT); ?>'>Infos bearbeiten</button><?php if ($plant['status'] == 'Eingepflanzt' && $plant['phase'] == 'Blütenphase'): ?><button class="btn btn-sm btn-cazubu" data-bs-toggle="modal" data-bs-target="#harvestConfirmModal">Pflanze ernten</button><?php elseif ($plant['status'] == 'Eingepflanzt'): ?><span class="d-inline-block" tabindex="0" data-bs-toggle="tooltip" title="Ernten ist nur in der Blütenphase möglich."><button class="btn btn-sm btn-cazubu" type="button" disabled style="pointer-events: none;">Pflanze ernten</button></span><?php endif; ?><?php if ($plant['status'] == 'Trocknend'): ?><button class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#finishDryingModal">Trocknung abschließen</button><?php endif; ?><button class="btn btn-sm btn-info text-white" data-bs-toggle="modal" data-bs-target="#apiUrlModal">API-URL</button></div></td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<table class="table cazubu-table-frameless">
|
|
<thead class="table-dark"><tr><th><ul class="nav nav-tabs card-header-tabs" id="detailTabs"><li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tab-activities">Aktivitäten (<?php echo count($plant_activities); ?>)</button></li><li class="nav-item"><button class="nav-link" id="sensor-tab-btn" data-bs-toggle="tab" data-bs-target="#tab-sensors">Sensoren</button></li><li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-measurements">Messungen (<?php echo count($plant_measurements); ?>)</button></li><li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-gallery">Bildergalerie (<?php echo count($gallery_images); ?>)</button></li></ul></th></tr></thead>
|
|
<tbody><tr><td class="p-3"><div class="tab-content">
|
|
<div class="tab-pane fade" id="tab-gallery"><div class="d-flex justify-content-between align-items-center mb-3"><h6 class="mb-0">Alle Bilder</h6><button class="btn btn-sm btn-cazubu" data-bs-toggle="modal" data-bs-target="#uploadImageModal">+ Neues Bild hochladen</button></div><div class="image-gallery"><?php if(empty($gallery_images)): ?><p class="text-muted">Noch keine Bilder für diese Pflanze hochgeladen.</p><?php endif; ?><?php foreach($gallery_images as $image): ?><div class="gallery-item text-center"><a href="<?php echo htmlspecialchars($image['file_path']); ?>" target="_blank"><img src="<?php echo htmlspecialchars($image['file_path']); ?>" class="gallery-image shadow-sm"></a><button class="btn btn-danger btn-sm delete-image-btn delete-btn" data-bs-toggle="modal" data-bs-target="#deleteConfirmModal" data-id="<?php echo $image['id']; ?>" data-name="Bild vom <?php echo date('d.m.Y', strtotime($image['uploaded_at'])); ?>" data-type="plant_image"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-circle-fill" viewBox="0 0 16 16"><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z"/></svg></button><div class="gallery-date"><?php echo date('d.m.Y', strtotime($image['uploaded_at'])); ?></div></div><?php endforeach; ?></div></div>
|
|
<div class="tab-pane fade show active" id="tab-activities"><div class="d-flex justify-content-between align-items-center mb-3"><h6 class="mb-0">Protokollierte Aktivitäten</h6><button class="btn btn-sm btn-cazubu" data-bs-toggle="modal" data-bs-target="#addActivityModal">+ Aktivität hinzufügen</button></div><table class="table table-sm table-striped border"><thead><tr><th style="width:160px;">Datum</th><th style="width:120px;">Aktion</th><th>Notiz</th></tr></thead><tbody><?php if(empty($plant_activities)): ?><tr><td colspan="3" class="text-center p-3"><i>Keine Aktivitäten protokolliert.</i></td></tr><?php endif; ?><?php foreach($plant_activities as $activity): ?><tr><td><?= date('d.m.Y H:i', strtotime($activity['activity_date'])) ?></td><td class="fw-bold"><?= htmlspecialchars($activity['activity_type']) ?></td><td><?= nl2br(htmlspecialchars($activity['note'])) ?></td></tr><?php endforeach; ?></tbody></table></div>
|
|
<div class="tab-pane fade" id="tab-measurements"><div class="d-flex justify-content-between align-items-center mb-3"><h6 class="mb-0">Größen-Messungen</h6><button class="btn btn-sm btn-cazubu" data-bs-toggle="modal" data-bs-target="#addMeasurementModal">+ Höhe messen</button></div><table class="table table-sm table-striped border"><thead><tr><th style="width:160px;">Datum</th><th>Höhe</th></tr></thead><tbody><?php if(empty($plant_measurements)): ?><tr><td colspan="2" class="text-center p-3"><i>Keine Messungen protokolliert.</i></td></tr><?php endif; ?><?php foreach($plant_measurements as $measurement): ?><tr><td><?= date('d.m.Y', strtotime($measurement['measurement_date'])) ?></td><td><?= htmlspecialchars($measurement['height_cm']) ?> cm</td></tr><?php endforeach; ?></tbody></table></div>
|
|
<div class="tab-pane fade" id="tab-sensors"><div id="sensor-charts-container" class="row"><div class="col-12 text-center p-5"><div class="spinner-border text-secondary" role="status"><span class="visually-hidden">Lade Graphen...</span></div><p class="text-muted mt-2">Lade Sensordaten...</p></div></div></div>
|
|
</div></td></tr></tbody>
|
|
</table>
|
|
<div class="modal fade" id="deleteConfirmModal" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Löschen bestätigen</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><p>Sind Sie sicher, dass Sie <strong id="item-type-to-delete"></strong> "<strong id="item-name-to-delete"></strong>" endgültig löschen möchten?</p><p class="text-danger" id="delete-warning"></p></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="button" class="btn btn-danger" id="confirmDeleteBtn">Ja, endgültig löschen</button></div></div></div></div>
|
|
<div class="modal fade" id="uploadImageModal" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Neues Bild hochladen</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><form id="image-upload-form" enctype="multipart/form-data"><input type="hidden" name="action" value="upload_plant_image"><input type="hidden" name="plant_id" value="<?php echo $plant_id; ?>"><div class="mb-3"><label for="plant_image_file" class="form-label">Bilddatei auswählen (JPG, PNG, GIF, WebP)</label><input class="form-control" type="file" id="plant_image_file" name="plant_image" required></div></form></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="submit" class="btn btn-primary" form="image-upload-form">Hochladen & Speichern</button></div></div></div></div>
|
|
<div class="modal fade" id="editPlantModal" tabindex="-1"><div class="modal-dialog modal-lg"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Pflanzen-Infos bearbeiten</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><form id="edit-plant-form"><input type="hidden" name="action" value="edit_plant"><input type="hidden" name="plant_id" value="<?php echo $plant_id; ?>"><div class="row"><div class="col-md-6 mb-3"><label class="form-label">Phase</label><select class="form-select" name="phase" required><option value="Keimend">Keimend</option><option value="Setzling">Setzling</option><option value="Wachstum">Wachstum</option><option value="Blütenphase">Blütenphase</option><option value="Ernte">Ernte</option><option value="Getrocknet">Getrocknet</option></select></div><div class="col-md-6 mb-3"><label class="form-label">Datum der Pflanzung</label><input type="date" class="form-control" name="plant_date" required></div></div><div class="row"><div class="col-md-6 mb-3"><label class="form-label">Zone</label><select class="form-select" name="zone_id" id="edit-zone-select" required><option value="">Bitte wählen...</option><?php foreach($zones as $zone) { echo "<option value='{$zone['id']}'>".htmlspecialchars($zone['name'])."</option>"; } ?></select></div><div class="col-md-6 mb-3"><label class="form-label">Pflanzgefäß</label><select class="form-select" name="container_id" id="edit-container-select" required disabled><option value="">Zuerst Zone wählen</option></select></div></div></form></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="submit" class="btn btn-primary" form="edit-plant-form">Änderungen speichern</button></div></div></div></div>
|
|
<div class="modal fade" id="harvestConfirmModal" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Ernte bestätigen</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><p>Möchtest du diese Pflanze wirklich ernten?</p><p class="text-muted">Der Status wird auf "Trocknend" gesetzt.</p></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="button" class="btn btn-success" id="confirmHarvestBtn">Ja, ernten</button></div></div></div></div>
|
|
<div class="modal fade" id="finishDryingModal" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Trocknung abschließen</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><p>Soll der Status dieser Pflanze auf "Geerntet" gesetzt werden?</p><p class="text-muted">Die Pflanze gilt damit als vollständig verarbeitet.</p></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="button" class="btn btn-dark" id="confirmFinishDryingBtn">Ja, Prozess abschließen</button></div></div></div></div>
|
|
<div class="modal fade" id="addActivityModal" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Aktivität hinzufügen</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><form id="activity-form"><input type="hidden" name="action" value="add_activity"><input type="hidden" name="plant_id" value="<?php echo $plant_id; ?>"><div class="mb-3"><label class="form-label">Aktivität</label><select class="form-select" name="activity_type" required><option value="Wässern">Wässern</option><option value="Düngen">Düngen</option><option value="Umtopfen">Umtopfen</option><option value="Schnitt">Schnitt</option><option value="Sonstiges">Sonstiges</option></select></div><div class="mb-3"><label class="form-label">Datum & Uhrzeit</label><input class="form-control" type="datetime-local" name="activity_date" required></div><div class="mb-3"><label class="form-label">Notiz (optional)</label><textarea class="form-control" name="note" rows="3"></textarea></div></form></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="submit" class="btn btn-primary" form="activity-form">Speichern</button></div></div></div></div>
|
|
<div class="modal fade" id="addMeasurementModal" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Höhe messen</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><form id="measurement-form"><input type="hidden" name="action" value="add_measurement"><input type="hidden" name="plant_id" value="<?php echo $plant_id; ?>"><div class="mb-3"><label class="form-label">Höhe in cm</label><input class="form-control" type="number" step="0.1" name="height_cm" required></div><div class="mb-3"><label class="form-label">Datum der Messung</label><input class="form-control" type="date" name="measurement_date" required></div></form></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button><button type="submit" class="btn btn-primary" form="measurement-form">Speichern</button></div></div></div></div>
|
|
<div class="modal fade" id="apiUrlModal" tabindex="-1"><div class="modal-dialog modal-lg"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">Sensor API-URL</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div><div class="modal-body"><p>Benutze die folgenden URLs, um Sensor-Daten für diese Pflanze (ID: <?php echo $plant_id; ?>) zu senden. Ersetze `DEIN_WERT` durch den gemessenen Wert.</p><?php if (empty($user_data['api_key'])): ?><div class="alert alert-warning">Du musst zuerst auf deiner Profil-Seite einen API-Key generieren.</div><?php else: $base_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]/cazubu/api.php"; $api_key_part = "apikey=" . urlencode($user_data['api_key']); $plant_part = "pflanze=" . $plant_id; ?><div class="mb-3"><label class="form-label fw-bold">URL für Temperatur:</label><input type="text" class="form-control" value="<?php echo "{$base_url}?{$api_key_part}&{$plant_part}&sensor=temp&wert=DEIN_WERT"; ?>" readonly></div><div class="mb-3"><label class="form-label fw-bold">URL für Feuchtigkeit:</label><input type="text" class="form-control" value="<?php echo "{$base_url}?{$api_key_part}&{$plant_part}&sensor=humidity&wert=DEIN_WERT"; ?>" readonly></div><?php endif; ?></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button></div></div></div></div>
|
|
<?php require_once 'includes/footer.php'; ?>
|