success(ProductCategoryModel::getTreeData(['*'], true)); } /** * 商品列表 */ #[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 . '%'); }); } $pageSize = (int) $request->input('pageSize', 10); $paginator = $query->orderBy('sort') ->orderBy('id') ->paginate($pageSize); // 当前门店的等级(售价 = 成本价 × (100 + 等级上浮比例) / 100) $user = $this->optionalUser($request); $store = $user !== null ? $this->boundStore($user) : null; $level = ($store !== null && $store->level_id > 0) ? $store->level : null; $paginator->getCollection()->transform( static function (ProductModel $product) use ($level): array { $row = $product->toArray(); // 实际价(按等级上浮比例换算;成本价不随序列化输出) $row['price'] = $level !== null ? CustomerLevelModel::calcLevelPrice($product->cost_price, $level->percent) : null; return $row; } ); return $this->success($paginator->toArray()); } /** * 商品详情(免登录浏览;登录门店按等级上浮比例显示换算价,未登录/未绑店/未设等级 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; $user = $this->optionalUser($request); $store = $user !== null ? $this->boundStore($user) : null; $level = ($store !== null && $store->level_id > 0) ? $store->level : null; if ($level !== null) { $price = CustomerLevelModel::calcLevelPrice($product->cost_price, $level->percent); } $data = $product->toArray(); $data['price'] = $price; return $this->success($data); } }