forked from 77media/video-flow
成片视频展示位置更换,与分镜视频排在一起 图标区分
This commit is contained in:
parent
86d0b8f153
commit
a55f7ad1d4
@ -54,7 +54,6 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
const [previewVideoId, setPreviewVideoId] = React.useState<string | null>(null);
|
||||
const [isFocusChatInput, setIsFocusChatInput] = React.useState(false);
|
||||
const [selectedView, setSelectedView] = React.useState<'final' | 'video' | null>(null);
|
||||
const [isFinalBarOpen, setIsFinalBarOpen] = React.useState(true);
|
||||
|
||||
const [aiEditingResult, setAiEditingResult] = React.useState<any>(null);
|
||||
// const aiEditingButtonRef = useRef<{ handleAIEditing: () => Promise<void> }>(null);
|
||||
@ -248,12 +247,12 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
console.log('changedIndex_work-flow', currentSketchIndex, taskObject);
|
||||
}, [currentSketchIndex, taskObject]);
|
||||
|
||||
// 当最终视频出现时,默认选中最终视频
|
||||
// 当最终视频出现时,强制切换到最终视频
|
||||
useEffect(() => {
|
||||
if (taskObject?.final?.url && selectedView === null) {
|
||||
if (taskObject?.final?.url) {
|
||||
setSelectedView('final');
|
||||
}
|
||||
}, [taskObject?.final?.url, selectedView]);
|
||||
}, [taskObject?.final?.url]);
|
||||
|
||||
// 监听粗剪是否完成
|
||||
useEffect(() => {
|
||||
@ -450,37 +449,6 @@ Please process this video editing request.`;
|
||||
>
|
||||
{isDesktop ? (
|
||||
<div className={`relative heroVideo-FIzuK1 ${['script'].includes(taskObject.currentStage) ? 'h-[calc(100vh-6rem)] w-[calc((100vh-6rem)/9*16)]' : 'h-[calc(100vh-6rem-200px)] w-[calc((100vh-6rem-200px)/9*16)]'}`} style={{ aspectRatio: "16 / 9" }} key={taskObject.currentStage+'_'+currentSketchIndex}>
|
||||
{/* 左侧最终视频缩略图栏(仅桌面) */}
|
||||
{taskObject?.final?.url && (
|
||||
<div
|
||||
className="absolute left-0 top-0 z-[50]"
|
||||
data-alt="final-sidebar"
|
||||
>
|
||||
<div className={`flex items-start`}>
|
||||
{isFinalBarOpen && (
|
||||
<div
|
||||
className="w-28 max-h-[60vh] overflow-y-auto rounded-lg backdrop-blur-lg bg-black/30 border border-white/20 shadow-xl p-2 mr-2"
|
||||
data-alt="final-thumbnails"
|
||||
>
|
||||
{/* 预留历史列表,目前仅展示当前最终视频 */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSelectedView('final')}
|
||||
className={`block w-full overflow-hidden rounded-md border ${selectedView === 'final' ? 'border-blue-500' : 'border-white/20'}`}
|
||||
data-alt="final-thumb-item"
|
||||
aria-label="Select final video"
|
||||
>
|
||||
<img
|
||||
src={getFirstFrame(taskObject.final.url)}
|
||||
alt="final"
|
||||
className="w-full h-auto object-cover"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<MediaViewer
|
||||
taskObject={taskObject}
|
||||
scriptData={scriptData}
|
||||
@ -540,8 +508,15 @@ Please process this video editing request.`;
|
||||
taskObject={taskObject}
|
||||
currentSketchIndex={currentSketchIndex}
|
||||
onSketchSelect={(index) => {
|
||||
if (index === -1) {
|
||||
// 点击最终视频
|
||||
setSelectedView('final');
|
||||
setCurrentSketchIndex(0);
|
||||
} else {
|
||||
// 点击普通视频
|
||||
setSelectedView('video');
|
||||
setCurrentSketchIndex(index);
|
||||
}
|
||||
}}
|
||||
onRetryVideo={handleRetryVideo}
|
||||
className={isDesktop ? 'auto-cols-[20%]' : (isTablet ? 'auto-cols-[25%]' : 'auto-cols-[33%]')}
|
||||
|
||||
@ -84,7 +84,6 @@ export function H5MediaViewer({
|
||||
const [activeIndex, setActiveIndex] = useState<number>(0);
|
||||
const [isPlaying, setIsPlaying] = useState<boolean>(false);
|
||||
const [isCatalogOpen, setIsCatalogOpen] = useState<boolean>(false);
|
||||
const [isFinalBarOpen, setIsFinalBarOpen] = useState<boolean>(true);
|
||||
|
||||
// 计算当前阶段类型
|
||||
const stage = (selectedView === 'final' && taskObject.final?.url)
|
||||
@ -372,26 +371,6 @@ export function H5MediaViewer({
|
||||
// 其他阶段:使用 Carousel
|
||||
return (
|
||||
<div ref={rootRef} data-alt="h5-media-viewer" className={`w-[100vw] relative ${stage === 'final_video' ? '' : 'px-4'}`}>
|
||||
{/* 左侧最终视频缩略图栏(H5) 视频暂停时展示 */}
|
||||
{taskObject?.final?.url && !isPlaying && (
|
||||
<div className={`absolute left-0 top-4 z-[10] ${stage === 'final_video' ? 'left-0' : 'left-4'}`} data-alt="final-sidebar-h5">
|
||||
<div className="flex items-start">
|
||||
{isFinalBarOpen && (
|
||||
<div className="w-[3rem] max-h-[50vh] overflow-y-auto rounded-md backdrop-blur-lg bg-black/30 border border-white/20 shadow-xl p-1" data-alt="final-thumbnails">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onSelectView && onSelectView('final')}
|
||||
className={`block w-full overflow-hidden rounded border ${selectedView === 'final' ? 'border-blue-500' : 'border-white/20'}`}
|
||||
data-alt="final-thumb-item"
|
||||
aria-label="Select final video"
|
||||
>
|
||||
<img src={getFirstFrame(taskObject.final.url)} alt="final" className="w-full h-auto object-contain" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{stage === 'final_video' && videoUrls.length > 0 && renderVideoSlides()}
|
||||
{stage === 'video' && videoUrls.length > 0 && renderVideoSlides()}
|
||||
{(stage === 'scene' || stage === 'character') && imageUrls.length > 0 && renderImageSlides()}
|
||||
|
||||
@ -4,7 +4,7 @@ import React, { useRef, useEffect, useState, useCallback } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { ProgressiveReveal, presets } from '@/components/ui/progressive-reveal';
|
||||
import { Loader2, X, SquareUserRound, MapPinHouse, Clapperboard, Video, RotateCcw, CircleAlert } from 'lucide-react';
|
||||
import { Loader2, X, SquareUserRound, MapPinHouse, Clapperboard, Video, RotateCcw, CircleAlert, Film } from 'lucide-react';
|
||||
import { TaskObject } from '@/api/DTO/movieEdit';
|
||||
import { getFirstFrame } from '@/utils/tools';
|
||||
import { AspectRatioValue } from '@/components/ChatInputBox/AspectRatioSelector';
|
||||
@ -187,7 +187,61 @@ export function ThumbnailGrid({
|
||||
|
||||
// 渲染视频阶段的缩略图
|
||||
const renderVideoThumbnails = (disabled: boolean = false) => (
|
||||
taskObject.videos.data.map((video, index) => {
|
||||
<>
|
||||
{/* 最终视频缩略图(排在第一位) */}
|
||||
{taskObject?.final?.url && (
|
||||
<div
|
||||
key="video-final"
|
||||
className={`relative aspect-auto rounded-lg overflow-hidden
|
||||
${selectedView === 'final' ? 'ring-2 ring-amber-500 z-10' : 'hover:ring-2 hover:ring-amber-500/50'}
|
||||
${aspectRatio === 'VIDEO_ASPECT_RATIO_LANDSCAPE' ? `min-w-[${cols}]` : 'min-w-[70px]'}
|
||||
`}
|
||||
onClick={() => !isDragging && !disabled && onSketchSelect(-1)}
|
||||
>
|
||||
{/* 视频层 */}
|
||||
<div className="relative w-full h-full transform hover:scale-105 transition-transform duration-500">
|
||||
<div
|
||||
className="w-full h-full relative"
|
||||
onMouseEnter={() => handleMouseEnter(-1)}
|
||||
onMouseLeave={() => handleMouseLeave(-1)}
|
||||
>
|
||||
<img
|
||||
className="w-full h-full object-contain"
|
||||
src={getFirstFrame(taskObject.final.url)}
|
||||
draggable="false"
|
||||
alt="final video thumbnail"
|
||||
/>
|
||||
{hoveredIndex === -1 && (
|
||||
<video
|
||||
className="absolute inset-0 w-full h-full object-contain"
|
||||
src={taskObject.final.url}
|
||||
autoPlay
|
||||
muted
|
||||
playsInline
|
||||
loop
|
||||
poster={getFirstFrame(taskObject.final.url)}
|
||||
preload="none"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 左上角三角标签 */}
|
||||
<div className='absolute top-0 left-0 z-20'>
|
||||
<div className="relative w-16 h-16">
|
||||
{/* 三角形背景 */}
|
||||
<div className="absolute top-0 left-0 w-0 h-0 border-t-[3rem] border-t-amber-400/60 border-r-[3rem] border-r-transparent" />
|
||||
{/* 图标 */}
|
||||
<div className="absolute top-1 left-1 flex flex-col items-center gap-0.5">
|
||||
<Film className="w-3.5 h-3.5 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 普通视频缩略图 */}
|
||||
{taskObject.videos.data.map((video, index) => {
|
||||
const urls: string = video.urls ? video.urls.join(',') : '';
|
||||
|
||||
return (
|
||||
@ -271,7 +325,8 @@ export function ThumbnailGrid({
|
||||
</div> */}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
})}
|
||||
</>
|
||||
);
|
||||
|
||||
// 渲染分镜草图阶段的缩略图
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user