params['ptStyle'] = dict::getDict('ptStyle', 'mall'); $this->isWx = util::isWx(); $userId = jwt::getLoginId(); if (empty($userId)) { if (!in_array($action->id, $this->guestAccess)) { util::fail('请先登录哈'); } } $userId = intval($userId); $this->userId = $userId; $user = UserClass::getById($userId, true); if (empty($user)) { if (!in_array($action->id, $this->guestAccess)) { util::fail('请先登录呢'); } } $this->user = $user; $shopId = Yii::$app->request->get('account'); // 从 $_GET 中取 $shopId = empty($shopId) ? Yii::$app->request->post('account') : $shopId; // 从 $_POST 中取 $shopId = intval($shopId); if (!empty($shopId)) { $this->shopId = $shopId; $shop = ShopClass::getById($shopId, true); if (!empty($shop)) { $this->shop = $shop; $mainId = $shop->mainId ?? 0; $main = MainClass::getById($mainId, true); $this->main = $main; $this->mainId = $mainId; $hdId = Yii::$app->request->get('hdId', 0); if (empty($hdId)) { //兼容早期代码,勿删,扫码付款页也用到,只写POST方式 $hdId = Yii::$app->request->post('hdId', 0); } if (!empty($hdId)) { $hd = HdClass::getById($hdId, true); if (!empty($hd)) { if (!empty($this->userId) && $hd->userId == $this->userId && $shopId == $hd->shopId) { // 已登录且 hd 归属当前用户:绑定门店客户上下文 $this->hd = $hd; $this->hdId = $hdId; $customId = $hd->customId ?? 0; $custom = CustomClass::getById($customId, true); $this->custom = $custom; $this->customId = $customId; } elseif (!empty($this->userId)) { // 已登录但 hd 与用户不匹配:清空店铺,防止恶意越权 $this->shop = null; $this->main = null; $this->mainId = 0; } // 未登录访客:保留 shop/main,仅不绑定 hd/custom,便于浏览分类/首页 } } } } return parent::beforeAction($action); } /** * 按 account 恢复门店与 mainId。 * BaseController 在 hdId 与当前用户/门店不匹配时会清空 shop,分享进店或换店后仍带旧 hdId 时必须走这里,否则浏览接口会误报无效门店。 * @return array shop、shopId、mainId */ protected function recoverShopContext() { $shopId = intval($this->shopId); if ($shopId <= 0) { util::fail('shopId不存在'); } $shop = $this->shop; if (empty($shop)) { // 被越权保护清空后,仍以当前 account 为准取门店,而不是沿用请求里的旧 hdId $shop = ShopClass::getById($shopId, true); if (!empty($shop)) { $this->shop = $shop; } } if (empty($shop)) { util::fail('无效门店'); } $mainId = intval($this->mainId); if ($mainId <= 0) { $mainId = intval($shop->mainId ?? 0); $this->mainId = $mainId; if ($mainId > 0 && empty($this->main)) { $this->main = MainClass::getById($mainId, true); } } if ($mainId <= 0) { util::fail('mainId不存在'); } return [ 'shop' => $shop, 'shopId' => $shopId, 'mainId' => $mainId, ]; } /** * 登录态解析当前门店 hdId。 * 已有 xhHd 则直接取 id;没有则走 CustomClass::buildRelation,与 ShopController::actionInfo 建客路径一致,避免分享直达漏掉拉新。 * 建客失败返回 hdId=0,由调用方决定是否阻断(浏览不阻断,下单再校验)。 * @param object|null $shop 门店对象,建客时必须有 * @param int $shopId 门店 id(xhShop.id) * @return array hdId、inviteBound,以及可能带上的 hd/custom * @throws \yii\db\IntegrityException */ protected function resolveLoggedInHd($shop, $shopId) { $empty = [ 'hdId' => 0, 'inviteBound' => 0, 'hd' => null, 'custom' => null, 'customId' => 0, ]; $hd = HdClass::getByCondition( ['shopId' => $shopId, 'userId' => $this->userId], false, null, 'id, customId' ); if (!empty($hd)) { return [ 'hdId' => intval($hd['id']), 'inviteBound' => 0, 'hd' => null, 'custom' => null, 'customId' => intval($hd['customId'] ?? 0), ]; } $user = $this->user; if (empty($shop) || empty($user)) { return $empty; } $inviterCustomId = (int)Yii::$app->request->get('inviterCustomId', 0); if ($inviterCustomId <= 0) { $inviterCustomId = (int)Yii::$app->request->post('inviterCustomId', 0); } $respond = CustomClass::buildRelation($shop, $user, $inviterCustomId); if (empty($respond) || empty($respond['hd'])) { return $empty; } $hd = $respond['hd']; $custom = $respond['custom'] ?? null; $hdId = intval(is_object($hd) ? $hd->id : ($hd['id'] ?? 0)); $customId = 0; if (!empty($custom)) { $customId = intval(is_object($custom) ? $custom->id : ($custom['id'] ?? 0)); } return [ 'hdId' => $hdId, 'inviteBound' => !empty($respond['inviteBound']) ? (int)$respond['inviteBound'] : 0, 'hd' => $hd, 'custom' => $custom, 'customId' => $customId, ]; } /** * 浏览/进店:先恢复门店,登录用户,再解析或创建当前店 hd。 * 游客不建客;建客失败不阻断浏览,调用方把 hdId=0 回给前端即可。 * @return array shop、shopId、mainId、hdId、inviteBound、resolved * @throws \yii\db\IntegrityException */ protected function recoverShopAndResolveHd() { $ctx = $this->recoverShopContext(); $resolved = [ 'hdId' => 0, 'inviteBound' => 0, 'hd' => null, 'custom' => null, 'customId' => 0, ]; if (intval($this->userId) > 0) { $resolved = $this->resolveLoggedInHd($ctx['shop'], $ctx['shopId']); } $ctx['hdId'] = intval($resolved['hdId'] ?? 0); $ctx['inviteBound'] = intval($resolved['inviteBound'] ?? 0); $ctx['resolved'] = $resolved; return $ctx; } /** * 把 resolveLoggedInHd 的结果写回控制器,供开团/参团等需要 $this->custom、$this->hd 的逻辑使用。 * @param array $resolved resolveLoggedInHd 返回值 * @throws \Exception */ protected function applyResolvedHd($resolved) { $hdId = intval($resolved['hdId'] ?? 0); if ($hdId <= 0) { return; } $this->hdId = $hdId; $hd = $resolved['hd'] ?? null; if (empty($hd) || !is_object($hd)) { $hd = HdClass::getById($hdId, true); } if (empty($hd) || !is_object($hd)) { return; } $this->hd = $hd; $custom = $resolved['custom'] ?? null; $customId = intval($hd->customId ?? ($resolved['customId'] ?? 0)); if ((empty($custom) || !is_object($custom)) && $customId > 0) { $custom = CustomClass::getById($customId, true); } if (!empty($custom) && is_object($custom)) { $this->custom = $custom; $this->customId = intval($custom->id ?? $customId); } } /** * 下单类接口:恢复门店并确保当前用户已绑定顾客。 * 未登录或建客失败时直接报请先登录,避免用空 custom / 空 shop 继续下单。 * @return array recoverShopAndResolveHd 的上下文 * @throws \yii\db\IntegrityException */ protected function ensureCustomerContext() { $ctx = $this->recoverShopAndResolveHd(); if (intval($this->userId) <= 0 || empty($this->user)) { util::fail('请先登录'); } $this->applyResolvedHd($ctx['resolved']); if (empty($this->custom)) { util::fail('请先登录'); } return $ctx; } }