import { useState } from "react"; import { Button } from "./ui/button"; import { Input } from "./ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "./ui/select"; import { Plus, Search } from "lucide-react"; import ProductTable from "./ProductTable"; import ProductDialog from "./ProductDialog"; export type ProductType = "raw_material" | "finished_product"; export type ProductUnit = "kg" | "g" | "l" | "ml" | "piece" | "box" | "pack" | "bottle" | "can" | "jar" | "bag" | "basin" | "container"; export interface Product { id: string; product_code: string; // 商品編號(系統自動生成) name: string; type: ProductType; unit: ProductUnit; barcode_value: string; // 條碼內容(預設等於商品編號) createdAt: string; } export default function ProductManagement() { const [products, setProducts] = useState([ // 原物料 { id: "1", product_code: "RM0001", name: "紅糖", type: "raw_material", unit: "pack", barcode_value: "RM0001", createdAt: "2025-11-01", }, { id: "2", product_code: "RM0002", name: "白糖", type: "raw_material", unit: "pack", barcode_value: "RM0002", createdAt: "2025-11-01", }, { id: "3", product_code: "RM0003", name: "砂糖", type: "raw_material", unit: "pack", barcode_value: "RM0003", createdAt: "2025-11-02", }, { id: "4", product_code: "RM0004", name: "全脂牛奶-小", type: "raw_material", unit: "bottle", barcode_value: "RM0004", createdAt: "2025-11-02", }, { id: "5", product_code: "RM0005", name: "煉乳", type: "raw_material", unit: "can", barcode_value: "RM0005", createdAt: "2025-11-03", }, { id: "6", product_code: "RM0006", name: "椰奶", type: "raw_material", unit: "can", barcode_value: "RM0006", createdAt: "2025-11-03", }, { id: "7", product_code: "RM0007", name: "鮮奶油", type: "raw_material", unit: "can", barcode_value: "RM0007", createdAt: "2025-11-04", }, { id: "8", product_code: "RM0008", name: "粉圓原料(生珍珠)", type: "raw_material", unit: "pack", barcode_value: "RM0008", createdAt: "2025-11-04", }, { id: "9", product_code: "RM0009", name: "仙草凍粉", type: "raw_material", unit: "pack", barcode_value: "RM0009", createdAt: "2025-11-05", }, { id: "10", product_code: "RM0010", name: "芋頭塊(原料)", type: "raw_material", unit: "kg", barcode_value: "RM0010", createdAt: "2025-11-05", }, { id: "11", product_code: "RM0011", name: "地瓜塊(原料)", type: "raw_material", unit: "kg", barcode_value: "RM0011", createdAt: "2025-11-06", }, { id: "12", product_code: "RM0012", name: "綠豆(乾)", type: "raw_material", unit: "kg", barcode_value: "RM0012", createdAt: "2025-11-06", }, { id: "13", product_code: "RM0013", name: "紅豆(乾)", type: "raw_material", unit: "kg", barcode_value: "RM0013", createdAt: "2025-11-07", }, { id: "14", product_code: "RM0014", name: "檸檬原汁", type: "raw_material", unit: "bottle", barcode_value: "RM0014", createdAt: "2025-11-07", }, { id: "15", product_code: "RM0015", name: "抹茶粉", type: "raw_material", unit: "can", barcode_value: "RM0015", createdAt: "2025-11-08", }, { id: "16", product_code: "RM0016", name: "可可粉", type: "raw_material", unit: "can", barcode_value: "RM0016", createdAt: "2025-11-08", }, { id: "17", product_code: "RM0017", name: "蜂蜜", type: "raw_material", unit: "bottle", barcode_value: "RM0017", createdAt: "2025-11-09", }, { id: "18", product_code: "RM0018", name: "果糖", type: "raw_material", unit: "can", barcode_value: "RM0018", createdAt: "2025-11-09", }, // 半成品 { id: "19", product_code: "SF0001", name: "粉粿原漿", type: "finished_product", unit: "bag", barcode_value: "SF0001", createdAt: "2025-11-10", }, { id: "20", product_code: "SF0002", name: "黑糖粉圓(未加糖)", type: "finished_product", unit: "basin", barcode_value: "SF0002", createdAt: "2025-11-10", }, { id: "21", product_code: "SF0003", name: "熟紅豆(未加糖)", type: "finished_product", unit: "basin", barcode_value: "SF0003", createdAt: "2025-11-11", }, { id: "22", product_code: "SF0004", name: "熟綠豆(未加糖)", type: "finished_product", unit: "basin", barcode_value: "SF0004", createdAt: "2025-11-11", }, { id: "23", product_code: "SF0005", name: "芋頭泥(無調味)", type: "finished_product", unit: "box", barcode_value: "SF0005", createdAt: "2025-11-12", }, { id: "24", product_code: "SF0006", name: "地瓜泥(無調味)", type: "finished_product", unit: "box", barcode_value: "SF0006", createdAt: "2025-11-12", }, { id: "25", product_code: "SF0007", name: "仙草原凍(整塊)", type: "finished_product", unit: "basin", barcode_value: "SF0007", createdAt: "2025-11-13", }, ]); const [searchTerm, setSearchTerm] = useState(""); const [typeFilter, setTypeFilter] = useState("all"); const [isDialogOpen, setIsDialogOpen] = useState(false); const [editingProduct, setEditingProduct] = useState(null); const filteredProducts = products.filter((product) => { const matchesSearch = product.name.toLowerCase().includes(searchTerm.toLowerCase()) || product.product_code.toLowerCase().includes(searchTerm.toLowerCase()) || product.barcode_value.includes(searchTerm); const matchesType = typeFilter === "all" || product.type === typeFilter; return matchesSearch && matchesType; }); const handleAddProduct = () => { setEditingProduct(null); setIsDialogOpen(true); }; const handleEditProduct = (product: Product) => { setEditingProduct(product); setIsDialogOpen(true); }; // 生成新的商品編號(根據類型使用不同前綴) const generateProductCode = (productType: ProductType): string => { if (productType === "raw_material") { // 原物料使用 RM 前綴 + 4 位數字 const rawMaterialProducts = products.filter(p => p.type === "raw_material"); if (rawMaterialProducts.length === 0) { return "RM0001"; } const maxNumber = rawMaterialProducts.reduce((max, product) => { const match = product.product_code.match(/RM(\d{4})/); if (match) { const num = parseInt(match[1], 10); return num > max ? num : max; } return max; }, 0); const nextNumber = maxNumber + 1; return `RM${nextNumber.toString().padStart(4, "0")}`; } else { // 半成品使用 SF 前綴 + 4 位數字 const finishedProducts = products.filter(p => p.type === "finished_product"); if (finishedProducts.length === 0) { return "SF0001"; } const maxNumber = finishedProducts.reduce((max, product) => { const match = product.product_code.match(/SF(\d{4})/); if (match) { const num = parseInt(match[1], 10); return num > max ? num : max; } return max; }, 0); const nextNumber = maxNumber + 1; return `SF${nextNumber.toString().padStart(4, "0")}`; } }; const handleSaveProduct = (product: Omit) => { if (editingProduct) { // Update existing product setProducts( products.map((p) => p.id === editingProduct.id ? { ...product, id: p.id, createdAt: p.createdAt, product_code: p.product_code } : p ) ); } else { // Add new product with auto-generated product_code based on type const product_code = generateProductCode(product.type); const newProduct: Product = { ...product, id: Date.now().toString(), product_code, createdAt: new Date().toISOString().split("T")[0], }; setProducts([newProduct, ...products]); } setIsDialogOpen(false); }; const handleDeleteProduct = (id: string) => { setProducts(products.filter((p) => p.id !== id)); }; return (
{/* Header */}

商品建檔管理

管理甜點店原物料與成品資料

{/* Toolbar */}
{/* Search */}
setSearchTerm(e.target.value)} className="pl-10" />
{/* Type Filter */} {/* Add Button */}
{/* Product Table */} {/* Product Dialog */}
); }