Browse Source

feat: 更新WebSocket客户端,添加消息类型支持和自动重连功能

test
hyh 3 months ago
parent
commit
bb9cd356c9
  1. 240
      src/CellularManagement.WebAPI/wwwroot/websocket.html

240
src/CellularManagement.WebAPI/wwwroot/websocket.html

@ -34,6 +34,13 @@
position: relative;
z-index: 1;
}
.stats-card {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(5px);
}
.dark .stats-card {
background: rgba(31, 41, 55, 0.9);
}
</style>
</head>
<body class="bg-gray-50 dark:bg-gray-900 h-screen flex flex-col">
@ -61,6 +68,14 @@
<div class="w-2 h-2 rounded-full bg-red-500 status-dot"></div>
<span class="text-sm text-gray-600 dark:text-gray-300">未连接</span>
</div>
<div id="stats" class="flex items-center space-x-4 ml-4">
<span class="text-sm text-gray-600 dark:text-gray-300">
消息: <span id="messageCount">0</span>
</span>
<span class="text-sm text-gray-600 dark:text-gray-300">
连接: <span id="connectionCount">0</span>
</span>
</div>
</div>
<div class="flex space-x-2">
<button id="connectBtn"
@ -83,11 +98,20 @@
<div class="max-w-4xl mx-auto h-full px-4 py-4">
<div class="flex justify-between items-center mb-2">
<h2 class="text-lg font-semibold text-gray-700 dark:text-gray-300">消息记录</h2>
<button id="clearBtn"
class="px-3 py-1 bg-gray-500 hover:bg-gray-600 text-white rounded-lg
shadow-sm transition-colors duration-200">
清空消息
</button>
<div class="flex space-x-2">
<select id="messageType"
class="px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg
dark:bg-gray-700 dark:text-white">
<option value="message">普通消息</option>
<option value="system">系统消息</option>
<option value="error">错误消息</option>
</select>
<button id="clearBtn"
class="px-3 py-1 bg-gray-500 hover:bg-gray-600 text-white rounded-lg
shadow-sm transition-colors duration-200">
清空消息
</button>
</div>
</div>
<div id="messages" class="h-full overflow-y-auto space-y-4">
<!-- 消息将在这里动态添加 -->
@ -205,6 +229,12 @@
// WebSocket 相关代码
let socket;
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
const reconnectDelay = 3000;
let messageCount = 0;
let connectionCount = 0;
const statusElement = document.getElementById('status');
const statusDot = statusElement.querySelector('.status-dot');
const statusText = statusElement.querySelector('span:last-child');
@ -215,6 +245,9 @@
const sendBtn = document.getElementById('sendBtn');
const wsAddressInput = document.getElementById('wsAddress');
const clearBtn = document.getElementById('clearBtn');
const messageTypeSelect = document.getElementById('messageType');
const messageCountElement = document.getElementById('messageCount');
const connectionCountElement = document.getElementById('connectionCount');
// 更新状态显示
function updateStatus(connected) {
@ -224,6 +257,8 @@
statusText.textContent = '已连接';
statusText.classList.remove('text-gray-600');
statusText.classList.add('text-green-600');
connectionCount++;
connectionCountElement.textContent = connectionCount;
} else {
statusDot.classList.remove('bg-green-500');
statusDot.classList.add('bg-red-500');
@ -234,7 +269,7 @@
}
// 添加消息到显示区域
function addMessage(message, isReceived = false) {
function addMessage(message, isReceived = false, type = 'message') {
const messageElement = document.createElement('div');
messageElement.className = `message flex ${isReceived ? 'justify-start' : 'justify-end'}`;
@ -242,140 +277,145 @@
messageContent.className = `flex items-start space-x-2 max-w-[80%]`;
const avatar = document.createElement('div');
avatar.className = `flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center
text-white font-bold ${isReceived ? 'bg-gray-500' : 'bg-indigo-500'}`;
avatar.textContent = isReceived ? 'S' : '我';
let avatarClass = 'flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center text-white font-bold';
switch(type) {
case 'system':
avatarClass += ' bg-blue-500';
avatar.textContent = '系';
break;
case 'error':
avatarClass += ' bg-red-500';
avatar.textContent = '错';
break;
default:
avatarClass += isReceived ? ' bg-gray-500' : ' bg-indigo-500';
avatar.textContent = isReceived ? 'S' : '我';
}
avatar.className = avatarClass;
const bubble = document.createElement('div');
bubble.className = `p-3 rounded-lg shadow-sm ${
isReceived
? 'bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-200'
: 'bg-indigo-500 text-white'
}`;
bubble.textContent = message;
let bubbleClass = 'p-3 rounded-lg shadow-sm';
if (isReceived) {
messageContent.appendChild(avatar);
messageContent.appendChild(bubble);
} else {
messageContent.appendChild(bubble);
messageContent.appendChild(avatar);
switch(type) {
case 'system':
bubbleClass += ' bg-blue-100 dark:bg-blue-900';
break;
case 'error':
bubbleClass += ' bg-red-100 dark:bg-red-900';
break;
default:
bubbleClass += isReceived ? ' bg-gray-100 dark:bg-gray-700' : ' bg-indigo-100 dark:bg-indigo-900';
}
bubble.className = bubbleClass;
bubble.textContent = message;
messageContent.appendChild(avatar);
messageContent.appendChild(bubble);
messageElement.appendChild(messageContent);
messagesContainer.appendChild(messageElement);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
// 收到消息时更新3D场景
if (isReceived) {
updateParticles();
}
}
// 更新粒子效果
function updateParticles() {
const positions = particleGeometry.attributes.position.array;
const colors = particleGeometry.attributes.color.array;
// 随机更新一些粒子的位置和颜色
for (let i = 0; i < particleCount; i += 10) {
positions[i * 3] = (Math.random() - 0.5) * 20;
positions[i * 3 + 1] = (Math.random() - 0.5) * 20;
positions[i * 3 + 2] = (Math.random() - 0.5) * 20;
colors[i * 3] = Math.random();
colors[i * 3 + 1] = Math.random();
colors[i * 3 + 2] = Math.random();
}
// 滚动到底部
messagesContainer.scrollTop = messagesContainer.scrollHeight;
particleGeometry.attributes.position.needsUpdate = true;
particleGeometry.attributes.color.needsUpdate = true;
// 更新消息计数
messageCount++;
messageCountElement.textContent = messageCount;
}
// 初始化 WebSocket 连接
function initWebSocket() {
const wsAddress = wsAddressInput.value.trim();
if (!wsAddress) {
addMessage('请输入WebSocket地址', true);
return;
}
// 连接WebSocket
function connect() {
try {
// 确保地址以 ws:// 开头
const normalizedAddress = wsAddress.startsWith('ws://')
? wsAddress
: `ws://${wsAddress}`;
socket = new WebSocket(normalizedAddress);
socket = new WebSocket(wsAddressInput.value);
socket.onopen = function() {
updateStatus(true);
addMessage('WebSocket 连接已建立', true);
addMessage('连接成功', false, 'system');
reconnectAttempts = 0;
};
socket.onclose = function(event) {
socket.onclose = function() {
updateStatus(false);
addMessage(`WebSocket 连接已关闭 (${event.code})`, true);
addMessage('连接已关闭', false, 'system');
attemptReconnect();
};
socket.onerror = function(error) {
addMessage(`连接错误: ${error.message || '未知错误'}`, true);
addMessage(`连接错误: ${error.message}`, false, 'error');
};
socket.onmessage = function(event) {
addMessage(event.data, true);
try {
const data = JSON.parse(event.data);
addMessage(data.content, true, data.type || 'message');
} catch (e) {
addMessage(event.data, true);
}
};
} catch (error) {
addMessage(`连接失败: ${error.message}`, true);
addMessage(`连接失败: ${error.message}`, false, 'error');
}
}
// 按钮事件处理
connectBtn.addEventListener('click', function() {
if (!socket || socket.readyState === WebSocket.CLOSED) {
initWebSocket();
// 尝试重新连接
function attemptReconnect() {
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
addMessage(`尝试重新连接 (${reconnectAttempts}/${maxReconnectAttempts})...`, false, 'system');
setTimeout(connect, reconnectDelay);
} else {
addMessage('达到最大重连次数,请手动重连', false, 'error');
}
});
}
disconnectBtn.addEventListener('click', function() {
if (socket && socket.readyState === WebSocket.OPEN) {
socket.close();
// 发送消息
function sendMessage() {
if (!socket || socket.readyState !== WebSocket.OPEN) {
addMessage('未连接到服务器', false, 'error');
return;
}
});
sendBtn.addEventListener('click', function() {
if (socket && socket.readyState === WebSocket.OPEN) {
const message = messageInput.value.trim();
if (message) {
socket.send(message);
addMessage(message);
messageInput.value = '';
}
} else {
addMessage('WebSocket 未连接', true);
const message = messageInput.value.trim();
if (!message) return;
const messageType = messageTypeSelect.value;
const data = {
type: messageType,
content: message,
timestamp: new Date().toISOString()
};
try {
socket.send(JSON.stringify(data));
addMessage(message, false, messageType);
messageInput.value = '';
} catch (error) {
addMessage(`发送失败: ${error.message}`, false, 'error');
}
});
}
// 按回车发送消息
messageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendBtn.click();
// 事件监听
connectBtn.addEventListener('click', connect);
disconnectBtn.addEventListener('click', function() {
if (socket) {
socket.close();
}
});
// 按回车连接WebSocket
wsAddressInput.addEventListener('keypress', function(e) {
sendBtn.addEventListener('click', sendMessage);
messageInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
connectBtn.click();
sendMessage();
}
});
// 清空消息
clearBtn.addEventListener('click', function() {
messagesContainer.innerHTML = '';
messageCount = 0;
messageCountElement.textContent = '0';
});
// 初始化Three.js场景
// 初始化Three.js
initThreeJS();
</script>
</body>

Loading…
Cancel
Save