Files
chatroom/app/Services/VipPresenceService.php
2026-04-12 23:25:38 +08:00

165 lines
4.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 文件功能:会员进退场主题服务
* 统一解析会员等级主题、用户自定义文案、特效和横幅风格,
* 避免聊天室进场与离场逻辑在多个位置重复拼装数据。
*/
namespace App\Services;
use App\Models\User;
/**
* 会员进退场与购买成功主题服务
* 统一生成会员欢迎横幅、离场横幅与购买成功喜报所需的文本、颜色、特效和样式数据。
*/
class VipPresenceService
{
/**
* 构造会员进退场主题服务实例。
*/
public function __construct(
private readonly VipService $vipService,
) {}
/**
* 构建会员入场主题数据。
*
* @return array<string, string|null|bool>
*/
public function buildJoinTheme(User $user): array
{
return $this->buildTheme($user, 'join');
}
/**
* 构建会员离场主题数据。
*
* @return array<string, string|null|bool>
*/
public function buildLeaveTheme(User $user): array
{
return $this->buildTheme($user, 'leave');
}
/**
* 构建会员购买成功主题数据。
*
* @return array<string, string|null|bool>
*/
public function buildPurchaseTheme(User $user): array
{
$vipLevel = $user->vipLevel;
if (! $user->isVip() || ! $vipLevel) {
return [
'enabled' => false,
'type' => 'purchase',
'text' => null,
'color' => null,
'effect' => null,
'banner_style' => null,
'level_name' => null,
'icon' => null,
];
}
return [
'enabled' => true,
'type' => 'purchase',
'text' => sprintf(
'恭喜 %s 成功开通【%s %s】尊享 VIP 特权,大家掌声欢迎!',
$user->username,
$vipLevel->icon ?: '👑',
$vipLevel->name
),
'color' => $vipLevel->color ?: '#f59e0b',
'effect' => 'fireworks',
'banner_style' => $vipLevel->joinBannerStyleKey(),
'level_name' => $vipLevel->name,
'icon' => $vipLevel->icon,
];
}
/**
* 统一构建会员进场或离场的主题数据。
*
* @param string $type join|leave
* @return array<string, string|null|bool>
*/
private function buildTheme(User $user, string $type): array
{
$vipLevel = $user->vipLevel;
if (! $user->isVip() || ! $vipLevel) {
return [
'enabled' => false,
'type' => $type,
'text' => null,
'color' => null,
'effect' => null,
'banner_style' => null,
'level_name' => null,
'icon' => null,
];
}
// 先读取个人自定义文案,只有等级允许时才参与覆盖。
$customMessage = $type === 'join'
? $this->formatCustomMessage($user->custom_join_message, $user->username)
: $this->formatCustomMessage($user->custom_leave_message, $user->username);
if (! $user->canCustomizeVipPresence()) {
$customMessage = null;
}
// 如果用户没有填写自定义文案,则回退到等级模板。
$templateMessage = $type === 'join'
? $this->vipService->getJoinMessage($user)
: $this->vipService->getLeaveMessage($user);
// 只有在等级允许自定义时,才允许覆盖默认特效。
$customEffect = $type === 'join'
? $user->custom_join_effect
: $user->custom_leave_effect;
if (! $user->canCustomizeVipPresence()) {
$customEffect = null;
}
return [
'enabled' => true,
'type' => $type,
'text' => $customMessage ?: $templateMessage,
'color' => $vipLevel->color ?: '#f59e0b',
'effect' => $this->normalizeEffect($customEffect ?: ($type === 'join' ? $vipLevel->joinEffectKey() : $vipLevel->leaveEffectKey())),
'banner_style' => $type === 'join' ? $vipLevel->joinBannerStyleKey() : $vipLevel->leaveBannerStyleKey(),
'level_name' => $vipLevel->name,
'icon' => $vipLevel->icon,
];
}
/**
* 格式化用户自定义文案,支持 {username} 占位符。
*/
private function formatCustomMessage(?string $message, string $username): ?string
{
$message = trim((string) $message);
if ($message === '') {
return null;
}
return str_replace('{username}', $username, $message);
}
/**
* 把 none 这类占位值转换为 null方便外部判断是否要播特效。
*/
private function normalizeEffect(string $effect): ?string
{
return $effect === 'none' ? null : $effect;
}
}