find(); } /** * 根据用户ID查找用户 * @param int $userid * @return Member|null */ public static function findByUserid(int $userid): ?Member { return self::where('userid', $userid)->find(); } /** * 验证密码 * 当前项目统一使用双重 MD5。 * * @param string $password 明文密码 * @return bool */ public function verifyPassword(string $password): bool { return self::makePassword($password) === $this->password; } /** * 生成系统使用的密码摘要 * @param string $password 明文密码 * @return string */ public static function makePassword(string $password): string { return md5(md5($password)); } /** * 检查用户是否被禁用 * @return bool */ public function isDisabled(): bool { return $this->disabled == 1; } /** * 检查账号是否过期 * @return bool */ public function isExpired(): bool { if (empty($this->endtime)) { return false; } return $this->endtime < time(); } /** * 获取用户套餐信息 * @return array|null */ public function getProductInfo(): ?array { // 套餐配置改由模型统一封装,避免业务层散落裸表查询。 $product = ProductList::findByVType((int) $this->v_type); if (!$product) { return null; } return $this->buildEffectiveProductInfo($product->toArray()); } /** * 获取代理商信息 * @return array|null */ public function getAgentInfo(): ?array { if (empty($this->formtypeid)) { return null; } return self::where('userid', $this->formtypeid)->find(); } /** * 记录登录日志 * @param bool $success * @param string $loginType * @return void */ public function logLogin(bool $success, string $loginType = 'password'): void { try { MemberLoginLog::recordLogin([ 'userid' => $this->userid, 'ip' => request()->ip(), 'time' => time(), 'succeed' => $success ? 1 : 0, 'diqu' => '', 'login_type' => $loginType, 'adminid' => 0, 'v_type' => $this->v_type ?? 0, ]); } catch (\Throwable $e) { // 日志记录失败不影响登录 } } /** * 构建与 acgpmw `MemberController` 对齐后的套餐信息。 * * 这里只补齐当前 tp 已实际用到的套餐二次加工逻辑: * 1. 处理特定版本新增平台 * 2. 处理用户单独平台覆盖 * 3. 处理公众号/微信绑定等特殊额度 * 4. 处理内部账号临时补平台 * * @param array $productInfo 原始套餐信息 * @return array */ private function buildEffectiveProductInfo(array $productInfo): array { $productInfo['platforms'] = (string) ($productInfo['platforms'] ?? ''); // 对齐 acgpmw:金钻/钻石新注册账号额外补充 B站 和 B家号。 if ((int) $this->regtime >= 1773158400 && in_array((int) $this->v_type, [123, 124], true) && (int) ($productInfo['video_num'] ?? 0) > 0 ) { $productInfo['platforms'] = self::appendPlatform($productInfo['platforms'], 2); $productInfo['platforms'] = self::appendPlatform($productInfo['platforms'], 5); } // 对齐 acgpmw:用户单独平台权限可直接覆盖套餐平台集合。 $specialPlatforms = DySpecialPlatforms::findActiveByUserid((int) $this->userid); $productInfo['sora_turntable_type'] = (int) ($specialPlatforms->sora_turntable_type ?? 0); if ($specialPlatforms) { $specialPlatformsData = $specialPlatforms->toArray(); if (!empty($specialPlatformsData['platforms'])) { $productInfo['platforms'] = (string) $specialPlatformsData['platforms']; } if (!empty($specialPlatformsData['kword_num'])) { $productInfo['kword_num'] = $specialPlatformsData['kword_num']; } if (!empty($specialPlatformsData['is_video_num']) && (int) ($productInfo['video_num'] ?? 0) < 0) { $productInfo['video_num'] = 1; } } // 对齐 acgpmw:用户单独绑定额度可覆盖微信/公众号绑定数量。 $specialBinding = DySpecialBinding::findActiveByUserid((int) $this->userid); if ($specialBinding) { $specialBindingData = $specialBinding->toArray(); if ((int) ($specialBindingData['wx_num'] ?? 0) > 0) { $productInfo['wx_num'] = (int) $specialBindingData['wx_num']; } if ((int) ($specialBindingData['wxgzh_num'] ?? 0) > 0) { $productInfo['wxgzh_num'] = (int) $specialBindingData['wxgzh_num']; } } $productInfo['soft_groups_auth'] = $this->resolveSoftGroupsAuth(); // 对齐 acgpmw:内部号在部分版本下临时追加 B家号、B站、公众号。 if ((int) $this->staff_type === 1 && in_array((int) $productInfo['soft_groups_auth'], [0, 2], true) && !$this->hasTitkAuth() ) { $productInfo['platforms'] = self::appendPlatform($productInfo['platforms'], 2); $productInfo['platforms'] = self::appendPlatform($productInfo['platforms'], 5); $productInfo['platforms'] = self::appendPlatform($productInfo['platforms'], 6); } return $productInfo; } /** * 计算软件账号等级标识。 * * 该规则直接按 acgpmw `MemberController` 中的 `soft_groups_auth` 判定对齐。 * * @return int */ private function resolveSoftGroupsAuth(): int { $vType = (int) $this->v_type; $softGroupsAuth = 0; $softGroupVTypes = [144, 145, 146, 147, 156]; if (in_array($vType, $softGroupVTypes, true)) { $softGroupsAuth = 1; } if (in_array($vType, [149, 152, 157], true)) { $softGroupsAuth = 2; } if (in_array($vType, [161], true)) { $softGroupsAuth = 3; } if (in_array($vType, [162], true)) { $softGroupsAuth = 4; } if (in_array($vType, [169], true)) { $softGroupsAuth = 6; } if (in_array($vType, [170], true)) { $softGroupsAuth = 7; } if (in_array($vType, [171, 172, 173], true)) { $softGroupsAuth = 8; } if (in_array($vType, [176, 177, 178, 179], true)) { $softGroupsAuth = 9; } if (in_array($vType, [180], true)) { $softGroupsAuth = 10; } return $softGroupsAuth; } /** * 判断当前用户是否属于 TikTok 特殊账号版本。 * * @return bool */ private function hasTitkAuth(): bool { return in_array((int) $this->v_type, [158, 159, 160, 163, 164, 166], true); } /** * 追加平台到逗号包裹的平台字符串中。 * * @param string $platforms 平台字符串,如 `,0,1,6,` * @param int $platform 平台编号 * @return string */ private static function appendPlatform(string $platforms, int $platform): string { if (strpos($platforms, ',' . $platform . ',') !== false) { return $platforms; } $platformList = []; $platformText = trim($platforms, ','); if ($platformText !== '') { foreach (explode(',', $platformText) as $item) { if ($item === '') { continue; } $platformList[] = (int) $item; } } $platformList[] = $platform; $platformList = array_values(array_unique($platformList)); sort($platformList); return ',' . implode(',', $platformList) . ','; } }