2026-04-24 21:17:44 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 文件功能:聊天室在线用户展示数据服务
|
|
|
|
|
* 负责统一拼装聊天室在线名单、Presence 频道与 Redis 在线状态使用的用户载荷。
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
namespace App\Services;
|
|
|
|
|
|
|
|
|
|
use App\Models\Sysparam;
|
|
|
|
|
use App\Models\User;
|
|
|
|
|
use App\Support\ChatDailyStatusCatalog;
|
|
|
|
|
|
2026-04-25 02:24:24 +08:00
|
|
|
/**
|
|
|
|
|
* 类功能:统一生成聊天室在线用户与身份展示相关载荷。
|
|
|
|
|
*/
|
2026-04-24 21:17:44 +08:00
|
|
|
class ChatUserPresenceService
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* 构建聊天室在线用户载荷。
|
|
|
|
|
*
|
|
|
|
|
* @return array<string, mixed>
|
|
|
|
|
*/
|
|
|
|
|
public function build(User $user): array
|
|
|
|
|
{
|
|
|
|
|
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
2026-04-25 02:24:24 +08:00
|
|
|
$user->loadMissing(['activePosition.position.department', 'vipLevel']);
|
|
|
|
|
$position = $user->activePosition?->position;
|
2026-04-24 21:17:44 +08:00
|
|
|
$payload = [
|
|
|
|
|
'id' => $user->id,
|
|
|
|
|
'user_id' => $user->id,
|
|
|
|
|
'username' => $user->username,
|
|
|
|
|
'level' => $user->user_level,
|
|
|
|
|
'user_level' => $user->user_level,
|
|
|
|
|
'sex' => $user->sex,
|
|
|
|
|
'headface' => $user->headface,
|
|
|
|
|
'headface_url' => $user->headfaceUrl,
|
|
|
|
|
'headfaceUrl' => $user->headfaceUrl,
|
|
|
|
|
'vip_icon' => $user->vipIcon(),
|
|
|
|
|
'vip_name' => $user->vipName(),
|
|
|
|
|
'vip_color' => $user->isVip() ? ($user->vipLevel?->color ?? '') : '',
|
|
|
|
|
'is_admin' => $user->user_level >= $superLevel,
|
|
|
|
|
'position_icon' => $position?->icon ?? '',
|
|
|
|
|
'position_name' => $position?->name ?? '',
|
|
|
|
|
'department_name' => $position?->department?->name ?? '',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$activeStatus = $this->currentDailyStatus($user);
|
|
|
|
|
if ($activeStatus !== null) {
|
|
|
|
|
$payload['daily_status_key'] = $activeStatus['key'];
|
|
|
|
|
$payload['daily_status_label'] = $activeStatus['label'];
|
|
|
|
|
$payload['daily_status_icon'] = $activeStatus['icon'];
|
|
|
|
|
$payload['daily_status_group'] = $activeStatus['group'];
|
|
|
|
|
$payload['daily_status_expires_at'] = $activeStatus['expires_at'];
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 22:47:27 +08:00
|
|
|
$signIdentity = $user->currentSignInIdentity();
|
|
|
|
|
if ($signIdentity !== null) {
|
|
|
|
|
$payload['sign_identity_key'] = $signIdentity->badge_code;
|
|
|
|
|
$payload['sign_identity_label'] = $signIdentity->badge_name;
|
|
|
|
|
$payload['sign_identity_icon'] = $signIdentity->badge_icon ?? '✅';
|
|
|
|
|
$payload['sign_identity_color'] = $signIdentity->badge_color ?? '#0f766e';
|
|
|
|
|
$payload['sign_identity_expires_at'] = $signIdentity->expires_at?->toIso8601String();
|
|
|
|
|
$payload['sign_identity_streak_days'] = (int) data_get($signIdentity->metadata, 'streak_days', 0);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 21:17:44 +08:00
|
|
|
return $payload;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-25 02:24:24 +08:00
|
|
|
/**
|
|
|
|
|
* 构建用户部门、职务与会员展示信息。
|
|
|
|
|
*
|
|
|
|
|
* @return array{
|
|
|
|
|
* department_name: string,
|
|
|
|
|
* position_icon: string,
|
|
|
|
|
* position_name: string,
|
|
|
|
|
* vip_icon: string,
|
|
|
|
|
* vip_name: string,
|
|
|
|
|
* vip_label: string,
|
|
|
|
|
* inline: string
|
|
|
|
|
* }
|
|
|
|
|
*/
|
|
|
|
|
public function buildIdentitySummary(User $user): array
|
|
|
|
|
{
|
|
|
|
|
$user->loadMissing(['activePosition.position.department', 'vipLevel']);
|
|
|
|
|
|
|
|
|
|
$position = $user->activePosition?->position;
|
|
|
|
|
$departmentName = $position?->department?->name ?? '无部门';
|
|
|
|
|
$positionIcon = $position?->icon ?? '';
|
|
|
|
|
$positionName = $position?->name ?? '无职务';
|
|
|
|
|
$vipIcon = $user->vipIcon();
|
|
|
|
|
$vipName = $user->vipName() ?: '普通会员';
|
|
|
|
|
$vipLabel = trim($vipIcon.' '.$vipName);
|
|
|
|
|
$positionLabel = trim($positionIcon.' '.$positionName);
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'department_name' => $departmentName,
|
|
|
|
|
'position_icon' => $positionIcon,
|
|
|
|
|
'position_name' => $positionName,
|
|
|
|
|
'vip_icon' => $vipIcon,
|
|
|
|
|
'vip_name' => $vipName,
|
|
|
|
|
'vip_label' => $vipLabel,
|
|
|
|
|
'inline' => "部门 {$departmentName} · 职务 {$positionLabel} · 会员 {$vipLabel}",
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 21:17:44 +08:00
|
|
|
/**
|
|
|
|
|
* 读取用户当前仍然有效的当日状态。
|
|
|
|
|
*
|
|
|
|
|
* @return array{key: string, label: string, icon: string, group: string, expires_at: string}|null
|
|
|
|
|
*/
|
|
|
|
|
public function currentDailyStatus(User $user): ?array
|
|
|
|
|
{
|
|
|
|
|
return ChatDailyStatusCatalog::resolveActiveStatus(
|
|
|
|
|
$user->daily_status_key,
|
|
|
|
|
$user->daily_status_expires_at,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|