This commit is contained in:
@@ -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>
|
||||
@@ -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') }}">← Zurück</a>
|
||||
</div>
|
||||
<p class="hint" style="max-width:480px; margin-left:auto; margin-right:auto;">
|
||||
Priorität = Position in der Warteschlange dieser Maschine (1 = als
|
||||
nächstes dran). Bestehende offene/pausierte Aufträge dieser
|
||||
Maschine rü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ü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ü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ä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">✓ Anlegen</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="btn-grid">
|
||||
<a class="big-btn primary" href="{{ url_for('leitstand_anlegen') }}">➕ Auftrag anlegen</a>
|
||||
<a class="big-btn" href="{{ url_for('leitstand_import') }}">↑ Aufträge importieren</a>
|
||||
<a class="big-btn green" href="{{ url_for('leitstand_uebersicht') }}">📋 Auftragsübersicht</a>
|
||||
<a class="big-btn amber" href="{{ url_for('leitstand_korrektur') }}">🔧 Buchungskorrektur</a>
|
||||
<a class="big-btn neutral" href="{{ url_for('leitstand_prioritaet') }}">↕ Auftragspriorität</a>
|
||||
<a class="big-btn" href="{{ url_for('leitstand_maschinen') }}">🛠 Zu Maschine springen</a>
|
||||
<a class="big-btn" href="{{ url_for('maschinenverwaltung') }}">🔒 Maschinenverwaltung</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -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') }}">← Zurü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äge fü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ählen</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-row compact">
|
||||
<button type="submit" class="big-btn small primary">↑ 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 (ü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 – ü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 – 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 %}
|
||||
@@ -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') }}">← Zurü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ä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>Ø/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ö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) }}">← Zurü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">Ø Stü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">✓ Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -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') }}">← Zurü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 %}
|
||||
@@ -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') }}">← Zurü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äge für diese Maschine.</div>
|
||||
{% elif auftraege %}
|
||||
<p class="hint">
|
||||
Reihenfolge per Drag & Drop ändern: Auftrag mit der Maus anfassen (Symbol
|
||||
☰) und an die gewünschte Position ziehen. Die neue Reihenfolge wird
|
||||
automatisch gespeichert. <em>Hinweis: funktioniert am PC/Laptop mit Maus; auf
|
||||
reinen Touch-Geräten ohne Maus ist Drag & Drop ggf. eingeschränkt.</em>
|
||||
</p>
|
||||
<noscript><div class="error-box">Für die Sortierung per Drag & Drop wird JavaScript benö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">☰</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 %}
|
||||
@@ -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') }}">← Zurü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äge gefunden.</div>
|
||||
{% else %}
|
||||
<div class="list-meta">{{ auftraege|length }} Aufträ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ö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) }}">← Zurü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ü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ät</span>
|
||||
<span>{{ auftrag.sid_fmt }} <span style="color:var(--text-dim); font-size:0.85em;">(änderbar unter "Auftragspriorität")</span></span>
|
||||
</div>
|
||||
</div>
|
||||
{% if not gesperrt %}
|
||||
<div class="action-row">
|
||||
<button type="submit" class="big-btn primary">✓ Speichern</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -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) }}">← Zurück</a>
|
||||
</div>
|
||||
{% if not auftraege %}
|
||||
<div class="empty-state">Keine offenen oder pausierten Aufträge fü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 %}
|
||||
@@ -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) }}">▶ 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ü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) }}">📝 Prod. erfassen</a>
|
||||
<a class="big-btn amber" href="{{ url_for('machine_pause', maschine_id=maschine.id) }}">⏸ Auftrag pausieren</a>
|
||||
{% if unter_soll %}
|
||||
<a class="big-btn red" href="{{ url_for('machine_beenden_confirm', maschine_id=maschine.id) }}">⏹ 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">⏹ Auftrag beenden</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -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) }}">← Zurü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ä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">✓ Speichern</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -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') }}">← Zurü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') }}">➕ 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ö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') }}">← Zurü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">✓ 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') }}">← Zurü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">🔒 Anmelden</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user