From fffced713cb778f175d56ffadbae2d1d3858b9b8 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sat, 28 Feb 2026 02:15:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=92=AD=E6=94=BE=E9=A1=B5=E9=9D=A2=E7=9A=84?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E5=9C=A8=E5=A4=A7=E5=B1=8F=E4=B8=8B=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=8A=BD=E5=B1=89=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/play/page.tsx | 117 ++++++-- src/components/AIChatPanel.tsx | 217 +++++++++++++- src/components/CorrectDialog.tsx | 54 ++-- src/components/DetailPanel.tsx | 491 ++++++++++++++++++++++++++++++- src/components/Drawer.tsx | 106 +++++++ 5 files changed, 921 insertions(+), 64 deletions(-) create mode 100644 src/components/Drawer.tsx diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index 4e5224f..c76c1eb 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -58,6 +58,7 @@ import DanmakuFilterSettings from '@/components/DanmakuFilterSettings'; import DetailPanel from '@/components/DetailPanel'; import DoubanComments from '@/components/DoubanComments'; import DownloadEpisodeSelector from '@/components/DownloadEpisodeSelector'; +import Drawer from '@/components/Drawer'; import EpisodeSelector from '@/components/EpisodeSelector'; import PageLayout from '@/components/PageLayout'; import PansouSearch from '@/components/PansouSearch'; @@ -132,6 +133,48 @@ function PlayPageClient() { // 详情面板状态 const [showDetailPanel, setShowDetailPanel] = useState(false); + // 大屏设备检测(判断选集面板是否在右侧) + const [isLargeScreen, setIsLargeScreen] = useState(false); + + // 检测是否为大屏设备 + useEffect(() => { + const checkScreenSize = () => { + setIsLargeScreen(window.innerWidth >= 768); // md断点 + }; + + checkScreenSize(); + window.addEventListener('resize', checkScreenSize); + return () => window.removeEventListener('resize', checkScreenSize); + }, []); + + // 抽屉管理:打开指定抽屉时关闭其他抽屉 + const openDrawer = (drawerName: 'pansou' | 'aiChat' | 'correct' | 'detail') => { + if (!isLargeScreen) { + // 小屏设备不需要互斥 + switch (drawerName) { + case 'pansou': + setShowPansouDialog(true); + break; + case 'aiChat': + setShowAIChat(true); + break; + case 'correct': + setShowCorrectDialog(true); + break; + case 'detail': + setShowDetailPanel(true); + break; + } + return; + } + + // 大屏设备:关闭其他抽屉 + setShowPansouDialog(drawerName === 'pansou'); + setShowAIChat(drawerName === 'aiChat'); + setShowCorrectDialog(drawerName === 'correct'); + setShowDetailPanel(drawerName === 'detail'); + }; + // 检查AI功能是否启用 useEffect(() => { if (typeof window !== 'undefined') { @@ -8103,7 +8146,7 @@ function PlayPageClient() { - - - {/* 弹窗内容 */}
+ + ) : ( +
setShowPansouDialog(false)} + > +
e.stopPropagation()} + > + {/* 弹窗头部 */} +
+

+ 搜索网盘资源: {detail?.title || ''} +

+ +
+ + {/* 弹窗内容 */} +
+ +
+
- + ) )} {/* AI问片面板 */} @@ -8436,6 +8495,8 @@ function PlayPageClient() { currentEpisode: currentEpisodeIndex + 1, }} welcomeMessage={aiDefaultMessageWithVideo ? aiDefaultMessageWithVideo.replace('{title}', detail.title || '') : `想了解《${detail.title}》的更多信息吗?我可以帮你查询剧情、演员、评价等。`} + useDrawer={isLargeScreen} + drawerWidth='w-[400px]' /> )} @@ -8460,6 +8521,8 @@ function PlayPageClient() { // 纠错成功后的回调 handleCorrectSuccess(); }} + useDrawer={isLargeScreen} + drawerWidth='w-[400px]' /> )} @@ -8507,6 +8570,8 @@ function PlayPageClient() { } sourceId={detail.id} source={detail.source} + useDrawer={isLargeScreen} + drawerWidth='w-[400px]' /> )} diff --git a/src/components/AIChatPanel.tsx b/src/components/AIChatPanel.tsx index eea4614..ddaf4a9 100644 --- a/src/components/AIChatPanel.tsx +++ b/src/components/AIChatPanel.tsx @@ -20,6 +20,8 @@ interface AIChatPanelProps { context?: VideoContext; welcomeMessage?: string; onStreamingChange?: (isStreaming: boolean) => void; + useDrawer?: boolean; + drawerWidth?: string; } export default function AIChatPanel({ @@ -28,6 +30,8 @@ export default function AIChatPanel({ context, welcomeMessage = '你好!我是MoonTVPlus的AI影视助手,有什么可以帮你的吗?', onStreamingChange, + useDrawer = false, + drawerWidth = 'w-full md:w-[25%]', }: AIChatPanelProps) { // 使用 useMemo 稳定 storage key,只在实际内容变化时才改变 const storageKey = useMemo(() => { @@ -136,22 +140,24 @@ export default function AIChatPanel({ inputRef.current.focus(); } - // 防止背景滚动 - const originalOverflow = document.body.style.overflow; - const originalPaddingRight = document.body.style.paddingRight; + // 只在非抽屉模式下防止背景滚动 + if (!useDrawer) { + const originalOverflow = document.body.style.overflow; + const originalPaddingRight = document.body.style.paddingRight; - // 获取滚动条宽度 - const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; + // 获取滚动条宽度 + const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; - document.body.style.overflow = 'hidden'; - document.body.style.paddingRight = `${scrollbarWidth}px`; + document.body.style.overflow = 'hidden'; + document.body.style.paddingRight = `${scrollbarWidth}px`; - return () => { - document.body.style.overflow = originalOverflow; - document.body.style.paddingRight = originalPaddingRight; - }; + return () => { + document.body.style.overflow = originalOverflow; + document.body.style.paddingRight = originalPaddingRight; + }; + } } - }, [isOpen]); + }, [isOpen, useDrawer]); const handleSendMessage = async () => { if (!input.trim() || isStreaming) return; @@ -303,7 +309,192 @@ export default function AIChatPanel({ console.log('已清空聊天上下文'); }; - const modalContent = ( + const modalContent = useDrawer ? ( + // 抽屉模式 +
+
+ {/* 头部 */} +
+
+
+ +
+
+

+ AI影视助手 +

+ {context?.title && ( +

+ 正在讨论: {context.title} + {context.year && ` (${context.year})`} +

+ )} +
+
+ +
+ + {/* 消息列表 */} +
+
+ {messages.map((message, index) => ( +
+
+ {/* 头像 */} +
+ {message.role === 'user' ? ( + + U + + ) : ( + + )} +
+ + {/* 消息内容 */} +
+ {message.role === 'user' ? ( +

+ {message.content} +

+ ) : ( +
+ + {message.content} + +
+ )} +
+
+
+ ))} + + {/* 加载指示器 */} + {isStreaming && ( +
+
+
+ +
+
+ + + AI正在思考... + +
+
+
+ )} + +
+
+
+ + {/* 输入区域 */} +
+
+ +