diff --git a/app/Http/Controllers/Mini/BaseMiniController.php b/app/Http/Controllers/Mini/BaseMiniController.php index 5ae9ab3..a0ee0d9 100644 --- a/app/Http/Controllers/Mini/BaseMiniController.php +++ b/app/Http/Controllers/Mini/BaseMiniController.php @@ -7,6 +7,7 @@ use App\Models\StoreModel; use App\Models\UserModel; use Illuminate\Http\Request; use Modules\Common\Http\Controllers\BaseController; +use Modules\SystemUser\Models\SysAccessToken; /** * 小程序端控制器基类 @@ -29,7 +30,30 @@ abstract class BaseMiniController extends BaseController } /** - * 门店端前置校验:type=门店 且 store_id>0 且门店正常 + * 可选登录场景手动识别当前用户(路由关闭 authorize 时使用) + * + * 手动解析 Bearer token;未携带 token、token 无效或非小程序用户时返回 null(不抛错)。 + */ + protected function optionalUser(Request $request): ?UserModel + { + $token = $request->bearerToken(); + if (empty($token)) { + return null; + } + $accessToken = SysAccessToken::findToken($token); + if ($accessToken === null || $accessToken->tokenable_type !== UserModel::class) { + return null; + } + $user = UserModel::find($accessToken->tokenable_id); + if ($user === null || $user->status === UserModel::STATUS_DISABLED) { + return null; + } + + return $user; + } + + /** + * 门店端前置校验 */ protected function ensureStoreBound(UserModel $user): StoreModel { @@ -46,8 +70,6 @@ abstract class BaseMiniController extends BaseController /** * 用户当前绑定的正常门店(未绑定/已停用返回 null,不抛错) - * - * 供商品浏览等「弱前置」场景使用:未绑定门店仍可浏览商品,仅价格不可见。 */ protected function boundStore(UserModel $user): ?StoreModel { diff --git a/app/Http/Controllers/Mini/ProductController.php b/app/Http/Controllers/Mini/ProductController.php index bae55d6..299efde 100644 --- a/app/Http/Controllers/Mini/ProductController.php +++ b/app/Http/Controllers/Mini/ProductController.php @@ -12,10 +12,7 @@ use Modules\AnnoRoute\Attribute\GetRoute; use Modules\AnnoRoute\Attribute\RequestAttribute; /** - * 小程序商品(分类树 + 列表) - * - * 商品浏览仅需登录:未绑定门店/门店未设客户等级的用户也可查看商品,仅价格不可见(price=null); - * 加购、下单仍由购物车/订单前置校验拦截,要求绑定门店并已设客户等级。 + * 小程序商品 */ #[RequestAttribute('/mini', 'mini', authGuard: 'users')] class ProductController extends BaseMiniController @@ -56,22 +53,15 @@ class ProductController extends BaseMiniController } /** - * 商品列表:价格取当前门店客户等级价; + * 商品列表 */ #[GetRoute('/product/list', authorize: false)] public function products(Request $request): JsonResponse { - $user = $this->currentUser($request); - $levelId = $this->boundStore($user)?->level_id ?? 0; - $query = ProductModel::query() ->where('status', ProductModel::STATUS_ON) ->with('category:id,name'); - if ($levelId > 0) { - $query->with(['prices' => static fn ($q) => $q->where('level_id', $levelId)]); - } - $categoryId = (int) $request->input('category_id', 0); if ($categoryId > 0) { $query->where('category_id', $categoryId); @@ -79,8 +69,7 @@ class ProductController extends BaseMiniController $keyword = trim((string) $request->input('keyword', '')); if ($keyword !== '') { $query->where(static function ($q) use ($keyword) { - $q->where('name', 'like', '%' . $keyword . '%') - ->orWhere('spec', 'like', '%' . $keyword . '%'); + $q->where('name', 'like', '%' . $keyword . '%'); }); } @@ -90,12 +79,28 @@ class ProductController extends BaseMiniController ->paginate($pageSize) ->toArray(); - // 扁平化价格:prices[0].actual_price → price(访问器经 toArray 自动输出换算后实际价; - // 未绑定门店或未设等级价为 null——未加载 prices 时 ?? null 兜底) - // unset prices 同时移除 price_type/percent,门店端无法反推成本;cost_price 已被 $hidden 过滤 foreach ($data['data'] as &$row) { - $row['price'] = $row['prices'][0]['actual_price'] ?? null; - unset($row['prices']); + $row['price'] = null; + } + + // 用户 + $user = $this->optionalUser($request); + if (!$user) return $this->success($data); + // 门店 + $store = $this->boundStore($user); + if(!$store) return $this->success('12313'); + + if ($store->level_id > 0) { + foreach ($data['data'] as &$row) { + $model = ProductPriceModel::where('product_id', $row['id'])->where('level_id', $store->level_id)->first(); + $price = ProductPriceModel::calcActualPrice( + $model->price_type, + $model->price, + $model->percent, + $row->cost_price, + ); + $row['price'] = $price; + } } return $this->success($data);