diff --git a/extensions/directus-extension-skrift-uebersicht/dist/index.js b/extensions/directus-extension-skrift-uebersicht/dist/index.js index 65b8730..2963f7d 100644 --- a/extensions/directus-extension-skrift-uebersicht/dist/index.js +++ b/extensions/directus-extension-skrift-uebersicht/dist/index.js @@ -85,12 +85,13 @@ const Board = { machines.value = m.data?.data || []; // Erster/letzter Empfänger je Auftrag (für die Adressspalte). const idx = {}; + const ids = orders.value.map((x) => x.id); try { - const ent = await api.get('/items/order_entries', { params: { - limit: -1, sort: 'order,letter_number', - filter: { order: { production_status: { _in: AKTIV_STATUS } } }, + const ent = ids.length ? await api.get('/items/order_entries', { params: { + limit: -1, sort: 'letter_number', + filter: { order: { _in: ids } }, fields: 'order,first_name,last_name,company,city,letter_number,free_text', - } }); + } }) : { data: { data: [] } }; for (const e of (ent.data?.data || [])) { const k = String(e.order?.id ?? e.order); if (!k || k === 'null') continue; @@ -111,7 +112,12 @@ const Board = { const eingeplantSet = computed(() => new Set(jobs.value.map((j) => String(j.order?.id)).filter((x) => x && x !== 'null'))); const queuedByFormat = computed(() => { const map = {}; - for (const j of jobs.value) { const f = j.format || '?'; if (!map[f]) map[f] = { n: 0, label: j.format_label || FORMAT_LABEL[f] || f }; map[f].n += 1; } + for (const j of jobs.value) { + if (j.status !== 'queued') continue; // nur wartende Jobs (nicht „im Druck") + const f = j.format || '?'; + if (!map[f]) map[f] = { n: 0, label: j.format_label || FORMAT_LABEL[f] || f }; + map[f].n += 1; + } return map; }); const gefiltert = computed(() => { @@ -154,33 +160,53 @@ const Board = { 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 td = (kids, extra) => h('td', { style: `padding:11px 12px;border-bottom:1px solid var(--border-subdued);font-size:14px;vertical-align:top;${extra || ''}` }, kids); + // Nächste konkrete Aufgabe für den Mitarbeiter (aus Status + Kuvert + Versandart). + function aufgabe(o) { + const einzeln = o.shipping_type === 'einzeln'; + switch (o.production_status) { + case 'eingegangen': return { t: 'Wartet auf Druck', c: 'var(--foreground-subdued)', i: 'hourglass_empty' }; + case 'im_druck': return { t: 'Im Druck', c: 'var(--primary,#1e50a5)', i: 'print' }; + 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' }; + default: return { t: STATUS_LABEL[o.production_status] || '', c: 'var(--foreground-subdued)', i: 'info' }; + } + } + async function setVersand(o, v) { + try { await api.patch('/items/orders/' + o.id, { shipping_type: v }); o.shipping_type = v; } + catch (e) { err.value = 'Versandart konnte nicht gesetzt werden.'; } + } + function versandToggle(o) { + const einzeln = o.shipping_type === 'einzeln'; + return h('button', { type: 'button', title: 'Umschalten Sammel/Einzel', onClick: () => setVersand(o, einzeln ? 'sammel' : 'einzeln'), + style: 'cursor:pointer;border:1px solid var(--border-normal);background:var(--background-page,#fff);border-radius:999px;padding:4px 11px;font:inherit;font-size:12.5px;font-weight:500;display:inline-flex;align-items:center;gap:5px;' }, + [icon(einzeln ? 'person' : 'groups'), einzeln ? 'Einzeln' : 'Sammel']); + } function zeile(o) { const e = entriesByOrder.value[String(o.id)]; const faellig = faelligBis(o.date_created, o.shipping_day); - const empf = e - ? h('div', { style: 'line-height:1.5;' }, [ - h('div', {}, empfKurz(e.erster) || '—'), - e.anzahl > 1 ? h('div', { style: 'color:var(--foreground-subdued);' }, '… ' + empfKurz(e.letzter)) : null, - ]) - : h('span', { style: 'color:var(--foreground-subdued);' }, '—'); - const briefOk = !!o.brief_gedruckt; - const kuvOk = !!o.kuvert_gedruckt; + const ag = aufgabe(o); + const eingeplant = eingeplantSet.value.has(String(o.id)); return h('tr', { key: 'o' + o.id }, [ - td(h('div', { style: 'line-height:1.4;' }, [ - o.order_name ? h('div', { style: 'font-weight:500;color:var(--primary,#1e50a5);' }, o.order_name) : null, - h('div', { style: 'font-weight:500;' }, kundeName(o) || `#${o.order_number}`), - h('div', { style: 'font-size:12.5px;color:var(--foreground-subdued);' }, `#${o.order_number} · ${o.entries_count || 0} Empf.`), + // Empfänger = Hauptinfo. + td(h('div', { style: 'line-height:1.45;' }, [ + 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, + ])), + // Auftrag = sekundär. + td(h('div', { style: 'line-height:1.4;font-size:13px;' }, [ + o.order_name ? h('div', { style: 'font-weight:500;color:var(--primary,#1e50a5);' }, o.order_name) : null, + h('div', {}, kundeName(o) || `#${o.order_number}`), + h('div', { style: 'color:var(--foreground-subdued);' }, `#${o.order_number} · ${o.entries_count || 0} Empf.`), ])), - td(empf), td(h('span', {}, o.format?.name || FORMAT_LABEL[o.format?.key] || o.format?.key || '—')), + td(h('span', { style: `display:inline-flex;align-items:center;gap:5px;font-weight:500;color:${ag.c};` }, [icon(ag.i), ag.t])), + td(versandToggle(o)), td(h('span', { style: faellig && faellig.getTime() < Date.now() ? 'color:var(--danger,#c62828);font-weight:500;' : '' }, dmY(faellig))), td(h('div', { style: 'display:flex;flex-direction:column;gap:4px;align-items:flex-start;' }, [ - druckBadge(briefOk, 'Brief'), - o.needs_envelope ? druckBadge(kuvOk, 'Kuvert') : h('span', { style: 'font-size:12px;color:var(--foreground-subdued);' }, 'ohne Kuvert'), - ])), - td(eingeplantSet.value.has(String(o.id)) - ? h('span', { style: 'display:inline-flex;align-items:center;gap:4px;font-size:12.5px;font-weight:500;color:var(--primary,#1e50a5);' }, [icon('check'), 'eingeplant']) - : h('span', { style: 'font-size:12.5px;color:var(--foreground-subdued);' }, 'nein')), + druckBadge(!!o.brief_gedruckt, 'Brief'), + o.needs_envelope ? druckBadge(!!o.kuvert_gedruckt, 'Kuvert') : null, + eingeplant ? h('span', { style: 'display:inline-flex;align-items:center;gap:3px;font-size:11.5px;font-weight:500;color:var(--primary,#1e50a5);' }, [icon('check'), 'eingeplant']) : null, + ].filter(Boolean))), td(statusPill(o)), ]); } @@ -218,13 +244,24 @@ const Board = { maschinenPanel(), loading.value ? h('div', { style: 'color:var(--foreground-subdued);' }, 'Lädt …') - : h('div', { style: 'border:1px solid var(--border-normal);border-radius:12px;overflow:auto;background:var(--background-page,#fff);' }, [ - h('table', { style: 'width:100%;border-collapse:collapse;' }, [ - h('thead', {}, h('tr', {}, [th('Auftrag'), th('Empfänger (erster · letzter)'), th('Format'), th('Fällig'), th('Druck'), th('Eingeplant'), th('Status')])), - h('tbody', {}, gefiltert.value.length ? gefiltert.value.map(zeile) : [h('tr', {}, h('td', { colspan: 7, style: 'padding:24px;text-align:center;color:var(--foreground-subdued);' }, 'Keine Aufträge.'))]), - ]), - ]), - h('div', { style: 'margin-top:10px;font-size:12.5px;color:var(--foreground-subdued);' }, `${gefiltert.value.length} von ${orders.value.length} offenen Aufträgen`), + : (() => { + const GRUPPEN = [['im_druck', 'Im Druck'], ['kuvertieren', 'Kuvertierung'], ['versandfertig', 'Versandfertig'], ['eingegangen', 'Eingegangen']]; + const kopf = () => h('thead', {}, h('tr', {}, [th('Empfänger (erster · letzter)'), th('Auftrag'), th('Format'), th('Aufgabe'), th('Versand'), th('Fällig'), th('Stand'), th('Status')])); + const sek = GRUPPEN.map(([st, label]) => { + const list = gefiltert.value.filter((o) => (o.production_status || 'eingegangen') === st); + if (!list.length) return null; + const m = STATUS_META[st]; + return h('div', { key: 'sec' + st, style: 'margin-bottom:22px;' }, [ + 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: 'font-size:13px;color:var(--foreground-subdued);' }, `${list.length} Auftrag/Aufträge`), + ]), + h('div', { style: 'border:1px solid var(--border-normal);border-radius:12px;overflow:auto;background:var(--background-page,#fff);' }, + [h('table', { style: 'width:100%;border-collapse:collapse;' }, [kopf(), h('tbody', {}, list.map(zeile))])]), + ]); + }).filter(Boolean); + return sek.length ? h('div', {}, sek) : 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 h(resolveComponent('private-view'), { title: 'Übersicht' }, { default: () => inhalt }); };