📚 Improved blueprint structures & templates for better organization
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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)
|
||||
|
||||
|
@ -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)}")
|
||||
|
||||
|
@ -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()
|
||||
|
BIN
backend/instance/printer_manager.db-shm
Normal file
BIN
backend/instance/printer_manager.db-shm
Normal file
Binary file not shown.
BIN
backend/instance/printer_manager.db-wal
Normal file
BIN
backend/instance/printer_manager.db-wal
Normal file
Binary file not shown.
@ -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>
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user