Feature Complete: Modern Glass UI, Sensor History, Seed Genetics & Cleanup
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 28s

This commit is contained in:
Gemini Bot
2025-12-07 19:07:29 +00:00
parent 0d0b57adc9
commit c13076a291
13 changed files with 23687 additions and 235 deletions

View File

@@ -62,36 +62,63 @@ $(document).ready(function() {
$('#zone-filter-select').on('change', function() { const zoneId = $(this).val(); const selectionContainer = $('#plant-target-selection'); selectionContainer.html('<div class="spinner-border spinner-border-sm" role="status"><span class="visually-hidden">Lade...</span></div>'); $.ajax({ type: 'GET', url: 'ajax_handler.php', data: { action: 'get_plants_by_zone', zone_id: zoneId }, dataType: 'json', success: function(response) { selectionContainer.empty(); if (response.success && response.data.length > 0) { let plantCheckboxes = '<div class="form-check"><input class="form-check-input" type="checkbox" id="select-all-plants" checked><label class="form-check-label fw-bold" for="select-all-plants">Alle auswählen/abwählen</label></div><hr class="my-2">'; plantCheckboxes += '<div class="row" style="max-height: 200px; overflow-y: auto;">'; response.data.forEach(function(plant) { plantCheckboxes += `<div class="col-md-6"><div class="form-check"><input class="form-check-input plant-checkbox" type="checkbox" name="plant_ids[]" value="${plant.id}" id="plant_${plant.id}" checked><label class="form-check-label" for="plant_${plant.id}">${plant.strain_name} (${plant.container_name})</label></div></div>`; }); plantCheckboxes += '</div>'; selectionContainer.html(plantCheckboxes); } else { selectionContainer.html('<p class="text-muted">Keine aktiven Pflanzen in dieser Auswahl gefunden.</p>'); } } }); });
$(document).on('change', '#select-all-plants', function() { $('#global-activity-form .plant-checkbox').prop('checked', $(this).prop('checked')); });
// Slider Logik für Samen
$('#ratio_sativa').on('input', function() {
const sativaVal = $(this).val();
$('#sativa-value-label').text(sativaVal);
$('#indica-value-label').text(100 - sativaVal);
});
// Sensor-Graphen Logik
$('#sensor-tab-btn').on('shown.bs.tab', function () {
if ($(this).data('loaded')) { return; }
$(this).data('loaded', true);
const plantId = new URLSearchParams(window.location.search).get('id');
let tempChart = null;
let humidityChart = null;
function loadSensorData(plantId, range) {
const chartsContainer = $('#sensor-charts-container');
chartsContainer.html('<div class="col-12 text-center p-5"><div class="spinner-border text-secondary" role="status"><span class="visually-hidden">Lade...</span></div></div>');
$.ajax({
type: 'GET', url: 'ajax_handler.php', data: { action: 'get_sensor_data', plant_id: plantId }, dataType: 'json',
type: 'GET', url: 'ajax_handler.php', data: { action: 'get_sensor_data', plant_id: plantId, range: range }, dataType: 'json',
success: function(response) {
chartsContainer.empty();
if (response.success && response.data.labels.length > 0) {
chartsContainer.html('<div class="col-lg-6 mb-4" id="temp-chart-wrapper"></div><div class="col-lg-6 mb-4" id="humidity-chart-wrapper"></div>');
const tempWrapper = $('#temp-chart-wrapper');
const humidityWrapper = $('#humidity-chart-wrapper');
if (response.data.temperature.some(val => val !== null)) {
tempWrapper.append('<h5>Temperaturverlauf</h5>');
let tempCanvas = $('<canvas>').attr('height', '300');
tempWrapper.append($('<div>').addClass('cazubu-table-frameless p-2').append(tempCanvas));
new Chart(tempCanvas, { type: 'line', data: { labels: response.data.labels, datasets: [{ label: 'Temperatur (°C)', data: response.data.temperature, borderColor: 'rgba(255, 99, 132, 1)', backgroundColor: 'rgba(255, 99, 132, 0.2)', fill: true, tension: 0.2, spanGaps: true }] }, options: { maintainAspectRatio: false, scales: { x: { ticks: { color: '#212529' } }, y: { ticks: { color: '#212529' } } }, plugins: { legend: { labels: { color: '#212529' } } } } });
if(tempChart) { tempChart.destroy(); }
tempChart = new Chart(tempCanvas, { type: 'line', data: { labels: response.data.labels, datasets: [{ label: 'Temperatur (°C)', data: response.data.temperature, borderColor: 'rgba(255, 99, 132, 1)', backgroundColor: 'rgba(255, 99, 132, 0.2)', fill: true, tension: 0.2, spanGaps: true, pointRadius: 3, pointHoverRadius: 5, borderWidth: 2 }] }, options: { maintainAspectRatio: false, scales: { x: { ticks: { color: '#212529', font: { size: 11 } } }, y: { ticks: { color: '#212529', font: { size: 11 } } } }, plugins: { legend: { labels: { color: '#212529', font: { size: 12 } } } } } });
} else { tempWrapper.append('<div class="cazubu-table-frameless p-3 text-center">Keine Temperaturdaten vorhanden.</div>'); }
if (response.data.humidity.some(val => val !== null)) {
humidityWrapper.append('<h5>Feuchtigkeitsverlauf</h5>');
let humidityCanvas = $('<canvas>').attr('height', '300');
humidityWrapper.append($('<div>').addClass('cazubu-table-frameless p-2').append(humidityCanvas));
new Chart(humidityCanvas, { type: 'line', data: { labels: response.data.labels, datasets: [{ label: 'Feuchtigkeit (%)', data: response.data.humidity, borderColor: 'rgba(54, 162, 235, 1)', backgroundColor: 'rgba(54, 162, 235, 0.2)', fill: true, tension: 0.2, spanGaps: true }] }, options: { maintainAspectRatio: false, scales: { x: { ticks: { color: '#212529' } }, y: { ticks: { color: '#212529' } } }, plugins: { legend: { labels: { color: '#212529' } } } } });
if(humidityChart) { humidityChart.destroy(); }
humidityChart = new Chart(humidityCanvas, { type: 'line', data: { labels: response.data.labels, datasets: [{ label: 'Feuchtigkeit (%)', data: response.data.humidity, borderColor: 'rgba(54, 162, 235, 1)', backgroundColor: 'rgba(54, 162, 235, 0.2)', fill: true, tension: 0.2, spanGaps: true, pointRadius: 3, pointHoverRadius: 5, borderWidth: 2 }] }, options: { maintainAspectRatio: false, scales: { x: { ticks: { color: '#212529', font: { size: 11 } } }, y: { ticks: { color: '#212529', font: { size: 11 } } } }, plugins: { legend: { labels: { color: '#212529', font: { size: 12 } } } } } });
} else { humidityWrapper.append('<div class="cazubu-table-frameless p-3 text-center">Keine Feuchtigkeitsdaten vorhanden.</div>'); }
} else { chartsContainer.html('<div class="col-12"><div class="cazubu-table-frameless p-3 text-center">Keine Sensordaten für diese Pflanze vorhanden.</div></div>'); }
} else { chartsContainer.html('<div class="col-12"><div class="cazubu-table-frameless p-3 text-center">Keine Sensordaten für diesen Zeitraum.</div></div>'); }
},
error: function() { chartsContainer.html('<div class="col-12"><div class="cazubu-table-frameless p-3 text-center text-danger">Fehler beim Laden der Sensordaten.</div></div>'); }
});
}
$('#sensor-tab-btn').on('shown.bs.tab', function () {
if ($(this).data('loaded')) { return; }
$(this).data('loaded', true);
const plantId = new URLSearchParams(window.location.search).get('id');
loadSensorData(plantId, '24h');
});
$(document).on('click', '.sensor-range-btn', function() {
$('.sensor-range-btn').removeClass('active');
$(this).addClass('active');
const range = $(this).data('range');
const plantId = new URLSearchParams(window.location.search).get('id');
loadSensorData(plantId, range);
});
});