'douyin', 1 => 'kuaishou', 2 => 'baijiahao', 3 => 'xiaohongshu', 4 => 'shipinhao', 5 => 'bilibili', 6 => 'gongzhonghao', 10 => 'tiktok', ]; /** * 页面展示名称。 * * acgpmw 模板内部会通过 `$this->platform_info[$platform]` 展示中文平台名, * 这里在 API 中直接返回前端所需文案,避免小程序自行猜测。 */ private const PLATFORM_NAME_MAP = [ 0 => '抖音', 1 => '快手', 2 => '百家号', 3 => '小红书', 4 => '视频号', 5 => 'B站', 6 => '公众号', 10 => 'TikTok', ]; /** * 获取平台账号管理页列表数据。 * * @param int $userid 当前登录用户ID * @param int|null $platform 当前筛选平台;为空时返回全部可见平台 * @return array * @throws \Exception */ public function getAccountList(int $userid, ?int $platform = null): array { $member = Member::findByUserid($userid); if (!$member) { throw new \Exception('用户不存在', 4006); } $productInfo = $member->getProductInfo(); $availablePlatforms = $this->resolveAvailablePlatforms($member, $productInfo); if (empty($availablePlatforms)) { throw new \Exception('暂无平台管理权限', 4004); } if ($platform !== null && !in_array($platform, $availablePlatforms, true)) { throw new \Exception('当前套餐暂无该平台权限', 4004); } $targetPlatform = $platform; $accounts = DyVideoUser::getPlatformAccountsByUserId($userid, $targetPlatform); $accountItems = []; foreach ($accounts as $account) { $accountPlatform = (int) $account->platform; if (!in_array($accountPlatform, $availablePlatforms, true)) { continue; } $accountItems[] = $this->buildAccountItem($account->toArray()); } $platformTabs = $this->buildPlatformTabs($availablePlatforms, $userid); $summary = $this->buildSummary($accountItems); return [ 'filters' => [ 'current_platform' => $targetPlatform, 'platforms' => $platformTabs, ], 'summary' => $summary, 'list' => $accountItems, ]; } /** * 计算当前用户可见平台。 * * 该逻辑直接对齐 acgpmw `platform::index()`: * 1. 从套餐 `product_list.platforms` 读取平台权限 * 2. 若为 146/147 且不在特殊账号名单中,仅允许抖音平台 * * @param Member $member 当前登录用户 * @param array|null $productInfo 套餐信息 * @return array */ private function resolveAvailablePlatforms(Member $member, ?array $productInfo): array { $platformText = trim((string) ($productInfo['platforms'] ?? ''), ','); if ($platformText === '') { return []; } $platforms = array_values(array_filter(array_map('intval', explode(',', $platformText)), static function ($item) { return array_key_exists($item, self::PLATFORM_NAME_MAP); })); $specialAccounts = $this->loadSpecialAccounts(); $isRestrictedVType = in_array((int) $member->v_type, [146, 147], true); $isSpecialAccount = in_array((int) $member->userid, $specialAccounts, true); if ($isRestrictedVType && !$isSpecialAccount) { return [0]; } return $platforms; } /** * 构建前端平台筛选项。 * * @param array $platforms 当前用户可见平台 * @param int $userid 当前用户ID * @return array> */ private function buildPlatformTabs(array $platforms, int $userid): array { $tabs = [ [ 'id' => null, 'name' => '全部平台', 'key' => 'all', 'count' => 0, ], ]; $allCount = 0; foreach ($platforms as $platform) { $count = DyVideoUser::where('userid', $userid) ->where('disabled', 0) ->where('platform', $platform) ->count(); $allCount += (int) $count; $tabs[] = [ 'id' => $platform, 'name' => self::PLATFORM_NAME_MAP[$platform] ?? ('平台' . $platform), 'key' => self::PLATFORM_KEY_MAP[$platform] ?? ('platform_' . $platform), 'count' => (int) $count, ]; } $tabs[0]['count'] = $allCount; return $tabs; } /** * 把数据库记录转换为前端可直接渲染的账号卡片。 * * 状态字段解释按 acgpmw `get_zhanghu_list()` 三列展示对齐: * - `is_endauth` => 账号授权状态 * - `aa_endauth` => 数据授权状态 * - `browser` => 异常状态 * * @param array $account dy_video_user 单条记录 * @return array */ private function buildAccountItem(array $account): array { $platform = (int) ($account['platform'] ?? 0); $countryName = ''; if ($platform === 10) { $titkInfo = DyVideoUserTitk::findByVuid((int) $account['id']); $countryName = (string) ($titkInfo->country_name ?? ''); } $accountAuth = (int) ($account['is_endauth'] ?? 0) === 1 ? $this->buildStatusBlock('授权到期', 'danger', '请重新完成平台授权') : $this->buildStatusBlock('授权正常', 'success', '当前账号授权可用'); $dataAuth = (int) ($account['aa_endauth'] ?? 0) === 1 ? $this->buildStatusBlock('授权到期', 'danger', '请重新完成数据授权') : $this->buildStatusBlock('授权正常', 'success', '当前数据授权可用'); $exceptionStatus = (int) ($account['browser'] ?? 0) === 1 ? $this->buildStatusBlock('发布异常', 'warning', '发布链路存在异常,需要人工处理') : $this->buildStatusBlock('使用正常', 'success', '当前账号发布链路正常'); return [ 'id' => (int) $account['id'], 'platform' => $platform, 'platform_name' => self::PLATFORM_NAME_MAP[$platform] ?? ('平台' . $platform), 'platform_key' => self::PLATFORM_KEY_MAP[$platform] ?? ('platform_' . $platform), 'nickname' => (string) ($account['dy_nickname'] ?? ''), 'avatar' => (string) ($account['dy_avatar'] ?? ''), 'intro' => (string) ($account['dy_intro'] ?? ''), 'phone' => (string) ($account['info_shouji'] ?? ''), 'country_name' => $countryName, 'proviceid' => (int) ($account['proviceid'] ?? 0), 'is_lanv' => (int) ($account['is_lanv'] ?? 0) === 1, 'is_qyh' => (int) ($account['is_qyh'] ?? 0) === 1, 'account_status' => $accountAuth, 'data_status' => $dataAuth, 'exception_status' => $exceptionStatus, 'status_overview' => $this->buildOverviewStatus($accountAuth, $dataAuth, $exceptionStatus), 'display_code' => '#P' . (int) $account['id'], ]; } /** * 构建单个状态块。 * * @param string $text 显示文案 * @param string $tone 视觉色调:success / warning / danger * @param string $hint 补充说明 * @return array */ private function buildStatusBlock(string $text, string $tone, string $hint): array { return [ 'text' => $text, 'tone' => $tone, 'hint' => $hint, ]; } /** * 汇总账号卡片主状态,便于列表页用一个醒目标记表示当前账号健康度。 * * @param array $accountAuth 账号授权状态 * @param array $dataAuth 数据授权状态 * @param array $exceptionStatus 异常状态 * @return array */ private function buildOverviewStatus(array $accountAuth, array $dataAuth, array $exceptionStatus): array { if ($accountAuth['tone'] === 'danger' || $dataAuth['tone'] === 'danger') { return $this->buildStatusBlock('需重新授权', 'danger', '账号授权或数据授权已到期'); } if ($exceptionStatus['tone'] === 'warning') { return $this->buildStatusBlock('存在异常', 'warning', '当前账号发布链路异常'); } return $this->buildStatusBlock('状态正常', 'success', '账号与发布状态均正常'); } /** * 统计当前筛选结果。 * * @param array> $items 列表项 * @return array */ private function buildSummary(array $items): array { $summary = [ 'total' => count($items), 'need_reauth_count' => 0, 'browser_exception_count' => 0, 'normal_count' => 0, ]; foreach ($items as $item) { $needReauth = $item['account_status']['tone'] === 'danger' || $item['data_status']['tone'] === 'danger'; $hasBrowserException = $item['exception_status']['tone'] === 'warning'; if ($needReauth) { $summary['need_reauth_count']++; } if ($hasBrowserException) { $summary['browser_exception_count']++; } if (!$needReauth && !$hasBrowserException) { $summary['normal_count']++; } } return $summary; } /** * 加载 acgpmw 的特殊账号名单。 * * 这里优先读取基线项目 `/root/work/acgpmw/data/other/tw_special_account.php`, * 保证 146/147 套餐用户的平台权限限制与原系统保持一致; * 若文件不存在,则退回空数组,接口仍可工作。 * * @return array */ private function loadSpecialAccounts(): array { $specialAccountFile = '/root/work/acgpmw/data/other/tw_special_account.php'; if (!is_file($specialAccountFile)) { return []; } $accounts = require $specialAccountFile; return is_array($accounts) ? array_values(array_map('intval', $accounts)) : []; } }