162 lines
4.5 KiB
TypeScript
162 lines
4.5 KiB
TypeScript
'use client';
|
||
import { useHello, useTRPC, useWebSocket, MessageType } from '@repo/client';
|
||
import { useQuery } from '@tanstack/react-query';
|
||
import { useRef, useState } from 'react';
|
||
|
||
export default function Home() {
|
||
const trpc = useTRPC();
|
||
const { data, isLoading } = useQuery(trpc.user.getUser.queryOptions());
|
||
const [message, setMessage] = useState('');
|
||
const [roomId, setRoomId] = useState('');
|
||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||
|
||
// 使用 WebSocket hook
|
||
const { messages, currentRoom, connecting, joinRoom, leaveRoom, sendMessage } = useWebSocket();
|
||
|
||
// 滚动到底部
|
||
const scrollToBottom = () => {
|
||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||
setTimeout(scrollToBottom, 100);
|
||
};
|
||
|
||
const handleJoinRoom = async () => {
|
||
const success = await joinRoom(roomId.trim());
|
||
if (success) {
|
||
setRoomId('');
|
||
}
|
||
};
|
||
|
||
const handleLeaveRoom = async () => {
|
||
await leaveRoom();
|
||
};
|
||
|
||
const handleSendMessage = async () => {
|
||
const success = await sendMessage({
|
||
text: message,
|
||
type: MessageType.TEXT,
|
||
});
|
||
if (success) {
|
||
setMessage('');
|
||
}
|
||
};
|
||
|
||
// 处理按回车发送消息
|
||
const handleKeyPress = (e: React.KeyboardEvent) => {
|
||
if (e.key === 'Enter' && !e.shiftKey) {
|
||
e.preventDefault();
|
||
handleSendMessage();
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="p-4">
|
||
<h1 className="text-2xl font-bold mb-4">WebSocket 房间测试</h1>
|
||
|
||
{/* 房间管理 */}
|
||
<div className="mb-6 p-4 border rounded">
|
||
<h2 className="text-xl mb-2">房间管理</h2>
|
||
{!currentRoom ? (
|
||
<div className="flex gap-2">
|
||
<input
|
||
type="text"
|
||
value={roomId}
|
||
onChange={(e) => setRoomId(e.target.value)}
|
||
onKeyPress={handleKeyPress}
|
||
disabled={connecting}
|
||
className="border border-gray-300 rounded px-3 py-2 flex-1"
|
||
placeholder="输入房间ID..."
|
||
/>
|
||
<button
|
||
onClick={handleJoinRoom}
|
||
disabled={connecting}
|
||
className={`px-4 py-2 rounded text-white ${
|
||
connecting ? 'bg-gray-400 cursor-not-allowed' : 'bg-green-500 hover:bg-green-600'
|
||
}`}
|
||
>
|
||
{connecting ? '连接中...' : '加入房间'}
|
||
</button>
|
||
</div>
|
||
) : (
|
||
<div className="flex gap-2 items-center">
|
||
<span>当前房间: {currentRoom}</span>
|
||
<button
|
||
onClick={handleLeaveRoom}
|
||
disabled={connecting}
|
||
className={`px-4 py-2 rounded text-white ${
|
||
connecting ? 'bg-gray-400 cursor-not-allowed' : 'bg-red-500 hover:bg-red-600'
|
||
}`}
|
||
>
|
||
离开房间
|
||
</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* 消息显示区域 */}
|
||
{currentRoom && (
|
||
<div className="mb-4">
|
||
<div className="border rounded p-4 h-[400px] overflow-y-auto mb-4 bg-gray-50">
|
||
{messages.map((msg, index) => (
|
||
<div
|
||
key={index}
|
||
className={`mb-2 p-2 rounded ${
|
||
msg.action === 'system'
|
||
? 'bg-gray-200 text-gray-700'
|
||
: msg.action === 'error'
|
||
? 'bg-red-100 text-red-700'
|
||
: 'bg-blue-100 text-blue-700'
|
||
}`}
|
||
>
|
||
<div className="flex items-center gap-2">
|
||
{msg.data.type === MessageType.IMAGE && msg.data.fileUri && (
|
||
<img src={msg.data.fileUri} alt="图片消息" className="max-w-xs" />
|
||
)}
|
||
{msg.data.type === MessageType.FILE && msg.data.fileUri && (
|
||
<a
|
||
href={msg.data.fileUri}
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="text-blue-600 hover:underline"
|
||
>
|
||
下载文件
|
||
</a>
|
||
)}
|
||
{msg.data.text && <div>{msg.data.text}</div>}
|
||
</div>
|
||
</div>
|
||
))}
|
||
<div ref={messagesEndRef} />
|
||
</div>
|
||
<div className="flex gap-2">
|
||
<input
|
||
type="text"
|
||
value={message}
|
||
onChange={(e) => setMessage(e.target.value)}
|
||
onKeyPress={handleKeyPress}
|
||
disabled={connecting}
|
||
className="border border-gray-300 rounded px-3 py-2 flex-1"
|
||
placeholder="输入消息..."
|
||
/>
|
||
<button
|
||
onClick={handleSendMessage}
|
||
disabled={connecting}
|
||
className={`px-4 py-2 rounded text-white ${
|
||
connecting ? 'bg-gray-400 cursor-not-allowed' : 'bg-blue-500 hover:bg-blue-600'
|
||
}`}
|
||
>
|
||
发送
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{!currentRoom && (
|
||
<div>
|
||
<p className="text-gray-600">提示: 请先加入一个房间开始聊天</p>
|
||
<p className="text-gray-600">打开多个浏览器窗口,输入相同的房间ID来测试房间内通信</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|