success(ProductCategoryModel::getTreeData(['*'], true)); } /** * 商品列表(登录门店附 cart_id/cart_quantity 供列表直接加减购物车; * data.cart 为购物车悬浮球汇总,未登录返回零值结构) */ #[GetRoute('/product/list', authorize: false)] public function products(Request $request): JsonResponse { $query = ProductModel::query() ->where('status', ProductModel::STATUS_ON) ->with('category:id,name'); $categoryId = (int) $request->input('category_id', 0); if ($categoryId > 0) { $query->where('category_id', $categoryId); } $keyword = trim((string) $request->input('keyword', '')); if ($keyword !== '') { $query->where(static function ($q) use ($keyword) { $q->where('name', 'like', '%' . $keyword . '%'); }); } // 先按分类树展示顺序(与小程序分类栏一致;不在启用分类树中的商品排最后),再按商品排序 $categoryIds = ProductCategoryModel::getTreeOrderedIds(true); if ($categoryIds !== []) { $cases = []; foreach ($categoryIds as $position => $categoryId) { $cases[] = "WHEN {$categoryId} THEN {$position}"; } $query->orderByRaw( 'CASE category_id ' . implode(' ', $cases) . ' ELSE ' . count($categoryIds) . ' END' ); } $pageSize = (int) $request->input('pageSize', 10); $paginator = $query->orderBy('sort') ->orderBy('id') ->paginate($pageSize); // 当前门店的等级(售价 = 成本价 × (100 + 等级上浮比例) / 100)与购物车行 $store = $this->optionalStore($request); $level = ($store !== null && $store->level_id > 0) ? $store->level : null; $cartService = app(CartService::class); $cartRows = $store !== null ? $cartService->cartRowMap($store->id) : []; $paginator->getCollection()->transform( static function (ProductModel $product) use ($level, $cartRows): array { $row = $product->toArray(); // 实际价(按等级上浮比例换算;成本价不随序列化输出) $row['price'] = $level !== null ? CustomerLevelModel::calcLevelPrice($product->cost_price, $level->percent) : null; // 购物车数量(列表直接加减用;不在购物车为 0/'0.00') $row['cart_id'] = $cartRows[$product->id]['id'] ?? 0; $row['cart_quantity'] = $cartRows[$product->id]['quantity'] ?? '0.00'; return $row; } ); $data = $paginator->toArray(); $data['cart'] = $cartService->summary($store); return $this->success($data); } /** * 商品详情(免登录浏览;登录门店按等级上浮比例显示换算价,未登录/未设等级 price=null) */ #[GetRoute('/product/{id}', authorize: false, where: ['id' => '[0-9]+'])] public function detail(int $id, Request $request): JsonResponse { $product = ProductModel::query() ->where('status', ProductModel::STATUS_ON) ->with('category:id,name') ->find($id); if ($product === null) { throw new RepositoryException('商品不存在或已下架'); } $price = null; $store = $this->optionalStore($request); $level = ($store !== null && $store->level_id > 0) ? $store->level : null; if ($level !== null) { $price = CustomerLevelModel::calcLevelPrice($product->cost_price, $level->percent); } $cartRows = $store !== null ? app(CartService::class)->cartRowMap($store->id) : []; $data = $product->toArray(); $data['price'] = $price; $data['cart_id'] = $cartRows[$product->id]['id'] ?? 0; $data['cart_quantity'] = $cartRows[$product->id]['quantity'] ?? '0.00'; return $this->success($data); } }