测试
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user