diff --git a/components/pages/work-flow.tsx b/components/pages/work-flow.tsx index 71c2ff5..fc15f17 100644 --- a/components/pages/work-flow.tsx +++ b/components/pages/work-flow.tsx @@ -8,13 +8,13 @@ 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 { AlertCircle, RefreshCw, Pause, Play, ChevronLast, MessageSquareText } from "lucide-react"; +import { AlertCircle, RefreshCw, Pause, Play, ChevronLast, ChevronsLeft, Bot, BriefcaseBusiness, Scissors } from "lucide-react"; import { motion } from "framer-motion"; import { GlassIconButton } from '@/components/ui/glass-icon-button'; import { SaveEditUseCase } from "@/app/service/usecase/SaveEditUseCase"; import { useSearchParams } from "next/navigation"; import SmartChatBox from "@/components/SmartChatBox/SmartChatBox"; -import { Drawer } from 'antd'; +import { Drawer, Tooltip } from 'antd'; const WorkFlow = React.memo(function WorkFlow() { useEffect(() => { @@ -28,6 +28,7 @@ const WorkFlow = React.memo(function WorkFlow() { const [previewVideoUrl, setPreviewVideoUrl] = React.useState(null); const [previewVideoId, setPreviewVideoId] = React.useState(null); const [isFocusChatInput, setIsFocusChatInput] = React.useState(false); + const [isHovered, setIsHovered] = React.useState(false); const searchParams = useSearchParams(); const episodeId = searchParams.get('episodeId') || ''; @@ -92,6 +93,7 @@ const WorkFlow = React.memo(function WorkFlow() { isPauseWorkFlow={isPauseWorkFlow} showGotoCutButton={showGotoCutButton} onGotoCut={generateEditPlan} + setIsPauseWorkFlow={setIsPauseWorkFlow} /> @@ -100,41 +102,10 @@ const WorkFlow = React.memo(function WorkFlow() { className="videoContainer-qteKNi" ref={containerRef} > - {dataLoadError ? ( - - - -

数据加载失败

-
- -

- {dataLoadError} -

- - retryLoadData?.()} - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - - 重试加载 - -
- ) : isLoading ? ( + {isLoading ? ( ) : ( -
+
)} @@ -171,35 +145,18 @@ const WorkFlow = React.memo(function WorkFlow() {
- {/* 暂停/播放按钮 */} - { - (taskObject.currentStage !== 'final_video') && ( -
- setIsPauseWorkFlow(!isPauseWorkFlow)} - /> - { !mode.includes('auto') && ( - - )} -
- ) - } - {/* 智能对话按钮 */} -
- setIsSmartChatBoxOpen(true)} - /> +
+ + setIsSmartChatBoxOpen(true)} + className="backdrop-blur-lg" + /> +
{/* 智能对话弹窗 */} diff --git a/components/pages/work-flow/media-viewer.tsx b/components/pages/work-flow/media-viewer.tsx index bc00f00..e671f4c 100644 --- a/components/pages/work-flow/media-viewer.tsx +++ b/components/pages/work-flow/media-viewer.tsx @@ -2,7 +2,7 @@ import React, { useRef, useEffect, useState, SetStateAction, useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; -import { Edit3, Play, Pause, Volume2, VolumeX, Maximize, Minimize, Loader2, X } from 'lucide-react'; +import { Edit3, Play, Pause, Volume2, VolumeX, Maximize, Minimize, Loader2, X, Scissors } from 'lucide-react'; import { ProgressiveReveal, presets } from '@/components/ui/progressive-reveal'; import { GlassIconButton } from '@/components/ui/glass-icon-button'; import { ScriptRenderer } from '@/components/script-renderer/ScriptRenderer'; @@ -26,6 +26,9 @@ interface MediaViewerProps { mode: string; onOpenChat?: () => void; setVideoPreview?: (url: string, id: string) => void; + showGotoCutButton?: boolean; + onGotoCut: () => void; + isSmartChatBoxOpen: boolean; } export const MediaViewer = React.memo(function MediaViewer({ @@ -41,11 +44,14 @@ export const MediaViewer = React.memo(function MediaViewer({ applyScript, mode, onOpenChat, - setVideoPreview + setVideoPreview, + showGotoCutButton, + onGotoCut, + isSmartChatBoxOpen }: MediaViewerProps) { const mainVideoRef = useRef(null); const finalVideoRef = useRef(null); - + const videoContentRef = useRef(null); // 音量控制状态 const [isMuted, setIsMuted] = useState(false); const [volume, setVolume] = useState(0.8); @@ -55,6 +61,17 @@ export const MediaViewer = React.memo(function MediaViewer({ const [isFullscreen, setIsFullscreen] = useState(false); const [finalVideoReady, setFinalVideoReady] = useState(false); const [userHasInteracted, setUserHasInteracted] = useState(false); + const [toosBtnRight, setToodsBtnRight] = useState('1rem'); + + useEffect(() => { + if (isSmartChatBoxOpen) { + const videoContentWidth = videoContentRef.current?.clientWidth ?? 0; + const right = (window.innerWidth * 0.25) - ((window.innerWidth - videoContentWidth) / 2) + 32; + setToodsBtnRight(right + 'px'); + } else { + setToodsBtnRight('1rem'); + } + }, [isSmartChatBoxOpen]) // 音量控制函数 const toggleMute = () => { @@ -421,12 +438,13 @@ export const MediaViewer = React.memo(function MediaViewer({ }; // 渲染视频内容 - const renderVideoContent = () => { + const renderVideoContent = (onGotoCut: () => void) => { const urls = taskObject.videos.data[currentSketchIndex].urls ? taskObject.videos.data[currentSketchIndex].urls.join(',') : ''; return (
{/* 背景模糊的图片 */} {taskObject.videos.data[currentSketchIndex].video_status !== 1 && ( @@ -479,22 +497,26 @@ export const MediaViewer = React.memo(function MediaViewer({ /> - {/* 添加到chat去编辑 按钮 */} - - - + }} /> + + {showGotoCutButton && ( + + + + )} +
)} @@ -672,7 +694,7 @@ export const MediaViewer = React.memo(function MediaViewer({ } if (taskObject.currentStage === 'video') { - return renderVideoContent(); + return renderVideoContent(onGotoCut); } if (taskObject.currentStage === 'script') { diff --git a/components/pages/work-flow/task-info.tsx b/components/pages/work-flow/task-info.tsx index bc51417..bde835d 100644 --- a/components/pages/work-flow/task-info.tsx +++ b/components/pages/work-flow/task-info.tsx @@ -8,7 +8,9 @@ import { Heart, Camera, Film, - Scissors + Scissors, + Play, + Pause } from 'lucide-react'; import { TaskObject } from '@/api/DTO/movieEdit'; import { GlassIconButton } from '@/components/ui/glass-icon-button'; @@ -21,6 +23,7 @@ interface TaskInfoProps { isPauseWorkFlow: boolean; showGotoCutButton: boolean; onGotoCut?: () => void; + setIsPauseWorkFlow: (isPauseWorkFlow: boolean) => void; } const stageIconMap = { @@ -46,7 +49,7 @@ const TAG_COLORS = ['#924eadcc', '#4c90a0', '#3b4a5a', '#957558']; // const TAG_COLORS = ['#6bf5f9', '#92a6fc', '#ac71fd', '#c73dfe']; // 阶段图标组件 -const StageIcons = ({ currentStage, isExpanded, isPauseWorkFlow }: { currentStage: number, isExpanded: boolean, isPauseWorkFlow: boolean }) => { +const StageIcons = ({ currentStage, isExpanded, isPauseWorkFlow, setIsPauseWorkFlow }: { currentStage: number, isExpanded: boolean, isPauseWorkFlow: boolean, setIsPauseWorkFlow: (isPauseWorkFlow: boolean) => void }) => { // 根据当前阶段重新排序图标 const orderedStages = useMemo(() => { const stages = Object.entries(stageIconMap).map(([stage, data]) => ({ @@ -58,69 +61,73 @@ const StageIcons = ({ currentStage, isExpanded, isPauseWorkFlow }: { currentStag }, [currentStage]); return ( - - - {orderedStages.map((stage, index) => { - const isCurrentStage = stage.stage === currentStage; - const Icon = stage.icon; - - // 只显示当前阶段或展开状态 - if (!isExpanded && !isCurrentStage) return null; - - return ( - 0 ? '8px' : '0px', - zIndex: isCurrentStage ? 2 : 1 - }} - > + + setIsPauseWorkFlow(!isPauseWorkFlow)} + > + + {orderedStages.map((stage, index) => { + const isCurrentStage = stage.stage === currentStage; + const Icon = stage.icon; + + // 只显示当前阶段或展开状态 + if (!isExpanded && !isCurrentStage) return null; + + return ( 0 ? '8px' : '0px', + zIndex: isCurrentStage ? 2 : 1 + }} > - + + + + - - ); - })} - - + ); + })} + + + ); }; @@ -130,7 +137,8 @@ export function TaskInfo({ roles, isPauseWorkFlow, showGotoCutButton, - onGotoCut + onGotoCut, + setIsPauseWorkFlow }: TaskInfoProps) { const [isScriptModalOpen, setIsScriptModalOpen] = useState(false); const [currentStage, setCurrentStage] = useState(0); @@ -284,7 +292,7 @@ export function TaskInfo({ onMouseEnter={() => setIsStageIconsExpanded(true)} onMouseLeave={() => setIsStageIconsExpanded(false)} > - + */} - {/* 跳转剪辑按钮 */} + {/* // 跳转剪辑按钮 {showGotoCutButton && ( - )} + )} */} )} diff --git a/components/ui/glass-icon-button.tsx b/components/ui/glass-icon-button.tsx index 291b694..753380b 100644 --- a/components/ui/glass-icon-button.tsx +++ b/components/ui/glass-icon-button.tsx @@ -13,6 +13,7 @@ interface GlassIconButtonProps { size?: 'sm' | 'md' | 'lg'; className?: string; [key: string]: any; // To allow spreading other props + text?: string; } const variantStyles = { @@ -37,12 +38,12 @@ const iconSizes = { const MotionButton = motion.button; export const GlassIconButton = forwardRef( - ({ icon: Icon, tooltip, variant = 'secondary', size = 'md', className, ...props }, ref) => { + ({ icon: Icon, tooltip, variant = 'secondary', size = 'md', className, text, ...props }, ref) => { return ( + {text && ( + {text} + )} {tooltip && (