B: Explizite lineare Druck-Warteschlange + Formatwechsel-Bestaetigung
Schema (bootstrap): - jobs.position (float) = explizite lineare Reihenfolge; machines.pending_format = vom Agent angefordertes naechstes Format - Service-Rechte: jobs.update +position, machines.update +pending_format Einreihen (skrift-orders): enqueue/enqueue-bulk vergeben position (ans Ende je Maschine) Board (produktion) Warteschlange: EINE lineare Liste je Maschine (nicht mehr nach Format gebuendelt), Hoch/Runter/Anfang/Ende-Umsortieren, Formatwechsel-Marker, laufende Jobs, Banner "Format einlegen -> bestaetigen" (setzt current_format, leert pending) Uebersicht (Mitarbeiter): Maschinen-Panel mit Bestaetigen/Starten + Vorschau der kommenden Format-Segmente; jobs nach position sortiert ACHTUNG Deploy: Bootstrap VOR Directus-Neustart UND vor Agent-Update (neue Felder/Rechte). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1249,6 +1249,15 @@ const handler = (router, { services, getSchema, logger }) => {
|
||||
const modus = (body.mode === 'direct' && !busy) ? 'direct' : 'queue';
|
||||
const prio = modus === 'direct' ? 100 : 0;
|
||||
|
||||
// Nächste freie Position in der linearen Warteschlange dieser Maschine
|
||||
// (neue Jobs hängen hinten an; im Board umsortierbar).
|
||||
const letzte = await svc('jobs').readByQuery({
|
||||
filter: { machine: { _eq: body.machine }, status: { _in: ['queued', 'printing'] } },
|
||||
sort: ['-position'], limit: 1, fields: ['position'],
|
||||
});
|
||||
let pos = (letzte && letzte.length && Number.isFinite(Number(letzte[0].position))) ? Number(letzte[0].position) : 0;
|
||||
const nextPos = () => (pos += 1);
|
||||
|
||||
// Reinigt eine Maß-Übersteuerung auf erlaubte Zahlenfelder (oder null).
|
||||
const clampParams = (p) => {
|
||||
if (!p || typeof p !== 'object') return null;
|
||||
@@ -1274,7 +1283,7 @@ const handler = (router, { services, getSchema, logger }) => {
|
||||
params: clampParams(sec.params), numbers: (typeof sec.numbers === 'string' && sec.numbers.trim()) ? sec.numbers.trim() : null,
|
||||
// Rollenschonende Zeichenreihenfolge (A6 quer) – nur fürs Schriftstück sinnvoll.
|
||||
spaltenweise: !!(sec.spaltenweise || body.spaltenweise),
|
||||
status: 'queued', priority: prio,
|
||||
status: 'queued', priority: prio, position: nextPos(),
|
||||
}));
|
||||
}
|
||||
if (!jobs.length) return res.status(400).json({ error: 'Kein Abschnitt zum Drucken gewählt.' });
|
||||
@@ -1284,14 +1293,14 @@ const handler = (router, { services, getSchema, logger }) => {
|
||||
const briefTpl = await tplByKey(LETTER_TPL[order.format?.key] || 'a4_single');
|
||||
jobs.push(await svc('jobs').createOne({
|
||||
order: order.id, machine: body.machine, type: 'brief', template: briefTpl,
|
||||
format: bf.key, format_label: bf.label, status: 'queued', priority: prio,
|
||||
format: bf.key, format_label: bf.label, status: 'queued', priority: prio, position: nextPos(),
|
||||
}));
|
||||
if (order.needs_envelope && order.envelope_labeling && order.envelope_labeling !== 'keine') {
|
||||
const ef = umschlagFormatOf(order);
|
||||
const envTpl = await tplByKey(ENVELOPE_TPL[order.envelope_format] || 'kuvert_a_v1');
|
||||
jobs.push(await svc('jobs').createOne({
|
||||
order: order.id, machine: body.machine, type: 'umschlag', template: envTpl,
|
||||
format: ef.key, format_label: ef.label, status: 'queued', priority: prio,
|
||||
format: ef.key, format_label: ef.label, status: 'queued', priority: prio, position: nextPos(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1345,6 +1354,22 @@ const handler = (router, { services, getSchema, logger }) => {
|
||||
return Object.keys(out).length ? out : null;
|
||||
};
|
||||
|
||||
// Lineare Position je Maschine: Startwert = höchste vorhandene Position der
|
||||
// Maschine, dann fortlaufend. So hängen die Sammel-Jobs hinten an und behalten
|
||||
// die (nach Auftragsnummer sortierte) Reihenfolge – im Board umsortierbar.
|
||||
const posByMachine = {};
|
||||
const nextPos = async (machine) => {
|
||||
const key = String(machine);
|
||||
if (posByMachine[key] === undefined) {
|
||||
const letzte = await svc('jobs').readByQuery({
|
||||
filter: { machine: { _eq: machine }, status: { _in: ['queued', 'printing'] } },
|
||||
sort: ['-position'], limit: 1, fields: ['position'],
|
||||
});
|
||||
posByMachine[key] = (letzte && letzte.length && Number.isFinite(Number(letzte[0].position))) ? Number(letzte[0].position) : 0;
|
||||
}
|
||||
return (posByMachine[key] += 1);
|
||||
};
|
||||
|
||||
const jobs = [];
|
||||
const uebersprungen = [];
|
||||
const mkJob = async (order, typ, fmt) => {
|
||||
@@ -1356,7 +1381,7 @@ const handler = (router, { services, getSchema, logger }) => {
|
||||
jobs.push(await svc('jobs').createOne({
|
||||
order: order.id, machine: cfg.machine, type: typ, template: cfg.template,
|
||||
format: fmt.key, format_label: cfg.label || fmt.label, params: clampParams(cfg.params),
|
||||
status: 'queued', priority: prioFor(cfg.machine),
|
||||
status: 'queued', priority: prioFor(cfg.machine), position: await nextPos(cfg.machine),
|
||||
}));
|
||||
};
|
||||
for (const order of orders) {
|
||||
|
||||
Reference in New Issue
Block a user