Lagerort-QR + Zuordnen per Scan

Web: druckbare QR-Etiketten fuer Lagerorte (Locations-Seite) und Route /l/<id>
(zeigt den Ort im Browser). Geteilter QR-Helfer (web/src/qr.jsx).

iOS: neuer Ablauf "Ort zuordnen" - erst Einzelstueck-QR (…/i/<UID>) scannen, dann
Lagerort-QR (…/l/<ID>); das Stueck wird dem Ort zugewiesen, danach gleich das
naechste. Plus die zuvor gebaute "Nachschlagen"-Kachel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-26 08:09:00 +02:00
parent 953e0aa483
commit 7f9895245c
8 changed files with 198 additions and 3 deletions

View File

@@ -0,0 +1,38 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { api } from "../api";
import Icon from "../components/Icon";
/**
* Ziel eines gescannten Lagerort-QR (/l/<id>). Im Browser zeigt es nur den
* Namen; das eigentliche Zuordnen (Stück → Ort) läuft über die App.
*/
export default function LocationResolve() {
const { id } = useParams();
const [name, setName] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
api.listLocations()
.then((ls) => {
const l = ls.find((x) => String(x.id) === String(id));
if (l) setName(l.name);
else setError("Lagerort nicht gefunden.");
})
.catch((e) => setError(e.message));
}, [id]);
return (
<div>
<div className="page-head">
<div>
<h1>Lagerort {name || `#${id}`}</h1>
<div className="sub">
{error || "Diesen QR-Code in der App scannen (Ort zuordnen), um Einzelstücke hier einzuordnen."}
</div>
</div>
</div>
{error && <div className="alert error"><Icon name="alert" size={16} />{error}</div>}
</div>
);
}

View File

@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { api } from "../api";
import { useConfirm } from "../confirm";
import Icon from "../components/Icon";
import { QrImg, printQrLabels } from "../qr";
export default function Locations() {
const confirm = useConfirm();
@@ -71,6 +72,12 @@ export default function Locations() {
<h1>Lagerorte</h1>
<div className="sub">Orte lassen sich verschachteln (z.B. Keller Regal 2 Fach A)</div>
</div>
{locations.length > 0 && (
<button className="btn" onClick={() => printQrLabels("Lagerort-Etiketten",
locations.map((l) => ({ text: `${window.location.origin}/l/${l.id}`, line1: l.name, line2: "Lagerort" })))}>
<Icon name="download" size={16} />QR-Etiketten drucken
</button>
)}
</div>
{error && <div className="alert error"><Icon name="alert" size={16} />{error}</div>}
@@ -108,9 +115,12 @@ export default function Locations() {
<span className="badge">in {nameById[l.parent_id]}</span>
)}
</span>
<button className="btn-icon danger" onClick={() => remove(l.id)} title="Löschen">
<Icon name="trash" size={16} />
</button>
<span style={{ display: "flex", alignItems: "center", gap: 8 }}>
<QrImg text={`${window.location.origin}/l/${l.id}`} size={44} />
<button className="btn-icon danger" onClick={() => remove(l.id)} title="Löschen">
<Icon name="trash" size={16} />
</button>
</span>
</li>
))}
{locations.length === 0 && <li className="empty">Noch keine Lagerorte.</li>}