Konsolidiere Spec-Kurzbeschreibung in ein gemeinsames Modul
main.js, result-overlay.js und session-list.js loesten dieselbe Aufgabe
(Spec-Felder zu einer Lesehilfe zusammenfassen) bislang mit drei leicht
unterschiedlichen Implementierungen - unterschiedliche Feldauswahl und
unterschiedlicher Umgang mit fehlenden Werten. Neues src/ui/describe-spec.js
buendelt das in describeSpec(spec, { placeholders }): ohne Platzhalter fuer
die kurze Treffer-Rueckmeldung und die "Zuletzt"-Zeile, mit Platzhalter fuer
die Sitzungsliste, wo feste Feldreihenfolge Wiedererkennung schafft.
Nutzt bei main.js zugleich die bereits vorhandene, jetzt exportierte
nextStackId aus session.js statt einer Zeile-fuer-Zeile-Kopie derselben
Buchstaben-Vergabe (nextFreeStackId entfaellt komplett).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+4
-18
@@ -6,7 +6,7 @@ import { runOcr, isOcrAvailable } from './ocr.js';
|
||||
import { recognize } from './pipeline.js';
|
||||
import {
|
||||
createSession, proposeAssignment, commitAssignment,
|
||||
undoLast, moveEntry, removeEntry,
|
||||
undoLast, moveEntry, removeEntry, nextStackId,
|
||||
} from './session.js';
|
||||
import { saveSession, loadSession, clearSession } from './storage.js';
|
||||
import { renderScanView } from './ui/scan-view.js';
|
||||
@@ -14,6 +14,7 @@ import { showResult } from './ui/result-overlay.js';
|
||||
import { askForStack } from './ui/ambiguous-dialog.js';
|
||||
import { askResumeSession } from './ui/resume-dialog.js';
|
||||
import { renderSessionList } from './ui/session-list.js';
|
||||
import { describeSpec } from './ui/describe-spec.js';
|
||||
|
||||
const app = document.querySelector('#app');
|
||||
const store = window.localStorage;
|
||||
@@ -64,22 +65,7 @@ function syncView() {
|
||||
|
||||
/** Kurzbeschreibung fuer die "Zuletzt"-Zeile. */
|
||||
function describeEntry(spec, stackId) {
|
||||
const parts = [
|
||||
spec.capacityGb ? `${spec.capacityGb}GB` : '?',
|
||||
spec.speed ?? '?',
|
||||
spec.formFactor ?? '',
|
||||
].filter(Boolean);
|
||||
return `${parts.join(' ')} → Stapel ${stackId}`;
|
||||
}
|
||||
|
||||
/** Naechster noch nicht vergebener Stapel-Buchstabe - fuer den Fall, dass der Nutzer im Rot-Dialog ausdruecklich einen neuen Stapel waehlt. */
|
||||
function nextFreeStackId(targetSession) {
|
||||
const used = new Set(targetSession.stacks.map((stack) => stack.id));
|
||||
for (const letter of 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
|
||||
if (!used.has(letter)) return letter;
|
||||
}
|
||||
// Nach Z weiter mit A2, B2, ... - in der Praxis nie erreicht (siehe session.js).
|
||||
return `A${targetSession.stacks.length}`;
|
||||
return `${describeSpec(spec)} → Stapel ${stackId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +110,7 @@ async function processCapture(getFrame) {
|
||||
stackId = answer.stackId;
|
||||
} else {
|
||||
// "neuer Stapel": unabhaengig von jeder Vermutung der naechste freie Buchstabe.
|
||||
stackId = nextFreeStackId(targetSession);
|
||||
stackId = nextStackId(targetSession);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Rein darstellend: baut aus Spec-Feldern eine kurze, deutsche Lesehilfe.
|
||||
// Kein window/document noetig - liefert nur eine Zeichenkette.
|
||||
|
||||
const PLACEHOLDER = '?';
|
||||
|
||||
/**
|
||||
* Fasst Kapazitaet, Rank, Geschwindigkeit und Bauform eines Specs zu einer
|
||||
* kurzen Lesehilfe zusammen. Frueher gab es davon drei leicht
|
||||
* unterschiedliche Fassungen (main.js, result-overlay.js, session-list.js) -
|
||||
* mit unterschiedlichen Feldern und unterschiedlichem Umgang mit fehlenden
|
||||
* Werten. Diese eine Fassung deckt beide Beduerfnisse ueber einen Schalter ab:
|
||||
*
|
||||
* - `placeholders: false` (Vorgabe): fehlende Felder werden weggelassen,
|
||||
* ein vollstaendig leeres Spec ergibt "ohne Angaben". Passend fuer die
|
||||
* kurz eingeblendete Treffer-Rueckmeldung und die "Zuletzt"-Zeile, wo ein
|
||||
* Platzhalter pro fehlendem Feld mehr verwirrt als hilft.
|
||||
* - `placeholders: true`: jedes Feld erscheint, fehlende als "?". Passend
|
||||
* fuer die Sitzungsliste, wo die feste Reihenfolge der vier Felder ueber
|
||||
* viele Stapel hinweg Wiedererkennung schafft.
|
||||
*
|
||||
* @param {object} spec
|
||||
* @param {{placeholders?: boolean}} [options]
|
||||
* @returns {string}
|
||||
*/
|
||||
export function describeSpec(spec, { placeholders = false } = {}) {
|
||||
const fields = [
|
||||
spec.capacityGb ? `${spec.capacityGb}GB` : null,
|
||||
spec.rank ?? null,
|
||||
spec.speed ?? null,
|
||||
spec.formFactor ?? null,
|
||||
];
|
||||
|
||||
if (placeholders) {
|
||||
return fields.map((value) => value ?? PLACEHOLDER).join(' ');
|
||||
}
|
||||
|
||||
const present = fields.filter(Boolean);
|
||||
return present.length > 0 ? present.join(' ') : 'ohne Angaben';
|
||||
}
|
||||
+13
-21
@@ -1,27 +1,19 @@
|
||||
function beschreibung(spec) {
|
||||
const teile = [
|
||||
spec.capacityGb ? `${spec.capacityGb}GB` : null,
|
||||
spec.rank,
|
||||
spec.speed,
|
||||
spec.formFactor,
|
||||
].filter(Boolean);
|
||||
return teile.join(' ') || 'ohne Angaben';
|
||||
}
|
||||
import { describeSpec } from './describe-spec.js';
|
||||
|
||||
/** Haelt pro Root die aktuell sichtbare Rueckmeldung samt Zeitgeber fest. */
|
||||
const aktuelleRueckmeldung = new WeakMap();
|
||||
const currentFeedback = new WeakMap();
|
||||
|
||||
/**
|
||||
* Blendet die Treffer-Rueckmeldung ein und nach kurzer Zeit wieder aus.
|
||||
* Gruen bei Barcode, gelb bei OCR. Keine Eingabe noetig.
|
||||
*/
|
||||
export function showResult(root, { stackId, spec, confidence }, dauerMs = 1200) {
|
||||
const vorherige = aktuelleRueckmeldung.get(root);
|
||||
if (vorherige) {
|
||||
clearTimeout(vorherige.timer);
|
||||
vorherige.overlay.remove();
|
||||
vorherige.resolve();
|
||||
aktuelleRueckmeldung.delete(root);
|
||||
export function showResult(root, { stackId, spec, confidence }, durationMs = 1200) {
|
||||
const previous = currentFeedback.get(root);
|
||||
if (previous) {
|
||||
clearTimeout(previous.timer);
|
||||
previous.overlay.remove();
|
||||
previous.resolve();
|
||||
currentFeedback.delete(root);
|
||||
}
|
||||
|
||||
const overlay = document.createElement('div');
|
||||
@@ -31,16 +23,16 @@ export function showResult(root, { stackId, spec, confidence }, dauerMs = 1200)
|
||||
<div class="detail"></div>
|
||||
<div class="pn"></div>
|
||||
`;
|
||||
overlay.querySelector('.detail').textContent = beschreibung(spec);
|
||||
overlay.querySelector('.detail').textContent = describeSpec(spec);
|
||||
overlay.querySelector('.pn').textContent = spec.partNumber ?? '';
|
||||
root.appendChild(overlay);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const timer = setTimeout(() => {
|
||||
overlay.remove();
|
||||
aktuelleRueckmeldung.delete(root);
|
||||
currentFeedback.delete(root);
|
||||
resolve();
|
||||
}, dauerMs);
|
||||
aktuelleRueckmeldung.set(root, { overlay, timer, resolve });
|
||||
}, durationMs);
|
||||
currentFeedback.set(root, { overlay, timer, resolve });
|
||||
});
|
||||
}
|
||||
|
||||
+3
-12
@@ -3,16 +3,7 @@
|
||||
// Sitzung. Kennt weder Kamera noch Erkennung - alles kommt ueber die
|
||||
// Rueckrufe, genau wie bei scan-view.js und ambiguous-dialog.js.
|
||||
|
||||
/** Kurzbeschreibung eines Specs fuer Stapel-Kopfzeilen und Eintrags-Zeilen ohne Teilenummer. */
|
||||
function describeSpec(spec) {
|
||||
const parts = [
|
||||
spec.capacityGb ? `${spec.capacityGb}GB` : '?',
|
||||
spec.rank ?? '?',
|
||||
spec.speed ?? '?',
|
||||
spec.formFactor ?? '?',
|
||||
];
|
||||
return parts.join(' ');
|
||||
}
|
||||
import { describeSpec } from './describe-spec.js';
|
||||
|
||||
/**
|
||||
* Kurzbezeichnung der Erkennungsquelle eines Eintrags - beim Sortieren
|
||||
@@ -52,7 +43,7 @@ export function renderSessionList(root, session, { onMove, onRemove, onEndSessio
|
||||
header.className = 'detail';
|
||||
header.style.textAlign = 'left';
|
||||
header.style.marginTop = '12px';
|
||||
header.textContent = `Stapel ${stack.id} — ${stack.count}x ${describeSpec(stack.spec)}`;
|
||||
header.textContent = `Stapel ${stack.id} — ${stack.count}x ${describeSpec(stack.spec, { placeholders: true })}`;
|
||||
body.appendChild(header);
|
||||
|
||||
for (const entry of session.entries.filter((candidate) => candidate.stackId === stack.id)) {
|
||||
@@ -65,7 +56,7 @@ export function renderSessionList(root, session, { onMove, onRemove, onEndSessio
|
||||
label.style.flex = '1';
|
||||
label.style.fontSize = '14px';
|
||||
label.style.textAlign = 'left';
|
||||
label.textContent = entry.spec.partNumber ?? describeSpec(entry.spec);
|
||||
label.textContent = entry.spec.partNumber ?? describeSpec(entry.spec, { placeholders: true });
|
||||
row.appendChild(label);
|
||||
|
||||
const sourceLabel = document.createElement('span');
|
||||
|
||||
Reference in New Issue
Block a user