Fix: Empfaenger/Suche (company-Feld), kontraststarke feste Farben + sichtbare Rahmen

ROOT CAUSE Empfaenger-"-" + tote Suche: order_entries hat KEIN company-Feld.
Die Abfrage forderte company an -> 403/FORBIDDEN -> ganzer Request scheiterte
-> Empfaenger-Index leer -> "-" ueberall + Suche ohne Daten. company aus allen
order_entries-Abfragen entfernt. Echte Empfaenger stehen in free_text (wird gelesen).

Farben/Barrierefreiheit: Extensions nutzten alte Directus-10-Variablen
(--border-normal etc.), die im aktuellen Theme nicht definiert sind -> blasse/
unsichtbare Rahmen, verschwimmende Farben. Alle unzuverlaessigen Theme-Variablen
durch feste, kontraststarke Farben ersetzt (WCAG-AA, helles Weiss-Blau-Theme):
sichtbare Rahmen (#b4c0d2), dunklere Labels (#566070), Text (#1b2430).
Status- und Ablauf-Pillen mit soliden Farben + Rahmen + kraeftigerer Schrift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-10-01 12:48:35 +02:00
parent bf59ab3f80
commit 550abd30e7
3 changed files with 183 additions and 183 deletions

View File

@@ -14,10 +14,10 @@ import { useApi } from '@directus/extensions-sdk';
const ACCENT = '#1E50A5'; const ACCENT = '#1E50A5';
// Klar umrandetes, theme-sicheres Eingabefeld (dezente Füllung → sieht wie ein Feld aus). // Klar umrandetes, theme-sicheres Eingabefeld (dezente Füllung → sieht wie ein Feld aus).
const WFELD = 'background:var(--background-subdued,#f4f6fa);border:1px solid var(--border-normal);border-radius:8px;padding:10px 12px;font:inherit;font-size:14px;color:var(--foreground-normal);outline:none;'; const WFELD = 'background:#eef2f8;border:1px solid #b4c0d2;border-radius:8px;padding:10px 12px;font:inherit;font-size:14px;color:#1b2430;outline:none;';
const WSELECT = WFELD + 'cursor:pointer;'; const WSELECT = WFELD + 'cursor:pointer;';
// Bereich = klar abgegrenzte weiße Karte mit sichtbarem Rahmen + feinem Schatten. // Bereich = klar abgegrenzte weiße Karte mit sichtbarem Rahmen + feinem Schatten.
const BEREICH = 'background:var(--background-page,#fff);border:1px solid var(--border-normal);border-radius:12px;padding:20px 22px;box-shadow:0 1px 2px rgba(16,24,40,.05);'; const BEREICH = 'background:#ffffff;border:1px solid #b4c0d2;border-radius:12px;padding:20px 22px;box-shadow:0 1px 2px rgba(16,24,40,.05);';
const STANDARD_PLATZHALTER = ['Anrede', 'Vorname', 'Nachname', 'Strasse', 'PLZ', 'Ort', 'Land', 'Briefnummer']; const STANDARD_PLATZHALTER = ['Anrede', 'Vorname', 'Nachname', 'Strasse', 'PLZ', 'Ort', 'Land', 'Briefnummer'];
// Echtes Directus-Icon (Material Symbols) statt Emoji. // Echtes Directus-Icon (Material Symbols) statt Emoji.
@@ -25,20 +25,20 @@ const icon = (name, extra = {}) => h(resolveComponent('v-icon'), { name, small:
function btn(label, onClick, kind, ic) { function btn(label, onClick, kind, ic) {
const base = 'cursor:pointer;border-radius:8px;padding:9px 16px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid;'; const base = 'cursor:pointer;border-radius:8px;padding:9px 16px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid;';
const style = kind === 'primary' ? base + `border-color:${ACCENT};background:${ACCENT};color:#fff;` const style = kind === 'primary' ? base + `border-color:${ACCENT};background:${ACCENT};color:#fff;`
: base + 'border-color:var(--border-normal);background:var(--background-page,#fff);color:var(--foreground-normal);'; : base + 'border-color:#b4c0d2;background:#ffffff;color:#1b2430;';
return h('button', { type: 'button', onClick, style }, [ic ? icon(ic) : null, label].filter(Boolean)); return h('button', { type: 'button', onClick, style }, [ic ? icon(ic) : null, label].filter(Boolean));
} }
function subdued(t, extra) { return h('div', { style: `color:var(--foreground-subdued);font-size:13px;${extra || ''}` }, t); } function subdued(t, extra) { return h('div', { style: `color:#566070;font-size:13px;${extra || ''}` }, t); }
function segToggle(value, opts, onSel) { function segToggle(value, opts, onSel) {
return h('div', { style: 'display:flex;width:100%;border-radius:8px;overflow:hidden;border:1px solid var(--border-normal);background:var(--background-page,#fff);' }, return h('div', { style: 'display:flex;width:100%;border-radius:8px;overflow:hidden;border:1px solid #b4c0d2;background:#ffffff;' },
opts.map((o) => h('button', { opts.map((o) => h('button', {
type: 'button', onClick: () => onSel(o.key), type: 'button', onClick: () => onSel(o.key),
style: `flex:1;padding:10px 8px;font:inherit;font-size:13px;text-align:center;cursor:pointer;border:none;` style: `flex:1;padding:10px 8px;font:inherit;font-size:13px;text-align:center;cursor:pointer;border:none;`
+ (value === o.key ? `background:${ACCENT};color:#fff;font-weight:500;` : `background:transparent;color:var(--foreground-normal);`), + (value === o.key ? `background:${ACCENT};color:#fff;font-weight:500;` : `background:transparent;color:#1b2430;`),
}, o.label))); }, o.label)));
} }
function bereichKopf(ic, txt) { return h('div', { style: 'display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;color:var(--foreground-normal);margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--border-subdued);' }, [h('span', { style: `color:${ACCENT};display:inline-flex;align-items:center;` }, icon(ic)), txt]); } function bereichKopf(ic, txt) { return h('div', { style: 'display:flex;align-items:center;gap:8px;font-size:15px;font-weight:600;color:#1b2430;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid #d2dae6;' }, [h('span', { style: `color:${ACCENT};display:inline-flex;align-items:center;` }, icon(ic)), txt]); }
function label(txt) { return h('label', { style: 'display:block;font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--foreground-subdued);margin-bottom:5px;' }, txt); } function label(txt) { return h('label', { style: 'display:block;font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:#566070;margin-bottom:5px;' }, txt); }
const NeuAuftrag = defineComponent({ const NeuAuftrag = defineComponent({
setup() { setup() {
@@ -541,13 +541,13 @@ const NeuAuftrag = defineComponent({
const txt = (d?.art === 'umschlag' ? '✉ Kuvert' : '📄 Schriftstück') + seite; const txt = (d?.art === 'umschlag' ? '✉ Kuvert' : '📄 Schriftstück') + seite;
return h('div', { style: 'display:flex;flex-direction:column;align-items:center;gap:4px;' }, [ return h('div', { style: 'display:flex;flex-direction:column;align-items:center;gap:4px;' }, [
src ? h('img', { src, onClick: () => { neu.lb = src; neu.lbDoc = d; }, style: 'width:100%;max-height:260px;object-fit:contain;border-radius:6px;background:#fff;cursor:zoom-in;box-shadow:0 1px 3px rgba(0,0,0,.12);' }) src ? h('img', { src, onClick: () => { neu.lb = src; neu.lbDoc = d; }, style: 'width:100%;max-height:260px;object-fit:contain;border-radius:6px;background:#fff;cursor:zoom-in;box-shadow:0 1px 3px rgba(0,0,0,.12);' })
: h('div', { style: 'width:100%;height:200px;border-radius:6px;display:flex;align-items:center;justify-content:center;background:#fff;color:var(--foreground-subdued);' }, 'Dok.'), : h('div', { style: 'width:100%;height:200px;border-radius:6px;display:flex;align-items:center;justify-content:center;background:#fff;color:#566070;' }, 'Dok.'),
h('span', { style: 'font-size:11px;color:var(--foreground-subdued);' }, txt), h('span', { style: 'font-size:11px;color:#566070;' }, txt),
]); ]);
}; };
// Weißes, einzeiliges Zellenfeld (feste Breite → Zeile scrollt bei Bedarf). // Weißes, einzeiliges Zellenfeld (feste Breite → Zeile scrollt bei Bedarf).
const feld = (lbl, val, on, ph, onPaste) => h('div', { style: 'display:flex;flex-direction:column;gap:3px;flex:1 1 0;min-width:90px;' }, [ const feld = (lbl, val, on, ph, onPaste) => h('div', { style: 'display:flex;flex-direction:column;gap:3px;flex:1 1 0;min-width:90px;' }, [
h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--foreground-subdued);' }, lbl), h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:#566070;' }, lbl),
h('input', { value: val, placeholder: ph || '', style: WFELD + 'width:100%;padding:7px 9px;font-size:13px;', onInput: on, onPaste }), h('input', { value: val, placeholder: ph || '', style: WFELD + 'width:100%;padding:7px 9px;font-size:13px;', onInput: on, onPaste }),
]); ]);
@@ -605,7 +605,7 @@ const NeuAuftrag = defineComponent({
h('input', { type: 'number', min: 1, max: 1000, step: 1, value: neu.anzahl, style: WFELD + 'width:170px;', h('input', { type: 'number', min: 1, max: 1000, step: 1, value: neu.anzahl, style: WFELD + 'width:170px;',
onInput: (e) => { neu.anzahl = e.target.value; neu.previewSession = null; }, onInput: (e) => { neu.anzahl = e.target.value; neu.previewSession = null; },
onBlur: (e) => { const n = Math.round(Number(e.target.value)); neu.anzahl = (Number.isFinite(n) && n) ? Math.max(1, Math.min(1000, n)) : 1; } }), onBlur: (e) => { const n = Math.round(Number(e.target.value)); neu.anzahl = (Number.isFinite(n) && n) ? Math.max(1, Math.min(1000, n)) : 1; } }),
h('div', { style: 'font-size:12px;color:var(--foreground-subdued,#888);margin-top:6px;line-height:1.5;' }, h('div', { style: 'font-size:12px;color:#566070;margin-top:6px;line-height:1.5;' },
'Ohne Kuvert werden keine Empfängeradressen gebraucht – es entstehen so viele gleiche Schriftstücke wie angegeben. ' 'Ohne Kuvert werden keine Empfängeradressen gebraucht – es entstehen so viele gleiche Schriftstücke wie angegeben. '
+ 'Sobald „Kuverts generieren" aktiv ist oder der Text eigene [[Platzhalter]] enthält, erscheint wieder die Empfängertabelle.'), + 'Sobald „Kuverts generieren" aktiv ist oder der Text eigene [[Platzhalter]] enthält, erscheint wieder die Empfängertabelle.'),
]) : h('div', {}, [ ]) : h('div', {}, [
@@ -613,7 +613,7 @@ const NeuAuftrag = defineComponent({
neu.rows.map((e, i) => h('div', { style: 'display:flex;gap:8px;align-items:center;' }, [ neu.rows.map((e, i) => h('div', { style: 'display:flex;gap:8px;align-items:center;' }, [
h('span', { style: `min-width:22px;font-weight:700;color:${ACCENT};` }, `#${i + 1}`), h('span', { style: `min-width:22px;font-weight:700;color:${ACCENT};` }, `#${i + 1}`),
h('div', { style: 'flex:1;min-width:0;display:flex;gap:6px;flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px;' }, zeile(e, i)), h('div', { style: 'flex:1;min-width:0;display:flex;gap:6px;flex-wrap:nowrap;overflow-x:auto;padding-bottom:2px;' }, zeile(e, i)),
h('button', { type: 'button', onClick: () => delZeile(i), style: 'cursor:pointer;border:none;background:transparent;color:var(--danger,#c62828);font-size:18px;padding:2px 6px;' }, '×'), h('button', { type: 'button', onClick: () => delZeile(i), style: 'cursor:pointer;border:none;background:transparent;color:#c0392b;font-size:18px;padding:2px 6px;' }, '×'),
]))), ]))),
h('div', { style: 'margin-top:12px;display:grid;grid-template-columns:1fr 1fr;gap:12px;' }, [ h('div', { style: 'margin-top:12px;display:grid;grid-template-columns:1fr 1fr;gap:12px;' }, [
btn('+ Empfänger', addZeile), btn('+ Empfänger', addZeile),
@@ -621,7 +621,7 @@ const NeuAuftrag = defineComponent({
]), ]),
]), ]),
// Postkarte: Hinweis auf das Kartenlayout; kein separates Kuvert. // Postkarte: Hinweis auf das Kartenlayout; kein separates Kuvert.
istPostkarte() ? h('div', { style: 'font-size:12px;color:var(--foreground-subdued,#888);margin-top:12px;line-height:1.5;' }, istPostkarte() ? h('div', { style: 'font-size:12px;color:#566070;margin-top:12px;line-height:1.5;' },
'Postkarte: Text auf der linken Hälfte, Absender + Empfänger rechts, Briefmarkenfeld oben rechts frei. Ein separates Kuvert wird nicht erzeugt.') : null, 'Postkarte: Text auf der linken Hälfte, Absender + Empfänger rechts, Briefmarkenfeld oben rechts frei. Ein separates Kuvert wird nicht erzeugt.') : null,
!istPostkarte() ? h('label', { style: 'display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer;margin-top:12px;' }, [ !istPostkarte() ? h('label', { style: 'display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer;margin-top:12px;' }, [
h('input', { type: 'checkbox', checked: neu.kuverts, onChange: (e) => { neu.kuverts = e.target.checked; neu.previewSession = null; }, style: 'width:16px;height:16px;' }), h('input', { type: 'checkbox', checked: neu.kuverts, onChange: (e) => { neu.kuverts = e.target.checked; neu.previewSession = null; }, style: 'width:16px;height:16px;' }),
@@ -650,7 +650,7 @@ const NeuAuftrag = defineComponent({
onInput: (e) => { neu.envelopeSenderScale = e.target.value; neu.previewSession = null; }, onInput: (e) => { neu.envelopeSenderScale = e.target.value; neu.previewSession = null; },
onBlur: (e) => { const n = Math.round(Number(e.target.value)); neu.envelopeSenderScale = (Number.isFinite(n) && n) ? Math.max(50, Math.min(200, n)) : 100; } }), onBlur: (e) => { const n = Math.round(Number(e.target.value)); neu.envelopeSenderScale = (Number.isFinite(n) && n) ? Math.max(50, Math.min(200, n)) : 100; } }),
]), ]),
h('div', { style: 'font-size:11px;color:var(--foreground-subdued,#888);margin-top:4px;line-height:1.5;' }, h('div', { style: 'font-size:11px;color:#566070;margin-top:4px;line-height:1.5;' },
istPostkarte() ? 'Empfänger steht darunter in der Anschriftzone (rechte Hälfte).' : 'Der Empfänger rutscht dann auf dem Kuvert automatisch nach unten rechts.'), istPostkarte() ? 'Empfänger steht darunter in der Anschriftzone (rechte Hälfte).' : 'Der Empfänger rutscht dann auf dem Kuvert automatisch nach unten rechts.'),
]) : null, ]) : null,
(neu.importOpen && !identischModus()) ? h('div', { style: 'margin-top:12px;' }, [ (neu.importOpen && !identischModus()) ? h('div', { style: 'margin-top:12px;' }, [
@@ -682,7 +682,7 @@ const NeuAuftrag = defineComponent({
neu.previewSession = null; neu.previewSession = null;
requestAnimationFrame(() => { try { ta.selectionStart = ta.selectionEnd = s + 1; } catch {} }); requestAnimationFrame(() => { try { ta.selectionStart = ta.selectionEnd = s + 1; } catch {} });
} }), } }),
h('div', { style: 'font-size:11px;color:var(--foreground-subdued,#888);margin-top:4px;line-height:1.5;' }, h('div', { style: 'font-size:11px;color:#566070;margin-top:4px;line-height:1.5;' },
'Tipp: [[seitenumbruch]] erzwingt an dieser Stelle eine neue Seite (mehrseitiger Brief). [[signatur1]] setzt die Unterschrift. ' 'Tipp: [[seitenumbruch]] erzwingt an dieser Stelle eine neue Seite (mehrseitiger Brief). [[signatur1]] setzt die Unterschrift. '
+ 'Platzhalter: [[Vorname]], [[Nachname]], [[Anrede]], [[Strasse]], [[PLZ]], [[Ort]] – im 5-Zeilen-Modus außerdem [[Zeile1]]…[[Zeile5]].'), + 'Platzhalter: [[Vorname]], [[Nachname]], [[Anrede]], [[Strasse]], [[PLZ]], [[Ort]] – im 5-Zeilen-Modus außerdem [[Zeile1]]…[[Zeile5]].'),
// ── Unterschrift auf den Brief ───────────────────────────────────── // ── Unterschrift auf den Brief ─────────────────────────────────────
@@ -727,12 +727,12 @@ const NeuAuftrag = defineComponent({
h('div', { style: 'flex:1 1 280px;max-width:420px;' }, [ h('div', { style: 'flex:1 1 280px;max-width:420px;' }, [
label('Kunde verknüpfen (E-Mail, optional)'), label('Kunde verknüpfen (E-Mail, optional)'),
h('input', { type: 'email', value: neu.customer_email, placeholder: 'kunde@example.de', style: WFELD + 'width:100%;', onInput: (e) => { neu.customer_email = e.target.value; pruefeKunde(); } }), h('input', { type: 'email', value: neu.customer_email, placeholder: 'kunde@example.de', style: WFELD + 'width:100%;', onInput: (e) => { neu.customer_email = e.target.value; pruefeKunde(); } }),
neu.kundeStatus === 'vorhanden' ? h('div', { style: 'font-size:12px;color:var(--success,#2e7d32);margin-top:5px;font-weight:600;' }, '✓ Bestehender Kunde wird verknüpft') : null, neu.kundeStatus === 'vorhanden' ? h('div', { style: 'font-size:12px;color:#1b6b2e;margin-top:5px;font-weight:600;' }, '✓ Bestehender Kunde wird verknüpft') : null,
neu.kundeStatus === 'neu' ? h('div', { style: 'font-size:12px;color:#1E50A5;margin-top:5px;font-weight:600;' }, 'Neuer Kunde – bitte unten Stammdaten erfassen.') : null, neu.kundeStatus === 'neu' ? h('div', { style: 'font-size:12px;color:#1E50A5;margin-top:5px;font-weight:600;' }, 'Neuer Kunde – bitte unten Stammdaten erfassen.') : null,
]), ]),
]), ]),
// Neukundenanlage erzwingen, sobald eine unbekannte E-Mail eingetragen ist. // Neukundenanlage erzwingen, sobald eine unbekannte E-Mail eingetragen ist.
neu.kundeStatus === 'neu' ? h('div', { style: 'margin-top:14px;border:1px solid var(--border-normal);border-radius:10px;padding:16px;background:var(--background-subdued,#f1f4f9);' }, [ neu.kundeStatus === 'neu' ? h('div', { style: 'margin-top:14px;border:1px solid #b4c0d2;border-radius:10px;padding:16px;background:#eef2f8;' }, [
h('div', { style: 'font-weight:600;margin-bottom:10px;' }, 'Neuen Kunden anlegen'), h('div', { style: 'font-weight:600;margin-bottom:10px;' }, 'Neuen Kunden anlegen'),
h('div', { style: 'display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;' }, [ h('div', { style: 'display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;' }, [
h('div', {}, [label('Vorname'), h('input', { value: neu.kundeVorname, style: WFELD + 'width:100%;', onInput: (e) => { neu.kundeVorname = e.target.value; } })]), h('div', {}, [label('Vorname'), h('input', { value: neu.kundeVorname, style: WFELD + 'width:100%;', onInput: (e) => { neu.kundeVorname = e.target.value; } })]),
@@ -751,8 +751,8 @@ const NeuAuftrag = defineComponent({
]); ]);
const aktionen = h('div', { class: 'sk-btnrow', style: 'display:flex;gap:8px;flex-wrap:wrap;' }, [ const aktionen = h('div', { class: 'sk-btnrow', style: 'display:flex;gap:8px;flex-wrap:wrap;' }, [
neu.hinweis ? h('div', { style: `color:var(--danger,#c62828);font-size:13px;width:100%;` }, neu.hinweis) : null, neu.hinweis ? h('div', { style: `color:#c0392b;font-size:13px;width:100%;` }, neu.hinweis) : null,
neu.err ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;width:100%;' }, neu.err) : null, neu.err ? h('div', { style: 'color:#c0392b;font-size:13px;width:100%;' }, neu.err) : null,
neu.msg ? h('div', { style: 'width:100%;' }, subdued(neu.msg)) : null, neu.msg ? h('div', { style: 'width:100%;' }, subdued(neu.msg)) : null,
btn(neu.pLaedt ? 'Vorschau …' : '👁 Vorschau', preview), btn(neu.pLaedt ? 'Vorschau …' : '👁 Vorschau', preview),
btn('In Druck geben', absenden, 'primary'), btn('In Druck geben', absenden, 'primary'),
@@ -776,7 +776,7 @@ const NeuAuftrag = defineComponent({
btn('Berechnen', seitenBerechnen), btn('Berechnen', seitenBerechnen),
]), ]),
neu.seitenInfo neu.seitenInfo
? h('pre', { style: 'margin:0;white-space:pre-wrap;font:inherit;font-size:13px;color:var(--foreground);' }, neu.seitenInfo) ? h('pre', { style: 'margin:0;white-space:pre-wrap;font:inherit;font-size:13px;color:#1b2430;' }, neu.seitenInfo)
: subdued('„Berechnen" klicken – zeigt, wie viele Seiten je Empfänger entstehen.'), : subdued('„Berechnen" klicken – zeigt, wie viele Seiten je Empfänger entstehen.'),
]) : null, ]) : null,
]); ]);
@@ -894,7 +894,7 @@ const NeuAuftrag = defineComponent({
function signaturPanel() { function signaturPanel() {
const sigFeld = (s, k, lbl, step) => h('div', { style: 'display:flex;flex-direction:column;gap:3px;flex:1;min-width:90px;' }, [ const sigFeld = (s, k, lbl, step) => h('div', { style: 'display:flex;flex-direction:column;gap:3px;flex:1;min-width:90px;' }, [
h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--foreground-subdued);' }, lbl), h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:#566070;' }, lbl),
h('input', { value: s[k], type: k === 'marker_key' ? 'text' : 'number', step: step || 'any', h('input', { value: s[k], type: k === 'marker_key' ? 'text' : 'number', step: step || 'any',
style: WFELD + 'width:100%;padding:7px 9px;font-size:13px;', style: WFELD + 'width:100%;padding:7px 9px;font-size:13px;',
onInput: (e) => { s[k] = k === 'marker_key' ? e.target.value : (parseFloat(e.target.value) || 0); sig.pdf = ''; } }), onInput: (e) => { s[k] = k === 'marker_key' ? e.target.value : (parseFloat(e.target.value) || 0); sig.pdf = ''; } }),
@@ -964,7 +964,7 @@ const NeuAuftrag = defineComponent({
]), ]),
]); ]);
const meldung = h('div', {}, [ const meldung = h('div', {}, [
sig.err ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;margin-top:8px;' }, sig.err) : null, sig.err ? h('div', { style: 'color:#c0392b;font-size:13px;margin-top:8px;' }, sig.err) : null,
sig.msg ? subdued(sig.msg, 'margin-top:8px;') : null, sig.msg ? subdued(sig.msg, 'margin-top:8px;') : null,
]); ]);
const links = h('div', { style: 'flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;' }, [b1, b2, meldung]); const links = h('div', { style: 'flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;' }, [b1, b2, meldung]);
@@ -984,7 +984,7 @@ const NeuAuftrag = defineComponent({
const navItem = (label, aktiv, onClick) => h('div', { const navItem = (label, aktiv, onClick) => h('div', {
onClick, onClick,
style: 'display:flex;align-items:center;gap:8px;border-radius:6px;padding:10px 12px;margin-bottom:3px;font-size:14px;cursor:pointer;' style: 'display:flex;align-items:center;gap:8px;border-radius:6px;padding:10px 12px;margin-bottom:3px;font-size:14px;cursor:pointer;'
+ (aktiv ? `background:${ACCENT};color:#fff;font-weight:600;` : 'color:var(--foreground-normal);'), + (aktiv ? `background:${ACCENT};color:#fff;font-weight:600;` : 'color:#1b2430;'),
}, label); }, label);
return () => h(resolveComponent('private-view'), { title: ansicht.value === 'signatur' ? 'Unterschriften' : 'Neuer Auftrag' }, { return () => h(resolveComponent('private-view'), { title: ansicht.value === 'signatur' ? 'Unterschriften' : 'Neuer Auftrag' }, {
@@ -995,7 +995,7 @@ const NeuAuftrag = defineComponent({
default: () => [ default: () => [
// Mobil: Button-Reihen bleiben in einer Zeile und füllen die Breite. // Mobil: Button-Reihen bleiben in einer Zeile und füllen die Breite.
h('style', {}, '@media(max-width:640px){.sk-btnrow>button{flex:1 1 auto!important;}}'), h('style', {}, '@media(max-width:640px){.sk-btnrow>button{flex:1 1 auto!important;}}'),
h('div', { style: 'padding:24px 28px;background:var(--background-subdued,#f1f4f9);min-height:100%;' }, h('div', { style: 'padding:24px 28px;background:#eef2f8;min-height:100%;' },
ansicht.value === 'signatur' ? signaturPanel() : (!geladen.value ? subdued('Lädt …') : formular())), ansicht.value === 'signatur' ? signaturPanel() : (!geladen.value ? subdued('Lädt …') : formular())),
neu.lb ? h(Teleport, { to: 'body' }, [ neu.lb ? h(Teleport, { to: 'body' }, [
h('div', { h('div', {

View File

@@ -69,12 +69,12 @@ const STATUS_LABEL = {
}; };
// Farbe + Material-Icon je Produktionsstatus (für den klaren Status-Pill). // Farbe + Material-Icon je Produktionsstatus (für den klaren Status-Pill).
const STATUS_META = { const STATUS_META = {
eingegangen: { bg: 'var(--background-subdued,#eef1f6)', fg: 'var(--foreground-subdued)', icon: 'inbox' }, eingegangen: { bg: '#eef2f8', fg: '#566070', bd: '#d2dae6', icon: 'inbox' },
im_druck: { bg: 'rgba(30,80,165,.12)', fg: '#1E50A5', icon: 'print' }, im_druck: { bg: '#e3ecfa', fg: '#1E50A5', bd: '#bcd0ef', icon: 'print' },
kuvertieren: { bg: 'rgba(106,63,208,.12)', fg: '#6a3fd0', icon: 'mail' }, kuvertieren: { bg: '#ece4fb', fg: '#5b32b8', bd: '#d3c4f2', icon: 'mail' },
versandfertig: { bg: 'rgba(230,160,0,.16)', fg: '#8a6d00', icon: 'inventory_2' }, versandfertig: { bg: '#fbeccb', fg: '#8a5a00', bd: '#f0d79a', icon: 'inventory_2' },
versendet: { bg: 'rgba(46,125,50,.14)', fg: 'var(--success,#2e7d32)', icon: 'local_shipping' }, versendet: { bg: '#e3f4e6', fg: '#1b6b2e', bd: '#bfe2c6', icon: 'local_shipping' },
storniert: { bg: 'rgba(198,40,40,.12)', fg: 'var(--danger,#c62828)', icon: 'cancel' }, storniert: { bg: '#fbe3e0', fg: '#c0392b', bd: '#f3c6bf', icon: 'cancel' },
}; };
// Tage, nach denen ein versendeter Auftrag automatisch ins Archiv wandert. // Tage, nach denen ein versendeter Auftrag automatisch ins Archiv wandert.
const ARCHIV_TAGE = 14; const ARCHIV_TAGE = 14;
@@ -86,11 +86,11 @@ const PARAM_FELDER = [
// Einheitliche, ruhige Optik über das ganze Board (Directus-Theme-Variablen → // Einheitliche, ruhige Optik über das ganze Board (Directus-Theme-Variablen →
// Light/Dark-sicher). Flach, klare Hierarchie, großzügige Abstände. // Light/Dark-sicher). Flach, klare Hierarchie, großzügige Abstände.
// Karte: 12px Radius, Haarlinie, dezenter Schatten, viel Innenabstand. // Karte: 12px Radius, Haarlinie, dezenter Schatten, viel Innenabstand.
const CARD = 'border:1px solid var(--border-subdued);border-radius:12px;padding:18px 20px;background:var(--background-page,#fff);box-shadow:0 1px 2px rgba(0,0,0,.04);'; const CARD = 'border:1px solid #d2dae6;border-radius:12px;padding:18px 20px;background:#ffffff;box-shadow:0 1px 2px rgba(0,0,0,.04);';
// Getönte Sektion (Formulare). // Getönte Sektion (Formulare).
const SECTION = 'background:var(--background-subdued,#f1f4f9);border:1px solid var(--border-subdued);border-radius:12px;padding:18px 20px;margin-bottom:16px;'; const SECTION = 'background:#eef2f8;border:1px solid #d2dae6;border-radius:12px;padding:18px 20px;margin-bottom:16px;';
const S_FELD = 'border:1px solid var(--border-normal);border-radius:8px;padding:8px 11px;background:var(--background-page,#fff);'; const S_FELD = 'border:1px solid #b4c0d2;border-radius:8px;padding:8px 11px;background:#ffffff;';
const S_INPUT = 'padding:8px 11px;border:1px solid var(--border-normal);border-radius:8px;background:var(--background-page);color:var(--foreground-normal);font:inherit;font-size:14px;'; const S_INPUT = 'padding:8px 11px;border:1px solid #b4c0d2;border-radius:8px;background:#ffffff;color:#1b2430;font:inherit;font-size:14px;';
const S_SELECT = S_INPUT + 'cursor:pointer;'; const S_SELECT = S_INPUT + 'cursor:pointer;';
// Directus-Primärfarbe (Marke) + Vorgangs-Akzente. // Directus-Primärfarbe (Marke) + Vorgangs-Akzente.
@@ -109,40 +109,40 @@ function btn(label, onClick, kind, ic) {
const style = kind === 'primary' const style = kind === 'primary'
? base + `border-color:${ACCENT};background:${ACCENT};color:#fff;` ? base + `border-color:${ACCENT};background:${ACCENT};color:#fff;`
: kind === 'danger' : kind === 'danger'
? base + 'border-color:var(--border-normal);background:var(--background-page,#fff);color:var(--danger,#c62828);' ? base + 'border-color:#b4c0d2;background:#ffffff;color:#c0392b;'
: base + 'border-color:var(--border-normal);background:var(--background-page,#fff);color:var(--foreground-normal);'; : base + 'border-color:#b4c0d2;background:#ffffff;color:#1b2430;';
return h('button', { type: 'button', onClick, style }, [ic ? icon(ic) : null, label].filter(Boolean)); return h('button', { type: 'button', onClick, style }, [ic ? icon(ic) : null, label].filter(Boolean));
} }
// Pill (Status/Badge): ruhig, lesbar. farbe = Hintergrund (Theme-Tint), textFarbe optional. // Pill (Status/Badge): ruhig, lesbar. farbe = Hintergrund (Theme-Tint), textFarbe optional.
function chip(text, farbe, textFarbe) { function chip(text, farbe, textFarbe) {
return h('span', { return h('span', {
style: `display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:500;padding:3px 11px;border-radius:999px;` style: `display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:500;padding:3px 11px;border-radius:999px;`
+ `background:${farbe || 'var(--background-subdued)'};color:${textFarbe || 'var(--foreground-subdued)'};white-space:nowrap;`, + `background:${farbe || '#eef2f8'};color:${textFarbe || '#566070'};white-space:nowrap;`,
}, text); }, text);
} }
function subdued(text, extra) { function subdued(text, extra) {
return h('div', { style: `color:var(--foreground-subdued);font-size:13px;${extra || ''}` }, text); return h('div', { style: `color:#566070;font-size:13px;${extra || ''}` }, text);
} }
// Eckdaten-Zeile: eine ruhige Zeile „Icon Wert · Icon Wert" statt Chip-Wand. // Eckdaten-Zeile: eine ruhige Zeile „Icon Wert · Icon Wert" statt Chip-Wand.
function metaItem(text) { function metaItem(text) {
return h('span', { style: 'display:inline-flex;align-items:center;gap:5px;color:var(--foreground-subdued);font-size:13.5px;white-space:nowrap;' }, text); return h('span', { style: 'display:inline-flex;align-items:center;gap:5px;color:#566070;font-size:13.5px;white-space:nowrap;' }, text);
} }
// Beschriftete Eckdaten-Kachel (Label oben, Wert darunter) – klare Struktur. // Beschriftete Eckdaten-Kachel (Label oben, Wert darunter) – klare Struktur.
function tile(labelTxt, value, gross) { function tile(labelTxt, value, gross) {
return h('div', { style: 'background:var(--background-subdued,#f1f4f9);border:1px solid var(--border-normal);border-radius:8px;padding:9px 12px;min-width:0;' }, [ return h('div', { style: 'background:#eef2f8;border:1px solid #b4c0d2;border-radius:8px;padding:9px 12px;min-width:0;' }, [
h('div', { style: 'font-size:11.5px;color:var(--foreground-subdued);' }, labelTxt), h('div', { style: 'font-size:11.5px;color:#566070;' }, labelTxt),
h('div', { style: `font-weight:500;overflow:hidden;text-overflow:ellipsis;${gross ? 'font-size:20px;line-height:1.1;margin-top:2px;' : 'font-size:15px;margin-top:3px;'}` }, value), h('div', { style: `font-weight:500;overflow:hidden;text-overflow:ellipsis;${gross ? 'font-size:20px;line-height:1.1;margin-top:2px;' : 'font-size:15px;margin-top:3px;'}` }, value),
]); ]);
} }
// Feld-Beschriftung über einem Eingabefeld. // Feld-Beschriftung über einem Eingabefeld.
function feldLabel(t) { function feldLabel(t) {
return h('label', { style: 'display:block;font-size:13px;font-weight:500;color:var(--foreground-subdued);margin-bottom:5px;' }, t); return h('label', { style: 'display:block;font-size:13px;font-weight:500;color:#566070;margin-bottom:5px;' }, t);
} }
// Editierbares Notizfeld (speichert beim Verlassen/Blur) – klar sichtbares Feld. // Editierbares Notizfeld (speichert beim Verlassen/Blur) – klar sichtbares Feld.
function notizFeld(wert, onSave, ph) { function notizFeld(wert, onSave, ph) {
return h('textarea', { return h('textarea', {
rows: 2, placeholder: ph || 'Notiz …', rows: 2, placeholder: ph || 'Notiz …',
style: 'width:100%;box-sizing:border-box;border:1px solid var(--border-normal);border-radius:8px;padding:9px 11px;font:inherit;font-size:14px;background:var(--background-page);color:var(--foreground-normal);resize:vertical;min-height:44px;', style: 'width:100%;box-sizing:border-box;border:1px solid #b4c0d2;border-radius:8px;padding:9px 11px;font:inherit;font-size:14px;background:#ffffff;color:#1b2430;resize:vertical;min-height:44px;',
value: wert || '', value: wert || '',
onChange: (e) => onSave(e.target.value), onChange: (e) => onSave(e.target.value),
}, wert || ''); }, wert || '');
@@ -166,12 +166,12 @@ function zielInland(e) {
} }
// Segmentierter Umschalter mit sichtbarem Rahmen: Optionen teilen sich die Breite. // Segmentierter Umschalter mit sichtbarem Rahmen: Optionen teilen sich die Breite.
function segToggle(value, opts, onSel) { function segToggle(value, opts, onSel) {
return h('div', { style: 'display:flex;width:100%;border:1px solid var(--border-normal);border-radius:8px;overflow:hidden;background:var(--background-subdued,#f1f4f9);' }, return h('div', { style: 'display:flex;width:100%;border:1px solid #b4c0d2;border-radius:8px;overflow:hidden;background:#eef2f8;' },
opts.map((o, i) => h('button', { opts.map((o, i) => h('button', {
type: 'button', disabled: o.disabled, onClick: () => { if (!o.disabled) onSel(o.key); }, type: 'button', disabled: o.disabled, onClick: () => { if (!o.disabled) onSel(o.key); },
style: `flex:1;padding:12px 8px;font:inherit;font-size:13px;text-align:center;cursor:${o.disabled ? 'not-allowed' : 'pointer'};border:none;` style: `flex:1;padding:12px 8px;font:inherit;font-size:13px;text-align:center;cursor:${o.disabled ? 'not-allowed' : 'pointer'};border:none;`
+ (i > 0 ? 'border-left:1px solid var(--border-normal);' : '') + (i > 0 ? 'border-left:1px solid #b4c0d2;' : '')
+ (value === o.key ? `background:${ACCENT};color:#fff;font-weight:700;` : 'background:transparent;color:var(--foreground-normal);') + (value === o.key ? `background:${ACCENT};color:#fff;font-weight:700;` : 'background:transparent;color:#1b2430;')
+ (o.disabled ? 'opacity:.45;' : ''), + (o.disabled ? 'opacity:.45;' : ''),
}, o.label))); }, o.label)));
} }
@@ -1369,16 +1369,16 @@ const Board = defineComponent({
function weiteresPanel(o) { function weiteresPanel(o) {
const dz = druckIndex.value[String(o.id)]; const dz = druckIndex.value[String(o.id)];
const nm = empfNamen.value[String(o.id)]; const nm = empfNamen.value[String(o.id)];
const feld = 'width:100%;box-sizing:border-box;border:1px solid var(--border-normal);border-radius:8px;padding:9px 11px;font:inherit;font-size:14px;background:var(--background-page);color:var(--foreground-normal);'; const feld = 'width:100%;box-sizing:border-box;border:1px solid #b4c0d2;border-radius:8px;padding:9px 11px;font:inherit;font-size:14px;background:#ffffff;color:#1b2430;';
return h('div', { style: 'border:1px solid var(--border-normal);border-radius:10px;overflow:hidden;' }, [ return h('div', { style: 'border:1px solid #b4c0d2;border-radius:10px;overflow:hidden;' }, [
h('div', { style: 'display:flex;align-items:center;gap:6px;font-size:13px;font-weight:500;color:var(--foreground-subdued);padding:9px 14px;border-bottom:1px solid var(--border-subdued);background:var(--background-subdued,#f6f8fb);' }, [icon('tune'), 'Weiteres']), h('div', { style: 'display:flex;align-items:center;gap:6px;font-size:13px;font-weight:500;color:#566070;padding:9px 14px;border-bottom:1px solid #d2dae6;background:#eef2f8;' }, [icon('tune'), 'Weiteres']),
h('div', { style: 'padding:14px;display:flex;flex-direction:column;gap:14px;' }, [ h('div', { style: 'padding:14px;display:flex;flex-direction:column;gap:14px;' }, [
// Druckverlauf: wann gedruckt + erster/letzter Empfänger. // Druckverlauf: wann gedruckt + erster/letzter Empfänger.
h('div', {}, [ h('div', {}, [
h('div', { style: 'font-size:11.5px;font-weight:500;color:var(--foreground-subdued);text-transform:uppercase;letter-spacing:.03em;margin-bottom:5px;' }, 'Druckverlauf'), h('div', { style: 'font-size:11.5px;font-weight:500;color:#566070;text-transform:uppercase;letter-spacing:.03em;margin-bottom:5px;' }, 'Druckverlauf'),
h('div', { style: 'font-size:14px;line-height:1.6;' }, [ h('div', { style: 'font-size:14px;line-height:1.6;' }, [
h('div', {}, dz ? `In den Druck: ${dmYhm(dz.erste)}${dz.letzte && dz.letzte.slice(0, 16) !== dz.erste.slice(0, 16) ? ' – ' + dmYhm(dz.letzte) : ''}` : 'Noch nicht gedruckt.'), h('div', {}, dz ? `In den Druck: ${dmYhm(dz.erste)}${dz.letzte && dz.letzte.slice(0, 16) !== dz.erste.slice(0, 16) ? ' – ' + dmYhm(dz.letzte) : ''}` : 'Noch nicht gedruckt.'),
nm ? h('div', { style: 'color:var(--foreground-subdued);' }, `Erster: ${nm.erste}${nm.anzahl > 1 ? ` · Letzter: ${nm.letzte}` : ''}`) : null, nm ? h('div', { style: 'color:#566070;' }, `Erster: ${nm.erste}${nm.anzahl > 1 ? ` · Letzter: ${nm.letzte}` : ''}`) : null,
]), ]),
]), ]),
// Verknüpfungen: beschriftete Felder. // Verknüpfungen: beschriftete Felder.
@@ -1389,13 +1389,13 @@ const Board = defineComponent({
o.customer o.customer
? h('div', { style: 'display:flex;align-items:center;gap:8px;' }, [ ? h('div', { style: 'display:flex;align-items:center;gap:8px;' }, [
h('span', { style: 'font-size:14px;' }, `${kundeName(o)}${o.customer.email ? ' · ' + o.customer.email : ''}`), h('span', { style: 'font-size:14px;' }, `${kundeName(o)}${o.customer.email ? ' · ' + o.customer.email : ''}`),
h('button', { type: 'button', title: 'Kontakt lösen', onClick: () => setOrderCustomer(o, ''), style: 'cursor:pointer;border:1px solid var(--border-normal);background:var(--background-page);border-radius:8px;padding:5px 10px;font:inherit;font-size:13px;color:var(--danger,#c62828);' }, 'lösen'), h('button', { type: 'button', title: 'Kontakt lösen', onClick: () => setOrderCustomer(o, ''), style: 'cursor:pointer;border:1px solid #b4c0d2;background:#ffffff;border-radius:8px;padding:5px 10px;font:inherit;font-size:13px;color:#c0392b;' }, 'lösen'),
]) ])
: h('input', { placeholder: 'kunde@example.de', style: feld, onChange: (e) => setOrderCustomer(o, e.target.value) }), : h('input', { placeholder: 'kunde@example.de', style: feld, onChange: (e) => setOrderCustomer(o, e.target.value) }),
]), ]),
]), ]),
// Aktionen (abgetrennt). // Aktionen (abgetrennt).
h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;border-top:1px solid var(--border-subdued);padding-top:14px;' }, [ h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;border-top:1px solid #d2dae6;padding-top:14px;' }, [
btn(o.keep_contacts ? 'In Kontakte gespeichert' : 'In Kontakte speichern', btn(o.keep_contacts ? 'In Kontakte gespeichert' : 'In Kontakte speichern',
() => toggleKeepContacts(o), o.keep_contacts ? 'primary' : 'default', o.keep_contacts ? 'how_to_reg' : 'contacts'), () => toggleKeepContacts(o), o.keep_contacts ? 'primary' : 'default', o.keep_contacts ? 'how_to_reg' : 'contacts'),
btn('Neu generieren', () => regenerieren(o.id), 'danger', 'autorenew'), btn('Neu generieren', () => regenerieren(o.id), 'danger', 'autorenew'),
@@ -1408,10 +1408,10 @@ const Board = defineComponent({
const k = order.production_status || 'eingegangen'; const k = order.production_status || 'eingegangen';
const m = STATUS_META[k] || STATUS_META.eingegangen; const m = STATUS_META[k] || STATUS_META.eingegangen;
// Farbiger Pill, der zugleich das Status-Dropdown ist (ein Element, klarer Status). // Farbiger Pill, der zugleich das Status-Dropdown ist (ein Element, klarer Status).
return h('div', { style: `display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:6px 12px 6px 14px;background:${m.bg};color:${m.fg};font-weight:500;font-size:13px;flex-shrink:0;` }, [ return h('div', { style: `display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:6px 12px 6px 14px;background:${m.bg};color:${m.fg};border:1px solid ${m.bd || '#d2dae6'};font-weight:600;font-size:13px;flex-shrink:0;` }, [
icon(m.icon), icon(m.icon),
h('select', { h('select', {
style: `border:none;background:transparent;color:${m.fg};font:inherit;font-size:13px;font-weight:500;cursor:pointer;padding:0;`, style: `border:none;background:transparent;color:${m.fg};font:inherit;font-size:13px;font-weight:600;cursor:pointer;padding:0;`,
value: k, onChange: (e) => setStatus(order, e.target.value), value: k, onChange: (e) => setStatus(order, e.target.value),
}, Object.entries(STATUS_LABEL).map(([kk, v]) => h('option', { value: kk, selected: k === kk }, v))), }, Object.entries(STATUS_LABEL).map(([kk, v]) => h('option', { value: kk, selected: k === kk }, v))),
]); ]);
@@ -1433,16 +1433,16 @@ const Board = defineComponent({
const bezahlt = o.payment_status === 'bezahlt'; const bezahlt = o.payment_status === 'bezahlt';
const identName = kundeName(o); const identName = kundeName(o);
// ── KOPF (getönt): Auswahl/Griff + Identität + Status ────────────────── // ── KOPF (getönt): Auswahl/Griff + Identität + Status ──────────────────
const kopf = h('div', { style: 'display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;padding:14px 16px;background:var(--background-subdued,#f6f8fb);border-bottom:1px solid var(--border-subdued);' }, [ const kopf = h('div', { style: 'display:flex;justify-content:space-between;align-items:flex-start;gap:12px;flex-wrap:wrap;padding:14px 16px;background:#eef2f8;border-bottom:1px solid #d2dae6;' }, [
h('div', { style: 'display:flex;gap:12px;align-items:flex-start;min-width:0;flex:1;' }, [ h('div', { style: 'display:flex;gap:12px;align-items:flex-start;min-width:0;flex:1;' }, [
opts2.dragHandle opts2.dragHandle
? h('span', { style: 'color:var(--foreground-subdued);cursor:grab;margin-top:3px;flex-shrink:0;', title: 'Ziehen zum Sortieren' }, icon('drag_indicator')) ? h('span', { style: 'color:#566070;cursor:grab;margin-top:3px;flex-shrink:0;', title: 'Ziehen zum Sortieren' }, icon('drag_indicator'))
: h('input', { type: 'checkbox', checked: istGewaehlt(o.id), onClick: (e) => toggleAuswahl(o.id, e), : h('input', { type: 'checkbox', checked: istGewaehlt(o.id), onClick: (e) => toggleAuswahl(o.id, e),
title: 'Für Sammel-Druck auswählen', style: 'width:19px;height:19px;margin-top:3px;cursor:pointer;flex-shrink:0;' }), title: 'Für Sammel-Druck auswählen', style: 'width:19px;height:19px;margin-top:3px;cursor:pointer;flex-shrink:0;' }),
h('div', { style: 'min-width:0;' }, [ h('div', { style: 'min-width:0;' }, [
o.order_name ? h('div', { style: 'font-size:12px;font-weight:500;color:#1E50A5;text-transform:uppercase;letter-spacing:.03em;margin-bottom:1px;' }, o.order_name) : null, o.order_name ? h('div', { style: 'font-size:12px;font-weight:500;color:#1E50A5;text-transform:uppercase;letter-spacing:.03em;margin-bottom:1px;' }, o.order_name) : null,
h('div', { style: 'font-size:20px;font-weight:500;letter-spacing:-.01em;line-height:1.2;' }, identName || `#${o.order_number}`), h('div', { style: 'font-size:20px;font-weight:500;letter-spacing:-.01em;line-height:1.2;' }, identName || `#${o.order_number}`),
h('div', { style: 'font-size:14px;color:var(--foreground-subdued);margin-top:2px;' }, (identName ? `#${o.order_number} · ` : '') + `${o.entries_count || 0} Empfänger`), h('div', { style: 'font-size:14px;color:#566070;margin-top:2px;' }, (identName ? `#${o.order_number} · ` : '') + `${o.entries_count || 0} Empfänger`),
]), ]),
]), ]),
statusSelect(o), statusSelect(o),
@@ -1458,9 +1458,9 @@ const Board = defineComponent({
const send = sendIndex.value[String(o.id)]; const send = sendIndex.value[String(o.id)];
const briefOk = !!o.brief_gedruckt || !!(send && send.brief.length); const briefOk = !!o.brief_gedruckt || !!(send && send.brief.length);
const kuvOk = !!o.kuvert_gedruckt || !!(send && send.umschlag.length); const kuvOk = !!o.kuvert_gedruckt || !!(send && send.umschlag.length);
const statusWort = (ok, ranges) => h('span', { style: `font-weight:500;color:${ok ? 'var(--success,#2e7d32)' : 'var(--danger,#c62828)'};` }, const statusWort = (ok, ranges) => h('span', { style: `font-weight:500;color:${ok ? '#1b6b2e' : '#c0392b'};` },
ok ? ('gedruckt' + (ranges && ranges.length ? ' · ' + ranges.join(', ') : '')) : 'nicht gedruckt'); ok ? ('gedruckt' + (ranges && ranges.length ? ' · ' + ranges.join(', ') : '')) : 'nicht gedruckt');
const druckStrip = h('div', { style: 'display:flex;gap:20px;flex-wrap:wrap;padding:10px 12px;background:var(--background-subdued,#f6f8fb);border:1px solid var(--border-normal);border-radius:8px;font-size:14px;' }, [ const druckStrip = h('div', { style: 'display:flex;gap:20px;flex-wrap:wrap;padding:10px 12px;background:#eef2f8;border:1px solid #b4c0d2;border-radius:8px;font-size:14px;' }, [
h('span', { style: 'display:inline-flex;align-items:center;gap:6px;' }, [icon('description'), 'Brief: ', statusWort(briefOk, send && send.brief)]), h('span', { style: 'display:inline-flex;align-items:center;gap:6px;' }, [icon('description'), 'Brief: ', statusWort(briefOk, send && send.brief)]),
o.needs_envelope ? h('span', { style: 'display:inline-flex;align-items:center;gap:6px;' }, [icon('mail'), 'Kuvert: ', statusWort(kuvOk, send && send.umschlag)]) : null, o.needs_envelope ? h('span', { style: 'display:inline-flex;align-items:center;gap:6px;' }, [icon('mail'), 'Kuvert: ', statusWort(kuvOk, send && send.umschlag)]) : null,
].filter(Boolean)); ].filter(Boolean));
@@ -1471,26 +1471,26 @@ const Board = defineComponent({
: null, : null,
o.linked_order?.order_number ? chip('Kuverts: #' + o.linked_order.order_number) : null, o.linked_order?.order_number ? chip('Kuverts: #' + o.linked_order.order_number) : null,
o.approval_status === 'pending' ? chip('wartet auf Freigabe', 'rgba(230,160,0,.18)', '#8a6d00') : null, o.approval_status === 'pending' ? chip('wartet auf Freigabe', 'rgba(230,160,0,.18)', '#8a6d00') : null,
o.approval_status === 'approved' ? chip('Motiv freigegeben', 'rgba(46,125,50,.14)', 'var(--success,#2e7d32)') : null, o.approval_status === 'approved' ? chip('Motiv freigegeben', 'rgba(46,125,50,.14)', '#1b6b2e') : null,
o.approval_status === 'changes' ? chip('Änderungswunsch', 'rgba(198,40,40,.14)', 'var(--danger,#c62828)') : null, o.approval_status === 'changes' ? chip('Änderungswunsch', 'rgba(198,40,40,.14)', '#c0392b') : null,
].filter(Boolean); ].filter(Boolean);
const pillRow = pills.length ? h('div', { style: 'display:flex;gap:7px;flex-wrap:wrap;' }, pills) : null; const pillRow = pills.length ? h('div', { style: 'display:flex;gap:7px;flex-wrap:wrap;' }, pills) : null;
// ── Sammelversand: Lieferadresse ─────────────────────────────────────── // ── Sammelversand: Lieferadresse ───────────────────────────────────────
const liefer = (o.shipping_type !== 'einzeln') ? lieferAdresse(o) : null; const liefer = (o.shipping_type !== 'einzeln') ? lieferAdresse(o) : null;
const lieferBox = liefer ? h('div', { style: 'padding:11px 13px;background:var(--background-subdued,#f6f8fb);border:1px solid var(--border-normal);border-radius:8px;font-size:14px;line-height:1.55;' }, [ const lieferBox = liefer ? h('div', { style: 'padding:11px 13px;background:#eef2f8;border:1px solid #b4c0d2;border-radius:8px;font-size:14px;line-height:1.55;' }, [
h('div', { style: 'display:flex;align-items:center;gap:5px;font-weight:500;color:var(--foreground-subdued);font-size:11.5px;text-transform:uppercase;letter-spacing:.04em;margin-bottom:3px;' }, [icon('local_shipping'), 'Versand an · ' + liefer.quelle]), h('div', { style: 'display:flex;align-items:center;gap:5px;font-weight:500;color:#566070;font-size:11.5px;text-transform:uppercase;letter-spacing:.04em;margin-bottom:3px;' }, [icon('local_shipping'), 'Versand an · ' + liefer.quelle]),
...liefer.zeilen.map((z) => h('div', {}, z)), ...liefer.zeilen.map((z) => h('div', {}, z)),
]) : null; ]) : null;
// ── Fußzeile: Nummer · Zahlung · Versandtag · Link ───────────────────── // ── Fußzeile: Nummer · Zahlung · Versandtag · Link ─────────────────────
const sub = [ const sub = [
h('span', { style: 'font-variant-numeric:tabular-nums;' }, '#' + o.order_number), h('span', { style: 'font-variant-numeric:tabular-nums;' }, '#' + o.order_number),
h('span', { style: `color:${bezahlt ? 'var(--success,#2e7d32)' : '#8a6d00'};font-weight:500;` }, bezahlt ? 'bezahlt' : (o.payment_status === 'storniert' ? 'storniert' : 'offen')), h('span', { style: `color:${bezahlt ? '#1b6b2e' : '#8a6d00'};font-weight:500;` }, bezahlt ? 'bezahlt' : (o.payment_status === 'storniert' ? 'storniert' : 'offen')),
(Number(o.count_ausland) > 0) ? h('span', {}, `${o.count_inland ?? 0} DE · ${o.count_ausland} Ausland`) : null, (Number(o.count_ausland) > 0) ? h('span', {}, `${o.count_inland ?? 0} DE · ${o.count_ausland} Ausland`) : null,
o.shipping_day ? h('span', {}, 'Versandtag ' + o.shipping_day.charAt(0).toUpperCase() + o.shipping_day.slice(1)) : null, o.shipping_day ? h('span', {}, 'Versandtag ' + o.shipping_day.charAt(0).toUpperCase() + o.shipping_day.slice(1)) : null,
h('a', { href: `/admin/content/orders/${o.id}`, target: '_blank', rel: 'noopener', style: 'display:inline-flex;align-items:center;gap:3px;color:#1E50A5;text-decoration:none;font-weight:500;' }, [icon('open_in_new'), 'Auftrag öffnen']), h('a', { href: `/admin/content/orders/${o.id}`, target: '_blank', rel: 'noopener', style: 'display:inline-flex;align-items:center;gap:3px;color:#1E50A5;text-decoration:none;font-weight:500;' }, [icon('open_in_new'), 'Auftrag öffnen']),
].filter(Boolean); ].filter(Boolean);
const subline = h('div', { style: 'display:flex;align-items:center;gap:12px;flex-wrap:wrap;font-size:13px;color:var(--foreground-subdued);' }, const subline = h('div', { style: 'display:flex;align-items:center;gap:12px;flex-wrap:wrap;font-size:13px;color:#566070;' },
sub.reduce((acc, el, i) => (i === 0 ? [el] : acc.concat(h('span', { style: 'color:var(--border-normal);', 'aria-hidden': 'true' }, '·'), el)), [])); sub.reduce((acc, el, i) => (i === 0 ? [el] : acc.concat(h('span', { style: 'color:#b4c0d2;', 'aria-hidden': 'true' }, '·'), el)), []));
// ── BODY ─────────────────────────────────────────────────────────────── // ── BODY ───────────────────────────────────────────────────────────────
const body = h('div', { style: 'padding:14px 16px;display:flex;flex-direction:column;gap:14px;' }, [ const body = h('div', { style: 'padding:14px 16px;display:flex;flex-direction:column;gap:14px;' }, [
specs, druckStrip, pillRow, lieferBox, specs, druckStrip, pillRow, lieferBox,
@@ -1499,7 +1499,7 @@ const Board = defineComponent({
weiteresOffen.value[o.id] ? weiteresPanel(o) : null, weiteresOffen.value[o.id] ? weiteresPanel(o) : null,
subline, subline,
].filter(Boolean)); ].filter(Boolean));
return h('div', { key: 'o' + o.id, style: 'border:1px solid var(--border-normal);border-radius:12px;overflow:hidden;background:var(--background-page,#fff);margin-bottom:14px;' }, [kopf, body]); return h('div', { key: 'o' + o.id, style: 'border:1px solid #b4c0d2;border-radius:12px;overflow:hidden;background:#ffffff;margin-bottom:14px;' }, [kopf, body]);
} }
function requestCard(req) { function requestCard(req) {
const istMuster = req.type === 'muster'; const istMuster = req.type === 'muster';
@@ -1516,31 +1516,31 @@ const Board = defineComponent({
['neu', 'in_bearbeitung', 'beantwortet', 'abgelehnt'].map((s) => h('option', { value: s, selected: req.status === s }, s))), ['neu', 'in_bearbeitung', 'beantwortet', 'abgelehnt'].map((s) => h('option', { value: s, selected: req.status === s }, s))),
]); ]);
const eck = [metaItem(req.product || 'Produkt?'), req.quantity ? metaItem(`Menge ${req.quantity}`) : null].filter(Boolean); const eck = [metaItem(req.product || 'Produkt?'), req.quantity ? metaItem(`Menge ${req.quantity}`) : null].filter(Boolean);
const metaRow = h('div', { style: 'display:flex;gap:11px;align-items:center;flex-wrap:wrap;margin:12px 0;padding:11px 0;border-top:1px solid var(--border-subdued);border-bottom:1px solid var(--border-subdued);' }, const metaRow = h('div', { style: 'display:flex;gap:11px;align-items:center;flex-wrap:wrap;margin:12px 0;padding:11px 0;border-top:1px solid #d2dae6;border-bottom:1px solid #d2dae6;' },
eck.reduce((acc, el, i) => (i === 0 ? [el] : acc.concat(h('span', { style: 'color:var(--border-normal);', 'aria-hidden': 'true' }, '·'), el)), [])); eck.reduce((acc, el, i) => (i === 0 ? [el] : acc.concat(h('span', { style: 'color:#b4c0d2;', 'aria-hidden': 'true' }, '·'), el)), []));
const nachricht = req.message ? h('div', { style: 'margin:0 0 12px;padding:12px 14px;background:var(--background-subdued,#f1f4f9);border-radius:10px;font-size:14px;line-height:1.6;white-space:pre-wrap;color:var(--foreground-normal);' }, req.message) : null; const nachricht = req.message ? h('div', { style: 'margin:0 0 12px;padding:12px 14px;background:#eef2f8;border-radius:10px;font-size:14px;line-height:1.6;white-space:pre-wrap;color:#1b2430;' }, req.message) : null;
const aktionen = h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;' }, [ const aktionen = h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;' }, [
// Muster (Druckprodukt) → manueller Druck; individuelles Angebot → kein Druck. // Muster (Druckprodukt) → manueller Druck; individuelles Angebot → kein Druck.
istMuster ? btn('In manuellen Druck', () => musterUebernehmen(req), 'primary', 'edit_note') : null, istMuster ? btn('In manuellen Druck', () => musterUebernehmen(req), 'primary', 'edit_note') : null,
btn('Details', () => openReqInfo(req), 'default', 'person'), btn('Details', () => openReqInfo(req), 'default', 'person'),
]); ]);
return h('div', { key: 'r' + req.id, style: 'border:1px solid var(--border-normal);border-radius:12px;background:var(--background-page,#fff);padding:16px 18px;margin-bottom:14px;' }, [kopf, metaRow, nachricht, aktionen]); return h('div', { key: 'r' + req.id, style: 'border:1px solid #b4c0d2;border-radius:12px;background:#ffffff;padding:16px 18px;margin-bottom:14px;' }, [kopf, metaRow, nachricht, aktionen]);
} }
// Charge-Karte: fasst API-Aufträge (Kunde+Typ+Versandtag+Eingangstag) zusammen. // Charge-Karte: fasst API-Aufträge (Kunde+Typ+Versandtag+Eingangstag) zusammen.
function chargeCard(c, opts) { function chargeCard(c, opts) {
const auf = expandedCharges.value.has(c.key); const auf = expandedCharges.value.has(c.key);
let faelligFarbe = 'var(--background-subdued)'; let faelligFarbe = '#eef2f8';
if (c.faellig) { if (c.faellig) {
const tage = Math.ceil((c.faellig.getTime() - Date.now()) / 864e5); const tage = Math.ceil((c.faellig.getTime() - Date.now()) / 864e5);
faelligFarbe = tage < 0 ? 'var(--danger-25,rgba(198,40,40,.15))' faelligFarbe = tage < 0 ? '#fbe3e0'
: tage <= 7 ? 'var(--warning-25,rgba(230,160,0,.18))' : 'var(--success-25,rgba(46,125,50,.12))'; : tage <= 7 ? '#fbeccb' : '#dff2e2';
} }
const kopf = h('div', { style: 'display:flex;align-items:center;gap:10px;flex-wrap:wrap;' }, [ const kopf = h('div', { style: 'display:flex;align-items:center;gap:10px;flex-wrap:wrap;' }, [
h('input', { type: 'checkbox', checked: chargeGewaehlt(c), onChange: () => toggleCharge(c), h('input', { type: 'checkbox', checked: chargeGewaehlt(c), onChange: () => toggleCharge(c),
title: 'Ganze Charge auswählen', style: 'width:16px;height:16px;cursor:pointer;flex-shrink:0;' }), title: 'Ganze Charge auswählen', style: 'width:16px;height:16px;cursor:pointer;flex-shrink:0;' }),
h('button', { type: 'button', onClick: () => toggleExpand(c.key), h('button', { type: 'button', onClick: () => toggleExpand(c.key),
style: 'cursor:pointer;border:none;background:transparent;color:var(--foreground-subdued);display:inline-flex;align-items:center;', title: 'Aufklappen' }, icon(auf ? 'expand_more' : 'chevron_right')), style: 'cursor:pointer;border:none;background:transparent;color:#566070;display:inline-flex;align-items:center;', title: 'Aufklappen' }, icon(auf ? 'expand_more' : 'chevron_right')),
h('div', { style: 'display:flex;align-items:center;gap:7px;font-weight:500;font-size:16px;' }, [icon('inbox'), `${c.kundeName} · ${c.produkt}`]), h('div', { style: 'display:flex;align-items:center;gap:7px;font-weight:500;font-size:16px;' }, [icon('inbox'), `${c.kundeName} · ${c.produkt}`]),
chip(`${c.orders.length} Aufträge`), chip(`${c.orders.length} Aufträge`),
c.versandtag ? chip('Versandtag ' + c.versandtag.charAt(0).toUpperCase() + c.versandtag.slice(1)) : null, c.versandtag ? chip('Versandtag ' + c.versandtag.charAt(0).toUpperCase() + c.versandtag.slice(1)) : null,
@@ -1560,7 +1560,7 @@ const Board = defineComponent({
]); ]);
const body = auf ? h('div', { style: 'margin-top:12px;display:flex;flex-direction:column;gap:2px;' }, c.orders.map((o) => orderCard(o, opts))) : null; const body = auf ? h('div', { style: 'margin-top:12px;display:flex;flex-direction:column;gap:2px;' }, c.orders.map((o) => orderCard(o, opts))) : null;
const chargeNotiz = notizFeld(chargeNotizen.value[c.key], (v) => setChargeNotiz(c.key, v), 'Notiz zur Charge …'); const chargeNotiz = notizFeld(chargeNotizen.value[c.key], (v) => setChargeNotiz(c.key, v), 'Notiz zur Charge …');
return h('div', { key: 'c' + c.key, style: 'border:1px solid var(--border-normal);border-radius:12px;background:var(--background-page,#fff);padding:16px 18px;margin-bottom:14px;' }, [kopf, chargeSpecs, chargeNotiz, body]); return h('div', { key: 'c' + c.key, style: 'border:1px solid #b4c0d2;border-radius:12px;background:#ffffff;padding:16px 18px;margin-bottom:14px;' }, [kopf, chargeSpecs, chargeNotiz, body]);
} }
// Aufträge einer Ansicht rendern: bei aktiver Suche als EINZELaufträge (damit // Aufträge einer Ansicht rendern: bei aktiver Suche als EINZELaufträge (damit
@@ -1590,7 +1590,7 @@ const Board = defineComponent({
]; ];
// Große, eindeutige Auswahlknöpfe: aktiv = blau/weiß, sonst weiß mit Rahmen. // Große, eindeutige Auswahlknöpfe: aktiv = blau/weiß, sonst weiß mit Rahmen.
const typWahl = h('div', {}, [ const typWahl = h('div', {}, [
h('div', { style: 'font-size:13px;font-weight:700;color:var(--foreground-normal);margin-bottom:8px;' }, '1. Was möchten Sie?'), h('div', { style: 'font-size:13px;font-weight:700;color:#1b2430;margin-bottom:8px;' }, '1. Was möchten Sie?'),
h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;' }, TYPEN.map((t) => { h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;' }, TYPEN.map((t) => {
const aktiv = sucheTyp.value === t.key; const aktiv = sucheTyp.value === t.key;
return h('button', { type: 'button', onClick: () => { sucheTyp.value = t.key; }, return h('button', { type: 'button', onClick: () => { sucheTyp.value = t.key; },
@@ -1601,7 +1601,7 @@ const Board = defineComponent({
]); ]);
// Großes, unverkennbar weißes Suchfeld. // Großes, unverkennbar weißes Suchfeld.
const feld = h('div', { style: 'margin-top:18px;' }, [ const feld = h('div', { style: 'margin-top:18px;' }, [
h('div', { style: 'font-size:13px;font-weight:700;color:var(--foreground-normal);margin-bottom:8px;' }, '2. Empfänger suchen'), h('div', { style: 'font-size:13px;font-weight:700;color:#1b2430;margin-bottom:8px;' }, '2. Empfänger suchen'),
h('input', { type: 'search', placeholder: 'Name, Straße, Ort oder Auftragsnummer eingeben …', h('input', { type: 'search', placeholder: 'Name, Straße, Ort oder Auftragsnummer eingeben …',
style: 'width:100%;box-sizing:border-box;background:#fff;color:#111;border:2px solid #cdd6e2;border-radius:10px;' style: 'width:100%;box-sizing:border-box;background:#fff;color:#111;border:2px solid #cdd6e2;border-radius:10px;'
+ 'font:inherit;font-size:22px;padding:16px 20px;outline:none;box-shadow:0 1px 3px rgba(0,0,0,.08);', + 'font:inherit;font-size:22px;padding:16px 20px;outline:none;box-shadow:0 1px 3px rgba(0,0,0,.08);',
@@ -1628,10 +1628,10 @@ const Board = defineComponent({
return h('div', { key: `s${o.id}-${e.nr}`, style: CARD + 'margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;' }, [ return h('div', { key: `s${o.id}-${e.nr}`, style: CARD + 'margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;' }, [
h('div', { style: 'min-width:0;' }, [ h('div', { style: 'min-width:0;' }, [
// Vollständige Anschrift zuerst (erste Zeile = Name, hervorgehoben). // Vollständige Anschrift zuerst (erste Zeile = Name, hervorgehoben).
...adrLines.map((z, i) => h('div', { style: i === 0 ? 'font-weight:700;font-size:16px;' : 'font-size:14px;color:var(--foreground-normal);' }, z)), ...adrLines.map((z, i) => h('div', { style: i === 0 ? 'font-weight:700;font-size:16px;' : 'font-size:14px;color:#1b2430;' }, z)),
// Darunter die Auftragsnummer (+ Position bei mehreren Empfängern). // Darunter die Auftragsnummer (+ Position bei mehreren Empfängern).
h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;margin-top:5px;align-items:center;' }, [ h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;margin-top:5px;align-items:center;' }, [
h('span', { style: 'font-size:13px;color:var(--foreground-subdued);' }, `Auftrag #${o.order_number}`), h('span', { style: 'font-size:13px;color:#566070;' }, `Auftrag #${o.order_number}`),
gesamt > 1 ? chip(`Nr. ${e.nr} von ${gesamt}`) : null, gesamt > 1 ? chip(`Nr. ${e.nr} von ${gesamt}`) : null,
]), ]),
]), ]),
@@ -1661,7 +1661,7 @@ const Board = defineComponent({
if (!baum.length) return [leiste, subdued('Keine offenen Übermittlungen.')]; if (!baum.length) return [leiste, subdued('Keine offenen Übermittlungen.')];
const pfeil = (offen) => h('span', { style: 'display:inline-block;width:14px;font-size:12px;color:var(--foreground-subdued);' }, offen ? '▾' : '▸'); const pfeil = (offen) => h('span', { style: 'display:inline-block;width:14px;font-size:12px;color:#566070;' }, offen ? '▾' : '▸');
const gruppenHaken = (subs) => h('input', { type: 'checkbox', checked: batchGruppeGewaehlt(subs), onClick: (e) => { e.stopPropagation(); batchGruppeToggle(subs); }, style: 'width:16px;height:16px;flex-shrink:0;' }); const gruppenHaken = (subs) => h('input', { type: 'checkbox', checked: batchGruppeGewaehlt(subs), onClick: (e) => { e.stopPropagation(); batchGruppeToggle(subs); }, style: 'width:16px;height:16px;flex-shrink:0;' });
const zeile = (s) => { const zeile = (s) => {
@@ -1677,7 +1677,7 @@ const Board = defineComponent({
]), ]),
h('div', { style: 'display:flex;gap:8px;align-items:center;flex-wrap:wrap;' }, [ h('div', { style: 'display:flex;gap:8px;align-items:center;flex-wrap:wrap;' }, [
chip(istText ? '✍ Text' : '📄 Druck-PDF'), chip(istText ? '✍ Text' : '📄 Druck-PDF'),
s.versendet ? chip('✓ versendet', 'var(--success-25,rgba(46,125,50,.15))') : null, s.versendet ? chip('✓ versendet', '#dff2e2') : null,
istText ? btn('✍ Schreibvorlage', () => batchSchreibvorlage(s)) : null, istText ? btn('✍ Schreibvorlage', () => batchSchreibvorlage(s)) : null,
]), ]),
]); ]);
@@ -1720,18 +1720,18 @@ const Board = defineComponent({
bestandMsg.value = `${row.bezeichnung}: ${delta >= 0 ? '+' : ''}${delta} → ${neu} ${row.einheit || ''}`; bestandMsg.value = `${row.bezeichnung}: ${delta >= 0 ? '+' : ''}${delta} → ${neu} ${row.einheit || ''}`;
setTimeout(() => { if (bestandMsg.value.startsWith(row.bezeichnung)) bestandMsg.value = ''; }, 3000); setTimeout(() => { if (bestandMsg.value.startsWith(row.bezeichnung)) bestandMsg.value = ''; }, 3000);
} }
const klLabel = (t) => h('span', { style: 'font-size:11px;color:var(--foreground-subdued);' }, t); const klLabel = (t) => h('span', { style: 'font-size:11px;color:#566070;' }, t);
function bestandZeile(b) { function bestandZeile(b) {
const unter = (Number(b.bestand) || 0) < (Number(b.mindestbestand) || 0); const unter = (Number(b.bestand) || 0) < (Number(b.mindestbestand) || 0);
if (!(b.id in bestandEingabe)) bestandEingabe[b.id] = ''; if (!(b.id in bestandEingabe)) bestandEingabe[b.id] = '';
return h('div', { key: 'inv' + b.id, style: `display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:6px 8px;border-radius:8px;margin-bottom:4px;${unter ? 'background:var(--danger-25,rgba(198,40,40,.08));' : ''}` }, [ return h('div', { key: 'inv' + b.id, style: `display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:6px 8px;border-radius:8px;margin-bottom:4px;${unter ? 'background:#fbe3e0;' : ''}` }, [
h('div', { style: 'flex:1 1 180px;min-width:150px;font-size:14px;' }, [ h('div', { style: 'flex:1 1 180px;min-width:150px;font-size:14px;' }, [
h('span', { style: 'font-weight:600;' }, b.bezeichnung || b.format), h('span', { style: 'font-weight:600;' }, b.bezeichnung || b.format),
unter ? h('span', { style: 'margin-left:8px;color:var(--danger,#c62828);font-weight:700;font-size:12px;' }, '• nachbestellen') : null, unter ? h('span', { style: 'margin-left:8px;color:#c0392b;font-weight:700;font-size:12px;' }, '• nachbestellen') : null,
]), ]),
h('div', { style: 'display:flex;align-items:center;gap:4px;' }, [klLabel('Bestand'), h('div', { style: 'display:flex;align-items:center;gap:4px;' }, [klLabel('Bestand'),
h('input', { type: 'number', value: b.bestand, style: 'width:84px;' + S_INPUT, onChange: (e) => bestandPatch(b, { bestand: Math.round(Number(e.target.value) || 0) }) }), h('input', { type: 'number', value: b.bestand, style: 'width:84px;' + S_INPUT, onChange: (e) => bestandPatch(b, { bestand: Math.round(Number(e.target.value) || 0) }) }),
h('span', { style: 'font-size:12px;color:var(--foreground-subdued);' }, b.einheit || '')]), h('span', { style: 'font-size:12px;color:#566070;' }, b.einheit || '')]),
h('div', { style: 'display:flex;align-items:center;gap:4px;' }, [klLabel('Mindest'), h('div', { style: 'display:flex;align-items:center;gap:4px;' }, [klLabel('Mindest'),
h('input', { type: 'number', value: b.mindestbestand, style: 'width:70px;' + S_INPUT, onChange: (e) => bestandPatch(b, { mindestbestand: Math.round(Number(e.target.value) || 0) }) })]), h('input', { type: 'number', value: b.mindestbestand, style: 'width:70px;' + S_INPUT, onChange: (e) => bestandPatch(b, { mindestbestand: Math.round(Number(e.target.value) || 0) }) })]),
h('div', { style: 'display:flex;align-items:center;gap:4px;' }, [ h('div', { style: 'display:flex;align-items:center;gap:4px;' }, [
@@ -1750,14 +1750,14 @@ const Board = defineComponent({
const items = rows.filter((b) => b.kategorie === k); const items = rows.filter((b) => b.kategorie === k);
if (!items.length) return null; if (!items.length) return null;
return h('div', { style: 'margin-bottom:8px;' }, [ return h('div', { style: 'margin-bottom:8px;' }, [
h('div', { style: 'font-size:12px;font-weight:700;color:var(--foreground-subdued);text-transform:uppercase;letter-spacing:.03em;margin:6px 0 2px;' }, kl), h('div', { style: 'font-size:12px;font-weight:700;color:#566070;text-transform:uppercase;letter-spacing:.03em;margin:6px 0 2px;' }, kl),
...items.map(bestandZeile), ...items.map(bestandZeile),
]); ]);
}); });
return h('div', { key: 'st' + s.id, style: CARD + 'margin-bottom:16px;' }, [ return h('div', { key: 'st' + s.id, style: CARD + 'margin-bottom:16px;' }, [
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;flex-wrap:wrap;gap:8px;' }, [ h('div', { style: 'display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;flex-wrap:wrap;gap:8px;' }, [
h('div', { style: 'display:flex;align-items:center;gap:7px;font-weight:500;font-size:16px;' }, [icon('store'), s.name]), h('div', { style: 'display:flex;align-items:center;gap:7px;font-weight:500;font-size:16px;' }, [icon('store'), s.name]),
unter ? chip(`⚠ ${unter}× nachbestellen`, 'var(--danger-25,rgba(198,40,40,.15))') : chip('✓ Bestand ok', 'var(--success-25,rgba(46,125,50,.15))'), unter ? chip(`⚠ ${unter}× nachbestellen`, '#fbe3e0') : chip('✓ Bestand ok', '#dff2e2'),
]), ]),
rows.length ? h('div', {}, katBloecke) : subdued('Keine Materialzeilen an diesem Standort.'), rows.length ? h('div', {}, katBloecke) : subdued('Keine Materialzeilen an diesem Standort.'),
]); ]);
@@ -1797,7 +1797,7 @@ const Board = defineComponent({
h('div', { style: 'display:flex;align-items:center;gap:8px;flex-wrap:wrap;' }, [ h('div', { style: 'display:flex;align-items:center;gap:8px;flex-wrap:wrap;' }, [
h('span', { style: `font-weight:700;font-size:14px;color:${ACCENT};` }, fg.label), h('span', { style: `font-weight:700;font-size:14px;color:${ACCENT};` }, fg.label),
chip(`${fg.jobs.length} Job(s)`), chip(`${fg.jobs.length} Job(s)`),
laeuft ? chip('▶ liegt ein – wird gedruckt', 'var(--success-25,rgba(46,125,50,.15))') laeuft ? chip('▶ liegt ein – wird gedruckt', '#dff2e2')
: (aktiv ? chip('⏸ wartet (anderes Format liegt ein)') : null), : (aktiv ? chip('⏸ wartet (anderes Format liegt ein)') : null),
]), ]),
laeuft laeuft
@@ -1845,10 +1845,10 @@ const Board = defineComponent({
return h('div', { return h('div', {
onClick: (e) => { if (e.target === e.currentTarget) close(); }, onClick: (e) => { if (e.target === e.currentTarget) close(); },
style: 'position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1000;display:flex;align-items:flex-start;justify-content:center;padding:5vh 16px;overflow:auto;', style: 'position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1000;display:flex;align-items:flex-start;justify-content:center;padding:5vh 16px;overflow:auto;',
}, [h('div', { style: `background:var(--background-page,#fff);border:1px solid var(--border-subdued);border-radius:12px;width:${breite || '620px'};max-width:100%;box-shadow:0 20px 60px rgba(0,0,0,.35);` }, inhalt)]); }, [h('div', { style: `background:#ffffff;border:1px solid #d2dae6;border-radius:12px;width:${breite || '620px'};max-width:100%;box-shadow:0 20px 60px rgba(0,0,0,.35);` }, inhalt)]);
} }
function modalKopf(titel, close) { function modalKopf(titel, close) {
return h('div', { style: 'display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-subdued);' }, [ return h('div', { style: 'display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid #d2dae6;' }, [
h('div', { style: 'font-weight:700;font-size:16px;' }, titel), h('div', { style: 'font-weight:700;font-size:16px;' }, titel),
btn('✕', close), btn('✕', close),
]); ]);
@@ -1856,9 +1856,9 @@ const Board = defineComponent({
function feldGrid(sec, secKey) { function feldGrid(sec, secKey) {
return h('div', { style: 'display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:12px 0;' }, PARAM_FELDER.map(([k, lbl]) => return h('div', { style: 'display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:12px 0;' }, PARAM_FELDER.map(([k, lbl]) =>
h('div', { style: S_FELD + 'display:flex;flex-direction:column;' }, [ h('div', { style: S_FELD + 'display:flex;flex-direction:column;' }, [
h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--foreground-subdued);margin-bottom:2px;' }, lbl), h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:#566070;margin-bottom:2px;' }, lbl),
h('input', { type: 'number', step: '0.01', value: sec[k], h('input', { type: 'number', step: '0.01', value: sec[k],
style: 'border:none;background:transparent;color:var(--foreground-normal);font:inherit;font-size:15px;font-weight:600;width:100%;padding:0;outline:none;', style: 'border:none;background:transparent;color:#1b2430;font:inherit;font-size:15px;font-weight:600;width:100%;padding:0;outline:none;',
onInput: (e) => { druck[secKey][k] = parseFloat(e.target.value) || 0; } }), onInput: (e) => { druck[secKey][k] = parseFloat(e.target.value) || 0; } }),
]))); ])));
} }
@@ -1871,20 +1871,20 @@ const Board = defineComponent({
h('input', { type: 'checkbox', checked: sec.enabled, onChange: (e) => { druck[secKey].enabled = e.target.checked; }, style: 'width:16px;height:16px;' }), h('input', { type: 'checkbox', checked: sec.enabled, onChange: (e) => { druck[secKey].enabled = e.target.checked; }, style: 'width:16px;height:16px;' }),
`${ikon} ${titel}`, `${ikon} ${titel}`,
]), ]),
sec.done ? chip('✓ bereits gedruckt', 'var(--success-25,rgba(46,125,50,.15))') : null, sec.done ? chip('✓ bereits gedruckt', '#dff2e2') : null,
]), ]),
h('select', { style: S_SELECT + 'width:100%;margin-bottom:6px;', value: sec.tplId, onChange: (e) => druckTplWechsel(secKey, e.target.value) }, h('select', { style: S_SELECT + 'width:100%;margin-bottom:6px;', value: sec.tplId, onChange: (e) => druckTplWechsel(secKey, e.target.value) },
opts.map((t) => h('option', { value: t.id, selected: String(sec.tplId) === String(t.id) }, t.name))), opts.map((t) => h('option', { value: t.id, selected: String(sec.tplId) === String(t.id) }, t.name))),
feldGrid(sec, secKey), feldGrid(sec, secKey),
h('div', { style: S_FELD + 'display:flex;flex-direction:column;gap:4px;' }, [ h('div', { style: S_FELD + 'display:flex;flex-direction:column;gap:4px;' }, [
h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--foreground-subdued);' }, 'Zu druckende Nummern'), h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:#566070;' }, 'Zu druckende Nummern'),
druck.intN > 0 ? h('div', { style: 'display:flex;gap:6px;flex-wrap:wrap;margin-bottom:6px;' }, [ druck.intN > 0 ? h('div', { style: 'display:flex;gap:6px;flex-wrap:wrap;margin-bottom:6px;' }, [
btn(`Alle (${druck.deN + druck.intN})`, () => { druck[secKey].numbers = `1-${Math.max(1, druck.deN + druck.intN)}`; }), btn(`Alle (${druck.deN + druck.intN})`, () => { druck[secKey].numbers = `1-${Math.max(1, druck.deN + druck.intN)}`; }),
druck.deN > 0 ? btn(`🇩🇪 nur Deutschland (${druck.deN})`, () => { druck[secKey].numbers = druck.deNums; }) : null, druck.deN > 0 ? btn(`🇩🇪 nur Deutschland (${druck.deN})`, () => { druck[secKey].numbers = druck.deNums; }) : null,
btn(`🌍 nur Welt (${druck.intN})`, () => { druck[secKey].numbers = druck.intNums; }), btn(`🌍 nur Welt (${druck.intN})`, () => { druck[secKey].numbers = druck.intNums; }),
]) : null, ]) : null,
h('input', { value: sec.numbers, placeholder: 'z. B. 1,4,8 oder 1-9 oder 1-3,5,8', h('input', { value: sec.numbers, placeholder: 'z. B. 1,4,8 oder 1-9 oder 1-3,5,8',
style: 'border:none;background:transparent;color:var(--foreground-normal);font:inherit;font-size:14px;width:100%;padding:0;outline:none;', style: 'border:none;background:transparent;color:#1b2430;font:inherit;font-size:14px;width:100%;padding:0;outline:none;',
onInput: (e) => { druck[secKey].numbers = e.target.value; } }), onInput: (e) => { druck[secKey].numbers = e.target.value; } }),
]), ]),
]); ]);
@@ -1894,7 +1894,7 @@ const Board = defineComponent({
const busy = druck.machine != null && maschineBusy(druck.machine); const busy = druck.machine != null && maschineBusy(druck.machine);
const body = h('div', { style: 'padding:18px 20px;' }, [ const body = h('div', { style: 'padding:18px 20px;' }, [
h('div', { style: 'display:flex;flex-direction:column;gap:4px;margin-bottom:14px;' }, [ h('div', { style: 'display:flex;flex-direction:column;gap:4px;margin-bottom:14px;' }, [
h('label', { style: 'font-size:12px;color:var(--foreground-subdued);' }, 'Maschine'), h('label', { style: 'font-size:12px;color:#566070;' }, 'Maschine'),
aktiveMaschinen.value.length aktiveMaschinen.value.length
? h('select', { style: S_SELECT + 'width:100%;', value: druck.machine, onChange: (e) => { druck.machine = e.target.value; if (maschineBusy(e.target.value)) druck.mode = 'queue'; } }, ? h('select', { style: S_SELECT + 'width:100%;', value: druck.machine, onChange: (e) => { druck.machine = e.target.value; if (maschineBusy(e.target.value)) druck.mode = 'queue'; } },
aktiveMaschinen.value.map((m) => h('option', { value: m.id, selected: String(druck.machine) === String(m.id) }, `${m.name}${maschineBusy(m.id) ? ' (druckt)' : ''}`))) aktiveMaschinen.value.map((m) => h('option', { value: m.id, selected: String(druck.machine) === String(m.id) }, `${m.name}${maschineBusy(m.id) ? ' (druckt)' : ''}`)))
@@ -1917,10 +1917,10 @@ const Board = defineComponent({
], (k) => { druck.mode = k; }), ], (k) => { druck.mode = k; }),
busy ? subdued('Maschine druckt gerade → nur Warteschlange.', 'margin-top:6px;') : null, busy ? subdued('Maschine druckt gerade → nur Warteschlange.', 'margin-top:6px;') : null,
]), ]),
druck.err ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;margin-top:8px;' }, druck.err) : null, druck.err ? h('div', { style: 'color:#c0392b;font-size:13px;margin-top:8px;' }, druck.err) : null,
druck.msg ? subdued(druck.msg, 'margin-top:8px;') : null, druck.msg ? subdued(druck.msg, 'margin-top:8px;') : null,
]); ]);
const foot = h('div', { style: 'display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid var(--border-subdued);' }, [ const foot = h('div', { style: 'display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid #d2dae6;' }, [
btn('Abbrechen', () => { druck.open = false; }), btn('Abbrechen', () => { druck.open = false; }),
btn('In Produktion geben', submitDruck, 'primary'), btn('In Produktion geben', submitDruck, 'primary'),
]); ]);
@@ -1940,12 +1940,12 @@ const Board = defineComponent({
g.aktiv ? h('div', {}, [ g.aktiv ? h('div', {}, [
h('div', { style: 'display:grid;grid-template-columns:1fr 1fr;gap:10px;' }, [ h('div', { style: 'display:grid;grid-template-columns:1fr 1fr;gap:10px;' }, [
h('div', {}, [ h('div', {}, [
h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Template'), h('label', { style: 'font-size:11px;color:#566070;' }, 'Template'),
h('select', { style: S_SELECT + 'width:100%;', value: g.template, onChange: (e) => bulkTplWechsel(g, e.target.value) }, h('select', { style: S_SELECT + 'width:100%;', value: g.template, onChange: (e) => bulkTplWechsel(g, e.target.value) },
tplOpts.length ? tplOpts.map((t) => h('option', { value: t.id, selected: String(g.template) === String(t.id) }, t.name)) : [h('option', { value: '' }, 'kein Template')]), tplOpts.length ? tplOpts.map((t) => h('option', { value: t.id, selected: String(g.template) === String(t.id) }, t.name)) : [h('option', { value: '' }, 'kein Template')]),
]), ]),
h('div', {}, [ h('div', {}, [
h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Maschine'), h('label', { style: 'font-size:11px;color:#566070;' }, 'Maschine'),
h('select', { style: S_SELECT + 'width:100%;', value: g.machine, onChange: (e) => { g.machine = e.target.value; } }, h('select', { style: S_SELECT + 'width:100%;', value: g.machine, onChange: (e) => { g.machine = e.target.value; } },
aktiveMaschinen.value.length ? aktiveMaschinen.value.map((mm) => h('option', { value: mm.id, selected: String(g.machine) === String(mm.id) }, mm.name)) : [h('option', { value: '' }, 'keine Maschine')]), aktiveMaschinen.value.length ? aktiveMaschinen.value.map((mm) => h('option', { value: mm.id, selected: String(g.machine) === String(mm.id) }, mm.name)) : [h('option', { value: '' }, 'keine Maschine')]),
]), ]),
@@ -1953,7 +1953,7 @@ const Board = defineComponent({
// Maße/Position wie beim normalen Druck editierbar (übersteuert das Template). // Maße/Position wie beim normalen Druck editierbar (übersteuert das Template).
h('div', { style: 'display:grid;grid-template-columns:repeat(6,1fr);gap:8px;margin-top:10px;' }, h('div', { style: 'display:grid;grid-template-columns:repeat(6,1fr);gap:8px;margin-top:10px;' },
PARAM_FELDER.map(([k, lbl]) => h('div', {}, [ PARAM_FELDER.map(([k, lbl]) => h('div', {}, [
h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--foreground-subdued);' }, lbl), h('label', { style: 'font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:#566070;' }, lbl),
h('input', { type: 'number', step: '0.01', value: g[k], style: S_INPUT + 'width:100%;', h('input', { type: 'number', step: '0.01', value: g[k], style: S_INPUT + 'width:100%;',
onInput: (e) => { g[k] = e.target.value; } }), onInput: (e) => { g[k] = e.target.value; } }),
]))), ]))),
@@ -1969,10 +1969,10 @@ const Board = defineComponent({
{ key: 'queue', label: '⏳ Warteschlange' }, { key: 'queue', label: '⏳ Warteschlange' },
], (k) => { bulk.mode = k; }), ], (k) => { bulk.mode = k; }),
]), ]),
bulk.err ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;margin-top:8px;' }, bulk.err) : null, bulk.err ? h('div', { style: 'color:#c0392b;font-size:13px;margin-top:8px;' }, bulk.err) : null,
bulk.msg ? subdued(bulk.msg, 'margin-top:8px;') : null, bulk.msg ? subdued(bulk.msg, 'margin-top:8px;') : null,
]); ]);
const foot = h('div', { style: 'display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid var(--border-subdued);' }, [ const foot = h('div', { style: 'display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid #d2dae6;' }, [
btn('Abbrechen', () => { bulk.open = false; }), btn('Abbrechen', () => { bulk.open = false; }),
btn('In Produktion geben', submitBulk, 'primary'), btn('In Produktion geben', submitBulk, 'primary'),
]); ]);
@@ -1985,7 +1985,7 @@ const Board = defineComponent({
const body = h('div', { style: 'padding:18px 20px;display:flex;flex-direction:column;gap:12px;' }, [ const body = h('div', { style: 'padding:18px 20px;display:flex;flex-direction:column;gap:12px;' }, [
// Vorlage wählen (benannte Mustertexte + Du/Sie). Platzhalter werden gefüllt. // Vorlage wählen (benannte Mustertexte + Du/Sie). Platzhalter werden gefüllt.
h('div', { style: 'display:flex;gap:10px;align-items:center;flex-wrap:wrap;' }, [ h('div', { style: 'display:flex;gap:10px;align-items:center;flex-wrap:wrap;' }, [
h('label', { style: 'font-size:12px;color:var(--foreground-subdued);font-weight:600;' }, 'Mustertext:'), h('label', { style: 'font-size:12px;color:#566070;font-weight:600;' }, 'Mustertext:'),
h('select', { style: S_SELECT + 'flex:1;min-width:220px;', value: String(manuell.vorlageId), onChange: (e) => musterVorlage(e.target.value) }, [ h('select', { style: S_SELECT + 'flex:1;min-width:220px;', value: String(manuell.vorlageId), onChange: (e) => musterVorlage(e.target.value) }, [
...musterListe.value.map((m) => h('option', { value: String(m.id), selected: String(manuell.vorlageId) === String(m.id) }, m.label || `Text ${m.id}`)), ...musterListe.value.map((m) => h('option', { value: String(m.id), selected: String(manuell.vorlageId) === String(m.id) }, m.label || `Text ${m.id}`)),
h('option', { value: 'sie', selected: manuell.vorlageId === 'sie' }, 'Standard Sie-Form'), h('option', { value: 'sie', selected: manuell.vorlageId === 'sie' }, 'Standard Sie-Form'),
@@ -1995,7 +1995,7 @@ const Board = defineComponent({
]), ]),
h('textarea', { style: S_INPUT + 'width:100%;min-height:200px;font-family:var(--family-monospace,monospace);', value: manuell.text, onInput: (e) => { manuell.text = e.target.value; } }), h('textarea', { style: S_INPUT + 'width:100%;min-height:200px;font-family:var(--family-monospace,monospace);', value: manuell.text, onInput: (e) => { manuell.text = e.target.value; } }),
// Kuvert automatisch mit der Adresse aus der Anfrage. // Kuvert automatisch mit der Adresse aus der Anfrage.
h('div', { style: 'display:flex;gap:12px;align-items:center;flex-wrap:wrap;background:var(--background-subdued,#f1f4f9);border-radius:8px;padding:10px 12px;' }, [ h('div', { style: 'display:flex;gap:12px;align-items:center;flex-wrap:wrap;background:#eef2f8;border-radius:8px;padding:10px 12px;' }, [
h('label', { style: 'display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer;font-weight:600;' }, [ h('label', { style: 'display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer;font-weight:600;' }, [
h('input', { type: 'checkbox', checked: manuell.kuvert, onChange: (e) => { manuell.kuvert = e.target.checked; }, style: 'width:16px;height:16px;' }), h('input', { type: 'checkbox', checked: manuell.kuvert, onChange: (e) => { manuell.kuvert = e.target.checked; }, style: 'width:16px;height:16px;' }),
'✉ Adresse aufs Kuvert', '✉ Adresse aufs Kuvert',
@@ -2006,24 +2006,24 @@ const Board = defineComponent({
manuell.kuvert ? subdued('→ ' + (musterAdresse().replace(/\n/g, ', ') || 'keine Adresse')) : null, manuell.kuvert ? subdued('→ ' + (musterAdresse().replace(/\n/g, ', ') || 'keine Adresse')) : null,
]), ]),
h('div', { style: 'display:grid;grid-template-columns:repeat(4,1fr);gap:8px;' }, [ h('div', { style: 'display:grid;grid-template-columns:repeat(4,1fr);gap:8px;' }, [
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Schrift'), h('div', {}, [h('label', { style: 'font-size:11px;color:#566070;' }, 'Schrift'),
h('select', { style: S_SELECT + 'width:100%;', value: manuell.font, onChange: (e) => { manuell.font = e.target.value; } }, ['tilda', 'alva', 'ellie'].map((f) => h('option', { value: f, selected: manuell.font === f }, f)))]), h('select', { style: S_SELECT + 'width:100%;', value: manuell.font, onChange: (e) => { manuell.font = e.target.value; } }, ['tilda', 'alva', 'ellie'].map((f) => h('option', { value: f, selected: manuell.font === f }, f)))]),
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Format'), h('div', {}, [h('label', { style: 'font-size:11px;color:#566070;' }, 'Format'),
h('select', { style: S_SELECT + 'width:100%;', value: manuell.format, onChange: (e) => { manuell.format = e.target.value; } }, h('select', { style: S_SELECT + 'width:100%;', value: manuell.format, onChange: (e) => { manuell.format = e.target.value; } },
[['a4', 'A4'], ['a5p', 'A5 hoch'], ['a5l', 'A5 quer'], ['dinlang_karte', 'DIN lang'], ['a6_hoch', 'A6 hoch'], ['a6_quer', 'A6 quer']].map(([v, l]) => h('option', { value: v, selected: manuell.format === v }, l)))]), [['a4', 'A4'], ['a5p', 'A5 hoch'], ['a5l', 'A5 quer'], ['dinlang_karte', 'DIN lang'], ['a6_hoch', 'A6 hoch'], ['a6_quer', 'A6 quer']].map(([v, l]) => h('option', { value: v, selected: manuell.format === v }, l)))]),
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Template'), h('div', {}, [h('label', { style: 'font-size:11px;color:#566070;' }, 'Template'),
h('select', { style: S_SELECT + 'width:100%;', value: manuell.template, onChange: (e) => { manuell.template = e.target.value; } }, briefTpls.map((t) => h('option', { value: t.id, selected: String(manuell.template) === String(t.id) }, t.name)))]), h('select', { style: S_SELECT + 'width:100%;', value: manuell.template, onChange: (e) => { manuell.template = e.target.value; } }, briefTpls.map((t) => h('option', { value: t.id, selected: String(manuell.template) === String(t.id) }, t.name)))]),
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Maschine'), h('div', {}, [h('label', { style: 'font-size:11px;color:#566070;' }, 'Maschine'),
h('select', { style: S_SELECT + 'width:100%;', value: manuell.machine, onChange: (e) => { manuell.machine = e.target.value; } }, aktiveMaschinen.value.map((m) => h('option', { value: m.id, selected: String(manuell.machine) === String(m.id) }, m.name)))]), h('select', { style: S_SELECT + 'width:100%;', value: manuell.machine, onChange: (e) => { manuell.machine = e.target.value; } }, aktiveMaschinen.value.map((m) => h('option', { value: m.id, selected: String(manuell.machine) === String(m.id) }, m.name)))]),
]), ]),
segToggle(manuell.mode, [ segToggle(manuell.mode, [
{ key: 'direct', label: '⚡ Direktdruck' }, { key: 'direct', label: '⚡ Direktdruck' },
{ key: 'queue', label: '⏳ Warteschlange' }, { key: 'queue', label: '⏳ Warteschlange' },
], (k) => { manuell.mode = k; }), ], (k) => { manuell.mode = k; }),
manuell.err ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;' }, manuell.err) : null, manuell.err ? h('div', { style: 'color:#c0392b;font-size:13px;' }, manuell.err) : null,
manuell.msg ? subdued(manuell.msg) : null, manuell.msg ? subdued(manuell.msg) : null,
]); ]);
const foot = h('div', { style: 'display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid var(--border-subdued);' }, [ const foot = h('div', { style: 'display:flex;justify-content:flex-end;gap:8px;padding:14px 20px;border-top:1px solid #d2dae6;' }, [
btn('Abbrechen', () => { manuell.open = false; }), btn('Abbrechen', () => { manuell.open = false; }),
btn('Erzeugen & drucken', submitMuster, 'primary'), btn('Erzeugen & drucken', submitMuster, 'primary'),
]); ]);
@@ -2039,9 +2039,9 @@ const Board = defineComponent({
: h('div', { style: 'display:flex;flex-direction:column;gap:6px;max-height:62vh;overflow:auto;' }, empfTreffer.value.length : h('div', { style: 'display:flex;flex-direction:column;gap:6px;max-height:62vh;overflow:auto;' }, empfTreffer.value.length
? empfTreffer.value.map((r) => h('div', { ? empfTreffer.value.map((r) => h('div', {
onClick: istOrder ? () => previewEntry(r.nr, empf.rows.findIndex((x) => x.nr === r.nr)) : undefined, onClick: istOrder ? () => previewEntry(r.nr, empf.rows.findIndex((x) => x.nr === r.nr)) : undefined,
style: 'display:flex;gap:12px;align-items:baseline;border:1px solid var(--border-subdued);border-radius:8px;padding:12px 14px;' style: 'display:flex;gap:12px;align-items:baseline;border:1px solid #d2dae6;border-radius:8px;padding:12px 14px;'
+ `${istOrder ? 'cursor:pointer;' : ''}` + `${istOrder ? 'cursor:pointer;' : ''}`
+ (istOrder && empf.selected === r.nr ? `border-color:${ACCENT};background:rgba(30,80,165,.07);` : 'background:var(--background-page);'), + (istOrder && empf.selected === r.nr ? `border-color:${ACCENT};background:rgba(30,80,165,.07);` : 'background:#ffffff;'),
}, [ }, [
h('span', { style: `min-width:40px;font-weight:700;color:${ACCENT};font-family:var(--family-monospace,monospace);` }, `#${r.nr}`), h('span', { style: `min-width:40px;font-weight:700;color:${ACCENT};font-family:var(--family-monospace,monospace);` }, `#${r.nr}`),
h('div', { style: 'flex:1;' }, [h('div', {}, r.zeile || '—'), r.extra ? subdued(r.extra, 'margin-top:2px;') : null]), h('div', { style: 'flex:1;' }, [h('div', {}, r.zeile || '—'), r.extra ? subdued(r.extra, 'margin-top:2px;') : null]),
@@ -2053,22 +2053,22 @@ const Board = defineComponent({
// quelle: Array [{url,label}] (Schriftstück, evtl. mehrseitig) oder einzelne URL (Kuvert). // quelle: Array [{url,label}] (Schriftstück, evtl. mehrseitig) oder einzelne URL (Kuvert).
const bilder = Array.isArray(quelle) ? quelle : (quelle ? [{ url: quelle, label: '' }] : []); const bilder = Array.isArray(quelle) ? quelle : (quelle ? [{ url: quelle, label: '' }] : []);
return h('div', { style: 'display:flex;flex-direction:column;gap:6px;' }, [ return h('div', { style: 'display:flex;flex-direction:column;gap:6px;' }, [
h('div', { style: 'font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--foreground-subdued);' }, h('div', { style: 'font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:#566070;' },
titel + (bilder.length > 1 ? ` · ${bilder.length} Seiten` : '')), titel + (bilder.length > 1 ? ` · ${bilder.length} Seiten` : '')),
...(bilder.length ? bilder.map((b) => h('div', { ...(bilder.length ? bilder.map((b) => h('div', {
onClick: () => { empf.lb = b.url; empf.lbTitel = titel + (b.label ? ' · ' + b.label : ''); }, onClick: () => { empf.lb = b.url; empf.lbTitel = titel + (b.label ? ' · ' + b.label : ''); },
style: 'position:relative;border:1px solid var(--border-subdued);border-radius:8px;background:#fff;display:flex;align-items:center;justify-content:center;min-height:150px;padding:8px;cursor:zoom-in;', style: 'position:relative;border:1px solid #d2dae6;border-radius:8px;background:#fff;display:flex;align-items:center;justify-content:center;min-height:150px;padding:8px;cursor:zoom-in;',
}, [ }, [
b.label ? h('div', { style: 'position:absolute;top:4px;left:6px;font-size:10px;color:var(--foreground-subdued);background:var(--background-page);padding:0 4px;border-radius:4px;' }, b.label) : null, b.label ? h('div', { style: 'position:absolute;top:4px;left:6px;font-size:10px;color:#566070;background:#ffffff;padding:0 4px;border-radius:4px;' }, b.label) : null,
h('img', { src: b.url, style: 'max-width:100%;max-height:30vh;object-fit:contain;' }), h('img', { src: b.url, style: 'max-width:100%;max-height:30vh;object-fit:contain;' }),
])) : [h('div', { style: 'border:1px solid var(--border-subdued);border-radius:8px;background:#fff;display:flex;align-items:center;justify-content:center;min-height:150px;padding:8px;' }, subdued('—'))]), ])) : [h('div', { style: 'border:1px solid #d2dae6;border-radius:8px;background:#fff;display:flex;align-items:center;justify-content:center;min-height:150px;padding:8px;' }, subdued('—'))]),
]); ]);
}; };
const vorschau = istOrder ? h('div', { style: 'flex:0 0 30%;min-width:220px;display:flex;flex-direction:column;gap:14px;' }, const vorschau = istOrder ? h('div', { style: 'flex:0 0 30%;min-width:220px;display:flex;flex-direction:column;gap:14px;' },
empf.selected == null ? [subdued('Empfänger anklicken → Vorschau (Klick aufs Bild = groß).')] empf.selected == null ? [subdued('Empfänger anklicken → Vorschau (Klick aufs Bild = groß).')]
: empf.pLoad ? [subdued('Vorschau wird geladen …')] : empf.pLoad ? [subdued('Vorschau wird geladen …')]
: [ : [
empf.perr ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;' }, empf.perr) : null, empf.perr ? h('div', { style: 'color:#c0392b;font-size:13px;' }, empf.perr) : null,
vorschauBox('📄 Schriftstück', empf.pl), vorschauBox('📄 Schriftstück', empf.pl),
vorschauBox('✉ Kuvert', empf.pe), vorschauBox('✉ Kuvert', empf.pe),
]) : null; ]) : null;
@@ -2094,8 +2094,8 @@ const Board = defineComponent({
const istPdf = (dateien.pvType || '').includes('pdf'); const istPdf = (dateien.pvType || '').includes('pdf');
const istBild = (dateien.pvType || '').startsWith('image/'); const istBild = (dateien.pvType || '').startsWith('image/');
const vorschauArea = dateien.pvLaden ? subdued('Vorschau wird geladen …', 'margin-top:12px;') const vorschauArea = dateien.pvLaden ? subdued('Vorschau wird geladen …', 'margin-top:12px;')
: dateien.pvErr ? h('div', { style: 'color:var(--danger,#c62828);font-size:13px;margin-top:12px;' }, dateien.pvErr) : dateien.pvErr ? h('div', { style: 'color:#c0392b;font-size:13px;margin-top:12px;' }, dateien.pvErr)
: dateien.pvUrl ? h('div', { style: 'margin-top:14px;border:1px solid var(--border-subdued);border-radius:8px;overflow:hidden;background:#fff;' }, [ : dateien.pvUrl ? h('div', { style: 'margin-top:14px;border:1px solid #d2dae6;border-radius:8px;overflow:hidden;background:#fff;' }, [
istPdf ? h('iframe', { src: dateien.pvUrl, style: 'width:100%;height:70vh;border:none;display:block;' }) istPdf ? h('iframe', { src: dateien.pvUrl, style: 'width:100%;height:70vh;border:none;display:block;' })
: istBild ? h('img', { src: dateien.pvUrl, style: 'display:block;max-width:100%;max-height:70vh;margin:0 auto;' }) : istBild ? h('img', { src: dateien.pvUrl, style: 'display:block;max-width:100%;max-height:70vh;margin:0 auto;' })
: h('div', { style: 'padding:16px;display:flex;flex-direction:column;gap:10px;align-items:flex-start;' }, [ : h('div', { style: 'padding:16px;display:flex;flex-direction:column;gap:10px;align-items:flex-start;' }, [
@@ -2133,11 +2133,11 @@ const Board = defineComponent({
type: 'button', onClick: () => { if (tab.value === 'suche' && t.key !== 'suche') { clearTimeout(sucheTimer); sucheText.value = ''; } tab.value = t.key; }, type: 'button', onClick: () => { if (tab.value === 'suche' && t.key !== 'suche') { clearTimeout(sucheTimer); sucheText.value = ''; } tab.value = t.key; },
style: 'display:flex;justify-content:space-between;align-items:center;gap:10px;width:100%;text-align:left;' style: 'display:flex;justify-content:space-between;align-items:center;gap:10px;width:100%;text-align:left;'
+ 'cursor:pointer;border:none;border-radius:8px;padding:11px 13px;margin-bottom:3px;font:inherit;font-size:14px;' + 'cursor:pointer;border:none;border-radius:8px;padding:11px 13px;margin-bottom:3px;font:inherit;font-size:14px;'
+ (aktiv ? `background:${ACCENT};color:#fff;font-weight:500;` : 'background:transparent;color:var(--foreground-normal);'), + (aktiv ? `background:${ACCENT};color:#fff;font-weight:500;` : 'background:transparent;color:#1b2430;'),
}, [ }, [
h('span', { style: 'display:inline-flex;align-items:center;gap:9px;min-width:0;' }, [icon(t.icon), h('span', {}, t.label)]), h('span', { style: 'display:inline-flex;align-items:center;gap:9px;min-width:0;' }, [icon(t.icon), h('span', {}, t.label)]),
h('span', { style: 'font-size:12px;font-weight:500;min-width:20px;text-align:center;border-radius:999px;padding:1px 8px;' h('span', { style: 'font-size:12px;font-weight:500;min-width:20px;text-align:center;border-radius:999px;padding:1px 8px;'
+ (aktiv ? 'background:rgba(255,255,255,.22);color:#fff;' : 'background:var(--background-subdued);color:var(--foreground-subdued);') }, String(tabCount(t.key))), + (aktiv ? 'background:rgba(255,255,255,.22);color:#fff;' : 'background:#eef2f8;color:#566070;') }, String(tabCount(t.key))),
]); ]);
})); }));
@@ -2168,11 +2168,11 @@ const Board = defineComponent({
h('button', { type: 'button', onClick: auswahlLeeren, style: 'cursor:pointer;border:1px solid rgba(255,255,255,.6);background:transparent;color:#fff;border-radius:7px;padding:6px 14px;font:inherit;font-size:13px;' }, 'Auswahl aufheben'), h('button', { type: 'button', onClick: auswahlLeeren, style: 'cursor:pointer;border:1px solid rgba(255,255,255,.6);background:transparent;color:#fff;border-radius:7px;padding:6px 14px;font:inherit;font-size:13px;' }, 'Auswahl aufheben'),
]) : null; ]) : null;
const inhalt = h('div', { style: 'padding:24px 28px;min-height:100%;background:var(--background-subdued,#f1f4f9);' }, [ const inhalt = h('div', { style: 'padding:24px 28px;min-height:100%;background:#eef2f8;' }, [
kopfzeile, kopfzeile,
bulkBar, bulkBar,
meldung.value ? h('div', { style: 'background:var(--success-25,rgba(46,125,50,.15));color:var(--success,#2e7d32);padding:9px 14px;border-radius:8px;margin-bottom:12px;font-size:13px;' }, meldung.value) : null, meldung.value ? h('div', { style: 'background:#dff2e2;color:#1b6b2e;padding:9px 14px;border-radius:8px;margin-bottom:12px;font-size:13px;' }, meldung.value) : null,
fehler.value ? h('div', { style: 'background:var(--danger-25,rgba(198,40,40,.12));color:var(--danger,#c62828);padding:9px 14px;border-radius:8px;margin-bottom:12px;font-size:13px;' }, fehler.value) : null, fehler.value ? h('div', { style: 'background:#fbe3e0;color:#c0392b;padding:9px 14px;border-radius:8px;margin-bottom:12px;font-size:13px;' }, fehler.value) : null,
loading.value ? subdued('Lädt …') : h('div', { style: 'display:flex;flex-direction:column;gap:2px;' }, tabInhalt()), loading.value ? subdued('Lädt …') : h('div', { style: 'display:flex;flex-direction:column;gap:2px;' }, tabInhalt()),
]); ]);

View File

@@ -19,12 +19,12 @@ const STATUS_LABEL = {
versandfertig: 'Versandfertig', versendet: 'Versendet', storniert: 'Storniert', versandfertig: 'Versandfertig', versendet: 'Versendet', storniert: 'Storniert',
}; };
const STATUS_META = { const STATUS_META = {
eingegangen: { bg: 'var(--background-subdued,#eef1f6)', fg: 'var(--foreground-subdued)', icon: 'inbox' }, eingegangen: { bg: '#eef2f8', fg: '#566070', bd: '#d2dae6', icon: 'inbox' },
im_druck: { bg: 'rgba(30,80,165,.12)', fg: '#1E50A5', icon: 'print' }, im_druck: { bg: '#e3ecfa', fg: '#1E50A5', bd: '#bcd0ef', icon: 'print' },
kuvertieren: { bg: 'rgba(106,63,208,.12)', fg: '#6a3fd0', icon: 'mail' }, kuvertieren: { bg: '#ece4fb', fg: '#5b32b8', bd: '#d3c4f2', icon: 'mail' },
versandfertig: { bg: 'rgba(230,160,0,.16)', fg: '#8a6d00', icon: 'inventory_2' }, versandfertig: { bg: '#fbeccb', fg: '#8a5a00', bd: '#f0d79a', icon: 'inventory_2' },
versendet: { bg: 'rgba(46,125,50,.14)', fg: 'var(--success,#2e7d32)', icon: 'local_shipping' }, versendet: { bg: '#e3f4e6', fg: '#1b6b2e', bd: '#bfe2c6', icon: 'local_shipping' },
storniert: { bg: 'rgba(198,40,40,.12)', fg: 'var(--danger,#c62828)', icon: 'cancel' }, storniert: { bg: '#fbe3e0', fg: '#c0392b', bd: '#f3c6bf', icon: 'cancel' },
}; };
const AKTIV_STATUS = ['im_druck', 'kuvertieren', 'versandfertig']; const AKTIV_STATUS = ['im_druck', 'kuvertieren', 'versandfertig'];
const FORMAT_LABEL = { a4: 'A4', a5p: 'A5 hoch', a5l: 'A5 quer', dinlang_karte: 'DIN lang', a6_hoch: 'A6 hoch', a6_quer: 'A6 quer', dinlang: 'DIN Lang', c6: 'C6', c4: 'C4' }; const FORMAT_LABEL = { a4: 'A4', a5p: 'A5 hoch', a5l: 'A5 quer', dinlang_karte: 'DIN lang', a6_hoch: 'A6 hoch', a6_quer: 'A6 quer', dinlang: 'DIN Lang', c6: 'C6', c4: 'C4' };
@@ -112,7 +112,7 @@ const Board = {
const ent = await api.get('/items/order_entries', { params: { const ent = await api.get('/items/order_entries', { params: {
limit: -1, sort: ['order', 'letter_number'], limit: -1, sort: ['order', 'letter_number'],
filter: { order: { production_status: { _in: AKTIV_STATUS } } }, filter: { order: { production_status: { _in: AKTIV_STATUS } } },
fields: 'order,letter_number,first_name,last_name,company,city,free_text', fields: 'order,letter_number,first_name,last_name,city,free_text',
} }); } });
const idx = {}; const idx = {};
for (const e of (ent.data?.data || [])) { for (const e of (ent.data?.data || [])) {
@@ -131,7 +131,7 @@ const Board = {
const ent = await api.get('/items/order_entries', { params: { const ent = await api.get('/items/order_entries', { params: {
limit: -1, sort: ['order', 'letter_number'], limit: -1, sort: ['order', 'letter_number'],
filter: { order: { production_status: { _in: AKTIV_STATUS } } }, filter: { order: { production_status: { _in: AKTIV_STATUS } } },
fields: 'order,letter_number,salutation,first_name,last_name,company,street,house_no,zip,city,country,free_text', fields: 'order,letter_number,salutation,first_name,last_name,street,house_no,zip,city,country,free_text',
} }); } });
const flach = []; const cnt = {}; const flach = []; const cnt = {};
for (const e of (ent.data?.data || [])) { for (const e of (ent.data?.data || [])) {
@@ -234,32 +234,32 @@ const Board = {
// ── Render-Helfer ───────────────────────────────────────────────────────── // ── Render-Helfer ─────────────────────────────────────────────────────────
const statusPillCtrl = (k0, onCh) => { const statusPillCtrl = (k0, onCh) => {
const k = k0 || 'eingegangen'; const m = STATUS_META[k] || STATUS_META.eingegangen; const k = k0 || 'eingegangen'; const m = STATUS_META[k] || STATUS_META.eingegangen;
return h('div', { style: `display:inline-flex;align-items:center;gap:5px;border-radius:8px;padding:5px 8px 5px 10px;background:${m.bg};color:${m.fg};font-weight:500;font-size:13px;` }, [ return h('div', { style: `display:inline-flex;align-items:center;gap:5px;border-radius:8px;padding:5px 8px 5px 10px;background:${m.bg};color:${m.fg};border:1px solid ${m.bd || '#d2dae6'};font-weight:600;font-size:13px;` }, [
icon(m.icon), icon(m.icon),
h('select', { style: `border:none;background:transparent;color:${m.fg};font:inherit;font-size:13px;font-weight:500;cursor:pointer;`, value: k, onChange: (e) => onCh(e.target.value) }, h('select', { style: `border:none;background:transparent;color:${m.fg};font:inherit;font-size:13px;font-weight:500;cursor:pointer;`, value: k, onChange: (e) => onCh(e.target.value) },
Object.entries(STATUS_LABEL).map(([kk, v]) => h('option', { value: kk, selected: k === kk }, v))), Object.entries(STATUS_LABEL).map(([kk, v]) => h('option', { value: kk, selected: k === kk }, v))),
]); ]);
}; };
const statusPill = (o) => statusPillCtrl(o.production_status, (v) => setStatus(o, v)); const statusPill = (o) => statusPillCtrl(o.production_status, (v) => setStatus(o, v));
const druckBadge = (ok, text) => h('span', { style: `display:inline-flex;align-items:center;gap:4px;font-size:12.5px;font-weight:500;padding:2px 8px;border-radius:999px;background:${ok ? 'rgba(46,125,50,.14)' : 'rgba(198,40,40,.12)'};color:${ok ? 'var(--success,#2e7d32)' : 'var(--danger,#c62828)'};` }, [icon(ok ? 'check' : 'close'), text]); const druckBadge = (ok, text) => h('span', { style: `display:inline-flex;align-items:center;gap:4px;font-size:12.5px;font-weight:500;padding:2px 8px;border-radius:999px;background:${ok ? 'rgba(46,125,50,.14)' : 'rgba(198,40,40,.12)'};color:${ok ? '#1b6b2e' : '#c0392b'};` }, [icon(ok ? 'check' : 'close'), text]);
const th = (t, extra) => h('th', { style: `text-align:left;font-size:12px;font-weight:500;color:var(--foreground-subdued);text-transform:uppercase;letter-spacing:.03em;padding:10px 12px;border-bottom:1px solid var(--border-normal);white-space:nowrap;${extra || ''}` }, t); const th = (t, extra) => h('th', { style: `text-align:left;font-size:12px;font-weight:500;color:#566070;text-transform:uppercase;letter-spacing:.03em;padding:10px 12px;border-bottom:1px solid #b4c0d2;white-space:nowrap;${extra || ''}` }, t);
const td = (kids, extra) => h('td', { style: `padding:11px 12px;border-bottom:1px solid var(--border-subdued);font-size:14px;vertical-align:top;${extra || ''}` }, kids); const td = (kids, extra) => h('td', { style: `padding:11px 12px;border-bottom:1px solid #d2dae6;font-size:14px;vertical-align:top;${extra || ''}` }, kids);
function aufgabe(o) { function aufgabe(o) {
const einzeln = o.shipping_type === 'einzeln'; const einzeln = o.shipping_type === 'einzeln';
switch (o.production_status) { switch (o.production_status) {
case 'eingegangen': return { t: 'Wartet auf Druck', c: 'var(--foreground-subdued)', i: 'hourglass_empty' }; case 'eingegangen': return { t: 'Wartet auf Druck', c: '#566070', i: 'hourglass_empty' };
case 'im_druck': return { t: 'Im Druck', c: '#1E50A5', i: 'print' }; case 'im_druck': return { t: 'Im Druck', c: '#1E50A5', i: 'print' };
case 'kuvertieren': return { t: (o.needs_envelope ? 'Kuvertieren' : 'Vorbereiten') + ' + frankieren', c: '#6a3fd0', i: 'mail' }; case 'kuvertieren': return { t: (o.needs_envelope ? 'Kuvertieren' : 'Vorbereiten') + ' + frankieren', c: '#6a3fd0', i: 'mail' };
case 'versandfertig': return { t: einzeln ? 'Einzelversand' : 'Sammelversand', c: '#8a6d00', i: 'local_shipping' }; case 'versandfertig': return { t: einzeln ? 'Einzelversand' : 'Sammelversand', c: '#8a6d00', i: 'local_shipping' };
default: return { t: STATUS_LABEL[o.production_status] || '', c: 'var(--foreground-subdued)', i: 'info' }; default: return { t: STATUS_LABEL[o.production_status] || '', c: '#566070', i: 'info' };
} }
} }
// Nur-Lese-Anzeige für Mitarbeiter: Versandart darf hier nicht geändert werden. // Nur-Lese-Anzeige für Mitarbeiter: Versandart darf hier nicht geändert werden.
function versandToggle(o) { function versandToggle(o) {
const einzeln = o.shipping_type === 'einzeln'; const einzeln = o.shipping_type === 'einzeln';
return h('span', { title: 'Versandart (nur Ansicht)', return h('span', { title: 'Versandart (nur Ansicht)',
style: 'border:1px solid var(--border-subdued);background:var(--background-subdued,#f2f4f8);border-radius:999px;padding:4px 11px;font-size:12.5px;font-weight:500;display:inline-flex;align-items:center;gap:5px;color:var(--foreground-normal);' }, style: 'border:1px solid #d2dae6;background:#eef2f8;border-radius:999px;padding:4px 11px;font-size:12.5px;font-weight:500;display:inline-flex;align-items:center;gap:5px;color:#1b2430;' },
[icon(einzeln ? 'person' : 'groups'), einzeln ? 'Einzeln' : 'Sammel']); [icon(einzeln ? 'person' : 'groups'), einzeln ? 'Einzeln' : 'Sammel']);
} }
// Nur-Lese-Anzeige für Mitarbeiter: Versanddatum darf hier nicht geändert werden. // Nur-Lese-Anzeige für Mitarbeiter: Versanddatum darf hier nicht geändert werden.
@@ -267,16 +267,16 @@ const Board = {
const faellig = o.versanddatum && o.versanddatum <= new Date().toISOString().slice(0, 10); const faellig = o.versanddatum && o.versanddatum <= new Date().toISOString().slice(0, 10);
const txt = o.versanddatum ? o.versanddatum : 'schnellstmöglich'; const txt = o.versanddatum ? o.versanddatum : 'schnellstmöglich';
return h('span', { title: 'Versanddatum (nur Ansicht)', return h('span', { title: 'Versanddatum (nur Ansicht)',
style: 'display:inline-flex;align-items:center;gap:5px;font-size:13px;color:' + (faellig ? 'var(--danger,#c62828)' : 'var(--foreground-normal)') + ';font-weight:' + (faellig ? '600' : '400') + ';' }, style: 'display:inline-flex;align-items:center;gap:5px;font-size:13px;color:' + (faellig ? '#c0392b' : '#1b2430') + ';font-weight:' + (faellig ? '600' : '400') + ';' },
[icon('event'), txt]); [icon('event'), txt]);
} }
// Ein Ablauf-Schritt: nicht nötig (✗, grau) · erledigt (✓, grün) · offen (amber). // Ein Ablauf-Schritt: nicht nötig (✗, grau) · erledigt (✓, grün) · offen (amber).
function stepPill(labelTxt, benoetigt, erledigt) { function stepPill(labelTxt, benoetigt, erledigt) {
let bg, fg, ic, zustand; let bg, fg, bd, ic, zustand;
if (!benoetigt) { bg = 'var(--background-subdued,#eef1f6)'; fg = 'var(--foreground-subdued)'; ic = 'close'; zustand = 'nicht nötig'; } if (!benoetigt) { bg = '#eef2f8'; fg = '#566070'; bd = '#d2dae6'; ic = 'close'; zustand = 'nicht nötig'; }
else if (erledigt) { bg = 'rgba(46,125,50,.14)'; fg = 'var(--success,#2e7d32)'; ic = 'check'; zustand = 'erledigt'; } else if (erledigt) { bg = '#e3f4e6'; fg = '#1b6b2e'; bd = '#bfe2c6'; ic = 'check'; zustand = 'erledigt'; }
else { bg = 'rgba(230,160,0,.2)'; fg = '#8a6d00'; ic = 'radio_button_unchecked'; zustand = 'offen'; } else { bg = '#fbeccb'; fg = '#8a5a00'; bd = '#f0d79a'; ic = 'radio_button_unchecked'; zustand = 'offen'; }
return h('span', { title: `${labelTxt}: ${zustand}`, style: `display:inline-flex;align-items:center;gap:4px;font-size:11.5px;font-weight:500;padding:3px 8px;border-radius:999px;background:${bg};color:${fg};white-space:nowrap;` }, [icon(ic), labelTxt]); return h('span', { title: `${labelTxt}: ${zustand}`, style: `display:inline-flex;align-items:center;gap:4px;font-size:12px;font-weight:600;padding:3px 9px;border-radius:999px;background:${bg};color:${fg};border:1px solid ${bd};white-space:nowrap;` }, [icon(ic), labelTxt]);
} }
function ablaufStrip(o) { function ablaufStrip(o) {
const fertig = ['versandfertig', 'versendet'].includes(o.production_status); const fertig = ['versandfertig', 'versendet'].includes(o.production_status);
@@ -294,14 +294,14 @@ const Board = {
function zeile(o, indent) { function zeile(o, indent) {
const e = entriesByOrder.value[String(o.id)]; const e = entriesByOrder.value[String(o.id)];
return h('tr', { key: 'o' + o.id }, [ return h('tr', { key: 'o' + o.id }, [
td(h('div', { style: `line-height:1.45;${indent ? 'padding-left:18px;border-left:2px solid var(--border-subdued);' : ''}` }, [ td(h('div', { style: `line-height:1.45;${indent ? 'padding-left:18px;border-left:2px solid #d2dae6;' : ''}` }, [
h('div', { style: 'font-weight:500;' }, empfKurz(e?.erster) || '—'), h('div', { style: 'font-weight:500;' }, empfKurz(e?.erster) || '—'),
(e && e.anzahl > 1) ? h('div', { style: 'font-size:12.5px;color:var(--foreground-subdued);' }, '… ' + empfKurz(e.letzter)) : null, (e && e.anzahl > 1) ? h('div', { style: 'font-size:12.5px;color:#566070;' }, '… ' + empfKurz(e.letzter)) : null,
])), ])),
td(h('div', { style: 'line-height:1.4;font-size:13px;' }, [ td(h('div', { style: 'line-height:1.4;font-size:13px;' }, [
o.order_name ? h('div', { style: 'font-weight:500;color:#1E50A5;' }, o.order_name) : null, o.order_name ? h('div', { style: 'font-weight:500;color:#1E50A5;' }, o.order_name) : null,
h('div', {}, kundeName(o) || `#${o.order_number}`), h('div', {}, kundeName(o) || `#${o.order_number}`),
h('div', { style: 'color:var(--foreground-subdued);' }, `#${o.order_number} · ${o.entries_count || 0} Empf.`), h('div', { style: 'color:#566070;' }, `#${o.order_number} · ${o.entries_count || 0} Empf.`),
])), ])),
td(h('span', {}, o.format?.name || FORMAT_LABEL[o.format?.key] || o.format?.key || '—')), td(h('span', {}, o.format?.name || FORMAT_LABEL[o.format?.key] || o.format?.key || '—')),
td(ablaufStrip(o)), td(ablaufStrip(o)),
@@ -344,17 +344,17 @@ const Board = {
return h('tr', { key: 'c' + c.key }, [ return h('tr', { key: 'c' + c.key }, [
td(h('div', { style: 'line-height:1.45;' }, [ td(h('div', { style: 'line-height:1.45;' }, [
h('div', { style: 'font-weight:500;' }, empfKurz(first?.erster) || '—'), h('div', { style: 'font-weight:500;' }, empfKurz(first?.erster) || '—'),
sumEmpf > 1 ? h('div', { style: 'font-size:12.5px;color:var(--foreground-subdued);' }, '… ' + (empfKurz(last?.letzter) || '—')) : null, sumEmpf > 1 ? h('div', { style: 'font-size:12.5px;color:#566070;' }, '… ' + (empfKurz(last?.letzter) || '—')) : null,
])), ])),
td(h('div', { style: 'line-height:1.4;font-size:13px;' }, [ td(h('div', { style: 'line-height:1.4;font-size:13px;' }, [
h('div', { style: 'font-weight:500;display:inline-flex;align-items:center;gap:6px;cursor:pointer;', title: auf ? 'Zuklappen' : 'Teil-Aufträge zeigen', onClick: () => { expandedCharges[c.key] = !auf; } }, h('div', { style: 'font-weight:500;display:inline-flex;align-items:center;gap:6px;cursor:pointer;', title: auf ? 'Zuklappen' : 'Teil-Aufträge zeigen', onClick: () => { expandedCharges[c.key] = !auf; } },
[icon(auf ? 'expand_more' : 'chevron_right'), icon('inbox'), c.kundeName]), [icon(auf ? 'expand_more' : 'chevron_right'), icon('inbox'), c.kundeName]),
h('div', { style: 'color:var(--foreground-subdued);' }, `${c.produkt} · ${c.orders.length} Aufträge · ${sumEmpf} Empf.`), h('div', { style: 'color:#566070;' }, `${c.produkt} · ${c.orders.length} Aufträge · ${sumEmpf} Empf.`),
])), ])),
td(h('span', {}, fmts.join(', ') || '—')), td(h('span', {}, fmts.join(', ') || '—')),
td(ablaufStripAgg(c.orders)), td(ablaufStripAgg(c.orders)),
td(h('span', { title: 'Versandart (nur Ansicht)', style: 'border:1px solid var(--border-subdued);background:var(--background-subdued,#f2f4f8);border-radius:999px;padding:4px 11px;font-size:12.5px;font-weight:500;display:inline-flex;align-items:center;gap:5px;color:var(--foreground-normal);' }, [icon(vIc), vTxt])), td(h('span', { title: 'Versandart (nur Ansicht)', style: 'border:1px solid #d2dae6;background:#eef2f8;border-radius:999px;padding:4px 11px;font-size:12.5px;font-weight:500;display:inline-flex;align-items:center;gap:5px;color:#1b2430;' }, [icon(vIc), vTxt])),
td(h('span', { title: 'Versanddatum (nur Ansicht)', style: 'display:inline-flex;align-items:center;gap:5px;font-size:13px;color:' + (dFaellig ? 'var(--danger,#c62828)' : 'var(--foreground-normal)') + ';font-weight:' + (dFaellig ? '600' : '400') + ';' }, [icon('event'), dTxt])), td(h('span', { title: 'Versanddatum (nur Ansicht)', style: 'display:inline-flex;align-items:center;gap:5px;font-size:13px;color:' + (dFaellig ? '#c0392b' : '#1b2430') + ';font-weight:' + (dFaellig ? '600' : '400') + ';' }, [icon('event'), dTxt])),
td(statusPillCtrl(stat, (v) => setChargeStatus(c, v))), td(statusPillCtrl(stat, (v) => setChargeStatus(c, v))),
]); ]);
} }
@@ -369,30 +369,30 @@ const Board = {
return rows; return rows;
} }
const kopfRow = () => h('thead', {}, h('tr', {}, [th('Empfänger (erster · letzter)'), th('Auftrag'), th('Format'), th('Ablauf'), th('Versand'), th('Versanddatum'), th('Status')])); const kopfRow = () => h('thead', {}, h('tr', {}, [th('Empfänger (erster · letzter)'), th('Auftrag'), th('Format'), th('Ablauf'), th('Versand'), th('Versanddatum'), th('Status')]));
const tabelle = (list) => h('div', { style: 'border:1px solid var(--border-normal);border-radius:12px;overflow:auto;background:var(--background-page,#fff);' }, const tabelle = (list) => h('div', { style: 'border:1px solid #b4c0d2;border-radius:12px;overflow:auto;background:#ffffff;' },
[h('table', { style: 'width:100%;border-collapse:collapse;' }, [kopfRow(), h('tbody', {}, gruppenZeilen(list))])]); [h('table', { style: 'width:100%;border-collapse:collapse;' }, [kopfRow(), h('tbody', {}, gruppenZeilen(list))])]);
const sektionKopf = (label, m, n) => h('div', { style: 'display:flex;align-items:center;gap:10px;margin-bottom:10px;' }, [ const sektionKopf = (label, m, n) => h('div', { style: 'display:flex;align-items:center;gap:10px;margin-bottom:10px;' }, [
h('span', { style: `display:inline-flex;align-items:center;gap:6px;font-size:16px;font-weight:500;color:${m.fg};` }, [icon(m.icon), label]), h('span', { style: `display:inline-flex;align-items:center;gap:6px;font-size:16px;font-weight:500;color:${m.fg};` }, [icon(m.icon), label]),
h('span', { style: 'font-size:13px;color:var(--foreground-subdued);' }, `${n} Auftrag/Aufträge`), h('span', { style: 'font-size:13px;color:#566070;' }, `${n} Auftrag/Aufträge`),
]); ]);
function maschinenPanel() { function maschinenPanel() {
const qf = queuedByFormat.value; const formate = Object.keys(qf); const qf = queuedByFormat.value; const formate = Object.keys(qf);
return h('div', { style: 'border:1px solid var(--border-normal);border-radius:12px;background:var(--background-page,#fff);margin-bottom:18px;overflow:hidden;' }, [ return h('div', { style: 'border:1px solid #b4c0d2;border-radius:12px;background:#ffffff;margin-bottom:18px;overflow:hidden;' }, [
h('div', { style: 'display:flex;align-items:center;gap:6px;font-size:13px;font-weight:500;color:var(--foreground-subdued);padding:10px 14px;border-bottom:1px solid var(--border-subdued);background:var(--background-subdued,#f6f8fb);' }, [icon('print'), 'Maschinen · Format einlegen und starten']), h('div', { style: 'display:flex;align-items:center;gap:6px;font-size:13px;font-weight:500;color:#566070;padding:10px 14px;border-bottom:1px solid #d2dae6;background:#eef2f8;' }, [icon('print'), 'Maschinen · Format einlegen und starten']),
h('div', { style: 'padding:14px;display:flex;flex-direction:column;gap:14px;' }, h('div', { style: 'padding:14px;display:flex;flex-direction:column;gap:14px;' },
aktiveMaschinen.value.length ? aktiveMaschinen.value.map((m) => h('div', { key: 'm' + m.id, style: 'display:flex;align-items:center;gap:12px;flex-wrap:wrap;' }, [ aktiveMaschinen.value.length ? aktiveMaschinen.value.map((m) => h('div', { key: 'm' + m.id, style: 'display:flex;align-items:center;gap:12px;flex-wrap:wrap;' }, [
h('div', { style: 'font-weight:500;min-width:150px;' }, [m.name, h('span', { style: 'color:var(--foreground-subdued);font-weight:400;font-size:13px;' }, m.current_format ? ` · eingelegt: ${FORMAT_LABEL[m.current_format] || m.current_format}` : ' · kein Format eingelegt')]), h('div', { style: 'font-weight:500;min-width:150px;' }, [m.name, h('span', { style: 'color:#566070;font-weight:400;font-size:13px;' }, m.current_format ? ` · eingelegt: ${FORMAT_LABEL[m.current_format] || m.current_format}` : ' · kein Format eingelegt')]),
...(formate.length ? formate.map((f) => h('button', { type: 'button', onClick: () => formatStarten(m, f), ...(formate.length ? formate.map((f) => h('button', { type: 'button', onClick: () => formatStarten(m, f),
style: `cursor:pointer;border-radius:8px;padding:8px 14px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;gap:6px;border:1px solid;${m.current_format === f ? 'border-color:#1E50A5;background:#1E50A5;color:#fff;' : 'border-color:var(--border-normal);background:var(--background-page,#fff);color:var(--foreground-normal);'}`, style: `cursor:pointer;border-radius:8px;padding:8px 14px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;gap:6px;border:1px solid;${m.current_format === f ? 'border-color:#1E50A5;background:#1E50A5;color:#fff;' : 'border-color:#b4c0d2;background:#ffffff;color:#1b2430;'}`,
}, [icon('play_arrow'), `${qf[f].label} (${qf[f].n})`])) }, [icon('play_arrow'), `${qf[f].label} (${qf[f].n})`]))
: [h('span', { style: 'color:var(--foreground-subdued);font-size:13px;' }, 'Keine Jobs in der Warteschlange.')]), : [h('span', { style: 'color:#566070;font-size:13px;' }, 'Keine Jobs in der Warteschlange.')]),
])) : [h('span', { style: 'color:var(--foreground-subdued);font-size:13px;' }, 'Keine aktive Maschine.')]), ])) : [h('span', { style: 'color:#566070;font-size:13px;' }, 'Keine aktive Maschine.')]),
]); ]);
} }
function uebersichtInhalt() { function uebersichtInhalt() {
if (loading.value) return h('div', { style: 'color:var(--foreground-subdued);' }, 'Lädt …'); if (loading.value) return h('div', { style: 'color:#566070;' }, 'Lädt …');
const GRUPPEN = [['im_druck', 'Im Druck'], ['kuvertieren', 'Kuvertierung']]; const GRUPPEN = [['im_druck', 'Im Druck'], ['kuvertieren', 'Kuvertierung']];
const sek = []; const sek = [];
for (const [st, label] of GRUPPEN) { for (const [st, label] of GRUPPEN) {
@@ -407,11 +407,11 @@ const Board = {
const mit = vf.filter((o) => o.versanddatum).sort((a, b) => String(a.versanddatum).localeCompare(String(b.versanddatum))); const mit = vf.filter((o) => o.versanddatum).sort((a, b) => String(a.versanddatum).localeCompare(String(b.versanddatum)));
sek.push(h('div', { key: 'secvf', style: 'margin-bottom:22px;' }, [ sek.push(h('div', { key: 'secvf', style: 'margin-bottom:22px;' }, [
sektionKopf('Versandfertig', STATUS_META.versandfertig, vf.length), sektionKopf('Versandfertig', STATUS_META.versandfertig, vf.length),
ohne.length ? h('div', { style: 'margin-bottom:12px;' }, [h('div', { style: 'font-size:13px;font-weight:500;color:var(--foreground-subdued);margin-bottom:6px;' }, 'Schnellstmöglich (' + ohne.length + ')'), tabelle(ohne)]) : null, ohne.length ? h('div', { style: 'margin-bottom:12px;' }, [h('div', { style: 'font-size:13px;font-weight:500;color:#566070;margin-bottom:6px;' }, 'Schnellstmöglich (' + ohne.length + ')'), tabelle(ohne)]) : null,
mit.length ? h('div', {}, [h('div', { style: 'font-size:13px;font-weight:500;color:var(--foreground-subdued);margin-bottom:6px;' }, 'Mit Versanddatum (' + mit.length + ')'), tabelle(mit)]) : null, mit.length ? h('div', {}, [h('div', { style: 'font-size:13px;font-weight:500;color:#566070;margin-bottom:6px;' }, 'Mit Versanddatum (' + mit.length + ')'), tabelle(mit)]) : null,
].filter(Boolean))); ].filter(Boolean)));
} }
return sek.length ? h('div', {}, [maschinenPanel(), ...sek]) : h('div', {}, [maschinenPanel(), h('div', { style: 'padding:28px;text-align:center;color:var(--foreground-subdued);border:1px solid var(--border-normal);border-radius:12px;background:var(--background-page,#fff);' }, 'Keine offenen Aufträge.')]); return sek.length ? h('div', {}, [maschinenPanel(), ...sek]) : h('div', {}, [maschinenPanel(), h('div', { style: 'padding:28px;text-align:center;color:#566070;border:1px solid #b4c0d2;border-radius:12px;background:#ffffff;' }, 'Keine offenen Aufträge.')]);
} }
function sucheInhalt() { function sucheInhalt() {
@@ -421,22 +421,22 @@ const Board = {
h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;' }, TYPEN.map(([k, l, ic]) => { h('div', { style: 'display:flex;gap:10px;flex-wrap:wrap;' }, TYPEN.map(([k, l, ic]) => {
const aktiv = sucheTyp.value === k; const aktiv = sucheTyp.value === k;
return h('button', { type: 'button', onClick: () => { sucheTyp.value = k; }, return h('button', { type: 'button', onClick: () => { sucheTyp.value = k; },
style: `cursor:pointer;border-radius:10px;padding:13px 20px;font:inherit;font-size:16px;font-weight:500;display:inline-flex;align-items:center;gap:8px;border:2px solid;${aktiv ? 'background:#1E50A5;color:#fff;border-color:#1E50A5;' : 'background:var(--background-page,#fff);color:var(--foreground-normal);border-color:var(--border-normal);'}` }, [icon(ic), l]); style: `cursor:pointer;border-radius:10px;padding:13px 20px;font:inherit;font-size:16px;font-weight:500;display:inline-flex;align-items:center;gap:8px;border:2px solid;${aktiv ? 'background:#1E50A5;color:#fff;border-color:#1E50A5;' : 'background:#ffffff;color:#1b2430;border-color:#b4c0d2;'}` }, [icon(ic), l]);
})), })),
]); ]);
const feld = h('div', { style: 'margin-top:18px;' }, [ const feld = h('div', { style: 'margin-top:18px;' }, [
h('div', { style: 'font-size:14px;font-weight:500;margin-bottom:8px;' }, '2. Empfänger suchen'), h('div', { style: 'font-size:14px;font-weight:500;margin-bottom:8px;' }, '2. Empfänger suchen'),
h('input', { type: 'search', placeholder: 'Name, Straße, Ort oder Auftragsnummer …', h('input', { type: 'search', placeholder: 'Name, Straße, Ort oder Auftragsnummer …',
style: 'width:100%;box-sizing:border-box;background:var(--background-page);color:var(--foreground-normal);border:2px solid var(--border-normal);border-radius:12px;font:inherit;font-size:22px;padding:16px 20px;outline:none;', style: 'width:100%;box-sizing:border-box;background:#ffffff;color:#1b2430;border:2px solid #b4c0d2;border-radius:12px;font:inherit;font-size:22px;padding:16px 20px;outline:none;',
onInput: (e) => sucheSetzen(e.target.value) }), onInput: (e) => sucheSetzen(e.target.value) }),
]); ]);
const rahmen = (kinder) => h('div', {}, [ const rahmen = (kinder) => h('div', {}, [
h('div', { style: 'background:var(--background-page,#fff);border:1px solid var(--border-normal);border-radius:12px;padding:20px 22px;margin-bottom:16px;' }, [typWahl, feld]), h('div', { style: 'background:#ffffff;border:1px solid #b4c0d2;border-radius:12px;padding:20px 22px;margin-bottom:16px;' }, [typWahl, feld]),
kinder, kinder,
]); ]);
if (!sucheQuery.value.trim()) return rahmen(h('div', { style: 'color:var(--foreground-subdued);' }, 'Suchbegriff eingeben – durchsucht die offenen Aufträge.')); if (!sucheQuery.value.trim()) return rahmen(h('div', { style: 'color:#566070;' }, 'Suchbegriff eingeben – durchsucht die offenen Aufträge.'));
const treffer = sucheTreffer.value; const treffer = sucheTreffer.value;
if (!treffer.length) return rahmen(h('div', { style: 'color:var(--foreground-subdued);' }, 'Keine Treffer.')); if (!treffer.length) return rahmen(h('div', { style: 'color:#566070;' }, 'Keine Treffer.'));
const trefferZeile = ({ e, o }) => { const trefferZeile = ({ e, o }) => {
const gesamt = entriesByOrder.value[String(o.id)]?.anzahl || 1; const gesamt = entriesByOrder.value[String(o.id)]?.anzahl || 1;
const adrLines = (e.adr && e.adr.length) ? e.adr : [e.name || '—']; const adrLines = (e.adr && e.adr.length) ? e.adr : [e.name || '—'];
@@ -444,15 +444,15 @@ const Board = {
const aktion = sucheTyp.value === 'objekt' const aktion = sucheTyp.value === 'objekt'
? h('a', { href: `/admin/content/orders/${o.id}`, target: '_blank', rel: 'noopener', style: 'display:inline-flex;align-items:center;gap:6px;background:#1E50A5;color:#fff;border-radius:8px;padding:9px 16px;font-size:14px;font-weight:500;text-decoration:none;' }, [icon('open_in_new'), 'Auftrag öffnen']) ? h('a', { href: `/admin/content/orders/${o.id}`, target: '_blank', rel: 'noopener', style: 'display:inline-flex;align-items:center;gap:6px;background:#1E50A5;color:#fff;border-radius:8px;padding:9px 16px;font-size:14px;font-weight:500;text-decoration:none;' }, [icon('open_in_new'), 'Auftrag öffnen'])
: (sucheTyp.value === 'umschlag' && !kannKuvert) : (sucheTyp.value === 'umschlag' && !kannKuvert)
? h('span', { style: 'color:var(--foreground-subdued);font-size:14px;' }, 'Kein Kuvert') ? h('span', { style: 'color:#566070;font-size:14px;' }, 'Kein Kuvert')
: h('button', { type: 'button', onClick: () => schnelldruck(o, e.nr, sucheTyp.value), : h('button', { type: 'button', onClick: () => schnelldruck(o, e.nr, sucheTyp.value),
style: 'cursor:pointer;display:inline-flex;align-items:center;gap:6px;background:#1E50A5;color:#fff;border:none;border-radius:8px;padding:10px 18px;font:inherit;font-size:15px;font-weight:500;' }, [icon('print'), 'In Warteschlange']); style: 'cursor:pointer;display:inline-flex;align-items:center;gap:6px;background:#1E50A5;color:#fff;border:none;border-radius:8px;padding:10px 18px;font:inherit;font-size:15px;font-weight:500;' }, [icon('print'), 'In Warteschlange']);
return h('div', { key: `s${o.id}-${e.nr}`, style: 'border:1px solid var(--border-normal);border-radius:12px;background:var(--background-page,#fff);padding:14px 16px;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;' }, [ return h('div', { key: `s${o.id}-${e.nr}`, style: 'border:1px solid #b4c0d2;border-radius:12px;background:#ffffff;padding:14px 16px;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;' }, [
h('div', { style: 'min-width:0;' }, [ h('div', { style: 'min-width:0;' }, [
...adrLines.map((z, i) => h('div', { style: i === 0 ? 'font-weight:500;font-size:16px;' : 'font-size:14px;color:var(--foreground-normal);' }, z)), ...adrLines.map((z, i) => h('div', { style: i === 0 ? 'font-weight:500;font-size:16px;' : 'font-size:14px;color:#1b2430;' }, z)),
h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;margin-top:5px;align-items:center;font-size:13px;color:var(--foreground-subdued);' }, [ h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;margin-top:5px;align-items:center;font-size:13px;color:#566070;' }, [
h('span', {}, `Auftrag #${o.order_number}`), h('span', {}, `Auftrag #${o.order_number}`),
gesamt > 1 ? h('span', { style: 'background:var(--background-subdued);border-radius:999px;padding:2px 9px;' }, `Nr. ${e.nr} von ${gesamt}`) : null, gesamt > 1 ? h('span', { style: 'background:#eef2f8;border-radius:999px;padding:2px 9px;' }, `Nr. ${e.nr} von ${gesamt}`) : null,
h('span', { style: `display:inline-flex;align-items:center;gap:4px;color:${(STATUS_META[o.production_status] || STATUS_META.eingegangen).fg};` }, [icon((STATUS_META[o.production_status] || STATUS_META.eingegangen).icon), STATUS_LABEL[o.production_status] || '']), h('span', { style: `display:inline-flex;align-items:center;gap:4px;color:${(STATUS_META[o.production_status] || STATUS_META.eingegangen).fg};` }, [icon((STATUS_META[o.production_status] || STATUS_META.eingegangen).icon), STATUS_LABEL[o.production_status] || '']),
]), ]),
]), ]),
@@ -464,7 +464,7 @@ const Board = {
const navItem = (key, label, ic) => h('button', { type: 'button', onClick: () => { clearTimeout(sucheTimer); sucheQuery.value = ''; view.value = key; if (key === 'suche') ladeSuche(); }, const navItem = (key, label, ic) => h('button', { type: 'button', onClick: () => { clearTimeout(sucheTimer); sucheQuery.value = ''; view.value = key; if (key === 'suche') ladeSuche(); },
style: 'display:flex;align-items:center;gap:10px;width:100%;text-align:left;cursor:pointer;border:none;border-radius:8px;padding:11px 13px;margin-bottom:3px;font:inherit;font-size:14px;' style: 'display:flex;align-items:center;gap:10px;width:100%;text-align:left;cursor:pointer;border:none;border-radius:8px;padding:11px 13px;margin-bottom:3px;font:inherit;font-size:14px;'
+ (view.value === key ? 'background:#1E50A5;color:#fff;font-weight:500;' : 'background:transparent;color:var(--foreground-normal);'), + (view.value === key ? 'background:#1E50A5;color:#fff;font-weight:500;' : 'background:transparent;color:#1b2430;'),
}, [icon(ic), label]); }, [icon(ic), label]);
return () => { return () => {
@@ -474,11 +474,11 @@ const Board = {
]); ]);
const inhalt = h('div', { style: 'padding:24px 28px;' }, [ const inhalt = h('div', { style: 'padding:24px 28px;' }, [
view.value === 'uebersicht' ? h('div', { style: 'display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:18px;' }, [ view.value === 'uebersicht' ? h('div', { style: 'display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:18px;' }, [
h('input', { type: 'search', placeholder: 'Auftrag, Kunde, Empfänger, Format …', style: 'flex:1;min-width:240px;box-sizing:border-box;border:1px solid var(--border-normal);border-radius:10px;padding:11px 14px;font:inherit;font-size:15px;background:var(--background-page);color:var(--foreground-normal);', onInput: (e) => sucheSetzen(e.target.value) }), h('input', { type: 'search', placeholder: 'Auftrag, Kunde, Empfänger, Format …', style: 'flex:1;min-width:240px;box-sizing:border-box;border:1px solid #b4c0d2;border-radius:10px;padding:11px 14px;font:inherit;font-size:15px;background:#ffffff;color:#1b2430;', onInput: (e) => sucheSetzen(e.target.value) }),
h('button', { type: 'button', onClick: () => laden(), style: 'cursor:pointer;border:1px solid var(--border-normal);background:var(--background-page,#fff);border-radius:8px;padding:9px 16px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;gap:6px;' }, [icon('refresh'), 'Aktualisieren']), h('button', { type: 'button', onClick: () => laden(), style: 'cursor:pointer;border:1px solid #b4c0d2;background:#ffffff;border-radius:8px;padding:9px 16px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;gap:6px;' }, [icon('refresh'), 'Aktualisieren']),
]) : null, ]) : null,
msg.value ? h('div', { style: 'background:var(--success-25,rgba(46,125,50,.14));color:var(--success,#2e7d32);padding:10px 14px;border-radius:8px;margin-bottom:12px;font-size:14px;' }, msg.value) : null, msg.value ? h('div', { style: 'background:#dff2e2;color:#1b6b2e;padding:10px 14px;border-radius:8px;margin-bottom:12px;font-size:14px;' }, msg.value) : null,
err.value ? h('div', { style: 'background:var(--danger-25,rgba(198,40,40,.12));color:var(--danger,#c62828);padding:10px 14px;border-radius:8px;margin-bottom:12px;font-size:14px;' }, err.value) : null, err.value ? h('div', { style: 'background:#fbe3e0;color:#c0392b;padding:10px 14px;border-radius:8px;margin-bottom:12px;font-size:14px;' }, err.value) : null,
view.value === 'suche' ? sucheInhalt() : uebersichtInhalt(), view.value === 'suche' ? sucheInhalt() : uebersichtInhalt(),
]); ]);
return h(resolveComponent('private-view'), { title: view.value === 'suche' ? 'Suche' : 'Übersicht' }, { navigation: () => navi, default: () => inhalt }); return h(resolveComponent('private-view'), { title: view.value === 'suche' ? 'Suche' : 'Übersicht' }, { navigation: () => navi, default: () => inhalt });