功能:右侧「房间」面板显示所有房间在线人数,点击可切换房间
- ChatController 新增 roomsOnlineStatus() 接口 - GET /rooms/online-status 返回所有房间名称+Redis 实时在线人数 - 右侧面板房间列表动态渲染:当前房间高亮蓝色,有人数绿色徽标,空房间灰色 - 点击其他房间直接跳转,当前房间禁止点击并标注「当前」 - 切换到「房间」Tab 时自动触发拉取
This commit is contained in:
@@ -552,6 +552,31 @@ class ChatController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回所有房间的在线人数,供右侧房间面板轮询使用。
|
||||
*
|
||||
* 合并 rooms 数据库记录与 Redis 在线名单,
|
||||
* 返回 [{ id, name, online, permit_level, door_open }] 数组。
|
||||
*/
|
||||
public function roomsOnlineStatus(): JsonResponse
|
||||
{
|
||||
$rooms = Room::orderBy('id')->get(['id', 'room_name', 'permit_level', 'door_open']);
|
||||
|
||||
$data = $rooms->map(function (Room $room) {
|
||||
$onlineCount = Redis::hlen("room:{$room->id}:users");
|
||||
|
||||
return [
|
||||
'id' => $room->id,
|
||||
'name' => $room->room_name,
|
||||
'online' => (int) $onlineCount,
|
||||
'permit_level' => $room->permit_level ?? 0,
|
||||
'door_open' => (bool) $room->door_open,
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json(['rooms' => $data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 离开房间 (等同于原版 LEAVE.ASP)
|
||||
*
|
||||
|
||||
@@ -55,8 +55,15 @@
|
||||
|
||||
{{-- 房间列表面板 --}}
|
||||
<div class="user-list-content" id="panel-rooms" style="display: none;">
|
||||
<div style="text-align: center; color: #999; padding: 20px 0; font-size: 11px;">
|
||||
<a href="{{ route('rooms.index') }}" target="_blank">打开大厅查看房间列表</a>
|
||||
{{-- 顶部标题栏 --}}
|
||||
<div style="text-align:center; padding:4px 6px; border-bottom:1px solid #cde; background:#f0f6ff;">
|
||||
<div style="color:#336699; font-weight:bold; font-size:12px;">所有聊天室</div>
|
||||
<div style="font-size:10px; color:#999; margin-top:1px;">点击可切换房间</div>
|
||||
</div>
|
||||
|
||||
{{-- 房间列表容器 --}}
|
||||
<div id="rooms-online-list" style="padding:4px 2px;">
|
||||
<div style="text-align:center; color:#bbb; padding:16px 0; font-size:11px;">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
// 切换名单/房间/贴图/酷库 面板
|
||||
['users', 'rooms', 'emoji', 'action'].forEach(t => {
|
||||
document.getElementById('panel-' + t).style.display = t === tab ? 'block' : 'none';
|
||||
document.getElementById('tab-' + t).classList.toggle('active', t === tab);
|
||||
document.getElementById('tab-' + t)?.classList.toggle('active', t === tab);
|
||||
});
|
||||
// 贴图 Tab 懒加载
|
||||
if (tab === 'emoji') {
|
||||
@@ -40,6 +40,64 @@
|
||||
img.removeAttribute('data-src');
|
||||
});
|
||||
}
|
||||
// 房间 Tab:拉取在线人数列表
|
||||
if (tab === 'rooms') {
|
||||
loadRoomsOnlineStatus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拉取所有房间在线人数并渲染到右侧面板
|
||||
*/
|
||||
const _currentRoomId = {{ $room->id }};
|
||||
|
||||
function loadRoomsOnlineStatus() {
|
||||
const container = document.getElementById('rooms-online-list');
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('{{ route('chat.rooms-online-status') }}')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.rooms || !data.rooms.length) {
|
||||
container.innerHTML =
|
||||
'<div style="text-align:center;color:#bbb;padding:16px 0;font-size:11px;">暂无房间</div>';
|
||||
return;
|
||||
}
|
||||
container.innerHTML = data.rooms.map(room => {
|
||||
const isCurrent = room.id === _currentRoomId;
|
||||
const closed = !room.door_open;
|
||||
const bg = isCurrent ? '#ecf4ff' : '#fff';
|
||||
const border = isCurrent ? '#aac5f0' : '#e0eaf5';
|
||||
const nameColor = isCurrent ? '#336699' : (closed ? '#bbb' : '#444');
|
||||
const badge = room.online > 0 ?
|
||||
`<span style="background:#e8f5e9;color:#2e7d32;border-radius:8px;padding:0 5px;font-size:10px;font-weight:bold;">${room.online} 人</span>` :
|
||||
`<span style="background:#f5f5f5;color:#bbb;border-radius:8px;padding:0 5px;font-size:10px;">空</span>`;
|
||||
const currentTag = isCurrent ?
|
||||
`<span style="font-size:9px;color:#336699;opacity:.7;margin-left:3px;">当前</span>` :
|
||||
'';
|
||||
const clickHandler = isCurrent ? '' : `onclick="location.href='/room/${room.id}'"`;
|
||||
|
||||
return `<div ${clickHandler}
|
||||
style="display:flex;align-items:center;justify-content:space-between;
|
||||
padding:5px 8px;margin:2px 3px;border-radius:5px;
|
||||
border:1px solid ${border};background:${bg};
|
||||
cursor:${isCurrent ? 'default' : 'pointer'};
|
||||
transition:background .15s;"
|
||||
onmouseover="if(${!isCurrent}) this.style.background='#ddeeff';"
|
||||
onmouseout="this.style.background='${bg}';">
|
||||
<span style="color:${nameColor};font-size:11px;font-weight:${isCurrent?'bold':'normal'};overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:90px;">
|
||||
${room.name}${currentTag}
|
||||
</span>
|
||||
${badge}
|
||||
</div>`;
|
||||
}).join('');
|
||||
})
|
||||
.catch(() => {
|
||||
container.innerHTML =
|
||||
'<div style="text-align:center;color:#f00;padding:10px;font-size:11px;">加载失败</div>';
|
||||
});
|
||||
}
|
||||
|
||||
// ── 分屏切换 ──────────────────────────────────────
|
||||
|
||||
@@ -147,6 +147,9 @@ Route::middleware(['chat.auth'])->group(function () {
|
||||
// 退出房间
|
||||
Route::post('/room/{id}/leave', [ChatController::class, 'leave'])->name('chat.leave');
|
||||
|
||||
// 所有房间在线人数(右侧房间面板用)
|
||||
Route::get('/rooms/online-status', [ChatController::class, 'roomsOnlineStatus'])->name('chat.rooms-online-status');
|
||||
|
||||
// 头像列表(供选择)
|
||||
Route::get('/headface/list', [ChatController::class, 'headfaceList'])->name('headface.list');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user