建房预检测
This commit is contained in:
@@ -8,12 +8,41 @@ import { useEffect,useState } from 'react';
|
|||||||
import { getAuthInfoFromBrowserCookie } from '@/lib/auth';
|
import { getAuthInfoFromBrowserCookie } from '@/lib/auth';
|
||||||
|
|
||||||
import PageLayout from '@/components/PageLayout';
|
import PageLayout from '@/components/PageLayout';
|
||||||
|
import Toast, { ToastProps } from '@/components/Toast';
|
||||||
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
||||||
|
|
||||||
import type { Room, RoomType } from '@/types/watch-room';
|
import type { Room, RoomType } from '@/types/watch-room';
|
||||||
|
|
||||||
type TabType = 'create' | 'join' | 'list';
|
type TabType = 'create' | 'join' | 'list';
|
||||||
|
|
||||||
|
function getScreenShareHostSupportError() {
|
||||||
|
if (typeof window === 'undefined') return null;
|
||||||
|
|
||||||
|
if (!window.isSecureContext) {
|
||||||
|
return '当前环境不是安全上下文(HTTPS/localhost),不支持屏幕共享';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!navigator.mediaDevices?.getDisplayMedia) {
|
||||||
|
return '当前浏览器不支持屏幕共享';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window.RTCPeerConnection === 'undefined') {
|
||||||
|
return '当前浏览器不支持实时屏幕传输';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScreenShareViewerSupportError() {
|
||||||
|
if (typeof window === 'undefined') return null;
|
||||||
|
|
||||||
|
if (typeof window.RTCPeerConnection === 'undefined') {
|
||||||
|
return '当前浏览器不支持实时屏幕传输';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export default function WatchRoomPage() {
|
export default function WatchRoomPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const watchRoom = useWatchRoomContext();
|
const watchRoom = useWatchRoomContext();
|
||||||
@@ -48,6 +77,16 @@ export default function WatchRoomPage() {
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [createLoading, setCreateLoading] = useState(false);
|
const [createLoading, setCreateLoading] = useState(false);
|
||||||
const [joinLoading, setJoinLoading] = useState(false);
|
const [joinLoading, setJoinLoading] = useState(false);
|
||||||
|
const [toast, setToast] = useState<ToastProps | null>(null);
|
||||||
|
|
||||||
|
const showToast = (message: string, type: ToastProps['type'] = 'info') => {
|
||||||
|
setToast({
|
||||||
|
message,
|
||||||
|
type,
|
||||||
|
duration: 3000,
|
||||||
|
onClose: () => setToast(null),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 加载房间列表
|
// 加载房间列表
|
||||||
const loadRooms = async (showLoading = false) => {
|
const loadRooms = async (showLoading = false) => {
|
||||||
@@ -82,10 +121,18 @@ export default function WatchRoomPage() {
|
|||||||
const handleCreateRoom = async (e: React.FormEvent) => {
|
const handleCreateRoom = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!createForm.roomName.trim()) {
|
if (!createForm.roomName.trim()) {
|
||||||
alert('请输入房间名称');
|
showToast('请输入房间名称', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (createForm.roomType === 'screen') {
|
||||||
|
const supportError = getScreenShareHostSupportError();
|
||||||
|
if (supportError) {
|
||||||
|
showToast(`当前设备无法创建屏幕共享房间:${supportError}`, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setCreateLoading(true);
|
setCreateLoading(true);
|
||||||
try {
|
try {
|
||||||
await createRoom({
|
await createRoom({
|
||||||
@@ -106,7 +153,7 @@ export default function WatchRoomPage() {
|
|||||||
roomType: 'sync',
|
roomType: 'sync',
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
alert(error.message || '创建房间失败');
|
showToast(error.message || '创建房间失败', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
setCreateLoading(false);
|
setCreateLoading(false);
|
||||||
}
|
}
|
||||||
@@ -117,10 +164,19 @@ export default function WatchRoomPage() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const targetRoomId = roomId || joinForm.roomId.trim().toUpperCase();
|
const targetRoomId = roomId || joinForm.roomId.trim().toUpperCase();
|
||||||
if (!targetRoomId) {
|
if (!targetRoomId) {
|
||||||
alert('请输入房间ID');
|
showToast('请输入房间ID', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const targetRoom = rooms.find((room) => room.id === targetRoomId);
|
||||||
|
if (targetRoom?.roomType === 'screen') {
|
||||||
|
const supportError = getScreenShareViewerSupportError();
|
||||||
|
if (supportError) {
|
||||||
|
showToast(`当前设备无法加入屏幕共享房间:${supportError}`, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setJoinLoading(true);
|
setJoinLoading(true);
|
||||||
try {
|
try {
|
||||||
const result = await joinRoom({
|
const result = await joinRoom({
|
||||||
@@ -138,7 +194,7 @@ export default function WatchRoomPage() {
|
|||||||
// 注意:加入房间后,isOwner 状态会在 useWatchRoom 中更新
|
// 注意:加入房间后,isOwner 状态会在 useWatchRoom 中更新
|
||||||
// 跳转逻辑会在 useEffect 中处理
|
// 跳转逻辑会在 useEffect 中处理
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
alert(error.message || '加入房间失败');
|
showToast(error.message || '加入房间失败', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
setJoinLoading(false);
|
setJoinLoading(false);
|
||||||
}
|
}
|
||||||
@@ -219,6 +275,14 @@ export default function WatchRoomPage() {
|
|||||||
|
|
||||||
// 从房间列表加入房间
|
// 从房间列表加入房间
|
||||||
const handleJoinFromList = (room: Room) => {
|
const handleJoinFromList = (room: Room) => {
|
||||||
|
if (room.roomType === 'screen') {
|
||||||
|
const supportError = getScreenShareViewerSupportError();
|
||||||
|
if (supportError) {
|
||||||
|
showToast(`当前设备无法加入屏幕共享房间:${supportError}`, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setJoinForm({
|
setJoinForm({
|
||||||
roomId: room.id,
|
roomId: room.id,
|
||||||
password: '',
|
password: '',
|
||||||
@@ -810,6 +874,7 @@ export default function WatchRoomPage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{toast && <Toast {...toast} />}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,47 @@
|
|||||||
import { Monitor, MonitorPlay, Users } from 'lucide-react';
|
import { Monitor, MonitorPlay, Users } from 'lucide-react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import Toast, { ToastProps } from '@/components/Toast';
|
||||||
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
||||||
import { useScreenShare } from '@/hooks/useScreenShare';
|
import { useScreenShare } from '@/hooks/useScreenShare';
|
||||||
|
|
||||||
const NEW_TAB_KEY_PREFIX = 'watch_room_screen_home_opened_';
|
const NEW_TAB_KEY_PREFIX = 'watch_room_screen_home_opened_';
|
||||||
|
|
||||||
|
function getScreenShareHostSupportError() {
|
||||||
|
if (typeof window === 'undefined') return null;
|
||||||
|
|
||||||
|
if (!window.isSecureContext) {
|
||||||
|
return '当前环境不是安全上下文(HTTPS/localhost),不支持屏幕共享';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!navigator.mediaDevices?.getDisplayMedia) {
|
||||||
|
return '当前浏览器不支持屏幕共享';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof window.RTCPeerConnection === 'undefined') {
|
||||||
|
return '当前浏览器不支持实时屏幕传输';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScreenShareViewerSupportError() {
|
||||||
|
if (typeof window === 'undefined') return null;
|
||||||
|
|
||||||
|
if (typeof window.RTCPeerConnection === 'undefined') {
|
||||||
|
return '当前浏览器不支持实时屏幕传输';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
export default function WatchRoomScreenPage() {
|
export default function WatchRoomScreenPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const watchRoom = useWatchRoomContext();
|
const watchRoom = useWatchRoomContext();
|
||||||
const { currentRoom, members, leaveRoom } = watchRoom;
|
const { currentRoom, members, leaveRoom } = watchRoom;
|
||||||
|
const [toast, setToast] = useState<ToastProps | null>(null);
|
||||||
const {
|
const {
|
||||||
currentRoom: screenRoom,
|
currentRoom: screenRoom,
|
||||||
isOwner,
|
isOwner,
|
||||||
@@ -26,6 +56,15 @@ export default function WatchRoomScreenPage() {
|
|||||||
stopSharing,
|
stopSharing,
|
||||||
} = useScreenShare();
|
} = useScreenShare();
|
||||||
|
|
||||||
|
const showToast = (message: string, type: ToastProps['type'] = 'info') => {
|
||||||
|
setToast({
|
||||||
|
message,
|
||||||
|
type,
|
||||||
|
duration: 3000,
|
||||||
|
onClose: () => setToast(null),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!currentRoom) {
|
if (!currentRoom) {
|
||||||
router.replace('/watch-room');
|
router.replace('/watch-room');
|
||||||
@@ -37,6 +76,19 @@ export default function WatchRoomScreenPage() {
|
|||||||
}
|
}
|
||||||
}, [currentRoom, router]);
|
}, [currentRoom, router]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!screenRoom || screenRoom.roomType !== 'screen') return;
|
||||||
|
|
||||||
|
const supportError = isOwner
|
||||||
|
? getScreenShareHostSupportError()
|
||||||
|
: getScreenShareViewerSupportError();
|
||||||
|
if (supportError) {
|
||||||
|
showToast(`当前设备无法使用屏幕共享房间:${supportError}`, 'error');
|
||||||
|
leaveRoom();
|
||||||
|
router.replace('/watch-room');
|
||||||
|
}
|
||||||
|
}, [isOwner, leaveRoom, router, screenRoom?.id, screenRoom?.roomType]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!screenRoom || !isOwner) return;
|
if (!screenRoom || !isOwner) return;
|
||||||
|
|
||||||
@@ -196,6 +248,7 @@ export default function WatchRoomScreenPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{toast && <Toast {...toast} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user