fenghuo/apps/web/app/page.tsx

162 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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.type === 'system'
? 'bg-gray-200 text-gray-700'
: msg.type === '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>
);
}