Add VIP presence themes and custom greetings
This commit is contained in:
@@ -16,10 +16,10 @@ use App\Models\User;
|
||||
class RoomBroadcastService
|
||||
{
|
||||
/**
|
||||
* 构造函数注入 VIP 服务(用于获取 VIP 专属入场/离场模板)
|
||||
* 构造函数注入会员进退场主题服务。
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly VipService $vipService,
|
||||
private readonly VipPresenceService $vipPresenceService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -43,11 +43,12 @@ class RoomBroadcastService
|
||||
|
||||
// 有 VIP:优先用专属进入模板,无模板则随机词加前缀
|
||||
if ($user->isVip() && $user->vipLevel) {
|
||||
$color = $user->vipLevel->color ?: '#f59e0b';
|
||||
$template = $this->vipService->getJoinMessage($user);
|
||||
$theme = $this->vipPresenceService->buildJoinTheme($user);
|
||||
$color = $theme['color'] ?: '#f59e0b';
|
||||
$template = $theme['text'];
|
||||
|
||||
if ($template) {
|
||||
return [$template, $color];
|
||||
return [(string) $template, $color];
|
||||
}
|
||||
|
||||
$text = '【'.$user->vipIcon().' '.$user->vipName().'】'.$this->randomWelcomeMsg($user);
|
||||
@@ -80,11 +81,12 @@ class RoomBroadcastService
|
||||
|
||||
// 有 VIP:优先用专属离场模板,无模板则随机词加前缀
|
||||
if ($user->isVip() && $user->vipLevel) {
|
||||
$color = $user->vipLevel->color ?: '#f59e0b';
|
||||
$template = $this->vipService->getLeaveMessage($user);
|
||||
$theme = $this->vipPresenceService->buildLeaveTheme($user);
|
||||
$color = $theme['color'] ?: '#f59e0b';
|
||||
$template = $theme['text'];
|
||||
|
||||
if ($template) {
|
||||
return [$template, $color];
|
||||
return [(string) $template, $color];
|
||||
}
|
||||
|
||||
$text = '【'.$user->vipIcon().' '.$user->vipName().'】'.$this->randomLeaveMsg($user);
|
||||
@@ -149,4 +151,36 @@ class RoomBroadcastService
|
||||
|
||||
return $templates[array_rand($templates)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建会员进退场横幅与特效的前端载荷。
|
||||
*
|
||||
* @param string $type join|leave
|
||||
* @return array<string, string|null>
|
||||
*/
|
||||
public function buildVipPresencePayload(User $user, string $type): array
|
||||
{
|
||||
$theme = $type === 'join'
|
||||
? $this->vipPresenceService->buildJoinTheme($user)
|
||||
: $this->vipPresenceService->buildLeaveTheme($user);
|
||||
|
||||
if (empty($theme['enabled'])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$text = trim((string) ($theme['text'] ?? ''));
|
||||
if ($text === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'presence_type' => $type,
|
||||
'presence_text' => $text,
|
||||
'presence_color' => (string) ($theme['color'] ?? ''),
|
||||
'presence_effect' => $theme['effect'] ? (string) $theme['effect'] : null,
|
||||
'presence_banner_style' => (string) ($theme['banner_style'] ?? ''),
|
||||
'presence_level_name' => (string) ($theme['level_name'] ?? ''),
|
||||
'presence_icon' => (string) ($theme['icon'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<?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');
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一构建会员进场或离场的主题数据。
|
||||
*
|
||||
* @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);
|
||||
|
||||
return [
|
||||
'enabled' => true,
|
||||
'type' => $type,
|
||||
'text' => $customMessage ?: $templateMessage,
|
||||
'color' => $vipLevel->color ?: '#f59e0b',
|
||||
'effect' => $type === 'join' ? $this->normalizeEffect($vipLevel->joinEffectKey()) : $this->normalizeEffect($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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user