currentUser($request); $store = $this->ensureStoreBound($user); if ($store->level_id <= 0 || $store->level === null) { return $this->error('门店未设置客户等级,无法加购,请联系客服'); } $productId = (int) $request->validated('product_id'); $product = ProductModel::where('status', ProductModel::STATUS_ON)->find($productId); if ($product === null) { return $this->error('商品不存在或已下架,请刷新后重试'); } $quantity = (string) $request->validated('quantity'); $cart = DB::transaction(function () use ($user, $productId, $quantity) { $row = CartModel::query() ->where('user_id', $user->id) ->where('product_id', $productId) ->lockForUpdate() ->first(); if ($row !== null) { $merged = bcadd((string) $row->quantity, $quantity, 2); if (bccomp($merged, self::MAX_QUANTITY, 2) > 0) { throw new RepositoryException('该商品在购物车中的数量已达上限'); } $row->quantity = $merged; $row->save(); return $row; } return CartModel::create([ 'user_id' => $user->id, 'product_id' => $productId, 'quantity' => $quantity, ]); }); return $this->success([ 'id' => $cart->id, 'quantity' => $cart->quantity, ], '已加入购物车'); } /** * 购物车列表 */ #[GetRoute('/cart', authorize: true)] public function index(Request $request): JsonResponse { $user = $this->currentUser($request); $store = $this->ensureStoreBound($user); $rows = CartModel::query() ->where('user_id', $user->id) ->orderBy('id', 'desc') ->get(); if ($rows->isEmpty()) { return $this->success([ 'items' => [], 'total_count' => 0, 'total_quantity' => '0.00', 'total_amount' => '0.00', ]); } $productIds = $rows->pluck('product_id') ->map(static fn ($id) => (int) $id) ->unique()->values()->all(); $products = ProductModel::withTrashed()->whereIn('id', $productIds)->get()->keyBy('id'); // 门店等级(售价 = 成本价 × (100 + 等级上浮比例) / 100) $level = $store->level_id > 0 ? $store->level : null; // 图片一次查回(避免 ProductModel::$appends images_arr 的 N+1)。 // 注意:image_ids 有 imageIds Attribute 访问器(get 返回数组),需取原始值 $allFileIds = []; foreach ($products as $product) { foreach (explode(',', (string) $product->getRawOriginal('image_ids')) as $fileId) { if ($fileId !== '') { $allFileIds[] = (int) $fileId; } } } $fileMap = SysFileModel::query() ->whereIn('id', $allFileIds) ->get()->keyBy('id'); $items = []; $totalQuantity = '0.00'; $totalAmount = '0.00'; foreach ($rows as $row) { $product = $products->get($row->product_id); $productOn = $product !== null && $product->status === ProductModel::STATUS_ON; // 实际价(按门店等级上浮比例换算);未设等级为 null $price = $level === null ? null : CustomerLevelModel::calcLevelPrice((float) ($product?->cost_price ?? 0), $level->percent); $buyable = $productOn && $price !== null; $quantity = (string) $row->quantity; $firstFileId = (int) (explode(',', (string) $product->getRawOriginal('image_ids'))[0] ?? 0); $firstFile = $firstFileId > 0 ? $fileMap->get($firstFileId) : null; $item = [ 'id' => $row->id, 'product_id' => $row->product_id, 'name' => $product->name ?? '', 'spec' => $product->spec ?? '', 'unit' => $product->unit ?? '', 'image' => $firstFile?->file_url ?? '', 'price' => $price, 'quantity' => $quantity, 'amount' => $buyable ? bcmul($price, $quantity, 2) : null, 'status' => $buyable ? 1 : 0, ]; $items[] = $item; if ($buyable) { $totalQuantity = bcadd($totalQuantity, $quantity, 2); $totalAmount = bcadd($totalAmount, $item['amount'], 2); } } return $this->success([ 'items' => $items, 'total_count' => count($items), 'total_quantity' => $totalQuantity, 'total_amount' => $totalAmount, ]); } /** * 修改数量(校验归属) */ #[PutRoute('/cart/{id}', authorize: true, where: ['id' => '[0-9]+'])] public function update(int $id, MiniCartRequest $request): JsonResponse { $user = $this->currentUser($request); $this->ensureStoreBound($user); $row = CartModel::query() ->where('id', $id) ->where('user_id', $user->id) ->first(); if ($row === null) { throw new RepositoryException('购物车项不存在'); } $row->quantity = (string) $request->validated('quantity'); $row->save(); return $this->success(['id' => $row->id, 'quantity' => $row->quantity], '已修改数量'); } /** * 删除单项(校验归属) */ #[DeleteRoute('/cart/{id}', authorize: true, where: ['id' => '[0-9]+'])] public function destroy(int $id, Request $request): JsonResponse { $user = $this->currentUser($request); $this->ensureStoreBound($user); $deleted = CartModel::query() ->where('id', $id) ->where('user_id', $user->id) ->delete(); if ($deleted === 0) { throw new RepositoryException('购物车项不存在'); } return $this->success([], '已删除'); } /** * 清空购物车(仅当前用户) */ #[DeleteRoute('/cart', authorize: true)] public function clear(Request $request): JsonResponse { $user = $this->currentUser($request); $this->ensureStoreBound($user); CartModel::query()->where('user_id', $user->id)->delete(); return $this->success([], '购物车已清空'); } }