Direkte Eingabe der Warengruppe biem Erfassen ergänzt

This commit is contained in:
2026-08-10 11:00:21 +02:00
parent a2d911f7e3
commit a917c5f64e
4 changed files with 74 additions and 41 deletions

View File

@@ -33,8 +33,10 @@ export async function listDetailView(
let banner = null;
/** article_id -> { best_market_ids, best_cents, spread_cents, prices } */
let priceHints = new Map();
// Zuletzt im Formular gewählter Markt - überlebt den Ansichtswechsel.
// Zuletzt im Formular gewählter Markt und Warengruppe - überleben
// den Ansichtswechsel.
let lastMarket = null;
let lastCategory = null;
// -------------------------------------------------------------------
// Laden
@@ -64,6 +66,8 @@ export async function listDetailView(
// cacheGet liefert den gespeicherten Wert unmittelbar; ein noch
// nie gesetzter Schlüssel ergibt undefined.
lastMarket = await db.cacheGet(`lastmarket:${listId}`).catch(() => null) || null;
lastCategory =
await db.cacheGet(`lastcategory:${listId}`).catch(() => null) || null;
markets = (await db.cacheGet(`markets:${listId}`)) || [];
categories = (await db.cacheGet(`categories:${listId}`)) || [];
meta = await db.cacheGet(`meta:${listId}`);
@@ -430,11 +434,13 @@ export async function listDetailView(
: null;
function markSelection() {
if (!marketField) return;
// Leeres Attribut = keine Vorgabe; das Stylesheet hebt eine
// getroffene Auswahl hervor.
if (marketField.value) marketField.removeAttribute("data-empty");
else marketField.setAttribute("data-empty", "");
for (const field of [marketField, categoryField]) {
if (!field) continue;
if (field.value) field.removeAttribute("data-empty");
else field.setAttribute("data-empty", "");
}
}
if (marketField && lastMarket
@@ -443,11 +449,23 @@ export async function listDetailView(
}
markSelection();
// Die Warengruppe bleibt im Formular unsichtbar: Sie kommt aus der
// Vorgabe des Artikels oder aus einem Vorschlag. Ein zweites
// Auswahlfeld würde die Zeile überladen, ohne oft gebraucht zu
// werden.
let chosenCategory = null;
const categoryField = categories.length
? el("select.category-select", {
title: "Warengruppe für diesen Eintrag",
onchange: () => {
markSelection();
db.cacheSet(`lastcategory:${listId}`, categoryField.value || null)
.catch(() => {});
},
},
el("option", { value: "" }, "— Vorgabe des Artikels —"),
categories.map((c) => el("option", { value: c.id }, c.name)))
: null;
if (categoryField && lastCategory
&& categories.some((c) => c.id === lastCategory)) {
categoryField.value = lastCategory;
}
const suggestionBox = el("ul.suggestions", { hidden: true });
@@ -469,12 +487,18 @@ export async function listDetailView(
variantField.value = suggestion.variant || "";
// Zuletzt verwendeter Markt des Artikels - genau das, was man
// beim Wiederholen eines Einkaufs erwartet.
// Zuletzt verwendeter Markt und zuletzt verwendete Warengruppe
// des Artikels - genau das, was man beim Wiederholen eines
// Einkaufs erwartet.
if (marketField && suggestion.market_id
&& markets.some((m) => m.id === suggestion.market_id)) {
marketField.value = suggestion.market_id;
markSelection();
}
chosenCategory = suggestion.category_id || null;
if (categoryField && suggestion.category_id
&& categories.some((c) => c.id === suggestion.category_id)) {
categoryField.value = suggestion.category_id;
}
markSelection();
closeSuggestions();
// Zum Ändern einladen, nicht zum Abschicken drängen.
qtyField.focus();
@@ -488,10 +512,9 @@ export async function listDetailView(
clearTimeout(suggestTimer);
const value = nameField.value.trim();
// Eine frei getippte Eingabe hebt die aus einem Vorschlag
// übernommene Warengruppe auf. Der Markt bleibt stehen: Er ist
// jetzt sichtbar ausgewählt, und wer ihn nicht will, ändert ihn.
chosenCategory = null;
// Markt und Warengruppe bleiben stehen: Beide sind sichtbar
// ausgewählt, und wer sie nicht will, ändert sie. Sie
// stillschweigend zurückzusetzen wäre überraschender.
if (value.length < 3 || !state.online) {
closeSuggestions();
@@ -551,16 +574,18 @@ export async function listDetailView(
variant: variantField.value.trim() || null,
};
if (marketField && marketField.value) payload.market_id = marketField.value;
if (chosenCategory) payload.category_id = chosenCategory;
if (categoryField && categoryField.value) {
payload.category_id = categoryField.value;
}
nameField.value = "";
countField.value = "";
qtyField.value = "";
unitField.value = "";
variantField.value = "";
chosenCategory = null;
// Der Markt bleibt absichtlich stehen: Wer eine Liste füllt,
// trägt meist mehrere Artikel für denselben Laden ein.
// Markt und Warengruppe bleiben absichtlich stehen: Wer eine
// Liste füllt, trägt meist mehrere Artikel für denselben Laden
// und oft auch für dasselbe Regal ein.
closeSuggestions();
await change("item.create", payload);
@@ -599,6 +624,9 @@ export async function listDetailView(
variant: variantField.value.trim() || null,
};
if (marketField && marketField.value) extras.market_id = marketField.value;
if (categoryField && categoryField.value) {
extras.category_id = categoryField.value;
}
// Bereits im eigenen Bestand: ohne Rückfrage auf die Liste.
if (lookup.source === "catalog") {
@@ -628,6 +656,8 @@ export async function listDetailView(
variant: confirmed.variant || null,
...(marketField && marketField.value
? { market_id: marketField.value } : {}),
...(categoryField && categoryField.value
? { category_id: categoryField.value } : {}),
});
}
@@ -638,7 +668,8 @@ export async function listDetailView(
return el("div.add-row", {},
el("div.name-wrap", {}, nameField, suggestionBox),
el("div.add-fields", {}, countField, qtyField, unitField, variantField),
marketField ? el("div.add-market", {}, marketField) : null,
categoryField ? el("div.add-select", {}, categoryField) : null,
marketField ? el("div.add-select", {}, marketField) : null,
el("div.add-actions", {},
cameraAvailable()
? el("button.secondary", {