📚 Improved blueprint structures & templates for better organization

This commit is contained in:
2025-06-11 08:53:07 +02:00
parent 23d6a8c6d0
commit 36c2466e53
10 changed files with 181 additions and 6 deletions

View File

@ -182,6 +182,7 @@ def api_get_calendar_events():
# Optional: Filter nach Druckern
printer_id = request.args.get('printer_id')
show_plug_events = request.args.get('show_plug_events', 'false').lower() == 'true'
with get_cached_session() as db_session:
# Jobs im angegebenen Zeitraum abfragen
@ -234,12 +235,89 @@ def api_get_calendar_events():
"description": job.description,
"userName": user_name,
"printerId": job.printer_id,
"printerName": printer_name
"printerName": printer_name,
"eventType": "job"
}
}
events.append(event)
# Steckdosen-Status-Events hinzufügen (falls gewünscht)
if show_plug_events:
from models import PlugStatusLog
# PlugStatusLog-Events im Zeitraum abfragen
plug_query = db_session.query(PlugStatusLog).filter(
PlugStatusLog.timestamp >= start_date,
PlugStatusLog.timestamp <= end_date
)
if printer_id:
plug_query = plug_query.filter(PlugStatusLog.printer_id == printer_id)
plug_logs = plug_query.order_by(PlugStatusLog.timestamp.desc()).all()
# Steckdosen-Events gruppieren (nur Statuswechsel anzeigen)
for i, log in enumerate(plug_logs):
# Prüfen ob es eine Statusänderung ist (nicht einfach ein Status-Check)
if i < len(plug_logs) - 1:
prev_log = plug_logs[i + 1]
if prev_log.status == log.status and prev_log.printer_id == log.printer_id:
continue # Gleicher Status, überspringen
# Drucker-Name für den Event
printer = db_session.query(Printer).filter_by(id=log.printer_id).first()
printer_name = printer.name if printer else f"Drucker {log.printer_id}"
# Event-Farbe basierend auf Status
plug_color = "#FF6B35" # Orange für Steckdosen-Events
if log.status == "on":
plug_color = "#4ECDC4" # Türkis für eingeschaltet
elif log.status == "off":
plug_color = "#FFD23F" # Gelb für ausgeschaltet
elif log.status == "disconnected":
plug_color = "#EE6C4D" # Rot für nicht erreichbar
# Status-Text übersetzen
status_text = {
"on": "Eingeschaltet",
"off": "Ausgeschaltet",
"connected": "Verbunden",
"disconnected": "Offline"
}.get(log.status, log.status)
# Quelle anzeigen
source_text = {
"system": "System",
"manual": "Manuell",
"api": "API",
"scheduler": "Scheduler"
}.get(log.source, log.source)
plug_event = {
"id": f"plug_{log.id}",
"title": f"🔌 {printer_name}: {status_text}",
"start": log.timestamp.isoformat(),
"end": log.timestamp.isoformat(), # Punktereignis
"color": plug_color,
"display": "list-item", # Als kleines Item anzeigen
"extendedProps": {
"eventType": "plug_status",
"status": log.status,
"printerId": log.printer_id,
"printerName": printer_name,
"source": source_text,
"powerConsumption": log.power_consumption,
"voltage": log.voltage,
"current": log.current,
"responseTime": log.response_time_ms,
"notes": log.notes,
"errorMessage": log.error_message
}
}
events.append(plug_event)
logger.info(f"📅 Kalender-Events abgerufen: {len(events)} Einträge für Zeitraum {start_date} bis {end_date}")
return jsonify(events)

View File

@ -446,11 +446,16 @@ def api_start_job_with_code():
# OTP als verwendet markieren
matching_request.otp_used_at = now
# Drucker einschalten (falls implementiert)
# Drucker einschalten über Tapo-Steckdose
if job.printer and job.printer.plug_ip:
try:
from utils.job_scheduler import toggle_plug
toggle_plug(job.printer_id, True)
from utils.job_scheduler import BackgroundTaskScheduler
scheduler = BackgroundTaskScheduler()
plug_success = scheduler.toggle_printer_plug(job.printer_id, True)
if plug_success:
logger.info(f"🔌 Drucker für Gast-Job {job.id} eingeschaltet")
else:
logger.warning(f"⚠️ Steckdose für Gast-Job {job.id} konnte nicht eingeschaltet werden")
except Exception as e:
logger.warning(f"Fehler beim Einschalten des Druckers: {str(e)}")

View File

