tag(功能):加入按照房间名称加入的功能
This commit is contained in:
@@ -23,6 +23,9 @@ type TokenResponse = {
|
||||
}
|
||||
|
||||
type ScreenFeed = { track: Track; label: string }
|
||||
type RoomHistoryItem = { id: string; title: string; visitedAt: string }
|
||||
|
||||
const ROOM_HISTORY_KEY = 'screen-share-room-history'
|
||||
|
||||
function ScreenTrack({ track, label }: ScreenFeed) {
|
||||
const mediaContainerRef = useRef<HTMLDivElement>(null)
|
||||
@@ -76,6 +79,14 @@ function App() {
|
||||
const [inviteCode, setInviteCode] = useState('')
|
||||
const [roomId, setRoomId] = useState('')
|
||||
const [roomTitle, setRoomTitle] = useState('')
|
||||
const [roomHistory, setRoomHistory] = useState<RoomHistoryItem[]>(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem(ROOM_HISTORY_KEY)
|
||||
return stored ? JSON.parse(stored) as RoomHistoryItem[] : []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
})
|
||||
const [connectionState, setConnectionState] = useState<'idle' | 'connecting' | 'connected'>('idle')
|
||||
const [roomRole, setRoomRole] = useState<Role | null>(null)
|
||||
const [isSharing, setIsSharing] = useState(false)
|
||||
@@ -107,6 +118,17 @@ function App() {
|
||||
setRemoteCount(room.remoteParticipants.size)
|
||||
}
|
||||
|
||||
function rememberRoom(room: Pick<RoomHistoryItem, 'id' | 'title'>) {
|
||||
setRoomHistory((history) => {
|
||||
const next = [
|
||||
{ ...room, visitedAt: new Date().toISOString() },
|
||||
...history.filter((item) => item.id !== room.id),
|
||||
].slice(0, 12)
|
||||
localStorage.setItem(ROOM_HISTORY_KEY, JSON.stringify(next))
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
async function submitAuth() {
|
||||
setError('')
|
||||
try {
|
||||
@@ -146,17 +168,39 @@ function App() {
|
||||
}
|
||||
setError('')
|
||||
try {
|
||||
const room = await apiRequest<{ id: string }>('/api/rooms', {
|
||||
const room = await apiRequest<{ id: string; title: string }>('/api/rooms', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ title: roomTitle.trim() }),
|
||||
}, session.token)
|
||||
setRoomId(room.id)
|
||||
setRoomTitle(room.title)
|
||||
rememberRoom(room)
|
||||
await connectRoom(room.id)
|
||||
} catch (cause) {
|
||||
setError(cause instanceof Error ? cause.message : '创建房间失败')
|
||||
}
|
||||
}
|
||||
|
||||
async function joinRoomByTitle() {
|
||||
if (!session || !roomTitle.trim()) {
|
||||
setError('请输入房间标题。')
|
||||
return
|
||||
}
|
||||
setError('')
|
||||
try {
|
||||
const room = await apiRequest<{ id: string; title: string }>('/api/rooms/join-by-title', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ title: roomTitle.trim() }),
|
||||
}, session.token)
|
||||
setRoomId(room.id)
|
||||
setRoomTitle(room.title)
|
||||
rememberRoom(room)
|
||||
await connectRoom(room.id)
|
||||
} catch (cause) {
|
||||
setError(cause instanceof Error ? cause.message : '加入房间失败')
|
||||
}
|
||||
}
|
||||
|
||||
async function connectRoom(targetRoomId = roomId.trim()) {
|
||||
if (!session) return
|
||||
if (!targetRoomId) {
|
||||
@@ -298,15 +342,31 @@ function App() {
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className="join-panel">
|
||||
<label>新房间标题<input value={roomTitle} onChange={(event) => setRoomTitle(event.target.value)} disabled={connected} /></label>
|
||||
<section className="join-panel room-panel">
|
||||
<label>房间标题<input list="room-title-history" value={roomTitle} onChange={(event) => setRoomTitle(event.target.value)} disabled={connected} placeholder="输入标题以创建或加入" />
|
||||
<datalist id="room-title-history">{roomHistory.map((item) => <option key={item.id} value={item.title} />)}</datalist>
|
||||
</label>
|
||||
<button type="button" className="primary" onClick={() => void createRoom()} disabled={connected}>创建房间</button>
|
||||
<label>房间 ID<input value={roomId} onChange={(event) => setRoomId(event.target.value)} disabled={connected} placeholder="创建后或从他人处获得" /></label>
|
||||
{!connected
|
||||
? <button type="button" className="secondary" onClick={() => void connectRoom()} disabled={connectionState === 'connecting'}>{connectionState === 'connecting' ? '正在连接…' : '加入房间'}</button>
|
||||
? <button type="button" className="secondary" onClick={() => void joinRoomByTitle()} disabled={connectionState === 'connecting'}>{connectionState === 'connecting' ? '正在连接…' : '按标题加入'}</button>
|
||||
: <button type="button" className="secondary" onClick={leaveRoom}>离开房间</button>}
|
||||
<label className="advanced-field">房间 ID(备用)<input value={roomId} onChange={(event) => setRoomId(event.target.value)} disabled={connected} placeholder="UUID" /></label>
|
||||
{!connected && <button type="button" className="secondary id-join" onClick={() => void connectRoom()} disabled={connectionState === 'connecting'}>使用 ID 加入</button>}
|
||||
</section>
|
||||
|
||||
{roomHistory.length > 0 && (
|
||||
<section className="room-history">
|
||||
<strong>最近房间</strong>
|
||||
{roomHistory.map((item) => (
|
||||
<button key={item.id} type="button" onClick={() => {
|
||||
setRoomTitle(item.title)
|
||||
setRoomId(item.id)
|
||||
void connectRoom(item.id)
|
||||
}} disabled={connected}>{item.title}</button>
|
||||
))}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{error && <p className="error" role="alert">{error}</p>}
|
||||
|
||||
<section className="status-bar" aria-live="polite">
|
||||
|
||||
Reference in New Issue
Block a user