Produktion: Suche-Reiter + Sammel-Druck mit editierbaren Maßen
Suche-Reiter (ganz oben, vor Neu): großes Suchfeld über alle aktiven Stufen (Neu, Warteschlange, Im Druck, Kuvertierung, Versandfertig), empfängergenau – Einzelaufträge zeigen den Namen, Mehrfachaufträge den Empfänger an der richtigen Briefnummer. Über dem Feld ein Typ-Umschalter (Schriftstück / Kuvert / Druckobjekte) mit je eigenem, im Reiter einstellbarem Standard-Template + Maschine (lokal gespeichert). Der Druck-Button gibt genau diesen Empfänger mit dem Standard-Template in die Warteschlange; Druckobjekte öffnet die Dateien zum Herunterladen. Sammel-Druck (Mass-Select): pro Format nicht nur Template + Maschine, sondern auch Maße/Position (Breite, Höhe, X, Y, Scale, Rotation) editierbar – übersteuert die Template-Werte wie beim Einzeldruck (enqueue-bulk reicht die params jetzt an die Jobs durch). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1267,6 +1267,17 @@ const handler = (router, { services, getSchema, logger }) => {
|
|||||||
const mode = body.mode === 'direct' ? 'direct' : 'queue';
|
const mode = body.mode === 'direct' ? 'direct' : 'queue';
|
||||||
const prioFor = (m) => (mode === 'direct' && !busySet.has(String(m))) ? 100 : 0;
|
const prioFor = (m) => (mode === 'direct' && !busySet.has(String(m))) ? 100 : 0;
|
||||||
|
|
||||||
|
// Reinigt eine Maß-Übersteuerung auf erlaubte Zahlenfelder (oder null) –
|
||||||
|
// wie in /enqueue, damit der Sammel-Druck Template-Werte übersteuern kann.
|
||||||
|
const clampParams = (p) => {
|
||||||
|
if (!p || typeof p !== 'object') return null;
|
||||||
|
const out = {};
|
||||||
|
for (const k of ['width', 'height', 'xpos', 'ypos', 'scale', 'rotation']) {
|
||||||
|
if (p[k] !== undefined && p[k] !== null && p[k] !== '' && !isNaN(Number(p[k]))) out[k] = Number(p[k]);
|
||||||
|
}
|
||||||
|
return Object.keys(out).length ? out : null;
|
||||||
|
};
|
||||||
|
|
||||||
const jobs = [];
|
const jobs = [];
|
||||||
const uebersprungen = [];
|
const uebersprungen = [];
|
||||||
const mkJob = async (order, typ, fmt) => {
|
const mkJob = async (order, typ, fmt) => {
|
||||||
@@ -1277,7 +1288,8 @@ const handler = (router, { services, getSchema, logger }) => {
|
|||||||
}
|
}
|
||||||
jobs.push(await svc('jobs').createOne({
|
jobs.push(await svc('jobs').createOne({
|
||||||
order: order.id, machine: cfg.machine, type: typ, template: cfg.template,
|
order: order.id, machine: cfg.machine, type: typ, template: cfg.template,
|
||||||
format: fmt.key, format_label: cfg.label || fmt.label, status: 'queued', priority: prioFor(cfg.machine),
|
format: fmt.key, format_label: cfg.label || fmt.label, params: clampParams(cfg.params),
|
||||||
|
status: 'queued', priority: prioFor(cfg.machine),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
for (const order of orders) {
|
for (const order of orders) {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ function faelligBis(dateCreated, shippingDay) {
|
|||||||
const dmY = (dt) => dt ? `${String(dt.getDate()).padStart(2, '0')}.${String(dt.getMonth() + 1).padStart(2, '0')}.${dt.getFullYear()}` : '';
|
const dmY = (dt) => dt ? `${String(dt.getDate()).padStart(2, '0')}.${String(dt.getMonth() + 1).padStart(2, '0')}.${dt.getFullYear()}` : '';
|
||||||
|
|
||||||
const TABS = [
|
const TABS = [
|
||||||
|
{ key: 'suche', label: '🔎 Suche' },
|
||||||
{ key: 'neu', label: '🆕 Neu' },
|
{ key: 'neu', label: '🆕 Neu' },
|
||||||
{ key: 'warteschlange', label: '⏳ Warteschlange' },
|
{ key: 'warteschlange', label: '⏳ Warteschlange' },
|
||||||
{ key: 'druck', label: '🖨 Im Druck' },
|
{ key: 'druck', label: '🖨 Im Druck' },
|
||||||
@@ -169,6 +170,12 @@ const Board = defineComponent({
|
|||||||
const api = useApi();
|
const api = useApi();
|
||||||
const tab = ref('neu');
|
const tab = ref('neu');
|
||||||
const suche = ref('');
|
const suche = ref('');
|
||||||
|
// Suche-Reiter: Objekttyp (Schriftstück/Kuvert/Druckobjekt), Standard-Templates
|
||||||
|
// je Typ + Zielmaschine (im Reiter einstellbar, lokal gespeichert), und ein
|
||||||
|
// flacher Empfänger-Index (eine Zeile je Empfänger, mit Briefnummer).
|
||||||
|
const sucheTyp = ref('brief');
|
||||||
|
const sucheTpl = reactive({ brief: null, umschlag: null, machine: null });
|
||||||
|
const sucheEintraege = ref([]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const fehler = ref('');
|
const fehler = ref('');
|
||||||
const meldung = ref('');
|
const meldung = ref('');
|
||||||
@@ -253,6 +260,7 @@ const Board = defineComponent({
|
|||||||
} });
|
} });
|
||||||
const idx = {};
|
const idx = {};
|
||||||
const namen = {};
|
const namen = {};
|
||||||
|
const flach = [];
|
||||||
for (const e of r.data?.data || []) {
|
for (const e of r.data?.data || []) {
|
||||||
const oid = String(e.order?.id ?? e.order ?? '');
|
const oid = String(e.order?.id ?? e.order ?? '');
|
||||||
if (!oid) continue;
|
if (!oid) continue;
|
||||||
@@ -262,9 +270,12 @@ const Board = defineComponent({
|
|||||||
const nm = entryName(e);
|
const nm = entryName(e);
|
||||||
if (!namen[oid]) namen[oid] = { erste: nm, letzte: nm, anzahl: 1 };
|
if (!namen[oid]) namen[oid] = { erste: nm, letzte: nm, anzahl: 1 };
|
||||||
else { namen[oid].letzte = nm; namen[oid].anzahl += 1; }
|
else { namen[oid].letzte = nm; namen[oid].anzahl += 1; }
|
||||||
|
// Eine durchsuchbare Zeile je Empfänger (mit Briefnummer) für den Suche-Reiter.
|
||||||
|
flach.push({ orderId: oid, nr: Number(e.letter_number) || flach.filter((x) => x.orderId === oid).length + 1, name: nm, hay: txt });
|
||||||
}
|
}
|
||||||
empfIndex.value = idx;
|
empfIndex.value = idx;
|
||||||
empfNamen.value = namen;
|
empfNamen.value = namen;
|
||||||
|
sucheEintraege.value = flach;
|
||||||
} catch { /* Suche läuft dann ohne Empfänger weiter */ }
|
} catch { /* Suche läuft dann ohne Empfänger weiter */ }
|
||||||
}
|
}
|
||||||
// Sende-Index über ALLE Jobs (auch bereits gedruckte): orderId →
|
// Sende-Index über ALLE Jobs (auch bereits gedruckte): orderId →
|
||||||
@@ -390,6 +401,7 @@ const Board = defineComponent({
|
|||||||
} finally { if (!leise) loading.value = false; }
|
} finally { if (!leise) loading.value = false; }
|
||||||
}
|
}
|
||||||
onMounted(laden);
|
onMounted(laden);
|
||||||
|
onMounted(sucheDefaultsLaden);
|
||||||
|
|
||||||
// Auto-Refresh: hält das Board aktuell, ohne dass man die Seite neu laden muss.
|
// Auto-Refresh: hält das Board aktuell, ohne dass man die Seite neu laden muss.
|
||||||
// Pausiert bei offenem Sammel-Dialog, im Hintergrund-Tab und während bereits
|
// Pausiert bei offenem Sammel-Dialog, im Hintergrund-Tab und während bereits
|
||||||
@@ -441,6 +453,56 @@ const Board = defineComponent({
|
|||||||
const versendetAktiv = () => orders.value.filter((o) => o.production_status === 'versendet' && !istArchiviert(o) && trifftSuche(orderHay(o)));
|
const versendetAktiv = () => orders.value.filter((o) => o.production_status === 'versendet' && !istArchiviert(o) && trifftSuche(orderHay(o)));
|
||||||
const archivListe = () => orders.value.filter((o) => istArchiviert(o) && trifftSuche(orderHay(o)));
|
const archivListe = () => orders.value.filter((o) => istArchiviert(o) && trifftSuche(orderHay(o)));
|
||||||
|
|
||||||
|
// ── Suche-Reiter: Empfänger-genaue Treffer über alle aktiven Stufen ────────
|
||||||
|
const SUCHE_AKTIV = ['eingegangen', 'im_druck', 'kuvertieren', 'versandfertig'];
|
||||||
|
const orderById = computed(() => {
|
||||||
|
const m = {};
|
||||||
|
for (const o of orders.value) m[String(o.id)] = o;
|
||||||
|
return m;
|
||||||
|
});
|
||||||
|
const sucheTreffer = computed(() => {
|
||||||
|
const q = suche.value.trim();
|
||||||
|
if (!q) return [];
|
||||||
|
const res = [];
|
||||||
|
for (const e of sucheEintraege.value) {
|
||||||
|
const o = orderById.value[e.orderId];
|
||||||
|
if (!o || !SUCHE_AKTIV.includes(o.production_status || 'eingegangen')) continue;
|
||||||
|
if (!trifftSuche([e.hay, o.order_number, o.product?.name].filter(Boolean).join(' '))) continue;
|
||||||
|
res.push({ e, o });
|
||||||
|
if (res.length >= 200) break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
// Standard-Templates/Maschine für den Schnelldruck lokal sichern/laden.
|
||||||
|
const SUCHE_KEY = 'skrift_suche_defaults';
|
||||||
|
function sucheDefaultsLaden() {
|
||||||
|
try {
|
||||||
|
const s = JSON.parse(localStorage.getItem(SUCHE_KEY) || '{}');
|
||||||
|
if (s.brief) sucheTpl.brief = s.brief;
|
||||||
|
if (s.umschlag) sucheTpl.umschlag = s.umschlag;
|
||||||
|
if (s.machine) sucheTpl.machine = s.machine;
|
||||||
|
} catch { /* ohne gespeicherte Defaults weiter */ }
|
||||||
|
}
|
||||||
|
function sucheDefaultsSpeichern() {
|
||||||
|
try { localStorage.setItem(SUCHE_KEY, JSON.stringify({ brief: sucheTpl.brief, umschlag: sucheTpl.umschlag, machine: sucheTpl.machine })); }
|
||||||
|
catch { /* egal */ }
|
||||||
|
}
|
||||||
|
// Schnelldruck: NUR den gewählten Empfänger (Briefnummer) des Typs mit dem im
|
||||||
|
// Reiter gesetzten Standard-Template in die Warteschlange geben.
|
||||||
|
async function schnelldruck(o, nr, typ) {
|
||||||
|
const tplId = typ === 'umschlag' ? sucheTpl.umschlag : sucheTpl.brief;
|
||||||
|
const machine = sucheTpl.machine || aktiveMaschinen.value[0]?.id || null;
|
||||||
|
if (!tplId) { fehler.value = `Bitte oben ein Standard-Template für ${typ === 'umschlag' ? 'Kuvert' : 'Schriftstück'} wählen.`; return; }
|
||||||
|
if (!machine) { fehler.value = 'Keine aktive Maschine verfügbar.'; return; }
|
||||||
|
try {
|
||||||
|
const sections = {};
|
||||||
|
sections[typ === 'umschlag' ? 'umschlag' : 'brief'] = { enabled: true, template: tplId, numbers: nr ? String(nr) : '' };
|
||||||
|
await api.post('/skrift-orders/enqueue', { order: o.id, machine, mode: 'queue', sections });
|
||||||
|
flash(`#${o.order_number} · ${typ === 'umschlag' ? '✉ Kuvert' : '📄 Schriftstück'}${nr ? ` Nr. ${nr}` : ''} → Warteschlange.`);
|
||||||
|
await laden();
|
||||||
|
} catch (e) { fehler.value = e?.response?.data?.error || e?.message || 'Einreihen fehlgeschlagen.'; }
|
||||||
|
}
|
||||||
|
|
||||||
const queuedByMachine = computed(() => {
|
const queuedByMachine = computed(() => {
|
||||||
const groups = {};
|
const groups = {};
|
||||||
for (const m of aktiveMaschinen.value) groups[m.id] = { machine: m, jobs: [] };
|
for (const m of aktiveMaschinen.value) groups[m.id] = { machine: m, jobs: [] };
|
||||||
@@ -453,6 +515,7 @@ const Board = defineComponent({
|
|||||||
return Object.values(groups).filter((g) => g.jobs.length);
|
return Object.values(groups).filter((g) => g.jobs.length);
|
||||||
});
|
});
|
||||||
const tabCount = (key) => {
|
const tabCount = (key) => {
|
||||||
|
if (key === 'suche') return sucheTreffer.value.length;
|
||||||
if (key === 'neu') return neueOrders.value.length + neueRequests.value.length;
|
if (key === 'neu') return neueOrders.value.length + neueRequests.value.length;
|
||||||
if (key === 'warteschlange') return jobs.value.filter((j) => j.status === 'queued').length;
|
if (key === 'warteschlange') return jobs.value.filter((j) => j.status === 'queued').length;
|
||||||
if (key === 'druck') return ordersByStatus('im_druck').length;
|
if (key === 'druck') return ordersByStatus('im_druck').length;
|
||||||
@@ -612,7 +675,11 @@ const Board = defineComponent({
|
|||||||
if (!sel.length) return;
|
if (!sel.length) return;
|
||||||
const map = {};
|
const map = {};
|
||||||
const add = (key, label, typ) => {
|
const add = (key, label, typ) => {
|
||||||
if (!map[key]) map[key] = { key, label, type: typ, aktiv: true, template: stdTpl(key, typ), machine: aktiveMaschinen.value[0]?.id ?? null };
|
if (!map[key]) {
|
||||||
|
const tid = stdTpl(key, typ);
|
||||||
|
const t = templates.value.find((x) => String(x.id) === String(tid));
|
||||||
|
map[key] = { key, label, type: typ, aktiv: true, template: tid, machine: aktiveMaschinen.value[0]?.id ?? null, ...paramFelder(t) };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
for (const o of sel) {
|
for (const o of sel) {
|
||||||
add(o.format?.key || 'a4', o.format?.name || o.format?.key || 'A4', 'brief');
|
add(o.format?.key || 'a4', o.format?.name || o.format?.key || 'A4', 'brief');
|
||||||
@@ -624,13 +691,21 @@ const Board = defineComponent({
|
|||||||
bulk.gruppen = Object.values(map);
|
bulk.gruppen = Object.values(map);
|
||||||
bulk.mode = 'queue'; bulk.msg = ''; bulk.err = ''; bulk.open = true;
|
bulk.mode = 'queue'; bulk.msg = ''; bulk.err = ''; bulk.open = true;
|
||||||
}
|
}
|
||||||
|
// Template im Sammel-Druck wechseln → Maße/Position aus dem neuen Template
|
||||||
|
// vorbelegen (der Operator kann sie danach je Format übersteuern).
|
||||||
|
function bulkTplWechsel(g, tplId) {
|
||||||
|
g.template = tplId;
|
||||||
|
const t = templates.value.find((x) => String(x.id) === String(tplId));
|
||||||
|
if (t) Object.assign(g, paramFelder(t));
|
||||||
|
}
|
||||||
async function submitBulk() {
|
async function submitBulk() {
|
||||||
const byFormat = {};
|
const byFormat = {};
|
||||||
const aktive = bulk.gruppen.filter((g) => g.aktiv);
|
const aktive = bulk.gruppen.filter((g) => g.aktiv);
|
||||||
if (!aktive.length) { bulk.err = 'Mindestens ein Format auswählen.'; return; }
|
if (!aktive.length) { bulk.err = 'Mindestens ein Format auswählen.'; return; }
|
||||||
for (const g of aktive) {
|
for (const g of aktive) {
|
||||||
if (!g.template || !g.machine) { bulk.err = `Für „${g.label}" bitte Template und Maschine wählen.`; return; }
|
if (!g.template || !g.machine) { bulk.err = `Für „${g.label}" bitte Template und Maschine wählen.`; return; }
|
||||||
byFormat[g.key] = { template: g.template, machine: g.machine, label: g.label };
|
byFormat[g.key] = { template: g.template, machine: g.machine, label: g.label,
|
||||||
|
params: { width: g.width, height: g.height, xpos: g.xpos, ypos: g.ypos, scale: g.scale, rotation: g.rotation } };
|
||||||
}
|
}
|
||||||
bulk.err = ''; bulk.msg = 'Wird eingereiht …';
|
bulk.err = ''; bulk.msg = 'Wird eingereiht …';
|
||||||
try {
|
try {
|
||||||
@@ -656,6 +731,9 @@ const Board = defineComponent({
|
|||||||
// Bevorzugt das als Standard fürs Format markierte Template (default_format), sonst Fallback.
|
// Bevorzugt das als Standard fürs Format markierte Template (default_format), sonst Fallback.
|
||||||
const tplForFormat = (fmt, typ) => (fmt && templates.value.find((t) => t.type === typ && t.default_format && t.default_format === fmt)) || null;
|
const tplForFormat = (fmt, typ) => (fmt && templates.value.find((t) => t.type === typ && t.default_format && t.default_format === fmt)) || null;
|
||||||
const tplToFelder = (t) => ({ tplId: t?.id ?? null, width: t?.width ?? 0, height: t?.height ?? 0, xpos: t?.xpos ?? 0, ypos: t?.ypos ?? 0, scale: t?.scale ?? 1, rotation: t?.rotation ?? 0 });
|
const tplToFelder = (t) => ({ tplId: t?.id ?? null, width: t?.width ?? 0, height: t?.height ?? 0, xpos: t?.xpos ?? 0, ypos: t?.ypos ?? 0, scale: t?.scale ?? 1, rotation: t?.rotation ?? 0 });
|
||||||
|
// Nur die editierbaren Maß-/Positionsfelder eines Templates (ohne tplId) – für
|
||||||
|
// den Sammel-Druck, wo das Template über g.template getrennt geführt wird.
|
||||||
|
const paramFelder = (t) => ({ width: t?.width ?? 0, height: t?.height ?? 0, xpos: t?.xpos ?? 0, ypos: t?.ypos ?? 0, scale: t?.scale ?? 1, rotation: t?.rotation ?? 0 });
|
||||||
|
|
||||||
function openDruck(order) {
|
function openDruck(order) {
|
||||||
// Standard-Template fürs Format (default_format) hat Vorrang, sonst alte Zuordnung.
|
// Standard-Template fürs Format (default_format) hat Vorrang, sonst alte Zuordnung.
|
||||||
@@ -1190,7 +1268,71 @@ const Board = defineComponent({
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Suche-Reiter ──────────────────────────────────────────────────────────
|
||||||
|
function sucheInhalt() {
|
||||||
|
const briefTpls = templates.value.filter((t) => t.type === 'brief');
|
||||||
|
const umschlagTpls = templates.value.filter((t) => t.type === 'umschlag');
|
||||||
|
const tplSelect = (typ) => {
|
||||||
|
const opts = typ === 'umschlag' ? umschlagTpls : briefTpls;
|
||||||
|
const val = typ === 'umschlag' ? sucheTpl.umschlag : sucheTpl.brief;
|
||||||
|
return h('select', { style: S_SELECT + 'width:100%;', value: val ?? '',
|
||||||
|
onChange: (e) => { const v = e.target.value || null; if (typ === 'umschlag') sucheTpl.umschlag = v; else sucheTpl.brief = v; sucheDefaultsSpeichern(); } },
|
||||||
|
[h('option', { value: '' }, '– Standard-Template –')]
|
||||||
|
.concat(opts.map((t) => h('option', { value: t.id, selected: String(val) === String(t.id) }, t.name))));
|
||||||
|
};
|
||||||
|
// Kopf: Typ-Umschalter + Standard-Templates/Maschine (im Reiter einstellbar).
|
||||||
|
const kopf = h('div', { style: SECTION }, [
|
||||||
|
h('div', { style: 'max-width:560px;margin-bottom:14px;' }, [
|
||||||
|
segToggle(sucheTyp.value, [
|
||||||
|
{ key: 'brief', label: '📄 Schriftstück' },
|
||||||
|
{ key: 'umschlag', label: '✉ Kuvert' },
|
||||||
|
{ key: 'objekt', label: '📎 Druckobjekte' },
|
||||||
|
], (k) => { sucheTyp.value = k; }),
|
||||||
|
]),
|
||||||
|
h('div', { style: 'display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;' }, [
|
||||||
|
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Standard-Template Schriftstück'), tplSelect('brief')]),
|
||||||
|
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Standard-Template Kuvert'), tplSelect('umschlag')]),
|
||||||
|
h('div', {}, [h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Maschine'),
|
||||||
|
h('select', { style: S_SELECT + 'width:100%;', value: sucheTpl.machine ?? '',
|
||||||
|
onChange: (e) => { sucheTpl.machine = e.target.value || null; sucheDefaultsSpeichern(); } },
|
||||||
|
[h('option', { value: '' }, aktiveMaschinen.value[0] ? `Automatisch (${aktiveMaschinen.value[0].name})` : '– keine –')]
|
||||||
|
.concat(aktiveMaschinen.value.map((m) => h('option', { value: m.id, selected: String(sucheTpl.machine) === String(m.id) }, m.name)))),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
subdued(sucheTyp.value === 'objekt'
|
||||||
|
? 'Druckobjekte: fertige Dateien des Auftrags zum manuellen Herunterladen.'
|
||||||
|
: 'Klick auf „In Warteschlange" gibt genau diesen Empfänger mit dem gewählten Standard-Template in die Queue.', 'margin-top:10px;'),
|
||||||
|
]);
|
||||||
|
// Großes Suchfeld (nutzt dasselbe Such-Feld wie oben).
|
||||||
|
const feld = h('input', { type: 'search', value: suche.value, placeholder: '🔎 Name, Straße, Ort, Auftragsnummer …',
|
||||||
|
style: S_INPUT + 'width:100%;font-size:20px;padding:14px 18px;margin:14px 0;', onInput: (e) => { suche.value = e.target.value; } });
|
||||||
|
|
||||||
|
if (!suche.value.trim()) return [kopf, feld, subdued('Suchbegriff eingeben – durchsucht Neu, Warteschlange, Im Druck, Kuvertierung und Versandfertig.')];
|
||||||
|
const treffer = sucheTreffer.value;
|
||||||
|
if (!treffer.length) return [kopf, feld, subdued('Keine Treffer in den aktiven Aufträgen.')];
|
||||||
|
|
||||||
|
const zeile = ({ e, o }) => {
|
||||||
|
const gesamt = empfNamen.value[String(o.id)]?.anzahl || 1;
|
||||||
|
const pos = gesamt > 1 ? `Nr. ${e.nr} von ${gesamt}` : 'Einzelauftrag';
|
||||||
|
const statusLbl = STATUS_LABEL[o.production_status || 'eingegangen'] || o.production_status || '—';
|
||||||
|
const aktion = sucheTyp.value === 'objekt'
|
||||||
|
? btn('📎 Dateien', () => openEmpf(o), 'primary')
|
||||||
|
: btn('🖨 In Warteschlange', () => schnelldruck(o, e.nr, sucheTyp.value), 'primary');
|
||||||
|
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: 'font-weight:700;font-size:15px;' }, e.name || '—'),
|
||||||
|
h('div', { style: 'display:flex;gap:8px;flex-wrap:wrap;margin-top:3px;align-items:center;' }, [
|
||||||
|
subdued(`#${o.order_number}`), chip(pos), chip(statusLbl), o.product?.name ? subdued(o.product.name) : null,
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
aktion,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
return [kopf, feld, h('div', { style: 'display:flex;flex-direction:column;gap:2px;' }, treffer.map(zeile))];
|
||||||
|
}
|
||||||
|
|
||||||
function tabInhalt() {
|
function tabInhalt() {
|
||||||
|
if (tab.value === 'suche') return sucheInhalt();
|
||||||
if (tab.value === 'neu') {
|
if (tab.value === 'neu') {
|
||||||
const items = [
|
const items = [
|
||||||
...renderGruppiert(neueOrders.value),
|
...renderGruppiert(neueOrders.value),
|
||||||
@@ -1348,17 +1490,26 @@ const Board = defineComponent({
|
|||||||
h('input', { type: 'checkbox', checked: g.aktiv, onChange: (e) => { g.aktiv = e.target.checked; }, style: 'width:16px;height:16px;' }),
|
h('input', { type: 'checkbox', checked: g.aktiv, onChange: (e) => { g.aktiv = e.target.checked; }, style: 'width:16px;height:16px;' }),
|
||||||
`${g.type === 'umschlag' ? '✉' : '📄'} ${g.label}`,
|
`${g.type === 'umschlag' ? '✉' : '📄'} ${g.label}`,
|
||||||
]),
|
]),
|
||||||
g.aktiv ? h('div', { style: 'display:grid;grid-template-columns:1fr 1fr;gap:10px;' }, [
|
g.aktiv ? h('div', {}, [
|
||||||
h('div', {}, [
|
h('div', { style: 'display:grid;grid-template-columns:1fr 1fr;gap:10px;' }, [
|
||||||
h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Template'),
|
h('div', {}, [
|
||||||
h('select', { style: S_SELECT + 'width:100%;', value: g.template, onChange: (e) => { g.template = e.target.value; } },
|
h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, '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('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')]),
|
||||||
h('div', {}, [
|
]),
|
||||||
h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, 'Maschine'),
|
h('div', {}, [
|
||||||
h('select', { style: S_SELECT + 'width:100%;', value: g.machine, onChange: (e) => { g.machine = e.target.value; } },
|
h('label', { style: 'font-size:11px;color:var(--foreground-subdued);' }, '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')]),
|
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')]),
|
||||||
|
]),
|
||||||
]),
|
]),
|
||||||
|
// 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;' },
|
||||||
|
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('input', { type: 'number', step: '0.01', value: g[k], style: S_INPUT + 'width:100%;',
|
||||||
|
onInput: (e) => { g[k] = e.target.value; } }),
|
||||||
|
]))),
|
||||||
]) : null,
|
]) : null,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user