Initial commit
Build und Push Docker Image / build-and-push (push) Failing after 49s

This commit is contained in:
2026-08-20 12:24:38 +02:00
commit 36180448e1
29 changed files with 2917 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>{{ title }} WDM Performance</title>
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='logo.svg') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div id="app">
<div class="header">
<img class="header-logo" src="{{ url_for('static', filename='logo.svg') }}" alt="Logo">
<h1>{{ title }}</h1>
{% if subtitle %}<div class="subtitle">{{ subtitle }}</div>{% endif %}
</div>
<div class="content {{ content_class or '' }}">
{% if error %}<div class="error-box">{{ error }}</div>{% endif %}
{% if info %}<div class="info-box">{{ info }}</div>{% endif %}
{% block content %}{% endblock %}
</div>
</div>
</body>
</html>
+49
View File
@@ -0,0 +1,49 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<p class="hint" style="max-width:480px; margin-left:auto; margin-right:auto;">
Priorit&auml;t = Position in der Warteschlange dieser Maschine (1 = als
n&auml;chstes dran). Bestehende offene/pausierte Auftr&auml;ge dieser
Maschine r&uuml;cken automatisch nach. Leer lassen, um den Auftrag ans
Ende einzureihen.
</p>
<form method="post" action="{{ url_for('leitstand_anlegen') }}" class="compact-form">
<div class="card compact">
<div class="form-group">
<label for="maschine_id">Maschine</label>
<select id="maschine_id" name="maschine_id" required>
{% for m in maschinen %}
<option value="{{ m.id }}" {% if eingabe.maschine_id|string == m.id|string %}selected{% endif %}>{{ m.name or ('Maschine ' ~ m.id) }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="auftragsnummer">Auftragsnummer</label>
<input type="text" id="auftragsnummer" name="auftragsnummer" placeholder="z.B. AT-2026-001" value="{{ eingabe.auftragsnummer or '' }}" autofocus required>
</div>
<div class="form-group">
<label for="artikel">Artikel (optional)</label>
<input type="text" id="artikel" name="artikel" placeholder="z.B. 1000042144 HLB2" value="{{ eingabe.artikel or '' }}">
</div>
<div class="form-row-2">
<div class="form-group">
<label for="einheiten">Produktionsmenge (St&uuml;ck)</label>
<input type="number" min="1" step="any" inputmode="decimal" id="einheiten" name="einheiten" value="{{ eingabe.einheiten or '' }}" required>
</div>
<div class="form-group">
<label for="soll_h">St&uuml;ck/Stunde (Soll)</label>
<input type="number" min="1" step="any" inputmode="decimal" id="soll_h" name="soll_h" value="{{ eingabe.soll_h or '' }}" required>
</div>
</div>
<div class="form-group">
<label for="prioritaet">Priorit&auml;t (optional)</label>
<input type="number" min="1" step="1" inputmode="numeric" id="prioritaet" name="prioritaet" placeholder="Freilassen = ans Ende der Warteschlange" value="{{ eingabe.prioritaet or '' }}">
</div>
</div>
<div class="action-row compact">
<button type="submit" class="big-btn small primary">&#10003; Anlegen</button>
</div>
</form>
{% endblock %}
+12
View File
@@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block content %}
<div class="btn-grid">
<a class="big-btn primary" href="{{ url_for('leitstand_anlegen') }}">&#10133; Auftrag anlegen</a>
<a class="big-btn" href="{{ url_for('leitstand_import') }}">&#8593; Auftr&auml;ge importieren</a>
<a class="big-btn green" href="{{ url_for('leitstand_uebersicht') }}">&#128203; Auftrags&uuml;bersicht</a>
<a class="big-btn amber" href="{{ url_for('leitstand_korrektur') }}">&#128295; Buchungskorrektur</a>
<a class="big-btn neutral" href="{{ url_for('leitstand_prioritaet') }}">&#8597; Auftragspriorit&auml;t</a>
<a class="big-btn" href="{{ url_for('leitstand_maschinen') }}">&#128736; Zu Maschine springen</a>
<a class="big-btn" href="{{ url_for('maschinenverwaltung') }}">&#128274; Maschinenverwaltung</a>
</div>
{% endblock %}
+105
View File
@@ -0,0 +1,105 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<div class="card compact">
<p class="hint">
Excel- (.xlsx) oder CSV-Datei mit den Spalten <strong>Maschine</strong>, <strong>man. Prio</strong>,
<strong>FA.-Nr.</strong>, <strong>Rest-Menge</strong>, <strong>Ist-Menge</strong>,
<strong>Artikel</strong> und <strong>Soll-pro-Stunde</strong> hochladen (weitere Spalten
wie Bezeichnung/Auftrag/Lieferdatum/Bemerkung werden ignoriert). Bei CSV werden
Trennzeichen (Komma/Semikolon/Tab) und Zahlformat (1.234,56 oder 1234.56)
automatisch erkannt.<br>
Auftr&auml;ge f&uuml;r unbekannte Maschinen werden verworfen, bereits vorhandene
FA.-Nrn. bleiben unangetastet. Ist die Rest-Menge 0, wird der Auftrag direkt als
abgeschlossen angelegt.
</p>
<form method="post" action="{{ url_for('leitstand_import') }}" enctype="multipart/form-data" class="compact-form">
<div class="form-group">
<label for="datei">Excel- oder CSV-Datei</label>
<div class="dropzone" id="dropzone">
<input type="file" id="datei" name="datei" accept=".xlsx,.csv" required>
<div class="dropzone-text" id="dropzone-text">Datei hierher ziehen oder klicken zum Ausw&auml;hlen</div>
</div>
</div>
<div class="action-row compact">
<button type="submit" class="big-btn small primary">&#8593; Importieren</button>
</div>
</form>
<script>
(function () {
var zone = document.getElementById('dropzone');
var input = document.getElementById('datei');
var text = document.getElementById('dropzone-text');
if (!zone || !input || !text) return;
var standardtext = text.textContent;
['dragenter', 'dragover'].forEach(function (evtName) {
zone.addEventListener(evtName, function (e) {
e.preventDefault();
zone.classList.add('dragover');
});
});
zone.addEventListener('dragleave', function (e) {
e.preventDefault();
zone.classList.remove('dragover');
});
zone.addEventListener('drop', function (e) {
e.preventDefault();
zone.classList.remove('dragover');
var dateien = e.dataTransfer && e.dataTransfer.files;
if (dateien && dateien.length) {
// Datei aktiv aus dem Drop-Ereignis übernehmen (statt uns auf das
// native Standardverhalten des überlagerten <input> zu verlassen -
// das greift nicht zuverlässig, weil wir dragover/drop hier ohnehin
// abfangen müssen, um die Hervorhebung zu steuern).
input.files = dateien;
input.dispatchEvent(new Event('change', { bubbles: true }));
}
});
input.addEventListener('change', function () {
text.textContent = (input.files && input.files.length) ? input.files[0].name : standardtext;
});
})();
</script>
</div>
{% if ergebnis %}
<div class="card">
<h3>Ergebnis</h3>
<p>
{{ ergebnis.importiert|length }} importiert,
{{ ergebnis.uebersprungen_vorhanden|length }} bereits vorhanden (&uuml;bersprungen),
{{ ergebnis.verworfen_maschine|length }} wegen unbekannter Maschine verworfen{% if ergebnis.fehlerhafte_zeilen %},
{{ ergebnis.fehlerhafte_zeilen|length }} fehlerhaft{% endif %}.
</p>
{% if ergebnis.importiert %}
<details open>
<summary>Importiert ({{ ergebnis.importiert|length }})</summary>
<ul>{% for z in ergebnis.importiert %}<li>{{ z }}</li>{% endfor %}</ul>
</details>
{% endif %}
{% if ergebnis.uebersprungen_vorhanden %}
<details>
<summary>Bereits vorhanden &ndash; &uuml;bersprungen ({{ ergebnis.uebersprungen_vorhanden|length }})</summary>
<ul>{% for z in ergebnis.uebersprungen_vorhanden %}<li>{{ z }}</li>{% endfor %}</ul>
</details>
{% endif %}
{% if ergebnis.verworfen_maschine %}
<details>
<summary>Maschine unbekannt &ndash; verworfen ({{ ergebnis.verworfen_maschine|length }})</summary>
<ul>{% for z in ergebnis.verworfen_maschine %}<li>{{ z }}</li>{% endfor %}</ul>
</details>
{% endif %}
{% if ergebnis.fehlerhafte_zeilen %}
<details>
<summary>Fehlerhafte Zeilen ({{ ergebnis.fehlerhafte_zeilen|length }})</summary>
<ul>{% for z in ergebnis.fehlerhafte_zeilen %}<li>{{ z }}</li>{% endfor %}</ul>
</details>
{% endif %}
</div>
{% endif %}
{% endblock %}
+53
View File
@@ -0,0 +1,53 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="get" action="{{ url_for('leitstand_korrektur') }}" class="filter-row">
<span>Maschine filtern:</span>
<select name="maschine_id" onchange="this.form.submit()">
<option value="">Alle Maschinen</option>
{% for m in maschinen %}
<option value="{{ m.id }}" {% if filter_maschine_id|string == m.id|string %}selected{% endif %}>{{ m.name or ('Maschine ' ~ m.id) }}</option>
{% endfor %}
</select>
<button type="submit">Filtern</button>
</form>
{% if not eintraege %}
<div class="empty-state">Keine Eintr&auml;ge gefunden.</div>
{% else %}
<div class="list-meta">{{ eintraege|length }} Buchungen (neueste zuerst)</div>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr><th>ID</th><th>Maschine</th><th>Zeit</th><th>Auftrag</th><th>Produziert</th><th>Status</th><th>&Oslash;/h</th><th>Grund</th><th class="col-actions"></th></tr>
</thead>
<tbody>
{% for m in eintraege %}
<tr>
<td>{{ m.id }}</td>
<td>{{ m.maschine_id|int }}</td>
<td>{{ m.zeit_fmt }}</td>
<td>{{ m.order }}</td>
<td>{{ m.produziert_fmt }}</td>
<td>{{ m.status }}</td>
<td>{{ m.h_avg_fmt }}</td>
<td>{{ m.p_grund or '' }}</td>
<td class="col-actions">
<div class="row-actions">
<a class="icon-btn" href="{{ url_for('leitstand_korrektur_bearbeiten', mde_id=m.id, maschine_id=filter_maschine_id) }}">Bearbeiten</a>
<form method="post" action="{{ url_for('leitstand_korrektur_loeschen', mde_id=m.id) }}" class="order-form">
<input type="hidden" name="maschine_id" value="{{ filter_maschine_id or '' }}">
<button type="submit" class="icon-btn danger">L&ouml;schen</button>
</form>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}
@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_korrektur', maschine_id=filter_maschine_id) }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="post" action="{{ url_for('leitstand_korrektur_bearbeiten', mde_id=eintrag.id) }}">
<input type="hidden" name="maschine_id_filter" value="{{ filter_maschine_id or '' }}">
<div class="card">
<div class="form-group">
<label for="order">Auftragsnummer</label>
<input type="text" id="order" name="order" value="{{ eintrag.order }}">
</div>
<div class="form-group">
<label for="produziert">Produziert</label>
<input type="number" step="any" id="produziert" name="produziert" value="{{ eintrag.produziert_fmt }}">
</div>
<div class="form-group">
<label for="status">Status</label>
<input type="text" id="status" name="status" value="{{ eintrag.status }}">
</div>
<div class="form-group">
<label for="h_avg">&Oslash; St&uuml;ck/Stunde</label>
<input type="number" step="any" id="h_avg" name="h_avg" value="{{ eintrag.h_avg_fmt }}">
</div>
<div class="form-group">
<label for="p_grund">Abweichungsgrund</label>
<input type="text" id="p_grund" name="p_grund" value="{{ eintrag.p_grund or '' }}">
</div>
</div>
<div class="action-row">
<button type="submit" class="big-btn primary">&#10003; Speichern</button>
</div>
</form>
{% endblock %}
+15
View File
@@ -0,0 +1,15 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<div class="machine-grid">
{% for m in maschinen %}
<a class="machine-link {{ 'aktiv' if m.hat_aktiven_auftrag else '' }}" href="{{ url_for('machine_main', maschine_id=m.id) }}">
<span class="machine-link-name">{{ m.name or ('Maschine ' ~ m.id) }}</span>
{% if m.aktiver_artikel %}<span class="machine-link-artikel">{{ m.aktiver_artikel }}</span>{% endif %}
<span class="machine-link-status">{{ "l\u00e4uft" if m.hat_aktiven_auftrag else "frei" }}</span>
</a>
{% endfor %}
</div>
{% endblock %}
+109
View File
@@ -0,0 +1,109 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="get" action="{{ url_for('leitstand_prioritaet') }}" class="filter-row">
<span>Maschine:</span>
<select name="maschine_id" onchange="this.form.submit()">
{% for m in maschinen %}
<option value="{{ m.id }}" {% if filter_maschine_id|string == m.id|string %}selected{% endif %}>{{ m.name or ('Maschine ' ~ m.id) }}</option>
{% endfor %}
</select>
<button type="submit">Anzeigen</button>
</form>
{% if filter_maschine_id and not auftraege %}
<div class="empty-state">Keine offenen/pausierten Auftr&auml;ge f&uuml;r diese Maschine.</div>
{% elif auftraege %}
<p class="hint">
Reihenfolge per Drag &amp; Drop &auml;ndern: Auftrag mit der Maus anfassen (Symbol
&#9776;) und an die gew&uuml;nschte Position ziehen. Die neue Reihenfolge wird
automatisch gespeichert. <em>Hinweis: funktioniert am PC/Laptop mit Maus; auf
reinen Touch-Ger&auml;ten ohne Maus ist Drag &amp; Drop ggf. eingeschr&auml;nkt.</em>
</p>
<noscript><div class="error-box">F&uuml;r die Sortierung per Drag &amp; Drop wird JavaScript ben&ouml;tigt.</div></noscript>
<div class="priority-list" id="priority-list" data-maschine-id="{{ filter_maschine_id }}">
{% for a in auftraege %}
<div class="priority-item" draggable="true" data-id="{{ a.id }}">
<span class="drag-handle">&#9776;</span>
<span class="sid-badge">#{{ loop.index }}</span>
<span class="priority-item-info">
<span>{{ a.auftragsnummer }}</span>
{% if a.artikel %}<span class="priority-item-artikel">{{ a.artikel }}</span>{% endif %}
</span>
<span class="tag">{{ a.status_label }}</span>
</div>
{% endfor %}
</div>
<div class="save-indicator" id="save-indicator" aria-live="polite"></div>
<script>
(function () {
var list = document.getElementById('priority-list');
if (!list) return;
var indicator = document.getElementById('save-indicator');
function getDragAfterElement(container, y) {
var items = Array.prototype.slice.call(container.querySelectorAll('.priority-item:not(.dragging)'));
return items.reduce(function (closest, child) {
var box = child.getBoundingClientRect();
var offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
}
return closest;
}, { offset: -Infinity, element: null }).element;
}
function updateBadges() {
Array.prototype.forEach.call(list.querySelectorAll('.priority-item'), function (el, idx) {
var badge = el.querySelector('.sid-badge');
if (badge) badge.textContent = '#' + (idx + 1);
});
}
function persistOrder() {
var ids = Array.prototype.map.call(list.querySelectorAll('.priority-item'), function (el) {
return el.getAttribute('data-id');
});
updateBadges();
if (indicator) indicator.textContent = 'Speichere…';
fetch("{{ url_for('leitstand_prioritaet_reihenfolge') }}", {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ maschine_id: list.getAttribute('data-maschine-id'), ids: ids })
}).then(function (resp) {
if (indicator) indicator.textContent = resp.ok ? 'Gespeichert.' : 'Fehler beim Speichern.';
}).catch(function () {
if (indicator) indicator.textContent = 'Fehler beim Speichern.';
});
}
list.addEventListener('dragstart', function (e) {
var item = e.target.closest('.priority-item');
if (!item) return;
item.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
});
list.addEventListener('dragend', function (e) {
var item = e.target.closest('.priority-item');
if (item) item.classList.remove('dragging');
persistOrder();
});
list.addEventListener('dragover', function (e) {
e.preventDefault();
var dragging = list.querySelector('.dragging');
if (!dragging) return;
var after = getDragAfterElement(list, e.clientY);
if (after == null) {
list.appendChild(dragging);
} else {
list.insertBefore(dragging, after);
}
});
})();
</script>
{% endif %}
{% endblock %}
+60
View File
@@ -0,0 +1,60 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="get" action="{{ url_for('leitstand_uebersicht') }}" class="filter-row">
<span>Maschine:</span>
<select name="maschine_id" onchange="this.form.submit()">
<option value="">Alle Maschinen</option>
{% for m in maschinen %}
<option value="{{ m.id }}" {% if filter_maschine_id|string == m.id|string %}selected{% endif %}>{{ m.name or ('Maschine ' ~ m.id) }}</option>
{% endfor %}
</select>
<span>Status:</span>
<select name="status" onchange="this.form.submit()">
<option value="offen_pause" {% if filter_status == "offen_pause" %}selected{% endif %}>Offen/Pausiert</option>
<option value="alle" {% if filter_status == "alle" %}selected{% endif %}>Alle</option>
</select>
<button type="submit">Filtern</button>
</form>
{% if not auftraege %}
<div class="empty-state">Keine Auftr&auml;ge gefunden.</div>
{% else %}
<div class="list-meta">{{ auftraege|length }} Auftr&auml;ge</div>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr><th>ID</th><th>Auftragsnr.</th><th>Artikel</th><th>Maschine</th><th>Menge</th><th>Stk/h</th><th>Status</th><th>Aktiv</th><th>SID</th><th class="col-actions"></th></tr>
</thead>
<tbody>
{% for a in auftraege %}
<tr>
<td>{{ a.id }}</td>
<td>{{ a.auftragsnummer }}</td>
<td>{{ a.artikel or "-" }}</td>
<td>{{ a.maschine_name }}</td>
<td>{{ a.einheiten_fmt }}</td>
<td>{{ a.soll_h_fmt }}</td>
<td>{{ a.status_label }}</td>
<td>{{ "Ja" if a.aktiv else "Nein" }}</td>
<td>{{ a.sid_fmt }}</td>
<td class="col-actions">
<div class="row-actions">
<a class="icon-btn" href="{{ url_for('leitstand_uebersicht_bearbeiten', auftrag_id=a.id, maschine_id=filter_maschine_id, status=filter_status) }}">Bearbeiten</a>
<form method="post" action="{{ url_for('leitstand_uebersicht_loeschen', auftrag_id=a.id) }}" class="order-form">
<input type="hidden" name="maschine_id" value="{{ filter_maschine_id or '' }}">
<input type="hidden" name="status" value="{{ filter_status }}">
<button type="submit" class="icon-btn danger">L&ouml;schen</button>
</form>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}
@@ -0,0 +1,46 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_uebersicht', maschine_id=filter_maschine_id, status=filter_status) }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="post" action="{{ url_for('leitstand_uebersicht_bearbeiten', auftrag_id=auftrag.id) }}">
<input type="hidden" name="maschine_id_filter" value="{{ filter_maschine_id or '' }}">
<input type="hidden" name="status_filter" value="{{ filter_status or '' }}">
<div class="card">
<div class="form-group">
<label for="maschine_id">Maschine</label>
<select id="maschine_id" name="maschine_id" {{ 'disabled' if gesperrt }} required>
{% for m in maschinen %}
<option value="{{ m.id }}" {% if auftrag.maschine_id|int == m.id %}selected{% endif %}>{{ m.name or ('Maschine ' ~ m.id) }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="auftragsnummer">Auftragsnummer</label>
<input type="text" id="auftragsnummer" name="auftragsnummer" value="{{ auftrag.auftragsnummer }}" {{ 'readonly' if gesperrt }} required>
</div>
<div class="form-group">
<label for="artikel">Artikel</label>
<input type="text" id="artikel" name="artikel" value="{{ auftrag.artikel or '' }}" {{ 'readonly' if gesperrt }}>
</div>
<div class="form-group">
<label for="einheiten">Produktionsmenge</label>
<input type="number" step="any" id="einheiten" name="einheiten" value="{{ auftrag.einheiten_fmt }}" {{ 'readonly' if gesperrt }} required>
</div>
<div class="form-group">
<label for="soll_h">St&uuml;ck pro Stunde</label>
<input type="number" step="any" id="soll_h" name="soll_h" value="{{ auftrag.soll_h_fmt }}" {{ 'readonly' if gesperrt }} required>
</div>
<div class="status-line"><span class="label">Status</span><span>{{ status_anzeige }}</span></div>
<div class="status-line">
<span class="label">Priorit&auml;t</span>
<span>{{ auftrag.sid_fmt }} <span style="color:var(--text-dim); font-size:0.85em;">(&auml;nderbar unter "Auftragspriorit&auml;t")</span></span>
</div>
</div>
{% if not gesperrt %}
<div class="action-row">
<button type="submit" class="big-btn primary">&#10003; Speichern</button>
</div>
{% endif %}
</form>
{% endblock %}
+25
View File
@@ -0,0 +1,25 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('machine_main', maschine_id=maschine.id) }}">&#8592; Zur&uuml;ck</a>
</div>
{% if not auftraege %}
<div class="empty-state">Keine offenen oder pausierten Auftr&auml;ge f&uuml;r diese Maschine.</div>
{% else %}
<div class="order-list">
{% for a in auftraege %}
<form method="post" action="{{ url_for('machine_auswahl_waehlen', maschine_id=maschine.id) }}" class="order-form">
<input type="hidden" name="auftrag_id" value="{{ a.id }}">
<button type="submit" class="order-item">
<span class="order-item-main">
<span class="order-item-nummer">{{ a.auftragsnummer }}</span>
{% if a.artikel %}<span class="order-item-menge">{{ a.artikel }}</span>{% endif %}
<span class="order-item-menge">{{ a.einheiten_fmt }} Stk.</span>
</span>
<span class="tag">{{ a.status_label }}</span>
</button>
</form>
{% endfor %}
</div>
{% endif %}
{% endblock %}
@@ -0,0 +1,13 @@
{% extends "base.html" %}
{% block content %}
<div class="confirm-box">
<h2>Wirklich beenden?</h2>
<p>Die Sollmenge ({{ soll_fmt }}) wurde noch nicht erreicht.<br>Bisher gemeldet: {{ bisherige_fmt }}.</p>
<div class="modal-actions">
<a class="big-btn neutral" href="{{ url_for('machine_main', maschine_id=maschine.id) }}">Abbrechen</a>
<form method="post" action="{{ url_for('machine_beenden', maschine_id=maschine.id) }}" class="order-form">
<button type="submit" class="big-btn red">Ja, beenden</button>
</form>
</div>
</div>
{% endblock %}
+31
View File
@@ -0,0 +1,31 @@
{% extends "base.html" %}
{% block content %}
{% if not auftrag %}
<div class="card">
<div class="empty-state">Kein aktiver Auftrag.</div>
</div>
<div class="btn-grid">
<a class="big-btn primary" href="{{ url_for('machine_auswahl', maschine_id=maschine.id) }}">&#9654; Start</a>
</div>
{% else %}
<div class="card">
<div class="status-line"><span class="label">Auftragsnummer</span><span>{{ auftrag.auftragsnummer }}</span></div>
{% if auftrag.artikel %}<div class="status-line"><span class="label">Artikel</span><span>{{ auftrag.artikel }}</span></div>{% endif %}
<div class="status-line"><span class="label">Status</span><span>{{ status_label }}</span></div>
<div class="status-line"><span class="label">Soll-Menge</span><span>{{ soll_fmt }}</span></div>
<div class="status-line"><span class="label">St&uuml;ck/Stunde (Soll)</span><span>{{ rate_fmt }}</span></div>
<div class="status-line"><span class="label">Bisher gemeldet</span><span>{{ bisherige_fmt }} ({{ fortschritt }}%)</span></div>
</div>
<div class="btn-grid">
<a class="big-btn green" href="{{ url_for('machine_erfassen', maschine_id=maschine.id) }}">&#128221; Prod. erfassen</a>
<a class="big-btn amber" href="{{ url_for('machine_pause', maschine_id=maschine.id) }}">&#9208; Auftrag pausieren</a>
{% if unter_soll %}
<a class="big-btn red" href="{{ url_for('machine_beenden_confirm', maschine_id=maschine.id) }}">&#9209; Auftrag beenden</a>
{% else %}
<form method="post" action="{{ url_for('machine_beenden', maschine_id=maschine.id) }}" class="order-form">
<button type="submit" class="big-btn red">&#9209; Auftrag beenden</button>
</form>
{% endif %}
</div>
{% endif %}
{% endblock %}
+28
View File
@@ -0,0 +1,28 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('machine_main', maschine_id=maschine.id) }}">&#8592; Zur&uuml;ck</a>
</div>
<div class="info-box">Bisher gemeldet: {{ bisherige_fmt }} / Soll: {{ soll_fmt }}</div>
<form method="post" action="{{ form_action }}">
<div class="card">
<div class="form-group">
<label for="einheiten">Bisher hergestellte Einheiten</label>
<input type="number" min="0" step="any" inputmode="decimal" id="einheiten" name="einheiten"
value="{{ eingabe_einheiten }}" autofocus required>
</div>
<div class="form-group">
<label for="abweichung_id">Abweichungsgrund</label>
<select id="abweichung_id" name="abweichung_id" required>
<option value="">-- bitte w&auml;hlen --</option>
{% for ab in abweichungen %}
<option value="{{ ab.id }}" {% if eingabe_abweichung_id|string == ab.id|string %}selected{% endif %}>{{ ab.beschreibung }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="action-row">
<button type="submit" class="big-btn primary">&#10003; Speichern</button>
</div>
</form>
{% endblock %}
+43
View File
@@ -0,0 +1,43 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
<form method="post" action="{{ url_for('maschinenverwaltung_logout') }}" class="order-form" style="display:inline-block;width:auto;margin-left:12px;">
<button type="submit" class="icon-btn">Abmelden</button>
</form>
</div>
<div class="btn-grid" style="margin-bottom:10px;">
<a class="big-btn small primary" href="{{ url_for('maschinenverwaltung_neu') }}">&#10133; Neue Maschine anlegen</a>
</div>
{% if not maschinen %}
<div class="empty-state">Keine Maschinen vorhanden.</div>
{% else %}
<div class="list-meta">{{ maschinen|length }} Maschinen</div>
<div class="table-wrap">
<table class="data-table">
<thead>
<tr><th>ID</th><th>Name</th><th>Standort</th><th class="col-actions"></th></tr>
</thead>
<tbody>
{% for m in maschinen %}
<tr>
<td>{{ m.id }}</td>
<td>{{ m.name or '' }}</td>
<td>{{ m.standort or '' }}</td>
<td class="col-actions">
<div class="row-actions">
<a class="icon-btn" href="{{ url_for('maschinenverwaltung_bearbeiten', maschine_id=m.id) }}">Bearbeiten</a>
<form method="post" action="{{ url_for('maschinenverwaltung_loeschen', maschine_id=m.id) }}" class="order-form">
<button type="submit" class="icon-btn danger">L&ouml;schen</button>
</form>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}
@@ -0,0 +1,21 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('maschinenverwaltung') }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="post" action="{{ url_for('maschinenverwaltung_neu') if neu else url_for('maschinenverwaltung_bearbeiten', maschine_id=maschine.id) }}" class="compact-form">
<div class="card compact">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" value="{{ maschine.name or '' }}" autofocus required>
</div>
<div class="form-group">
<label for="standort">Standort</label>
<input type="text" id="standort" name="standort" value="{{ maschine.standort or '' }}">
</div>
</div>
<div class="action-row compact">
<button type="submit" class="big-btn small primary">&#10003; Speichern</button>
</div>
</form>
{% endblock %}
@@ -0,0 +1,18 @@
{% extends "base.html" %}
{% block content %}
<div class="back-row top">
<a class="big-btn small neutral" href="{{ url_for('leitstand_home') }}">&#8592; Zur&uuml;ck</a>
</div>
<form method="post" action="{{ url_for('maschinenverwaltung_login') }}" class="compact-form">
<input type="hidden" name="next" value="{{ next }}">
<div class="card compact">
<div class="form-group">
<label for="passwort">Passwort</label>
<input type="password" id="passwort" name="passwort" autofocus required>
</div>
</div>
<div class="action-row compact">
<button type="submit" class="big-btn small primary">&#128274; Anmelden</button>
</div>
</form>
{% endblock %}