/** * 建立生產工單頁面 * 動態 BOM 表單:選擇倉庫 → 選擇原物料 → 選擇批號 → 輸入用量 */ import { useState, useEffect } from "react"; import { Factory, Plus, Trash2, ArrowLeft, Save, AlertTriangle, Calendar } from 'lucide-react'; import { Button } from "@/Components/ui/button"; import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout"; import { Head, router, useForm } from "@inertiajs/react"; import { getBreadcrumbs } from "@/utils/breadcrumb"; import { SearchableSelect } from "@/Components/ui/searchable-select"; import { Input } from "@/Components/ui/input"; import { Label } from "@/Components/ui/label"; import { Textarea } from "@/Components/ui/textarea"; interface Product { id: number; name: string; code: string; base_unit?: { id: number; name: string } | null; } interface Warehouse { id: number; name: string; } interface Unit { id: number; name: string; } interface InventoryOption { id: number; product_id: number; product_name: string; product_code: string; batch_number: string; box_number: string | null; quantity: number; arrival_date: string | null; expiry_date: string | null; unit_name: string | null; } interface BomItem { inventory_id: string; quantity_used: string; unit_id: string; // 顯示用 product_name?: string; batch_number?: string; available_qty?: number; } interface Props { products: Product[]; warehouses: Warehouse[]; units: Unit[]; } export default function ProductionCreate({ products, warehouses, units }: Props) { const [selectedWarehouse, setSelectedWarehouse] = useState(""); const [inventoryOptions, setInventoryOptions] = useState([]); const [isLoadingInventory, setIsLoadingInventory] = useState(false); const [bomItems, setBomItems] = useState([]); const { data, setData, processing, errors } = useForm({ product_id: "", warehouse_id: "", output_quantity: "", output_batch_number: "", output_box_count: "", production_date: new Date().toISOString().split('T')[0], expiry_date: "", remark: "", items: [] as { inventory_id: number; quantity_used: number; unit_id: number | null }[], }); // 當選擇倉庫時,載入該倉庫的可用庫存 useEffect(() => { if (selectedWarehouse) { setIsLoadingInventory(true); fetch(route('api.production.warehouses.inventories', selectedWarehouse)) .then(res => res.json()) .then((inventories: InventoryOption[]) => { setInventoryOptions(inventories); setIsLoadingInventory(false); }) .catch(() => setIsLoadingInventory(false)); } else { setInventoryOptions([]); } }, [selectedWarehouse]); // 同步 warehouse_id 到 form data useEffect(() => { setData('warehouse_id', selectedWarehouse); }, [selectedWarehouse]); // 新增 BOM 項目 const addBomItem = () => { setBomItems([...bomItems, { inventory_id: "", quantity_used: "", unit_id: "", }]); }; // 移除 BOM 項目 const removeBomItem = (index: number) => { setBomItems(bomItems.filter((_, i) => i !== index)); }; // 更新 BOM 項目 const updateBomItem = (index: number, field: keyof BomItem, value: string) => { const updated = [...bomItems]; updated[index] = { ...updated[index], [field]: value }; // 如果選擇了庫存,自動填入顯示資訊 if (field === 'inventory_id' && value) { const inv = inventoryOptions.find(i => String(i.id) === value); if (inv) { updated[index].product_name = inv.product_name; updated[index].batch_number = inv.batch_number; updated[index].available_qty = inv.quantity; } } setBomItems(updated); }; // 產生成品批號建議 const generateBatchNumber = () => { if (!data.product_id) return; const product = products.find(p => String(p.id) === data.product_id); if (!product) return; const date = data.production_date.replace(/-/g, ''); const suggested = `${product.code}-TW-${date}-01`; setData('output_batch_number', suggested); }; // 提交表單 const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // 轉換 BOM items 格式 const formattedItems = bomItems .filter(item => item.inventory_id && item.quantity_used) .map(item => ({ inventory_id: parseInt(item.inventory_id), quantity_used: parseFloat(item.quantity_used), unit_id: item.unit_id ? parseInt(item.unit_id) : null, })); // 使用 router.post 提交完整資料 router.post(route('production-orders.store'), { ...data, items: formattedItems, }); }; return (

建立生產單

記錄生產使用的原物料與產出成品

{/* 成品資訊 */}

成品資訊

setData('product_id', v)} options={products.map(p => ({ label: `${p.name} (${p.code})`, value: String(p.id), }))} placeholder="選擇成品" className="w-full h-9" /> {errors.product_id &&

{errors.product_id}

}
setData('output_quantity', e.target.value)} placeholder="例如: 50" className="h-9" /> {errors.output_quantity &&

{errors.output_quantity}

}
setData('output_batch_number', e.target.value)} placeholder="例如: AB-TW-20260121-01" className="h-9 font-mono" />
{errors.output_batch_number &&

{errors.output_batch_number}

}
setData('output_box_count', e.target.value)} placeholder="例如: 10" className="h-9" />
setData('production_date', e.target.value)} className="h-9 pl-9" />
{errors.production_date &&

{errors.production_date}

}
setData('expiry_date', e.target.value)} className="h-9 pl-9" />
({ label: w.name, value: String(w.id), }))} placeholder="選擇倉庫" className="w-full h-9" /> {errors.warehouse_id &&

{errors.warehouse_id}

}