173 lines
6.7 KiB
JavaScript
173 lines
6.7 KiB
JavaScript
import { createTextElement, textValue } from '../../shared/dom.js';
|
|
|
|
const EMPTY_CONNECTION_IDS_HTML = '<p class="text-gray-500 text-sm">\u6682\u65e0\u53ef\u7528\u7684\u8fde\u63a5ID</p>';
|
|
const EMPTY_USERS_HTML = '<p class="text-gray-500 text-sm">\u6682\u65e0\u5728\u7ebf\u7528\u6237</p>';
|
|
const HALL_LABEL = '\u5927\u5385\uff08\u672a\u52a0\u5165\u623f\u95f4\uff09';
|
|
const HOST_LABEL = '\u623f\u4e3b';
|
|
const PARTICIPANT_LABEL = '\u6210\u5458';
|
|
const UNKNOWN_USER_LABEL = '\u533f\u540d\u7528\u6237';
|
|
const UNSET_USER_ID_LABEL = '\u672a\u8bbe\u7f6eID';
|
|
const SELF_LABEL = '\u81ea\u5df1';
|
|
const SELECT_LABEL = '\u9009\u62e9';
|
|
const USER_COUNT_SUFFIX = '\u4eba';
|
|
const ONLINE_USERS_SUMMARY_SUFFIX = ' \u4e2aWebSocket\u7528\u6237\u5728\u7ebf';
|
|
|
|
function getRoleTagClass(role) {
|
|
if (role === 'host') {
|
|
return 'text-xs px-2 py-1 rounded-full bg-indigo-500/20 text-indigo-300';
|
|
}
|
|
if (role === 'participant') {
|
|
return 'text-xs px-2 py-1 rounded-full bg-white/10 text-gray-300';
|
|
}
|
|
return 'text-xs px-2 py-1 rounded-full bg-emerald-500/20 text-emerald-300';
|
|
}
|
|
|
|
export async function fetchOnlineUsers() {
|
|
const response = await fetch('/signaling/users');
|
|
if (!response.ok) {
|
|
throw new Error('Failed to fetch online users');
|
|
}
|
|
|
|
const data = await response.json();
|
|
return Array.isArray(data.users) ? data.users : [];
|
|
}
|
|
|
|
export async function fetchConnectionDirectory() {
|
|
const [connectionResponse, usersResponse] = await Promise.all([
|
|
fetch('/signaling/connection-ids'),
|
|
fetch('/signaling/users')
|
|
]);
|
|
|
|
if (!connectionResponse.ok) {
|
|
throw new Error('Failed to fetch connection IDs');
|
|
}
|
|
if (!usersResponse.ok) {
|
|
throw new Error('Failed to fetch online users');
|
|
}
|
|
|
|
const connectionData = await connectionResponse.json();
|
|
const usersData = await usersResponse.json();
|
|
|
|
return {
|
|
connectionIds: connectionData.connectionIds || [],
|
|
users: Array.isArray(usersData.users) ? usersData.users : []
|
|
};
|
|
}
|
|
|
|
export function renderConnectionIds({ connectionIds, idsContainer, connectionIdsList, onSelectConnectionId }) {
|
|
if (!idsContainer) {
|
|
return;
|
|
}
|
|
|
|
idsContainer.innerHTML = '';
|
|
|
|
if (connectionIds.length === 0) {
|
|
idsContainer.innerHTML = EMPTY_CONNECTION_IDS_HTML;
|
|
} else {
|
|
connectionIds.forEach((connectionId) => {
|
|
const item = document.createElement('div');
|
|
item.className = 'flex items-center justify-between p-2 bg-white/5 rounded-lg hover:bg-white/10 cursor-pointer transition-colors';
|
|
|
|
const label = document.createElement('span');
|
|
label.className = 'text-sm';
|
|
label.textContent = connectionId;
|
|
|
|
const button = document.createElement('button');
|
|
button.className = 'text-xs bg-indigo-600 hover:bg-indigo-700 px-2 py-1 rounded';
|
|
button.type = 'button';
|
|
button.textContent = SELECT_LABEL;
|
|
button.addEventListener('click', () => onSelectConnectionId(connectionId));
|
|
|
|
item.appendChild(label);
|
|
item.appendChild(button);
|
|
idsContainer.appendChild(item);
|
|
});
|
|
}
|
|
|
|
if (connectionIdsList) {
|
|
connectionIdsList.classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
export function renderOnlineUsers({ users, currentUserId, onlineUsersList, usersContainer, onlineUsersSummary }) {
|
|
if (!onlineUsersList || !usersContainer || !onlineUsersSummary) {
|
|
return;
|
|
}
|
|
|
|
onlineUsersSummary.textContent = `${users.length}${ONLINE_USERS_SUMMARY_SUFFIX}`;
|
|
usersContainer.innerHTML = '';
|
|
|
|
if (users.length === 0) {
|
|
usersContainer.innerHTML = EMPTY_USERS_HTML;
|
|
onlineUsersList.classList.remove('hidden');
|
|
return;
|
|
}
|
|
|
|
const groupedUsers = users.reduce((groups, user) => {
|
|
const groupName = user.connectionId ? `\u623f\u95f4 ${user.connectionId}` : HALL_LABEL;
|
|
if (!groups[groupName]) {
|
|
groups[groupName] = [];
|
|
}
|
|
groups[groupName].push(user);
|
|
return groups;
|
|
}, {});
|
|
|
|
Object.entries(groupedUsers).forEach(([groupName, roomUsers]) => {
|
|
const section = document.createElement('div');
|
|
section.className = 'rounded-lg border border-white/10 bg-white/5 p-3';
|
|
|
|
const roomTitle = document.createElement('div');
|
|
roomTitle.className = 'flex items-center justify-between mb-2';
|
|
roomTitle.appendChild(createTextElement('span', 'text-sm font-medium text-white', groupName));
|
|
roomTitle.appendChild(createTextElement('span', 'text-xs text-gray-400', `${roomUsers.length} ${USER_COUNT_SUFFIX}`));
|
|
section.appendChild(roomTitle);
|
|
|
|
const roomList = document.createElement('div');
|
|
roomList.className = 'space-y-2';
|
|
|
|
roomUsers.forEach((user) => {
|
|
const userName = user.name || user.userId || UNKNOWN_USER_LABEL;
|
|
const avatar = user.avatar || '/images/p2.png';
|
|
const roleLabel = user.role === 'host'
|
|
? HOST_LABEL
|
|
: (user.role === 'participant' ? PARTICIPANT_LABEL : HALL_LABEL);
|
|
const isSelf = Boolean(user.userId) && user.userId === currentUserId;
|
|
const identity = user.userId || user.socketId || user.participantId || UNSET_USER_ID_LABEL;
|
|
|
|
const userItem = document.createElement('div');
|
|
userItem.className = 'flex items-center justify-between rounded-lg bg-black/20 px-3 py-2';
|
|
|
|
const profile = document.createElement('div');
|
|
profile.className = 'flex items-center gap-3 min-w-0';
|
|
|
|
const avatarImage = document.createElement('img');
|
|
avatarImage.src = textValue(avatar);
|
|
avatarImage.alt = textValue(userName);
|
|
avatarImage.className = 'w-8 h-8 rounded-full object-cover';
|
|
profile.appendChild(avatarImage);
|
|
|
|
const info = document.createElement('div');
|
|
info.className = 'min-w-0';
|
|
info.appendChild(createTextElement('div', 'text-sm text-white truncate', userName));
|
|
info.appendChild(createTextElement('div', 'text-xs text-gray-400 truncate', identity));
|
|
profile.appendChild(info);
|
|
|
|
const status = document.createElement('div');
|
|
status.className = 'flex items-center gap-2';
|
|
status.appendChild(createTextElement('span', getRoleTagClass(user.role), roleLabel));
|
|
if (isSelf) {
|
|
status.appendChild(createTextElement('span', 'text-xs text-gray-500', SELF_LABEL));
|
|
}
|
|
|
|
userItem.appendChild(profile);
|
|
userItem.appendChild(status);
|
|
roomList.appendChild(userItem);
|
|
});
|
|
|
|
section.appendChild(roomList);
|
|
usersContainer.appendChild(section);
|
|
});
|
|
|
|
onlineUsersList.classList.remove('hidden');
|
|
}
|