浏览代码

feat: map Homelegance Excel columns for product catalog import

- Model, Description, Long Description, Collection Name
- Feature 1-10 joined with " | " separator
- Additional Dimension 1-10 + Setup Size joined as dimensions
- UNIT PRICE / PROMO PRICE (promo takes priority)
- AVAILABILITY, URL fields mapped correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tony T 2 天之前
父节点
当前提交
cc531abf78
共有 1 个文件被更改,包括 35 次插入15 次删除
  1. 35 15
      client/src/pages/DataSources.tsx

+ 35 - 15
client/src/pages/DataSources.tsx

@@ -191,26 +191,46 @@ export default function DataSources() {
   const handleImportProducts = () => {
     const rows = parseCSV(productCsvText);
     if (rows.length === 0) { toast.error("No CSV rows found"); return; }
-    const first = rows[0].map(c => c.toLowerCase());
+    const first = rows[0].map(c => c.trim().toLowerCase());
     const hasHeader = first.includes("model");
     const dataRows = hasHeader ? rows.slice(1) : rows;
-    const idx = (name: string) => hasHeader ? first.indexOf(name.toLowerCase()) : -1;
-    const cols = ["model","description","categories","collection","price","availability","features","dimensions","imageurl"];
-    const colIdx: Record<string, number> = {};
-    cols.forEach(c => { colIdx[c] = idx(c); });
+    const idx = (name: string) => first.indexOf(name.trim().toLowerCase());
+
+    // ── Homelegance Excel column mapping ──────────────────────────────
+    const col = {
+      model:          idx("model"),
+      description:    idx("description"),
+      longDesc:       idx("long description"),
+      collection:     idx("collection name"),
+      price:          idx("unit price"),
+      promoPrice:     idx("promo price"),
+      availability:   idx("availability"),
+      setupSize:      idx("setup size"),
+      url:            idx("url"),
+      // Feature 1–10
+      features:       Array.from({ length: 10 }, (_, i) => idx(`feature ${i + 1}`)),
+      // Additional Dimension 1–10
+      dimensions:     Array.from({ length: 10 }, (_, i) => idx(`additional dimension ${i + 1}`)),
+    };
+
+    const get = (r: string[], i: number) => (i >= 0 ? r[i]?.trim() || "" : "");
+    const joinCols = (r: string[], indices: number[]) =>
+      indices.map(i => get(r, i)).filter(Boolean).join(" | ") || undefined;
+
     const items = dataRows
-      .filter(r => r[colIdx.model >= 0 ? colIdx.model : 0])
+      .filter(r => get(r, col.model))
       .map(r => ({
-        model: r[colIdx.model >= 0 ? colIdx.model : 0] || "",
-        description: colIdx.description >= 0 ? r[colIdx.description] || undefined : undefined,
-        categories: colIdx.categories >= 0 ? r[colIdx.categories] || undefined : undefined,
-        collection: colIdx.collection >= 0 ? r[colIdx.collection] || undefined : undefined,
-        price: colIdx.price >= 0 ? r[colIdx.price] || undefined : undefined,
-        availability: colIdx.availability >= 0 ? r[colIdx.availability] || undefined : undefined,
-        features: colIdx.features >= 0 ? r[colIdx.features] || undefined : undefined,
-        dimensions: colIdx.dimensions >= 0 ? r[colIdx.dimensions] || undefined : undefined,
-        imageUrl: colIdx.imageurl >= 0 ? r[colIdx.imageurl] || undefined : undefined,
+        model:        get(r, col.model),
+        description:  get(r, col.description) || get(r, col.longDesc) || undefined,
+        collection:   get(r, col.collection) || undefined,
+        price:        get(r, col.promoPrice) || get(r, col.price) || undefined,
+        availability: get(r, col.availability) || undefined,
+        features:     joinCols(r, col.features),
+        dimensions:   [get(r, col.setupSize), ...col.dimensions.map(i => get(r, i))]
+                        .filter(Boolean).join(" | ") || undefined,
+        imageUrl:     get(r, col.url) || undefined,
       }));
+
     if (items.length === 0) { toast.error("No valid product rows"); return; }
     importProducts.mutate({ products: items, replaceAll: replaceAllProducts });
   };