From dea6552983a82c5643dd5edb156e24a361e7b349 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sun, 7 Dec 2025 11:17:56 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E9=9D=A2=E6=9D=BF=E4=B8=AD?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=81=8A=E5=A4=A9=E5=AE=A4=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WATCH_ROOM_README.md | 8 +- src/app/admin/page.tsx | 211 ++++++++++++++++++++++++++ src/app/api/admin/watch-room/route.ts | 98 ++++++++++++ src/lib/admin.types.ts | 6 + 4 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 src/app/api/admin/watch-room/route.ts diff --git a/WATCH_ROOM_README.md b/WATCH_ROOM_README.md index 4f656cc..7674923 100644 --- a/WATCH_ROOM_README.md +++ b/WATCH_ROOM_README.md @@ -91,10 +91,11 @@ pnpm watch-room:server # 在另一个终端运行 ## 待实现功能 🚧 ### 高优先级(核心功能) -- ⏳ **管理面板配置** +- ✅ **管理面板配置** - 添加观影室开关 - 配置服务器类型(内部/外部) - 外部服务器地址和鉴权配置 + - API 端点: `/api/admin/watch-room` ### 中优先级(增强功能) - ⏳ **WebRTC 语音聊天** @@ -292,9 +293,8 @@ interface WatchRoomConfig { ## 已知问题 -1. **管理面板配置未添加**: 目前使用默认配置(启用内部服务器) -2. **语音聊天未实现**: 仅支持文字和表情 -3. **房间成员列表未显示**: 可以在聊天窗口顶部看到在线人数,但没有详细成员列表 +1. **语音聊天未实现**: 仅支持文字和表情 +2. **房间成员列表未显示**: 可以在聊天窗口顶部看到在线人数,但没有详细成员列表 --- diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 03bc9db..8e145df 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -5852,6 +5852,204 @@ const LiveSourceConfig = ({ ); }; +// 观影室配置组件 +const WatchRoomConfig = ({ + config, + refreshConfig, +}: { + config: AdminConfig | null; + refreshConfig: () => Promise; +}) => { + const { alertModal, showAlert, hideAlert } = useAlertModal(); + const { isLoading, withLoading } = useLoadingState(); + const [settings, setSettings] = useState({ + enabled: false, + serverType: 'internal' as 'internal' | 'external', + externalServerUrl: '', + externalServerAuth: '', + }); + + useEffect(() => { + if (config?.WatchRoomConfig) { + setSettings({ + enabled: config.WatchRoomConfig.enabled || false, + serverType: config.WatchRoomConfig.serverType || 'internal', + externalServerUrl: config.WatchRoomConfig.externalServerUrl || '', + externalServerAuth: config.WatchRoomConfig.externalServerAuth || '', + }); + } + }, [config]); + + const handleSave = async () => { + await withLoading('saveWatchRoomConfig', async () => { + try { + // 验证外部服务器配置 + if (settings.serverType === 'external' && !settings.externalServerUrl.trim()) { + showError('外部服务器地址不能为空', showAlert); + return; + } + + const resp = await fetch('/api/admin/watch-room', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(settings), + }); + + if (!resp.ok) { + const data = await resp.json().catch(() => ({})); + throw new Error(data.error || `保存失败: ${resp.status}`); + } + + showSuccess('保存成功,刷新页面后生效', showAlert); + await refreshConfig(); + } catch (err) { + showError(err instanceof Error ? err.message : '保存失败', showAlert); + throw err; + } + }); + }; + + if (!config) { + return ( +
+ 加载中... +
+ ); + } + + return ( +
+ {/* 功能开关 */} +
+
+

+ 启用观影室功能 +

+

+ 开启后,用户可以创建和加入观影室,实现多人同步观看 +

+
+ +
+ + {/* 服务器类型选择 */} +
+ + +

+ {settings.serverType === 'internal' + ? '使用内置的 Socket.IO 服务器,无需额外配置' + : '使用独立部署的 Socket.IO 服务器,适合高并发场景'} +

+
+ + {/* 外部服务器配置 */} + {settings.serverType === 'external' && ( +
+
+ + + setSettings({ ...settings, externalServerUrl: e.target.value }) + } + placeholder='http://your-server:3001' + className='w-full px-3 py-2 text-sm text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent' + /> +

+ 外部 Socket.IO 服务器的完整地址(包含协议和端口) +

+
+ +
+ + + setSettings({ ...settings, externalServerAuth: e.target.value }) + } + placeholder='可选:服务器鉴权密钥' + className='w-full px-3 py-2 text-sm text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400 focus:border-transparent' + /> +

+ 如果外部服务器需要鉴权,请填写密钥 +

+
+
+ )} + + {/* 使用说明 */} +
+
+ 使用说明 +
+
    +
  • 观影室功能允许多人同步观看视频,支持播放控制同步和聊天
  • +
  • 内部服务器模式无需额外配置,适合中小型部署
  • +
  • 外部服务器模式需要单独部署 Socket.IO 服务器(参考 server/watch-room-standalone-server.js)
  • +
  • 更改配置后需要重启服务器才能生效
  • +
+
+ + {/* 保存按钮 */} +
+ +
+ + {/* 通用弹窗组件 */} + +
+ ); +}; + function AdminPageClient() { const { alertModal, showAlert, hideAlert } = useAlertModal(); const { isLoading, withLoading } = useLoadingState(); @@ -5869,6 +6067,7 @@ function AdminPageClient() { configFile: false, dataMigration: false, customAdFilter: false, + watchRoomConfig: false, }); // 获取管理员配置 @@ -6057,6 +6256,18 @@ function AdminPageClient() { + {/* 观影室配置标签 */} + + } + isExpanded={expandedTabs.watchRoomConfig} + onToggle={() => toggleTab('watchRoomConfig')} + > + + + {/* 分类配置标签 */} u.username === username + ); + if (!user || user.role !== 'admin' || user.banned) { + return NextResponse.json({ error: '权限不足' }, { status: 401 }); + } + } + + // 更新缓存中的观影室配置 + adminConfig.WatchRoomConfig = { + enabled, + serverType, + externalServerUrl, + externalServerAuth, + }; + + // 写入数据库 + await db.saveAdminConfig(adminConfig); + + return NextResponse.json( + { ok: true }, + { + headers: { + 'Cache-Control': 'no-store', // 不缓存结果 + }, + } + ); + } catch (error) { + console.error('更新观影室配置失败:', error); + return NextResponse.json( + { + error: '更新观影室配置失败', + details: (error as Error).message, + }, + { status: 500 } + ); + } +} diff --git a/src/lib/admin.types.ts b/src/lib/admin.types.ts index 8f6c30a..b280d02 100644 --- a/src/lib/admin.types.ts +++ b/src/lib/admin.types.ts @@ -63,6 +63,12 @@ export interface AdminConfig { channelNumber?: number; disabled?: boolean; }[]; + WatchRoomConfig?: { + enabled: boolean; + serverType: 'internal' | 'external'; + externalServerUrl?: string; + externalServerAuth?: string; + }; } export interface AdminConfigResult {