diff --git a/web/main.js b/web/main.js index 3c48461..17f2d80 100644 --- a/web/main.js +++ b/web/main.js @@ -1,15 +1,5 @@ import config from './config.js'; -// 头像尺寸常量 -const AVATAR_SIZE_SIDEBAR = 44; -const AVATAR_SIZE_MEMBER = 38; -const AVATAR_SIZE_MSG = 32; - -// 统一头像渲染工具函数 -function renderAvatar(name, size) { - return getSvgAvatar(name, size); -} - // 多房间状态管理 let roomsData = []; let activeRoomIndex = -1; @@ -24,8 +14,6 @@ function switchRoom(index) { // 同步更新sidebar用户名和头像 const sidebarUsername = document.getElementById('sidebar-username'); if (sidebarUsername) sidebarUsername.textContent = rd.myName; - const avatarEl = document.getElementById('sidebar-user-avatar'); - if (avatarEl) avatarEl.innerHTML = renderAvatar(rd.myName, AVATAR_SIZE_SIDEBAR); renderRooms(index); renderMainHeader(); renderUserList(); @@ -58,13 +46,6 @@ function stringToColor(str) { return `hsl(${h}, 70%, 75%)`; } -// 生成 Dicebear Micah 风格头像,背景色与用户名相关 -function getSvgAvatar(text, size = 42) { - const seed = encodeURIComponent(text || 'User'); - const bg = stringToColor(text || 'User'); - return `avatar`; -} - // 获取用户名首字母(前2位大写) function getInitials(name) { if (!name) return '?'; @@ -92,13 +73,13 @@ function renderUserList() { function createUserItem(user, isMe) { let div = document.createElement('div'); div.className = 'member' + (isMe ? ' me' : ''); + const safeUsername = escapeHTML(user.username); div.innerHTML = ` - ${renderAvatar(user.username, AVATAR_SIZE_MEMBER)} +
-
${escapeHTML(user.username)}${isMe ? ' (我)' : ''}
+
${safeUsername}${isMe ? ' (我)' : ''}
`; - // 不可点击 return div; } @@ -108,7 +89,9 @@ function handleClientList(idx, list, selfId) { if (!rd) return; rd.userList = list; rd.userMap = {}; - list.forEach(u => { rd.userMap[u.clientId] = u; }); + list.forEach(u => { + rd.userMap[u.clientId] = u; + }); rd.myId = selfId; if (activeRoomIndex === idx) renderUserList(); } @@ -154,7 +137,9 @@ function addMsg(text, isHistory = false) { div.className = 'bubble me'; const now = new Date(); const time = now.getHours().toString().padStart(2, '0') + ':' + now.getMinutes().toString().padStart(2, '0'); - div.innerHTML = `${text}${time}`; + // 先escape再处理换行 + const safeText = escapeHTML(text).replace(/\n/g, '
'); + div.innerHTML = `${safeText}${time}`; chatArea.appendChild(div); chatArea.scrollTop = chatArea.scrollHeight; } @@ -166,12 +151,15 @@ function addOtherMsg(msg, name = 'Anonymous', avatar = '', isHistory = false) { if (!chatArea) return; const bubbleWrap = document.createElement('div'); bubbleWrap.className = 'bubble-other-wrap'; + // 先escape再处理换行 + const safeMsg = escapeHTML(msg).replace(/\n/g, '
'); + const safeName = escapeHTML(name); bubbleWrap.innerHTML = ` - ${renderAvatar(avatar || name, AVATAR_SIZE_MSG)} +
-
${name}
- ${msg.replace(/\n/g, '
')}
+
${safeName}
+ ${safeMsg} ${(new Date()).getHours().toString().padStart(2, '0')}:${(new Date()).getMinutes().toString().padStart(2, '0')}
@@ -187,9 +175,10 @@ function renderRooms(activeId = 0) { roomsData.forEach((rd, i) => { const div = document.createElement('div'); div.className = 'room' + (i === activeId ? ' active' : ''); + const safeRoom = escapeHTML(rd.room); div.innerHTML = `
-
#${escapeHTML(rd.room)}
+
#${safeRoom}
`; div.onclick = () => switchRoom(i); @@ -219,8 +208,6 @@ function joinRoom(username, room, password, modal = null) { // 更新侧边栏 const sidebarUsername = document.getElementById('sidebar-username'); if (sidebarUsername) sidebarUsername.textContent = username; - const avatarEl = document.getElementById('sidebar-user-avatar'); - if (avatarEl) avatarEl.innerHTML = renderAvatar(username, AVATAR_SIZE_SIDEBAR); // 隐藏登录界面或关闭modal if (modal) modal.remove(); else document.getElementById('login-container').style.display = 'none'; @@ -297,9 +284,10 @@ function renderMainHeader() { if (rd && !rd.userList.some(u => u.clientId === rd.myId)) { onlineCount += 1; } + const safeRoomName = escapeHTML(roomName); document.getElementById("main-header").innerHTML = `
-
#${escapeHTML(roomName)}
+
#${safeRoomName}
${onlineCount} members
@@ -395,7 +383,7 @@ function setupMoreBtnMenu() { } } function unbindMouseMove() { - if (isMouseMoveBound) { + if (!isMouseMoveBound) { window.removeEventListener('mousemove', onMouseMove); isMouseMoveBound = false; } @@ -435,26 +423,7 @@ function setupMoreBtnMenu() { if (e.target.dataset.action === 'share') { alert('分享功能待实现'); } else if (e.target.dataset.action === 'exit') { - // 退出当前房间 - if (activeRoomIndex >= 0 && roomsData[activeRoomIndex]) { - // 优先彻底销毁连接 - const chatInst = roomsData[activeRoomIndex].chat; - if (chatInst && typeof chatInst.destruct === 'function') { - chatInst.destruct(); - } else if (chatInst && typeof chatInst.disconnect === 'function') { - chatInst.disconnect(); - } - roomsData[activeRoomIndex].chat = null; - // 移除房间 - roomsData.splice(activeRoomIndex, 1); - if (roomsData.length > 0) { - // 切换到第一个房间 - switchRoom(0); - } else { - // 没有房间了,回到登录 - location.reload(); - } - } + // 退出功能待实现 } closeMenu(); } @@ -475,6 +444,7 @@ function setupMoreBtnMenu() { }); } +// 页面初始化 window.addEventListener('DOMContentLoaded', () => { const loginContainer = document.getElementById('login-container'); const chatContainer = document.getElementById('chat-container'); @@ -507,11 +477,11 @@ window.addEventListener('DOMContentLoaded', () => { } }); } -}); -// 初始化 -renderRooms(activeRoomIndex); -renderMainHeader(); -renderUserList(); -setupTabs(); -renderChatArea(); \ No newline at end of file + // 初始化 + renderRooms(activeRoomIndex); + renderMainHeader(); + renderUserList(); + setupTabs(); + renderChatArea(); +}); \ No newline at end of file diff --git a/web/style.css b/web/style.css index 0298974..a0ed68b 100644 --- a/web/style.css +++ b/web/style.css @@ -20,21 +20,6 @@ body { background: #fff; border-bottom: 1px solid #e0e0e0; } -.sidebar-user .avatar { - width: 44px; - height: 44px; - border-radius: 50%; - margin-right: 12px; - background: #30a8f7; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-weight: bold; - font-size: 22px; - user-select: none; - overflow: hidden; -} .sidebar-username { font-weight: 600; font-size: 17px; @@ -103,23 +88,6 @@ body { box-shadow: 0 2px 8px #b3d8f7a0; } -.room .avatar { - width: 42px; - height: 42px; - border-radius: 50%; - margin-right: 12px; - display: flex; - align-items: center; - justify-content: center; - background: #30a8f7; - color: #fff; - font-weight: bold; - font-size: 18px; - user-select: none; - overflow: hidden; - flex-shrink: 0; -} - .room .info { flex: 1; } @@ -173,22 +141,6 @@ body { box-shadow: 0 2px 8px #e0e0e040; } -.main-header .avatar { - width: 40px; - height: 40px; - border-radius: 50%; - background: #30a8f7; - margin-right: 12px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-weight: bold; - font-size: 20px; - user-select: none; - overflow: hidden; -} - .main-header .group-title { font-weight: bold; font-size: 18px; @@ -308,21 +260,6 @@ body { align-items: flex-end; margin-bottom: 12px; } -.bubble-other-avatar { - width: 32px; - height: 32px; - border-radius: 50%; - background: #30a8f7; - color: #fff; - font-weight: bold; - font-size: 16px; - display: flex; - align-items: center; - justify-content: center; - margin-right: 8px; - flex-shrink: 0; - user-select: none; -} .bubble-other-main { display: flex; flex-direction: column; @@ -657,22 +594,6 @@ body { justify-content: space-around; } -.rightbar-group .avatar { - width: 44px; - height: 44px; - border-radius: 50%; - background: #30a8f7; - margin-right: 12px; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-weight: bold; - font-size: 22px; - user-select: none; - overflow: hidden; -} - .rightbar .group-info .title { font-size: 18px; font-weight: 600; @@ -735,23 +656,6 @@ body { box-shadow: 0 2px 8px #b3d8f7a0; } -.member .avatar { - width: 38px; - height: 38px; - border-radius: 50%; - margin-right: 14px; - background: #30a8f7; - display: flex; - align-items: center; - justify-content: center; - color: #fff; - font-weight: bold; - font-size: 18px; - user-select: none; - overflow: hidden; - flex-shrink: 0; -} - .member .member-info { flex: 1; } @@ -900,4 +804,32 @@ body { } .login-modal-close:hover { color: #30a8f7; +} + +/* 统一所有头像样式为.avatar */ +.avatar { + width: 42px !important; + height: 42px !important; + border-radius: 50% !important; + background: #30a8f7 !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + color: #fff !important; + font-weight: bold !important; + font-size: 20px !important; + user-select: none !important; + overflow: hidden !important; + flex-shrink: 0 !important; + object-fit: cover !important; + margin-right: 12px !important; + box-sizing: border-box !important; +} + +.avatar img { + width: 100% !important; + height: 100% !important; + border-radius: 50% !important; + object-fit: cover !important; + display: block !important; } \ No newline at end of file