From b4b203a117abb3c6527fbc15d82cb65f2d089b23 Mon Sep 17 00:00:00 2001
From: Scarriffle
Date: Sun, 26 Jul 2026 09:54:35 +0200
Subject: [PATCH] Etiketten-Export: Trennzeichen waehlbar
(Komma/Semikolon/Tab), gemerkt
P-touch will Komma, wir hatten fest Semikolon - jetzt einstellbar und in
localStorage gemerkt, sodass man es nur einmal setzt. Standard ist Komma.
Anfuehrungszeichen werden passend zum gewaehlten Trennzeichen gesetzt.
Co-Authored-By: Claude Opus 4.8
---
web/src/pages/Transfer.jsx | 30 ++++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/web/src/pages/Transfer.jsx b/web/src/pages/Transfer.jsx
index a967c10..42e5661 100644
--- a/web/src/pages/Transfer.jsx
+++ b/web/src/pages/Transfer.jsx
@@ -4,17 +4,20 @@ import { useConfirm } from "../confirm";
import Icon from "../components/Icon";
import { asTree } from "../categoryTree";
-// Baut die Etiketten-CSV (Semikolon, BOM für Excel). QR-Inhalt = Link aufs Stück.
-function buildLabelCsv(rows, origin) {
+// Baut die Etiketten-CSV mit wählbarem Trennzeichen (BOM für Excel-Umlaute).
+// QR-Inhalt = Link aufs Stück.
+function buildLabelCsv(rows, origin, delim = ",") {
const head = ["QR-Inhalt", "UID", "Produkt", "Marke", "Kategorie", "Lagerort"];
+ const delimRe = delim === "\t" ? "\\t" : delim;
+ const needsQuote = new RegExp(`[${delimRe}"\\n\\r]`);
const esc = (v) => {
const s = String(v ?? "");
- return /[";\n\r]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
+ return needsQuote.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
};
- const lines = [head.join(";")];
+ const lines = [head.map(esc).join(delim)];
for (const r of rows) {
lines.push([`${origin}/i/${r.uid}`, r.uid, r.product, r.brand, r.category, r.location]
- .map(esc).join(";"));
+ .map(esc).join(delim));
}
return "" + lines.join("\r\n");
}
@@ -32,9 +35,16 @@ export default function Transfer() {
const [selCats, setSelCats] = useState(() => new Set());
const [labelBusy, setLabelBusy] = useState(false);
const [labelInfo, setLabelInfo] = useState(null);
+ // Gemerktes Trennzeichen (Standard Komma – P-touch mag das lieber).
+ const [labelDelim, setLabelDelim] = useState(() => localStorage.getItem("label_delim") || ",");
useEffect(() => { api.listCategories().then(setCategories).catch(() => {}); }, []);
+ function changeDelim(v) {
+ setLabelDelim(v);
+ localStorage.setItem("label_delim", v);
+ }
+
function toggleCat(id, on) {
setSelCats((prev) => {
const neu = new Set(prev);
@@ -50,7 +60,7 @@ export default function Transfer() {
try {
const rows = await api.labelRows([...selCats]);
if (!rows.length) { setLabelInfo("Keine Einzelstücke in der Auswahl."); return; }
- const csv = buildLabelCsv(rows, window.location.origin);
+ const csv = buildLabelCsv(rows, window.location.origin, labelDelim);
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
@@ -206,6 +216,14 @@ export default function Transfer() {
verknüpfen – sie erzeugt QR-Code und Text automatisch. Kategorien wählen
(Unterkategorien sind enthalten); ohne Auswahl kommen alle Einzelstücke.
+
{asTree(categories).filter((c) => c.tracking === "object").map((c) => (