feat(video): add user-specific video query and filter accounts functionality
- Introduced `buildUserQuery` method in `DysVideoLog` model to create a base query for user-specific video logs. - Added `getVideoFilterAccountsByUserId` method in `DyVideoUser` model to retrieve active accounts for a specified user. - Updated routing to include new video work API endpoints under `v1/video-work`, requiring user authentication.
This commit is contained in:
@@ -0,0 +1,662 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\api\service;
|
||||
|
||||
use app\api\model\DysVideoLog;
|
||||
use app\api\model\DyVideoUser;
|
||||
use app\api\model\Member;
|
||||
use think\db\Query;
|
||||
|
||||
/**
|
||||
* 视频作品服务。
|
||||
*
|
||||
* 该服务按 acgpmw `video_info.php` 的 `video_list()` / `get_videos()`
|
||||
* 最小可用范围对齐,为小程序提供视频作品列表的只读展示能力。
|
||||
*/
|
||||
class VideoWorkService
|
||||
{
|
||||
/**
|
||||
* 平台中文名按 acgpmw `data/other/platforms.php` 对齐。
|
||||
*/
|
||||
private const PLATFORM_NAME_MAP = [
|
||||
0 => 'D音',
|
||||
1 => 'K手',
|
||||
2 => 'B家号',
|
||||
3 => '小红薯',
|
||||
4 => '视P号',
|
||||
5 => 'B哩哔哩',
|
||||
6 => '公Z号',
|
||||
10 => 'TiTk',
|
||||
];
|
||||
|
||||
/**
|
||||
* 平台英文键按 acgpmw `data/other/platforms_py.php` 对齐。
|
||||
*/
|
||||
private const PLATFORM_KEY_MAP = [
|
||||
0 => 'douyin',
|
||||
1 => 'kuaishou',
|
||||
2 => 'baijiahao',
|
||||
3 => 'xiaohongshu',
|
||||
4 => 'shipinhao',
|
||||
5 => 'bilibili',
|
||||
6 => 'gongzhonghao',
|
||||
10 => 'tiktok',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取视频作品列表。
|
||||
*
|
||||
* @param int $userid 当前登录用户ID
|
||||
* @param array<string, mixed> $params 前端查询参数
|
||||
* @return array<string, mixed>
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getVideoList(int $userid, array $params = []): array
|
||||
{
|
||||
$member = Member::findByUserid($userid);
|
||||
if (!$member) {
|
||||
throw new \Exception('用户不存在', 4004);
|
||||
}
|
||||
|
||||
$platform = $this->normalizeOptionalInt($params['platform'] ?? 'all', '平台参数格式错误');
|
||||
$vuid = $this->normalizeOptionalInt($params['vuid'] ?? 'all', '账号参数格式错误');
|
||||
$page = max(1, (int) ($params['page'] ?? 1));
|
||||
$pageSize = min(30, max(1, (int) ($params['page_size'] ?? 12)));
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
$accountOptions = $this->loadAccountOptions($userid, $availablePlatforms);
|
||||
if ($vuid !== null && !array_key_exists($vuid, $accountOptions['map'])) {
|
||||
throw new \Exception('当前账号不存在或已解绑', 4004);
|
||||
}
|
||||
|
||||
$baseQuery = $this->buildFilteredQuery($userid, [
|
||||
'platform' => $platform,
|
||||
'vuid' => $vuid,
|
||||
]);
|
||||
|
||||
$total = (int) (clone $baseQuery)->count();
|
||||
$records = (clone $baseQuery)
|
||||
->field([
|
||||
'id',
|
||||
'vuid',
|
||||
'cron_id',
|
||||
'aweme_id',
|
||||
'aweme_nid',
|
||||
'dy_item_id',
|
||||
'dy_title',
|
||||
'kwords',
|
||||
'dy_video_status',
|
||||
'dy_cover',
|
||||
'dy_create_time',
|
||||
'dy_share_url',
|
||||
'dy_comment_count',
|
||||
'dy_digg_count',
|
||||
'dy_play_count',
|
||||
'addtime',
|
||||
'fabu_type',
|
||||
'disabled',
|
||||
'status',
|
||||
'fberrinfo',
|
||||
'platform',
|
||||
'tplid',
|
||||
])
|
||||
->order('id', 'desc')
|
||||
->page($page, $pageSize)
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
$items = [];
|
||||
foreach ($records as $record) {
|
||||
$items[] = $this->buildVideoItem($record, $accountOptions['map']);
|
||||
}
|
||||
|
||||
return [
|
||||
'filters' => [
|
||||
'current_platform' => $platform,
|
||||
'platforms' => $this->buildPlatformFilters($userid, $availablePlatforms, $vuid, $platform),
|
||||
'current_vuid' => $vuid,
|
||||
'accounts' => $accountOptions['items'],
|
||||
],
|
||||
'summary' => $this->buildSummary(clone $baseQuery),
|
||||
'pagination' => [
|
||||
'page' => $page,
|
||||
'page_size' => $pageSize,
|
||||
'total' => $total,
|
||||
'has_more' => $page * $pageSize < $total,
|
||||
],
|
||||
'list' => $items,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载账号筛选项。
|
||||
*
|
||||
* @param int $userid 用户ID
|
||||
* @param array<int> $availablePlatforms 可见平台
|
||||
* @return array{items: array<int, array<string, mixed>>, map: array<int, array<string, mixed>>}
|
||||
*/
|
||||
private function loadAccountOptions(int $userid, array $availablePlatforms): array
|
||||
{
|
||||
$accounts = DyVideoUser::getVideoFilterAccountsByUserId($userid)->toArray();
|
||||
|
||||
$items = [
|
||||
[
|
||||
'id' => null,
|
||||
'name' => '全部账号',
|
||||
],
|
||||
];
|
||||
$accountMap = [];
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$platform = (int) ($account['platform'] ?? 0);
|
||||
if (!in_array($platform, $availablePlatforms, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$accountId = (int) ($account['id'] ?? 0);
|
||||
$accountMap[$accountId] = $account;
|
||||
$items[] = [
|
||||
'id' => $accountId,
|
||||
'name' => sprintf(
|
||||
'%s(%s)#P%d',
|
||||
self::PLATFORM_NAME_MAP[$platform] ?? ('平台' . $platform),
|
||||
(string) ($account['dy_nickname'] ?? '未命名账号'),
|
||||
$accountId
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'items' => $items,
|
||||
'map' => $accountMap,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建筛选后的作品查询。
|
||||
*
|
||||
* @param int $userid 用户ID
|
||||
* @param array<string, int|null> $filters 筛选条件
|
||||
* @return Query
|
||||
*/
|
||||
private function buildFilteredQuery(int $userid, array $filters): Query
|
||||
{
|
||||
$query = DysVideoLog::buildUserQuery($userid);
|
||||
|
||||
if (($filters['vuid'] ?? null) !== null) {
|
||||
$query->where('vuid', (int) $filters['vuid']);
|
||||
}
|
||||
|
||||
if (($filters['platform'] ?? null) !== null) {
|
||||
$query->where('platform', (int) $filters['platform']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建平台筛选项。
|
||||
*
|
||||
* 这里按当前账号筛选条件统计数量,使前端切平台时与当前账号范围一致。
|
||||
*
|
||||
* @param int $userid 用户ID
|
||||
* @param array<int> $availablePlatforms 可见平台
|
||||
* @param int|null $vuid 当前账号筛选
|
||||
* @param int|null $currentPlatform 当前平台筛选
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
private function buildPlatformFilters(int $userid, array $availablePlatforms, ?int $vuid, ?int $currentPlatform): array
|
||||
{
|
||||
$tabs = [
|
||||
[
|
||||
'id' => null,
|
||||
'name' => '全部平台',
|
||||
'key' => 'all',
|
||||
'count' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$allCount = 0;
|
||||
foreach ($availablePlatforms as $platform) {
|
||||
$query = $this->buildFilteredQuery($userid, [
|
||||
'platform' => $platform,
|
||||
'vuid' => $vuid,
|
||||
]);
|
||||
$count = (int) $query->count();
|
||||
$allCount += $count;
|
||||
|
||||
$tabs[] = [
|
||||
'id' => $platform,
|
||||
'name' => self::PLATFORM_NAME_MAP[$platform] ?? ('平台' . $platform),
|
||||
'key' => self::PLATFORM_KEY_MAP[$platform] ?? ('platform_' . $platform),
|
||||
'count' => $count,
|
||||
'active' => $currentPlatform === $platform,
|
||||
];
|
||||
}
|
||||
|
||||
$tabs[0]['count'] = $allCount;
|
||||
$tabs[0]['active'] = $currentPlatform === null;
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建顶部统计卡片。
|
||||
*
|
||||
* @param Query $query 已按当前筛选条件收窄的查询对象
|
||||
* @return array<string, int>
|
||||
*/
|
||||
private function buildSummary(Query $query): array
|
||||
{
|
||||
return [
|
||||
'total' => (int) (clone $query)->count(),
|
||||
'published_count' => (int) (clone $query)->whereRaw('(dy_video_status in (1,5) or aweme_id <> "" or dy_item_id <> "" or aweme_nid <> "")')->count(),
|
||||
'reviewing_count' => (int) (clone $query)->where('dy_video_status', 4)->count(),
|
||||
'failed_count' => (int) (clone $query)->whereIn('status', [2, 3])->count(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建前端作品卡片数据。
|
||||
*
|
||||
* @param array<string, mixed> $record 原始作品记录
|
||||
* @param array<int, array<string, mixed>> $accountMap 账号信息映射
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildVideoItem(array $record, array $accountMap): array
|
||||
{
|
||||
$platform = (int) ($record['platform'] ?? 0);
|
||||
$accountId = (int) ($record['vuid'] ?? 0);
|
||||
$account = $accountMap[$accountId] ?? [];
|
||||
$title = $this->buildVideoTitle($record);
|
||||
$previewUrl = $this->buildPreviewUrl($record);
|
||||
$statusInfo = $this->buildStatusInfo($record);
|
||||
$publishTimeText = $this->buildPublishTimeText($record);
|
||||
|
||||
return [
|
||||
'id' => (int) ($record['id'] ?? 0),
|
||||
'title' => $title,
|
||||
'cover' => (string) ($record['dy_cover'] ?? ''),
|
||||
'platform' => $platform,
|
||||
'platform_name' => self::PLATFORM_NAME_MAP[$platform] ?? ('平台' . $platform),
|
||||
'platform_key' => self::PLATFORM_KEY_MAP[$platform] ?? ('platform_' . $platform),
|
||||
'account_id' => $accountId,
|
||||
'account_name' => (string) ($account['dy_nickname'] ?? '未命名账号'),
|
||||
'account_avatar' => (string) ($account['dy_avatar'] ?? ''),
|
||||
'cron_id' => (int) ($record['cron_id'] ?? 0),
|
||||
'tplid' => (int) ($record['tplid'] ?? 0),
|
||||
'play_count' => (int) ($record['dy_play_count'] ?? 0),
|
||||
'digg_count' => (int) ($record['dy_digg_count'] ?? 0),
|
||||
'comment_count' => (int) ($record['dy_comment_count'] ?? 0),
|
||||
'publish_time_text' => $publishTimeText,
|
||||
'status' => $statusInfo,
|
||||
'preview_url' => $previewUrl,
|
||||
'has_preview' => $previewUrl !== '',
|
||||
'is_article' => (int) ($record['fabu_type'] ?? 0) === 101,
|
||||
'display_code' => '#V' . (int) ($record['id'] ?? 0),
|
||||
'task_code' => '#C' . (int) ($record['cron_id'] ?? 0),
|
||||
'material_code' => (int) ($record['tplid'] ?? 0) > 0 ? '#M' . (int) $record['tplid'] : '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装作品标题。
|
||||
*
|
||||
* 对齐 acgpmw:优先 `dy_title`,否则使用 `kwords` 拼接。
|
||||
*
|
||||
* @param array<string, mixed> $record 原始作品记录
|
||||
* @return string
|
||||
*/
|
||||
private function buildVideoTitle(array $record): string
|
||||
{
|
||||
$title = trim((string) ($record['dy_title'] ?? ''));
|
||||
if ($title !== '') {
|
||||
return $title;
|
||||
}
|
||||
|
||||
$keywords = trim((string) ($record['kwords'] ?? ''), ',');
|
||||
if ($keywords === '') {
|
||||
return '暂无作品信息';
|
||||
}
|
||||
|
||||
return '#' . str_replace(',', ' #', $keywords);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建作品状态块。
|
||||
*
|
||||
* 对齐 acgpmw `get_videos()` 的状态展示优先级:
|
||||
* 1. 定时中
|
||||
* 2. 发布失败
|
||||
* 3. 已发布 / 未公开 / 审核中 / 好友可见 / 私密视频
|
||||
* 4. 待处理
|
||||
*
|
||||
* @param array<string, mixed> $record 原始作品记录
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildStatusInfo(array $record): array
|
||||
{
|
||||
$platform = (int) ($record['platform'] ?? 0);
|
||||
$dyCreateTime = (int) ($record['dy_create_time'] ?? 0);
|
||||
$status = (int) ($record['status'] ?? 0);
|
||||
$dyVideoStatus = (int) ($record['dy_video_status'] ?? 0);
|
||||
$isPublished = !empty($record['aweme_id']) || !empty($record['dy_item_id']) || !empty($record['aweme_nid']);
|
||||
|
||||
if (in_array($platform, [0, 4], true) && $dyCreateTime > time()) {
|
||||
return [
|
||||
'text' => '定时中',
|
||||
'tone' => 'warning',
|
||||
'hint' => '作品已进入定时发布队列',
|
||||
];
|
||||
}
|
||||
|
||||
if (in_array($status, [2, 3], true)) {
|
||||
$errorText = $this->translatePublishError((string) ($record['fberrinfo'] ?? ''), $platform);
|
||||
return [
|
||||
'text' => '发布失败',
|
||||
'tone' => 'danger',
|
||||
'hint' => $errorText !== '' ? $errorText : '作品发布失败,请回到原系统查看详情',
|
||||
];
|
||||
}
|
||||
|
||||
if (in_array($dyVideoStatus, [1, 5], true) || $isPublished) {
|
||||
return [
|
||||
'text' => '已发布',
|
||||
'tone' => 'success',
|
||||
'hint' => '作品已成功发布到对应平台',
|
||||
];
|
||||
}
|
||||
|
||||
if ($dyVideoStatus === 2) {
|
||||
return [
|
||||
'text' => '未公开',
|
||||
'tone' => 'danger',
|
||||
'hint' => '作品当前为未公开状态',
|
||||
];
|
||||
}
|
||||
|
||||
if ($dyVideoStatus === 4) {
|
||||
return [
|
||||
'text' => '审核中',
|
||||
'tone' => 'primary',
|
||||
'hint' => '作品已提交平台审核,请稍后查看',
|
||||
];
|
||||
}
|
||||
|
||||
if ($dyVideoStatus === 6) {
|
||||
return [
|
||||
'text' => '好友可见',
|
||||
'tone' => 'info',
|
||||
'hint' => '作品仅好友可见',
|
||||
];
|
||||
}
|
||||
|
||||
if ($dyVideoStatus === 7) {
|
||||
return [
|
||||
'text' => '私密视频',
|
||||
'tone' => 'warning',
|
||||
'hint' => '作品当前为私密视频',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'text' => '待处理',
|
||||
'tone' => 'slate',
|
||||
'hint' => '作品正在处理或等待平台返回结果',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建发布时间文案。
|
||||
*
|
||||
* @param array<string, mixed> $record 原始作品记录
|
||||
* @return string
|
||||
*/
|
||||
private function buildPublishTimeText(array $record): string
|
||||
{
|
||||
$platform = (int) ($record['platform'] ?? 0);
|
||||
$dyCreateTime = (int) ($record['dy_create_time'] ?? 0);
|
||||
$addtime = (int) ($record['addtime'] ?? 0);
|
||||
|
||||
$publishTime = $addtime;
|
||||
if ($dyCreateTime > 0) {
|
||||
$publishTime = $dyCreateTime;
|
||||
}
|
||||
|
||||
if (in_array($platform, [0, 4], true) && $dyCreateTime > time()) {
|
||||
return '将于 ' . $this->formatDateTime($dyCreateTime) . ' 发布';
|
||||
}
|
||||
|
||||
return $this->formatDateTime($publishTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成作品预览链接。
|
||||
*
|
||||
* 对齐 acgpmw `get_videos()` 中各平台的链接处理规则。
|
||||
*
|
||||
* @param array<string, mixed> $record 原始作品记录
|
||||
* @return string
|
||||
*/
|
||||
private function buildPreviewUrl(array $record): string
|
||||
{
|
||||
$platform = (int) ($record['platform'] ?? 0);
|
||||
$status = (int) ($record['status'] ?? 0);
|
||||
$shareUrl = (string) ($record['dy_share_url'] ?? '');
|
||||
$awemeId = (string) ($record['aweme_id'] ?? '');
|
||||
$dyItemId = (string) ($record['dy_item_id'] ?? '');
|
||||
$dyCreateTime = (int) ($record['dy_create_time'] ?? 0);
|
||||
|
||||
if ($platform === 0 && $shareUrl !== '') {
|
||||
$shareUrl = 'https://www.douyin.com/video/' . $awemeId;
|
||||
if (strpos((string) ($record['dy_share_url'] ?? ''), 'https://video-cn.snssdk.com/') !== false) {
|
||||
$shareUrl = (string) ($record['dy_share_url'] ?? '');
|
||||
}
|
||||
if ($dyCreateTime < time() && $awemeId !== '') {
|
||||
$shareUrl = 'https://www.douyin.com/video/' . $awemeId;
|
||||
}
|
||||
}
|
||||
|
||||
if ($platform === 5 && $status === 1 && $dyItemId !== '') {
|
||||
$shareUrl = 'https://www.bilibili.com/video/' . $dyItemId;
|
||||
}
|
||||
|
||||
if ($platform === 2 && $status === 1 && $dyItemId !== '') {
|
||||
$shareUrl = 'https://mbd.baidu.com/newspage/data/videolanding?nid=sv_' . $dyItemId;
|
||||
}
|
||||
|
||||
if ($platform === 4 && strpos($shareUrl, 'https://weixin.qq.com/sph/') === false) {
|
||||
$shareUrl = '';
|
||||
}
|
||||
|
||||
return $shareUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析发布异常原因。
|
||||
*
|
||||
* 这里直接沿用 acgpmw `video_info::getycinfo()` 的关键信息匹配规则。
|
||||
*
|
||||
* @param string $errorInfo 原始错误信息
|
||||
* @param int $platform 平台编号
|
||||
* @return string
|
||||
*/
|
||||
private function translatePublishError(string $errorInfo, int $platform): string
|
||||
{
|
||||
if ($errorInfo === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($platform === 0) {
|
||||
$map = [
|
||||
'"error_code":10008' => '授权过期',
|
||||
'用户未登录' => '授权过期',
|
||||
'上传视频按钮超时' => '视频上传超时',
|
||||
'寻找描述输入框超时' => '素材或内容处理超时',
|
||||
'"error_code":2114033,' => '包含不合法文字',
|
||||
'"status_code":-2158,' => '发布频繁或异常',
|
||||
'"error_code":2100005,' => '参数不合法',
|
||||
'"error_code":2190003,' => '授权异常',
|
||||
'"error_code":2114005,' => '视频投稿功能已封禁[#G]',
|
||||
'"error_code":2100004,' => '系统繁忙异常',
|
||||
'"status_code":-20' => '视频投稿功能已封禁[#M]',
|
||||
'"error_code":2190019,' => '系统发布失败或异常',
|
||||
'"status_msg":"sms"' => '发布短信验证',
|
||||
'健康分不足投稿功能受限' => '健康分不足投稿功能受限',
|
||||
];
|
||||
|
||||
return $this->matchErrorText($errorInfo, $map);
|
||||
}
|
||||
|
||||
if ($platform === 1) {
|
||||
return $this->matchErrorText($errorInfo, [
|
||||
'ACCESS_DENIED' => '授权过期',
|
||||
'user_request_limit' => '发布限制或异常',
|
||||
'video_not_uploaded' => '视频上传异常',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($platform === 2) {
|
||||
return $this->matchErrorText($errorInfo, [
|
||||
'"errno":60001009' => '账号内容质量不足,今日还可发布0篇内容',
|
||||
'"errno":60000005' => '账号状态异常',
|
||||
'"errno":105011' => '百家号开放平台业务调整,已关闭您的接口使用权限',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($platform === 3) {
|
||||
return $this->matchErrorText($errorInfo, [
|
||||
'当日发布数已达到上限' => '当日发布数已达到上限',
|
||||
'系统正在升级中' => '系统平台升级维护中',
|
||||
'发布笔记需要绑定手机' => '发布笔记需要绑定手机号',
|
||||
'笔记发布失败' => '作品笔记发布失败',
|
||||
'用户被封号' => '用户被封号',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($platform === 4) {
|
||||
return $this->matchErrorText($errorInfo, [
|
||||
'"errcode":-11217' => '暂未绑定手机号',
|
||||
'"errcode":-11216' => '完成实名后才可以发表',
|
||||
'cookie失效' => '授权过期',
|
||||
'"errCode":300334' => '授权过期(授权完有其他扫码操作)',
|
||||
]);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 按关键字匹配错误提示。
|
||||
*
|
||||
* @param string $errorInfo 原始错误信息
|
||||
* @param array<string, string> $map 关键字到提示文案映射
|
||||
* @return string
|
||||
*/
|
||||
private function matchErrorText(string $errorInfo, array $map): string
|
||||
{
|
||||
foreach ($map as $needle => $message) {
|
||||
if (strpos($errorInfo, $needle) !== false) {
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当前用户可见平台。
|
||||
*
|
||||
* 对齐 acgpmw:
|
||||
* 1. 先使用已按 `MemberController` 二次加工后的套餐平台
|
||||
* 2. 146/147 且不在特殊名单中,只允许 D音
|
||||
*
|
||||
* @param Member $member 当前登录用户
|
||||
* @param array<string, mixed>|null $productInfo 套餐信息
|
||||
* @return array<int>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载云图文特殊账号名单。
|
||||
*
|
||||
* @return array<int>
|
||||
*/
|
||||
private function loadSpecialAccounts(): array
|
||||
{
|
||||
$file = root_path() . '../acgpmw/data/other/tw_special_account.php';
|
||||
if (!is_file($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$accounts = require $file;
|
||||
|
||||
return is_array($accounts) ? array_values(array_map('intval', $accounts)) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化可选整数参数。
|
||||
*
|
||||
* @param mixed $value 原始输入
|
||||
* @param string $errorMessage 错误提示
|
||||
* @return int|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function normalizeOptionalInt($value, string $errorMessage): ?int
|
||||
{
|
||||
if ($value === null || $value === '' || $value === 'all') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_numeric((string) $value)) {
|
||||
throw new \Exception($errorMessage, 400);
|
||||
}
|
||||
|
||||
return (int) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一格式化时间。
|
||||
*
|
||||
* @param int $timestamp 时间戳
|
||||
* @return string
|
||||
*/
|
||||
private function formatDateTime(int $timestamp): string
|
||||
{
|
||||
if ($timestamp <= 0) {
|
||||
return '--';
|
||||
}
|
||||
|
||||
return date('Y-m-d H:i', $timestamp);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user