Files
chatroom/app/Models/VipLevel.php
T

216 lines
5.1 KiB
PHP

<?php
/**
* 文件功能:VIP 会员等级模型
* 存储会员名称、图标、颜色、倍率、专属进入/离开模板
* 后台可完整 CRUD 管理
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class VipLevel extends Model
{
use HasFactory;
/**
* 会员进退场支持的特效选项。
*
* @var array<int, string>
*/
public const EFFECT_OPTIONS = [
'none',
'fireworks',
'rain',
'lightning',
'snow',
'sakura',
'meteors',
'gold-rain',
'hearts',
'confetti',
'fireflies',
];
/**
* 会员进退场支持的横幅风格选项。
*
* @var array<int, string>
*/
public const BANNER_STYLE_OPTIONS = [
'aurora',
'storm',
'royal',
'cosmic',
'farewell',
];
/** @var string 表名 */
protected $table = 'vip_levels';
/** @var array 可批量赋值字段 */
protected $fillable = [
'name',
'icon',
'color',
'exp_multiplier',
'jjb_multiplier',
'join_templates',
'leave_templates',
'join_effect',
'leave_effect',
'join_banner_style',
'leave_banner_style',
'allow_custom_messages',
'sort_order',
'price',
'duration_days',
];
/** @var array 类型转换 */
protected $casts = [
'exp_multiplier' => 'float',
'jjb_multiplier' => 'float',
'sort_order' => 'integer',
'price' => 'float',
'duration_days' => 'integer',
'allow_custom_messages' => 'boolean',
];
/**
* 判断当前等级是否高于指定等级。
* 依靠 sort_order 判断。
*/
public function isHigherThan(self|int|null $other): bool
{
if ($other === null) {
return true;
}
$otherOrder = ($other instanceof self)
? $other->sort_order
: self::where('id', $other)->value('sort_order') ?? 0;
return $this->sort_order > $otherOrder;
}
/**
* 计算相对于另一个等级的差价。
* 如果当前等级价格更低,则返回 0。
*/
public function getUpgradePrice(self|int|null $other): float
{
if ($other === null) {
return (float) $this->price;
}
$otherPrice = ($other instanceof self)
? (float) $other->price
: (float) (self::where('id', $other)->value('price') ?? 0);
$diff = (float) $this->price - $otherPrice;
return max(0.0, $diff);
}
/**
* 关联:该等级下的所有用户
*/
public function users(): HasMany
{
return $this->hasMany(User::class, 'vip_level_id');
}
/**
* 获取进入聊天室的专属欢迎语模板数组
*/
public function getJoinTemplatesArrayAttribute(): array
{
if (empty($this->join_templates)) {
return [];
}
$decoded = json_decode($this->join_templates, true);
return is_array($decoded) ? $decoded : [];
}
/**
* 获取离开聊天室的专属提示语模板数组
*/
public function getLeaveTemplatesArrayAttribute(): array
{
if (empty($this->leave_templates)) {
return [];
}
$decoded = json_decode($this->leave_templates, true);
return is_array($decoded) ? $decoded : [];
}
/**
* 从模板数组中随机选一条,替换 {username} 占位符
*
* @param array $templates 模板数组
* @param string $username 用户名
*/
public static function renderTemplate(array $templates, string $username): ?string
{
if (empty($templates)) {
return null;
}
$template = $templates[array_rand($templates)];
return str_replace('{username}', $username, $template);
}
/**
* 获取规范化后的入场特效键名。
*/
public function joinEffectKey(): string
{
return in_array($this->join_effect, self::EFFECT_OPTIONS, true)
? (string) $this->join_effect
: 'none';
}
/**
* 获取规范化后的离场特效键名。
*/
public function leaveEffectKey(): string
{
return in_array($this->leave_effect, self::EFFECT_OPTIONS, true)
? (string) $this->leave_effect
: 'none';
}
/**
* 获取规范化后的入场横幅风格键名。
*/
public function joinBannerStyleKey(): string
{
return in_array($this->join_banner_style, self::BANNER_STYLE_OPTIONS, true)
? (string) $this->join_banner_style
: 'aurora';
}
/**
* 获取规范化后的离场横幅风格键名。
*/
public function leaveBannerStyleKey(): string
{
return in_array($this->leave_banner_style, self::BANNER_STYLE_OPTIONS, true)
? (string) $this->leave_banner_style
: 'farewell';
}
}