@ -483,6 +483,14 @@ def start_job(job_id):
db_session.close()
return jsonify({"error": "Drucker ist nicht online"}), 400
# Drucker einschalten über Tapo-Steckdose
from utils.job_scheduler import BackgroundTaskScheduler
scheduler = BackgroundTaskScheduler()
plug_success = scheduler.toggle_printer_plug(job.printer_id, True)
if not plug_success:
jobs_logger.warning(f"⚠️ Steckdose für Job {job_id} konnte nicht eingeschaltet werden")
# Job als laufend markieren
job.status = "running"
job.start_at = datetime.now()
@ -490,6 +498,9 @@ def start_job(job_id):
db_session.commit()
if plug_success:
jobs_logger.info(f"🔌 Drucker für Job {job_id} eingeschaltet")
# Job-Objekt für die Antwort serialisieren
job_dict = job.to_dict()
db_session.close()

Binary file not shown.

Binary file not shown.

View File

@ -703,12 +703,18 @@
</div>
</div>
{% if current_user.is_authenticated and current_user.is_admin %}
<div class="pt-2 border-t border-slate-200 dark:border-slate-600">
<div class="pt-2 border-t border-slate-200 dark:border-slate-600 space-y-1">
<a href="{{ url_for('admin.admin_dashboard') }}"
class="flex items-center space-x-2 text-slate-600 dark:text-slate-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200">
<span class="text-sm">⚙️</span>
<span class="text-xs">Admin-Dashboard</span>
</a>
<a href="{{ url_for('calendar.calendar_view') }}"
class="flex items-center space-x-2 text-slate-500 dark:text-slate-500 hover:text-green-600 dark:hover:text-green-400 transition-colors duration-200"
title="Steckdosen-Status Historie">
<span class="text-sm">🔌</span>
<span class="text-xs">Status-Kalender</span>
</a>
</div>
{% endif %}
</div>

View File

@ -885,6 +885,32 @@
</div>
</div>
<!-- Additional Options Row -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<!-- Steckdosen-Events Toggle -->
<div>
<label class="flex items-center cursor-pointer">
<input type="checkbox" id="showPlugEvents" class="sr-only">
<div class="relative">
<div class="w-11 h-6 bg-gray-200 dark:bg-gray-700 rounded-full shadow-inner transition-colors duration-300"></div>
<div class="dot absolute w-4 h-4 bg-white rounded-full shadow top-1 left-1 transition-transform duration-300"></div>
</div>
<div class="ml-3">
<span class="text-sm font-medium text-mercedes-black dark:text-slate-300">
🔌 Steckdosen-Status anzeigen
</span>
<div class="text-xs text-mercedes-gray dark:text-slate-400">
Ein-/Ausschalt-Ereignisse der Drucker-Steckdosen
</div>
</div>
</label>
</div>
<!-- Spacer for future options -->
<div></div>
<div></div>
</div>
<!-- Quick Analytics -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="stat-card active p-4">
@ -1178,7 +1204,32 @@ document.addEventListener('DOMContentLoaded', function() {
startTime: '08:00',
endTime: '18:00'
},
events: '/api/calendar/events',
events: function(info, successCallback, failureCallback) {
const params = new URLSearchParams({
start: info.start.toISOString(),
end: info.end.toISOString()
});
// Drucker-Filter hinzufügen
const printerFilter = document.getElementById('printerFilter');
if (printerFilter && printerFilter.value) {
params.append('printer_id', printerFilter.value);
}
// Steckdosen-Events hinzufügen falls aktiviert
const showPlugEvents = document.getElementById('showPlugEvents');
if (showPlugEvents && showPlugEvents.checked) {
params.append('show_plug_events', 'true');
}
fetch(`/api/calendar/events?${params.toString()}`)
.then(response => response.json())
.then(data => successCallback(data))
.catch(error => {
console.error('Fehler beim Laden der Events:', error);
failureCallback(error);
});
},
editable: canEdit,
selectable: canEdit,
selectMirror: true,
@ -1223,6 +1274,30 @@ document.addEventListener('DOMContentLoaded', function() {
calendar.refetchEvents();
});
// Steckdosen-Events Toggle Handler
const showPlugEventsToggle = document.getElementById('showPlugEvents');
if (showPlugEventsToggle) {
showPlugEventsToggle.addEventListener('change', function() {
// Toggle-Animation
const toggleElement = this.nextElementSibling;
const dot = toggleElement.querySelector('.dot');
const toggleBg = toggleElement.querySelector('div');
if (this.checked) {
dot.classList.add('translate-x-5');
toggleBg.classList.remove('bg-gray-200', 'dark:bg-gray-700');
toggleBg.classList.add('bg-green-500', 'dark:bg-green-600');
} else {
dot.classList.remove('translate-x-5');
toggleBg.classList.remove('bg-green-500', 'dark:bg-green-600');
toggleBg.classList.add('bg-gray-200', 'dark:bg-gray-700');
}
// Kalender neu laden
calendar.refetchEvents();
});
}
// Form Submit Handler
document.getElementById('eventForm').addEventListener('submit', async function(e) {
e.preventDefault();