This commit is contained in:
2025-06-25 16:12:51 +08:00
parent dbcc89b8fb
commit 28aec960e2
15 changed files with 2013 additions and 45 deletions

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nailao - 暗色主题聊天室</title>
<title>奶酪 - 暗色主题聊天室</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.5/axios.min.js"></script>
<style>
@@ -190,6 +190,7 @@
align-items: center;
justify-content: center;
font-weight: bold;
flex-shrink: 0;
}
#logout-btn {
@@ -266,51 +267,79 @@
flex-direction: column;
}
.message {
max-width: 70%;
padding: 12px 16px;
margin-bottom: 1rem;
border-radius: 12px;
position: relative;
.message-container {
display: flex;
margin-bottom: 1.5rem;
animation: fadeIn 0.3s ease-out;
}
.message-container.sent {
align-self: flex-end;
flex-direction: row-reverse;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.message.received {
background: var(--bg-light);
align-self: flex-start;
border-bottom-left-radius: 4px;
.message-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: linear-gradient(45deg, var(--accent), #7e6efc);
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
flex-shrink: 0;
margin: 0 12px;
}
.message.sent {
.message-body {
max-width: 70%;
display: flex;
flex-direction: column;
}
.message-name {
font-size: 0.8rem;
font-weight: bold;
margin-bottom: 4px;
color: var(--text-secondary);
}
.message-bubble {
padding: 12px 16px;
border-radius: 12px;
position: relative;
}
.message-container.received .message-bubble {
background: var(--bg-light);
border-bottom-left-radius: 4px;
align-self: flex-start;
}
.message-container.sent .message-bubble {
background: var(--accent);
color: white;
align-self: flex-end;
border-bottom-right-radius: 4px;
align-self: flex-end;
}
.message-header {
.message-info {
display: flex;
justify-content: space-between;
margin-bottom: 6px;
font-size: 0.8rem;
}
.username {
font-weight: bold;
justify-content: flex-end;
margin-top: 5px;
}
.timestamp {
color: var(--text-secondary);
font-size: 0.7rem;
margin-left: 8px;
color: var(--text-secondary);
}
.sent .timestamp {
.message-container.sent .timestamp {
color: rgba(255, 255, 255, 0.7);
}
@@ -324,6 +353,32 @@
padding: 1.5rem;
border-top: 1px solid var(--border);
background: rgba(30, 30, 30, 0.7);
position: relative;
}
.input-toolbar {
display: flex;
gap: 12px;
margin-bottom: 12px;
}
.toolbar-btn {
width: 36px;
height: 36px;
border-radius: 8px;
background: rgba(255, 255, 255, 0.07);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
font-size: 16px;
cursor: pointer;
transition: all 0.2s;
}
.toolbar-btn:hover {
background: rgba(255, 255, 255, 0.15);
color: var(--text-primary);
}
.input-container {
@@ -471,13 +526,29 @@
::-webkit-scrollbar-thumb:hover {
background: var(--accent);
}
/* 语音录制按钮样式 */
#voice-btn {
transition: all 0.3s;
color: var(--accent);
}
#voice-btn.recording {
animation: pulse 1s infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); box-shadow: 0 0 10px var(--accent); }
100% { transform: scale(1); }
}
</style>
</head>
<body>
<!-- 登录页面 -->
<div id="login-container">
<div class="login-header">
<h1>Nailao云聊天室</h1>
<h1>奶酪云聊天室</h1>
<p>安全通讯 · 暗色主题 · 极致体验</p>
</div>
<form class="login-form" id="login-form">
@@ -526,6 +597,19 @@
</div>
<div class="message-input-area">
<!-- 工具栏 -->
<div class="input-toolbar">
<div class="toolbar-btn" id="image-btn">
<i class="fas fa-image"></i>
</div>
<div class="toolbar-btn" id="voice-btn">
<i class="fas fa-microphone"></i>
</div>
<div class="toolbar-btn" id="attach-btn">
<i class="fas fa-paperclip"></i>
</div>
</div>
<div class="input-container">
<textarea id="message-input" placeholder="输入消息..." autocomplete="off"></textarea>
<div class="input-actions">
@@ -547,12 +631,18 @@
// 当前用户信息
let currentUser = {
id: '',
name: ''
name: '',
avatarColor: '#6a55fa' // 新增用户头像颜色属性
};
// 为不同用户生成不同颜色的头像
const avatarColors = [
'#6a55fa', '#f87171', '#4ade80', '#fbbf24', '#60a5fa', '#c084fc', '#fb923c'
];
// WebSocket连接
let socket = null;
const serverUrl = "ws://t-ws.nailaoyun.cn/ws/";
const serverUrl = "ws://t-ws.奶酪yun.cn/ws/";
// const serverUrl = "ws://127.0.0.1:18282";
// DOM元素引用
@@ -573,6 +663,9 @@
const onlineCount = document.getElementById('online-count');
const emojiBtn = document.getElementById('emoji-btn');
const emojiPicker = document.getElementById('emoji-picker');
const imageBtn = document.getElementById('image-btn');
const voiceBtn = document.getElementById('voice-btn');
const attachBtn = document.getElementById('attach-btn');
// 登录时清除本地缓存
function clearStoredCredentials() {
@@ -612,8 +705,13 @@
currentUser.id = userId;
currentUser.name = userName;
// 为用户生成头像颜色
const randomIndex = Math.floor(Math.random() * avatarColors.length);
currentUser.avatarColor = avatarColors[randomIndex];
// 更新用户UI
userAvatar.textContent = userName.charAt(0).toUpperCase();
userAvatar.style.background = currentUser.avatarColor;
currentUsername.textContent = `${userName} 的聊天`;
// 隐藏登录页,显示聊天页
@@ -637,7 +735,8 @@
socket.send(JSON.stringify({
type: 'login',
userId: currentUser.id,
userName: currentUser.name
userName: currentUser.name,
avatarColor: currentUser.avatarColor
}));
};
@@ -687,6 +786,7 @@
addMessage({
userId: message.userId,
name: message.userName,
avatarColor: message.avatarColor || avatarColors[Math.floor(Math.random() * avatarColors.length)],
text: message.content,
timestamp: new Date(message.timestamp),
type: message.userId === currentUser.id ? 'sent' : 'received'
@@ -711,6 +811,7 @@
type: 'chat',
userId: currentUser.id,
userName: currentUser.name,
avatarColor: currentUser.avatarColor,
content: text,
timestamp: Date.now()
};
@@ -722,6 +823,7 @@
addMessage({
userId: currentUser.id,
name: currentUser.name,
avatarColor: currentUser.avatarColor,
text: text,
timestamp: new Date(),
type: 'sent'
@@ -766,28 +868,33 @@
scrollToBottom();
}
// 添加聊天消息到UI
// 添加聊天消息到UI(优化后的结构)
function addMessage(msg) {
const noMessages = messagesContainer.querySelector('.no-messages');
if (noMessages) noMessages.remove();
const messageElement = document.createElement('div');
messageElement.className = `message ${msg.type}`;
const messageContainer = document.createElement('div');
messageContainer.className = `message-container ${msg.type}`;
// 格式化时间
const hours = msg.timestamp.getHours().toString().padStart(2, '0');
const minutes = msg.timestamp.getMinutes().toString().padStart(2, '0');
const timeString = `${hours}:${minutes}`;
messageElement.innerHTML = `
<div class="message-header">
<span class="username">${msg.name}</span>
messageContainer.innerHTML = `
<div class="message-avatar" style="background: ${msg.avatarColor}">${msg.name.charAt(0).toUpperCase()}</div>
<div class="message-body">
<div class="message-name">${msg.name}</div>
<div class="message-bubble">
<div class="message-content">${escapeHtml(msg.text)}</div>
</div>
<div class="message-info">
<span class="timestamp">${timeString}</span>
</div>
<div class="message-content">${escapeHtml(msg.text)}</div>
`;
</div>
`;
messagesContainer.appendChild(messageElement);
messagesContainer.appendChild(messageContainer);
scrollToBottom();
}
@@ -796,7 +903,6 @@
userListContainer.innerHTML = '';
onlineCount.textContent = `(${users.length})`;
console.log(users, 'ssssssssssssss')
if (users.length === 0) {
userListContainer.innerHTML = '<div class="no-users">暂无在线用户</div>';
return;
@@ -806,7 +912,7 @@
const currentUserItem = document.createElement('div');
currentUserItem.className = 'user-item active';
currentUserItem.innerHTML = `
<div class="user-avatar">${currentUser.name.charAt(0).toUpperCase()}</div>
<div class="user-avatar" style="background: ${currentUser.avatarColor}">${currentUser.name.charAt(0).toUpperCase()}</div>
<div class="user-name">${currentUser.name} ()</div>
<div class="status-indicator connected"></div>
`;
@@ -814,16 +920,17 @@
// 添加其他用户
users.filter(user => user.id != currentUser.id).forEach(user => {
const avatarColor = user.avatarColor || avatarColors[Math.floor(Math.random() * avatarColors.length)];
const userItem = document.createElement('div');
userItem.className = 'user-item';
userItem.innerHTML = `
<div class="user-avatar">${user.name.charAt(0).toUpperCase()}</div>
<div class="user-avatar" style="background: ${avatarColor}">${user.name.charAt(0).toUpperCase()}</div>
<div class="user-name">${user.name}</div>
<div class="status-indicator connected"></div>
`;
userListContainer.appendChild(userItem);
});
// 插入到user-list-container
}
// 初始化Emoji选择器
@@ -881,6 +988,28 @@
location.reload();
}
// 语音录制功能
function handleVoiceRecording() {
if (!voiceBtn.classList.contains('recording')) {
// 开始录制
voiceBtn.classList.add('recording');
voiceBtn.innerHTML = '<i class="fas fa-square"></i>';
document.getElementById('voice-btn').style.backgroundColor = 'rgba(248, 113, 113, 0.2)';
// 这里应该添加实际录制逻辑
setTimeout(() => {
// 模拟完成录制
handleVoiceRecordingEnd();
}, 3000);
}
}
function handleVoiceRecordingEnd() {
voiceBtn.classList.remove('recording');
voiceBtn.innerHTML = '<i class="fas fa-microphone"></i>';
document.getElementById('voice-btn').style.backgroundColor = '';
}
// 事件监听
document.addEventListener('DOMContentLoaded', () => {
initializePage();
@@ -915,6 +1044,19 @@
// 退出登录
logoutBtn.addEventListener('click', handleLogout);
// 图片按钮功能
imageBtn.addEventListener('click', () => {
alert('图片上传功能已准备就绪');
});
// 语音按钮功能
voiceBtn.addEventListener('click', handleVoiceRecording);
// 附件按钮功能
attachBtn.addEventListener('click', () => {
alert('附件上传功能已准备就绪');
});
});
</script>
</body>