inventoryService = $inventoryService; } /** * 配方列表 */ public function index(Request $request): Response { $query = Recipe::query(); if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('code', 'like', "%{$search}%") ->orWhere('name', 'like', "%{$search}%"); $productIds = $this->inventoryService->getProductsByName($search)->pluck('id'); $q->orWhereIn('product_id', $productIds); }); } $query->orderBy($request->input('sort_field', 'created_at'), $request->input('sort_direction', 'desc')); $recipes = $query->paginate($request->input('per_page', 10))->withQueryString(); // Manual Hydration $productIds = $recipes->pluck('product_id')->unique()->filter()->toArray(); $products = $this->inventoryService->getProductsByIds($productIds)->keyBy('id'); $recipes->getCollection()->transform(function ($recipe) use ($products) { $recipe->product = $products->get($recipe->product_id); return $recipe; }); return Inertia::render('Production/Recipe/Index', [ 'recipes' => $recipes, 'filters' => $request->only(['search', 'per_page', 'sort_field', 'sort_direction']), ]); } /** * 新增配方表單 */ public function create(): Response { return Inertia::render('Production/Recipe/Create', [ 'products' => $this->inventoryService->getAllProducts(), 'units' => $this->inventoryService->getUnits(), ]); } /** * 儲存配方 */ public function store(Request $request) { $validated = $request->validate([ 'product_id' => 'required|exists:products,id', 'code' => 'required|string|max:50|unique:recipes,code', 'name' => 'required|string|max:255', 'description' => 'nullable|string', 'yield_quantity' => 'required|numeric|min:0.01', 'items' => 'required|array|min:1', 'items.*.product_id' => 'required|exists:products,id', 'items.*.quantity' => 'required|numeric|min:0.0001', 'items.*.unit_id' => 'nullable|exists:units,id', 'items.*.remark' => 'nullable|string', ]); DB::transaction(function () use ($validated) { $recipe = Recipe::create([ 'product_id' => $validated['product_id'], 'code' => $validated['code'], 'name' => $validated['name'], 'description' => $validated['description'], 'yield_quantity' => $validated['yield_quantity'], 'is_active' => true, ]); foreach ($validated['items'] as $item) { RecipeItem::create([ 'recipe_id' => $recipe->id, 'product_id' => $item['product_id'], 'quantity' => $item['quantity'], 'unit_id' => $item['unit_id'], 'remark' => $item['remark'], ]); } }); return redirect()->route('recipes.index')->with('success', '配方已建立'); } /** * 編輯配方表單 */ public function edit(Recipe $recipe): Response { // Hydrate Product $recipe->product = $this->inventoryService->getProduct($recipe->product_id); // Load items with details $items = $recipe->items; $productIds = $items->pluck('product_id')->unique()->toArray(); $products = $this->inventoryService->getProductsByIds($productIds)->keyBy('id'); $units = $this->inventoryService->getUnits()->keyBy('id'); foreach ($items as $item) { $item->product = $products->get($item->product_id); $item->unit = $units->get($item->unit_id); } return Inertia::render('Production/Recipe/Edit', [ 'recipe' => $recipe, 'products' => $this->inventoryService->getAllProducts(), 'units' => $this->inventoryService->getUnits(), ]); } /** * 更新配方 */ public function update(Request $request, Recipe $recipe) { $validated = $request->validate([ 'product_id' => 'required|exists:products,id', 'code' => 'required|string|max:50|unique:recipes,code,' . $recipe->id, 'name' => 'required|string|max:255', 'description' => 'nullable|string', 'yield_quantity' => 'required|numeric|min:0.01', 'items' => 'required|array|min:1', 'items.*.product_id' => 'required|exists:products,id', 'items.*.quantity' => 'required|numeric|min:0.0001', 'items.*.unit_id' => 'nullable|exists:units,id', 'items.*.remark' => 'nullable|string', ]); DB::transaction(function () use ($validated, $recipe) { $recipe->update([ 'product_id' => $validated['product_id'], 'code' => $validated['code'], 'name' => $validated['name'], 'description' => $validated['description'], 'yield_quantity' => $validated['yield_quantity'], ]); // Sync items (Delete all and recreate) $recipe->items()->delete(); foreach ($validated['items'] as $item) { RecipeItem::create([ 'recipe_id' => $recipe->id, 'product_id' => $item['product_id'], 'quantity' => $item['quantity'], 'unit_id' => $item['unit_id'], 'remark' => $item['remark'], ]); } }); return redirect()->route('recipes.index')->with('success', '配方已更新'); } /** * 刪除配方 */ public function destroy(Recipe $recipe) { $recipe->delete(); return redirect()->back()->with('success', '配方已刪除'); } }