filled('keyword')) { $keyword = $request->keyword; $query->where(function ($q) use ($keyword) { $q->where('name', 'like', "%{$keyword}%") ->orWhere('code', 'like', "%{$keyword}%") ->orWhere('barcode', 'like', "%{$keyword}%"); }); } // 类型筛选 if ($request->filled('type')) { $query->where('type', $request->type); } // 品牌筛选 if ($request->filled('brand_id')) { $query->where('brand_id', $request->brand_id); } $perPage = $request->input('limit', 15); $goods = $query->orderBy('created_at', 'desc')->paginate($perPage); // 格式化数据 $goods->getCollection()->transform(function ($item) { return [ 'id' => $item->id, 'name' => $item->name, 'code' => $item->code, 'barcode' => $item->barcode, 'type' => $item->type, 'type_label' => $item->type == 'normal' ? '普通商品' : '组套商品', 'retail_price' => $item->retail_price, 'cost_price' => $item->cost_price, 'unit' => $item->unit, 'brand' => $item->brand ? ['id' => $item->brand->id, 'name' => $item->brand->name] : null, 'suppliers' => $item->suppliers->map(function ($s) { return ['id' => $s->id, 'name' => $s->name]; }), 'weight' => $item->weight, 'packaging_cost' => $item->packaging_cost, 'shipping_packaging_cost' => $item->shipping_packaging_cost, 'volume' => $item->volume, 'length' => $item->length, 'width' => $item->width, 'height' => $item->height, 'batch_management' => $item->batch_management, 'created_at' => $item->created_at, 'updated_at' => $item->updated_at, ]; }); return response()->json([ 'code' => 200, 'data' => [ 'list' => $goods->items(), 'total' => $goods->total(), 'current_page' => $goods->currentPage(), 'last_page' => $goods->lastPage(), ], 'message' => 'success' ]); } /** * 获取所有商品(用于下拉选择) */ public function all(Request $request) { $query = Goods::select('id', 'name', 'code', 'retail_price', 'cost_price', 'type'); if ($request->filled('type')) { $query->where('type', $request->type); } $goods = $query->get(); return response()->json([ 'code' => 200, 'data' => $goods, 'message' => 'success' ]); } /** * 商品详情 */ public function show($id) { $goods = Goods::with(['brand', 'suppliers', 'comboItems.goods'])->findOrFail($id); $data = [ 'id' => $goods->id, 'name' => $goods->name, 'code' => $goods->code, 'barcode' => $goods->barcode, 'category' => $goods->category, 'unit' => $goods->unit, 'weight' => $goods->weight, 'retail_price' => $goods->retail_price, 'cost_price' => $goods->cost_price, 'stock_warning' => $goods->stock_warning, 'type' => $goods->type, 'custom_id' => $goods->custom_id, 'packaging_cost' => $goods->packaging_cost, 'shipping_packaging_cost' => $goods->shipping_packaging_cost, 'volume' => $goods->volume, 'length' => $goods->length, 'width' => $goods->width, 'height' => $goods->height, 'brand_id' => $goods->brand_id, 'brand' => $goods->brand ? ['id' => $goods->brand->id, 'name' => $goods->brand->name] : null, 'suppliers' => $goods->suppliers->map(function ($s) { return ['id' => $s->id, 'name' => $s->name]; }), 'batch_management' => $goods->batch_management, ]; if ($goods->type == 'combo') { $data['combo_items'] = $goods->comboItems->map(function ($item) { return [ 'goods_id' => $item->goods_id, 'goods_name' => $item->goods->name, 'goods_code' => $item->goods->code, 'quantity' => $item->quantity, ]; }); } return response()->json([ 'code' => 200, 'data' => $data, 'message' => 'success' ]); } /** * 创建商品 */ public function store(Request $request) { $rules = [ 'name' => 'required|string|max:255', 'barcode' => 'nullable|string|max:100', 'type' => 'required|in:normal,combo', 'unit' => 'required|string|max:20', 'retail_price' => 'required|numeric|min:0', 'cost_price' => 'required|numeric|min:0', 'weight' => 'nullable|numeric|min:0', 'packaging_cost' => 'nullable|numeric|min:0', 'shipping_packaging_cost' => 'nullable|numeric|min:0', 'volume' => 'nullable|numeric|min:0', 'length' => 'nullable|numeric|min:0', 'width' => 'nullable|numeric|min:0', 'height' => 'nullable|numeric|min:0', 'brand_id' => 'nullable|exists:brands,id', 'supplier_ids' => 'nullable|array', 'supplier_ids.*' => 'exists:suppliers,id', 'batch_management' => 'nullable|boolean', 'custom_id' => 'nullable|string|max:100', 'category' => 'nullable|string|max:50', 'stock_warning' => 'nullable|integer|min:0', ]; // 如果是组套商品,需要验证组合项 if ($request->type == 'combo') { $rules['combo_items'] = 'required|array|min:1'; $rules['combo_items.*.goods_id'] = 'required|exists:goods,id'; $rules['combo_items.*.quantity'] = 'required|integer|min:1'; } $request->validate($rules); // 自动生成商品编码(如果未提供) $code = $request->code; if (!$code) { $code = $this->generateGoodsCode(); } else { // 检查唯一性 if (Goods::where('code', $code)->exists()) { return response()->json(['code' => 400, 'message' => '商品编码已存在'], 400); } } try { DB::beginTransaction(); $goods = Goods::create([ 'name' => $request->name, 'code' => $code, 'barcode' => $request->barcode, 'category' => $request->category, 'unit' => $request->unit, 'weight' => $request->weight ?? 0, 'retail_price' => $request->retail_price, 'cost_price' => $request->cost_price, 'stock_warning' => $request->stock_warning ?? 0, 'type' => $request->type, 'custom_id' => $request->custom_id, 'packaging_cost' => $request->packaging_cost ?? 0, 'shipping_packaging_cost' => $request->shipping_packaging_cost ?? 0, 'volume' => $request->volume ?? 0, 'length' => $request->length ?? 0, 'width' => $request->width ?? 0, 'height' => $request->height ?? 0, 'brand_id' => $request->brand_id, 'batch_management' => $request->batch_management ?? false, ]); // 关联供应商 if ($request->has('supplier_ids')) { $goods->suppliers()->sync($request->supplier_ids); } // 如果是组套商品,添加组合项 if ($request->type == 'combo' && $request->has('combo_items')) { foreach ($request->combo_items as $item) { // 检查子商品不能是组套商品(避免嵌套) $childGoods = Goods::find($item['goods_id']); if ($childGoods->type == 'combo') { throw new \Exception('组合商品不能包含另一个组合商品'); } $goods->comboItems()->create([ 'goods_id' => $item['goods_id'], 'quantity' => $item['quantity'], ]); } } DB::commit(); return response()->json([ 'code' => 200, 'data' => ['id' => $goods->id], 'message' => '创建成功' ]); } catch (\Exception $e) { DB::rollBack(); return response()->json([ 'code' => 500, 'message' => '创建失败:' . $e->getMessage() ], 500); } } /** * 更新商品 */ public function update(Request $request, $id) { $goods = Goods::findOrFail($id); $rules = [ 'name' => 'sometimes|required|string|max:255', 'barcode' => 'sometimes|required|string|max:100', 'type' => 'sometimes|required|in:normal,combo', 'unit' => 'sometimes|required|string|max:20', 'retail_price' => 'sometimes|required|numeric|min:0', 'cost_price' => 'sometimes|required|numeric|min:0', 'weight' => 'nullable|numeric|min:0', 'packaging_cost' => 'nullable|numeric|min:0', 'shipping_packaging_cost' => 'nullable|numeric|min:0', 'volume' => 'nullable|numeric|min:0', 'length' => 'nullable|numeric|min:0', 'width' => 'nullable|numeric|min:0', 'height' => 'nullable|numeric|min:0', 'brand_id' => 'nullable|exists:brands,id', 'supplier_ids' => 'nullable|array', 'supplier_ids.*' => 'exists:suppliers,id', 'batch_management' => 'nullable|boolean', 'custom_id' => 'nullable|string|max:100', 'category' => 'nullable|string|max:50', 'stock_warning' => 'nullable|integer|min:0', ]; if ($request->has('code') && $request->code != $goods->code) { $rules['code'] = 'required|string|unique:goods,code,' . $id; } if ($request->type == 'combo') { $rules['combo_items'] = 'sometimes|array|min:1'; $rules['combo_items.*.goods_id'] = 'required|exists:goods,id'; $rules['combo_items.*.quantity'] = 'required|integer|min:1'; } $request->validate($rules); try { DB::beginTransaction(); $updateData = $request->only([ 'name', 'code', 'barcode', 'category', 'unit', 'weight', 'retail_price', 'cost_price', 'stock_warning', 'type', 'custom_id', 'packaging_cost', 'shipping_packaging_cost', 'volume', 'length', 'width', 'height', 'brand_id', 'batch_management' ]); $goods->update($updateData); // 更新供应商关联 if ($request->has('supplier_ids')) { $goods->suppliers()->sync($request->supplier_ids); } // 更新组合项(如果类型是组套) if ($request->type == 'combo') { if ($request->has('combo_items')) { // 删除旧的组合项 $goods->comboItems()->delete(); // 添加新的 foreach ($request->combo_items as $item) { $childGoods = Goods::find($item['goods_id']); if ($childGoods->type == 'combo') { throw new \Exception('组合商品不能包含另一个组合商品'); } $goods->comboItems()->create([ 'goods_id' => $item['goods_id'], 'quantity' => $item['quantity'], ]); } } } else { // 如果是普通商品,删除所有组合项 $goods->comboItems()->delete(); } DB::commit(); return response()->json([ 'code' => 200, 'message' => '更新成功' ]); } catch (\Exception $e) { DB::rollBack(); return response()->json([ 'code' => 500, 'message' => '更新失败:' . $e->getMessage() ], 500); } } /** * 删除商品 */ public function destroy($id) { $goods = Goods::findOrFail($id); // 检查是否被组合商品引用 if ($goods->parentCombos()->exists()) { return response()->json([ 'code' => 400, 'message' => '该商品已被组合商品引用,无法删除' ], 400); } $goods->delete(); return response()->json([ 'code' => 200, 'message' => '删除成功' ]); } /** * 生成商品编码 */ private function generateGoodsCode() { $prefix = 'G'; $date = date('Ymd'); $last = Goods::where('code', 'like', $prefix . $date . '%') ->orderBy('code', 'desc') ->first(); if ($last) { $num = intval(substr($last->code, -4)) + 1; } else { $num = 1; } return $prefix . $date . str_pad($num, 4, '0', STR_PAD_LEFT); } }