From 324b4cee906808236723deef9acec171a947f19c Mon Sep 17 00:00:00 2001 From: moux1024 <403053463@qq.com> Date: Tue, 23 Sep 2025 20:50:53 +0800 Subject: [PATCH 01/10] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20chatbox=E7=9A=84?= =?UTF-8?q?=E6=96=B0=E6=B6=88=E6=81=AF=E6=8F=90=E7=A4=BA=E4=B8=8E=E5=BE=BD?= =?UTF-8?q?=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/SmartChatBox/SmartChatBox.tsx | 22 +++++++++++- components/pages/work-flow.tsx | 46 ++++++++++++++++++------ 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/components/SmartChatBox/SmartChatBox.tsx b/components/SmartChatBox/SmartChatBox.tsx index 7ba47fe..39cb4c9 100644 --- a/components/SmartChatBox/SmartChatBox.tsx +++ b/components/SmartChatBox/SmartChatBox.tsx @@ -19,6 +19,8 @@ interface SmartChatBoxProps { onClearPreview?: () => void; setIsFocusChatInput?: (v: boolean) => void; aiEditingResult?: any; + /** 新消息回调:用于外层处理未展开时的气泡提示 */ + onNewMessage?: (snippet: string) => void; } interface MessageGroup { @@ -47,7 +49,8 @@ export default function SmartChatBox({ previewVideoId, onClearPreview, setIsFocusChatInput, - aiEditingResult + aiEditingResult, + onNewMessage }: SmartChatBoxProps) { // 消息列表引用 const listRef = useRef(null); @@ -103,6 +106,23 @@ export default function SmartChatBox({ onMessagesUpdate: handleMessagesUpdate }); + // 监听消息新增,向外层抛出前10个字符的文本片段 + const prevLenRef = useRef(0); + useEffect(() => { + const len = messages.length; + if (len > prevLenRef.current && len > 0) { + const last = messages[len - 1]; + // 提取第一个文本块 + const textBlock = last.blocks.find(b => (b as any).type === 'text') as any; + const text = textBlock?.text || ''; + if (text && onNewMessage) { + const snippet = text.slice(0, 20); + onNewMessage(snippet); + } + } + prevLenRef.current = len; + }, [messages, onNewMessage]); + // 监听智能剪辑结果,自动发送消息到聊天框 // useEffect(() => { // if (aiEditingResult && isSmartChatBoxOpen) { diff --git a/components/pages/work-flow.tsx b/components/pages/work-flow.tsx index 95e5fa1..0114a13 100644 --- a/components/pages/work-flow.tsx +++ b/components/pages/work-flow.tsx @@ -10,7 +10,7 @@ import { MediaViewer } from "./work-flow/media-viewer"; import { ThumbnailGrid } from "./work-flow/thumbnail-grid"; import { useWorkflowData } from "./work-flow/use-workflow-data"; import { usePlaybackControls } from "./work-flow/use-playback-controls"; -import { Bot, TestTube } from "lucide-react"; +import { Bot, TestTube, MessageCircle } from "lucide-react"; import { GlassIconButton } from '@/components/ui/glass-icon-button'; import { SaveEditUseCase } from "@/app/service/usecase/SaveEditUseCase"; import { useSearchParams } from "next/navigation"; @@ -48,6 +48,8 @@ const WorkFlow = React.memo(function WorkFlow() { const [isEditModalOpen, setIsEditModalOpen] = React.useState(false); const [activeEditTab, setActiveEditTab] = React.useState('1'); const [isSmartChatBoxOpen, setIsSmartChatBoxOpen] = React.useState(true); + const [chatTip, setChatTip] = React.useState(null); + const [hasUnread, setHasUnread] = React.useState(false); const [previewVideoUrl, setPreviewVideoUrl] = React.useState(null); const [previewVideoId, setPreviewVideoId] = React.useState(null); const [isFocusChatInput, setIsFocusChatInput] = React.useState(false); @@ -617,15 +619,30 @@ Please process this video editing request.`; {/* 智能对话按钮 */}
{isMobile ? ( - setIsSmartChatBoxOpen(true)} - className="backdrop-blur-lg" - /> +
+ {(!isSmartChatBoxOpen && chatTip) && ( +
+ {chatTip} +
+ )} + {/* 红点徽标 */} + {(!isSmartChatBoxOpen && hasUnread) && ( + + )} + { + setIsSmartChatBoxOpen(true); + setChatTip(null); + setHasUnread(false); + }} + className="backdrop-blur-lg bg-custom-purple border-transparent hover:opacity-90" + /> +
) : ( { + if (!isSmartChatBoxOpen && snippet) { + setChatTip(snippet); + setHasUnread(true); + // 3秒后自动消失 + setTimeout(() => setChatTip(null), 3000); + } + }} onClearPreview={() => { setPreviewVideoUrl(null); setPreviewVideoId(null); From f82e4d8059b0b678651616aadd553523be6607f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Tue, 23 Sep 2025 20:55:57 +0800 Subject: [PATCH 02/10] =?UTF-8?q?H5=E9=A1=B6=E9=83=A8=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/layout/top-bar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/layout/top-bar.tsx b/components/layout/top-bar.tsx index c83c405..1225494 100644 --- a/components/layout/top-bar.tsx +++ b/components/layout/top-bar.tsx @@ -261,7 +261,7 @@ export function TopBar({ collapsed, isDesktop=true }: { collapsed: boolean, isDe left: (pathname === "/" || !isDesktop) ? "0" : (collapsed ? "2.5rem" : "16rem") }} > -
+
{pathname === "/" && (
); diff --git a/components/ChatInputBox/ChatInputBox.tsx b/components/ChatInputBox/ChatInputBox.tsx index 763b7c1..64d0573 100644 --- a/components/ChatInputBox/ChatInputBox.tsx +++ b/components/ChatInputBox/ChatInputBox.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useEffect, useRef } from "react"; +import { useState, useEffect, useRef, useCallback } from "react"; import { ChevronDown, ChevronUp, @@ -103,6 +103,33 @@ const debounce = (func: Function, wait: number) => { */ export function ChatInputBox({ noData }: { noData: boolean }) { const { isMobile, isDesktop } = useDeviceType(); + + // 模板快捷入口拖动相关状态 + const templateScrollRef = useRef(null); + const [isTemplateDragging, setIsTemplateDragging] = useState(false); + const [templateStartX, setTemplateStartX] = useState(0); + const [templateScrollLeft, setTemplateScrollLeft] = useState(0); + + // 模板快捷入口拖动事件处理 + const handleTemplateMouseDown = useCallback((e: React.MouseEvent) => { + e.preventDefault(); + setIsTemplateDragging(true); + setTemplateStartX(e.pageX - templateScrollRef.current!.offsetLeft); + setTemplateScrollLeft(templateScrollRef.current!.scrollLeft); + }, []); + + const handleTemplateMouseMove = useCallback((e: React.MouseEvent) => { + if (!isTemplateDragging) return; + e.preventDefault(); + const x = e.pageX - templateScrollRef.current!.offsetLeft; + const walk = (x - templateStartX) * 2; + templateScrollRef.current!.scrollLeft = templateScrollLeft - walk; + }, [isTemplateDragging, templateStartX, templateScrollLeft]); + + const handleTemplateMouseUp = useCallback(() => { + setIsTemplateDragging(false); + }, []); + // 控制面板展开/收起状态 const [isExpanded, setIsExpanded] = useState(false); @@ -510,7 +537,14 @@ export function ChatInputBox({ noData }: { noData: boolean }) { {/* 第三行:模板快捷入口水平滚动 */}
-
+
{isTemplateLoading && (!templateStoryList || templateStoryList.length === 0) ? ( // 骨架屏:若正在加载且没有数据 Array.from({ length: 6 }).map((_, idx) => ( @@ -525,7 +559,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
) : ( From 7e49b48d0fc18d25a61c5ff88f67b4d1f3bf4acc Mon Sep 17 00:00:00 2001 From: moux1024 <403053463@qq.com> Date: Wed, 24 Sep 2025 15:24:47 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20h5=E8=A7=86=E9=A2=91?= =?UTF-8?q?=E4=BD=BF=E7=94=A8card=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/pages/home-page2.tsx | 2 +- components/ui/VideoCoverflow.tsx | 41 +++++++++++++++++++------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/components/pages/home-page2.tsx b/components/pages/home-page2.tsx index 0eb4bba..f75a0c4 100644 --- a/components/pages/home-page2.tsx +++ b/components/pages/home-page2.tsx @@ -276,7 +276,7 @@ export function HomePage2() { {/* 动态锚点:来源于服务端 homeTab 配置,title 作为锚点与标题 */} {homeTabs.map((tab) => ( -
(sectionRefs.current as any)[tab.title.toLowerCase()] = el}> +
(sectionRefs.current as any)[tab.title.toLowerCase()] = el}>
))} diff --git a/components/ui/VideoCoverflow.tsx b/components/ui/VideoCoverflow.tsx index b64b350..5f1bd1c 100644 --- a/components/ui/VideoCoverflow.tsx +++ b/components/ui/VideoCoverflow.tsx @@ -2,11 +2,13 @@ import React from 'react'; import { Swiper, SwiperSlide } from 'swiper/react'; -import { Autoplay, EffectCoverflow } from 'swiper/modules'; +import { Autoplay, EffectCoverflow, EffectCards } from 'swiper/modules'; import type { Swiper as SwiperType } from 'swiper/types'; +import { useDeviceType } from '@/hooks/useDeviceType'; import 'swiper/css'; import 'swiper/css/effect-coverflow'; +import 'swiper/css/effect-cards'; /** 默认视频列表(来自 home-page2.tsx 中的数组) */ const DEFAULT_VIDEOS: string[] = [ @@ -40,21 +42,22 @@ const VideoCoverflow: React.FC = ({ }) => { const swiperRef = React.useRef(null); const videoRefs = React.useRef>({}); - const [isMobile, setIsMobile] = React.useState(false); + const { isMobile } = useDeviceType(); const [activeIndex, setActiveIndex] = React.useState(0); const playActive = React.useCallback((activeIndex: number) => { Object.entries(videoRefs.current).forEach(([key, el]) => { - if (!el) return; + const video = el as HTMLVideoElement | null; + if (!video) return; const index = Number(key); if (index === activeIndex) { // 尝试播放当前居中视频 - el.play().catch(() => {}); + video.play().catch(() => {}); } else { // 暂停其他视频,重置到起点以减少解码负担 - el.pause(); + video.pause(); try { - el.currentTime = 0; + video.currentTime = 0; } catch {} } }); @@ -115,28 +118,32 @@ const VideoCoverflow: React.FC = ({

{videos.map((src, index) => ( -
+