Web: Chargen auswaehlen und Lagerort der Auswahl setzen

Chargenliste bekommt Auswahl-Checkboxen. Das obere Panel wirkt jetzt auf die
Auswahl: "N ausgewaehlt -> Lagerort setzen" (leer = Ort entfernen, z.B. beim
Aufloesen eines Orts). Schnellwahl "alle sichtbaren" (respektiert Filter) und
"alle ohne Lagerort". DataTable meldet dafuer die sichtbaren Zeilen
(onVisibleRows).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-29 14:04:19 +02:00
parent 826f4df4bd
commit 51c02091ed
2 changed files with 59 additions and 11 deletions

View File

@@ -32,6 +32,8 @@ export default function Charges() {
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
const [bulkLoc, setBulkLoc] = useState("");
const [selected, setSelected] = useState(() => new Set());
const [visible, setVisible] = useState([]); // aktuell gefiltert sichtbare Chargen
async function load() {
setLoading(true);
@@ -49,6 +51,17 @@ export default function Charges() {
const ohneOrt = useMemo(() => lots.filter((l) => !l.location_id), [lots]);
function toggle(id) {
setSelected((alt) => {
const neu = new Set(alt);
if (neu.has(id)) neu.delete(id); else neu.add(id);
return neu;
});
}
// Menge von IDs zur Auswahl hinzufügen (für „alle sichtbaren/ohne Ort").
function selectAll(ids) { setSelected(new Set(ids)); }
function clearSelection() { setSelected(new Set()); }
async function setLocation(lotId, locId) {
setError(null);
try {
@@ -59,12 +72,14 @@ export default function Charges() {
}
}
async function applyBulk() {
if (!bulkLoc || ohneOrt.length === 0) return;
// Lagerort für die aktuell ausgewählten Chargen setzen (leer = Ort entfernen).
async function applyToSelection() {
if (selected.size === 0) return;
setError(null);
try {
await api.bulkLotLocation(ohneOrt.map((l) => l.id), bulkLoc);
await api.bulkLotLocation([...selected], bulkLoc);
setBulkLoc("");
clearSelection();
await load();
} catch (err) {
setError(err.message);
@@ -72,6 +87,12 @@ export default function Charges() {
}
const columns = [
{ key: "select", header: "", label: "Auswahl", fixed: true, width: 44,
render: (l) => (
<input type="checkbox" style={{ width: "auto", margin: 0, cursor: "pointer" }}
checked={selected.has(l.id)} onChange={() => toggle(l.id)}
aria-label={`${l.product_name} auswählen`} />
) },
{ key: "thumb", header: "", label: "Bild", fixed: true, width: 56,
render: (l) => <ProduktThumb productId={l.product_id} alt={l.product_name} /> },
{ key: "product", header: "Artikel", grow: true, min: 180,
@@ -120,26 +141,43 @@ export default function Charges() {
{error && <div className="alert error"><Icon name="alert" size={16} />{error}</div>}
{isAdmin && ohneOrt.length > 0 && (
{isAdmin && (
<div className="card" style={{ marginBottom: "var(--sp-3)" }}>
<div className="card-head"><Icon name="location" /><h2>Lagerort für alle ohne Ort setzen</h2></div>
<div className="card-head"><Icon name="location" /><h2>Lagerort für ausgewählte Chargen setzen</h2></div>
<p className="muted small mt-0">
{ohneOrt.length} Charge(n) haben noch keinen Lagerort. Ort wählen und in einem Klick allen zuweisen.
{selected.size > 0
? `${selected.size} Charge(n) ausgewählt diese bekommen den gewählten Lagerort (leer = Ort entfernen).`
: "Chargen in der Tabelle anhaken, dann hier den Lagerort setzen. Oder unten schnell alle sichtbaren / alle ohne Ort auswählen."}
</p>
<div className="field-inline">
<select value={bulkLoc} onChange={(e) => setBulkLoc(e.target.value)} style={{ maxWidth: 360 }}>
<option value=""> Lagerort wählen </option>
<div className="field-inline" style={{ flexWrap: "wrap" }}>
<select value={bulkLoc} onChange={(e) => setBulkLoc(e.target.value)} style={{ maxWidth: 360 }}
disabled={selected.size === 0}>
<option value=""> ohne Lagerort </option>
{locationOptions(locations).map((o) => <option key={o.id} value={o.id}>{o.label}</option>)}
</select>
<button className="btn primary" disabled={!bulkLoc} onClick={applyBulk}>
<Icon name="check" size={16} />Auf alle {ohneOrt.length} anwenden
<button className="btn primary" disabled={selected.size === 0} onClick={applyToSelection}>
<Icon name="check" size={16} />Auf {selected.size} Auswahl anwenden
</button>
</div>
<div className="field-inline" style={{ flexWrap: "wrap", marginTop: "var(--sp-2)", marginBottom: 0 }}>
<button type="button" className="btn sm ghost" onClick={() => selectAll(visible.map((l) => l.id))}
disabled={visible.length === 0}>
Alle {visible.length} sichtbaren auswählen
</button>
<button type="button" className="btn sm ghost" onClick={() => selectAll(ohneOrt.map((l) => l.id))}
disabled={ohneOrt.length === 0}>
Alle {ohneOrt.length} ohne Lagerort auswählen
</button>
{selected.size > 0 && (
<button type="button" className="btn sm ghost" onClick={clearSelection}>Auswahl aufheben</button>
)}
</div>
</div>
)}
<div className="card">
<DataTable id="charges" columns={columns} rows={lots} loading={loading}
onVisibleRows={setVisible}
getRowKey={(l) => l.id} empty="Keine Chargen im Bestand." />
</div>
</div>