forked from 77media/video-flow
角色和场景一起展示
This commit is contained in:
parent
93a205135c
commit
628ff70a0c
@ -625,21 +625,25 @@ export interface Role {
|
|||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: string;
|
||||||
status: number;
|
status: number;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
interface Scene {
|
interface Scene {
|
||||||
url: string;
|
url: string;
|
||||||
script: string;
|
script: string;
|
||||||
status: number;
|
status: number;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
interface ShotSketch {
|
interface ShotSketch {
|
||||||
url: string;
|
url: string;
|
||||||
script: string;
|
script: string;
|
||||||
status: number;
|
status: number;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
export interface ShotVideo {
|
export interface ShotVideo {
|
||||||
video_id: string;
|
video_id: string;
|
||||||
urls: string[];
|
urls: string[];
|
||||||
video_status: number;
|
video_status: number;
|
||||||
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行loading文字映射
|
// 执行loading文字映射
|
||||||
|
|||||||
@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
.media-Ocdu1O {
|
.media-Ocdu1O {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@ -77,7 +77,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<div className="w-full overflow-hidden h-[calc(100vh-6rem)] absolute top-[4rem] left-0 right-0 px-[1rem]">
|
<div className="w-full overflow-hidden h-[calc(100vh-5rem)] absolute top-[4rem] left-0 right-0 px-[1rem]">
|
||||||
<div className="w-full h-full">
|
<div className="w-full h-full">
|
||||||
<div className="splashContainer-otuV_A">
|
<div className="splashContainer-otuV_A">
|
||||||
<div className="content-vPGYx8">
|
<div className="content-vPGYx8">
|
||||||
@ -131,7 +131,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
) : isLoading ? (
|
) : isLoading ? (
|
||||||
<Skeleton className="w-full aspect-video rounded-lg" />
|
<Skeleton className="w-full aspect-video rounded-lg" />
|
||||||
) : (
|
) : (
|
||||||
<div className={`heroVideo-FIzuK1 ${['final_video', '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={currentSketchIndex}>
|
<div className={`heroVideo-FIzuK1 ${['final_video', '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}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<MediaViewer
|
<MediaViewer
|
||||||
taskObject={taskObject}
|
taskObject={taskObject}
|
||||||
@ -151,7 +151,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{taskObject.currentStage !== 'final_video' && taskObject.currentStage !== 'script' && (
|
{taskObject.currentStage !== 'final_video' && taskObject.currentStage !== 'script' && (
|
||||||
<div className="h-[112px] w-[calc((100vh-6rem-200px)/9*16)]">
|
<div className="h-[123px] w-[calc((100vh-6rem-200px)/9*16)]">
|
||||||
<ThumbnailGrid
|
<ThumbnailGrid
|
||||||
isDisabledFocus={isEditModalOpen || isPauseWorkFlow || isSmartChatBoxOpen}
|
isDisabledFocus={isEditModalOpen || isPauseWorkFlow || isSmartChatBoxOpen}
|
||||||
taskObject={taskObject}
|
taskObject={taskObject}
|
||||||
|
|||||||
@ -546,14 +546,29 @@ export const MediaViewer = React.memo(function MediaViewer({
|
|||||||
)}
|
)}
|
||||||
{/* 只在生成过程中或没有分镜图片时使用ProgressiveReveal */}
|
{/* 只在生成过程中或没有分镜图片时使用ProgressiveReveal */}
|
||||||
{currentSketch.status === 1 && (
|
{currentSketch.status === 1 && (
|
||||||
<img
|
<AnimatePresence mode="wait">
|
||||||
key={currentSketchIndex}
|
<motion.img
|
||||||
src={currentSketch.url}
|
key={currentSketch.url}
|
||||||
alt={`NG-Sketch ${currentSketchIndex + 1}`}
|
src={currentSketch.url}
|
||||||
className="w-full h-full rounded-lg object-cover"
|
className="w-full h-full rounded-lg object-cover"
|
||||||
/>
|
// 用 circle clip-path 实现“扩散”
|
||||||
|
initial={{ clipPath: "circle(0% at 50% 50%)" }}
|
||||||
|
animate={{ clipPath: "circle(150% at 50% 50%)" }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
transition={{ duration: 1, ease: "easeInOut" }}
|
||||||
|
/>
|
||||||
|
</AnimatePresence>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div className="absolute top-0 left-0 right-0 p-2">
|
||||||
|
{/* 角色类型 */}
|
||||||
|
{currentSketch.type === 'role' && (
|
||||||
|
<div className="inline-flex items-center px-2 py-1 rounded-full bg-purple-500/20 backdrop-blur-sm">
|
||||||
|
<span className="text-xs text-purple-400">Role: {currentSketch.name}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 操作按钮组 */}
|
{/* 操作按钮组 */}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
<motion.div
|
<motion.div
|
||||||
@ -636,13 +651,13 @@ export const MediaViewer = React.memo(function MediaViewer({
|
|||||||
return renderScriptContent();
|
return renderScriptContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taskObject.currentStage === 'scene') {
|
if (taskObject.currentStage === 'scene' || taskObject.currentStage === 'character') {
|
||||||
return renderSketchContent(taskObject.scenes.data[currentSketchIndex]);
|
return renderSketchContent([...taskObject.roles.data, ...taskObject.scenes.data][currentSketchIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taskObject.currentStage === 'shot_sketch') {
|
if (taskObject.currentStage === 'shot_sketch') {
|
||||||
return renderSketchContent(taskObject.shot_sketch.data[currentSketchIndex]);
|
return renderSketchContent(taskObject.shot_sketch.data[currentSketchIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderSketchContent(taskObject.scenes.data[currentSketchIndex]);
|
return null;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import React, { useRef, useEffect, useState, useCallback } from 'react';
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
import { ProgressiveReveal, presets } from '@/components/ui/progressive-reveal';
|
import { ProgressiveReveal, presets } from '@/components/ui/progressive-reveal';
|
||||||
import { Loader2, X } from 'lucide-react';
|
import { Loader2, X, SquareUserRound, MapPinHouse, Clapperboard } from 'lucide-react';
|
||||||
import { TaskObject } from '@/api/DTO/movieEdit';
|
import { TaskObject } from '@/api/DTO/movieEdit';
|
||||||
|
|
||||||
interface ThumbnailGridProps {
|
interface ThumbnailGridProps {
|
||||||
@ -45,7 +45,7 @@ export function ThumbnailGrid({
|
|||||||
if (taskObject.currentStage === 'video') {
|
if (taskObject.currentStage === 'video') {
|
||||||
return taskObject.videos.data;
|
return taskObject.videos.data;
|
||||||
} else if (taskObject.currentStage === 'scene' || taskObject.currentStage === 'character') {
|
} else if (taskObject.currentStage === 'scene' || taskObject.currentStage === 'character') {
|
||||||
return taskObject.scenes.data;
|
return [...taskObject.roles.data, ...taskObject.scenes.data];
|
||||||
} else if (taskObject.currentStage === 'shot_sketch') {
|
} else if (taskObject.currentStage === 'shot_sketch') {
|
||||||
return taskObject.shot_sketch.data;
|
return taskObject.shot_sketch.data;
|
||||||
}
|
}
|
||||||
@ -251,13 +251,32 @@ export function ThumbnailGrid({
|
|||||||
<img
|
<img
|
||||||
className="w-full h-full object-cover select-none"
|
className="w-full h-full object-cover select-none"
|
||||||
src={sketch.url}
|
src={sketch.url}
|
||||||
alt={`NG ${index + 1}`}
|
|
||||||
draggable="false"
|
draggable="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
|
<div className='absolute top-0 left-0 right-0 p-2'>
|
||||||
<span className="text-xs text-white/90">Scene {index + 1}</span>
|
{/* 角色类型 */}
|
||||||
|
{sketch.type === 'role' && (
|
||||||
|
<div className="inline-flex items-center px-2 py-1 rounded-full bg-purple-500/20 backdrop-blur-sm">
|
||||||
|
<SquareUserRound className="w-3 h-3 text-purple-400 mr-1" />
|
||||||
|
<span className="text-xs text-purple-400">Role</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* 场景类型 */}
|
||||||
|
{sketch.type === 'scene' && (
|
||||||
|
<div className="inline-flex items-center px-2 py-1 rounded-full bg-blue-500/20 backdrop-blur-sm">
|
||||||
|
<MapPinHouse className="w-3 h-3 text-blue-400 mr-1" />
|
||||||
|
<span className="text-xs text-blue-400">Scene</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* 分镜类型 */}
|
||||||
|
{(!sketch.type || sketch.type === 'shot_sketch') && (
|
||||||
|
<div className="inline-flex items-center px-2 py-1 rounded-full bg-amber-500/20 backdrop-blur-sm">
|
||||||
|
<Clapperboard className="w-3 h-3 text-amber-400 mr-1" />
|
||||||
|
<span className="text-xs text-amber-400">Shot {index + 1}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -269,7 +288,7 @@ export function ThumbnailGrid({
|
|||||||
<div
|
<div
|
||||||
ref={thumbnailsRef}
|
ref={thumbnailsRef}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className="w-full h-full grid grid-flow-col auto-cols-[20%] gap-4 overflow-x-auto hide-scrollbar px-1 py-1 cursor-grab active:cursor-grabbing focus:outline-none select-none"
|
className="w-full h-full grid grid-flow-col auto-cols-[20%] gap-2 overflow-x-auto hide-scrollbar px-1 py-1 cursor-grab active:cursor-grabbing focus:outline-none select-none"
|
||||||
autoFocus
|
autoFocus
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
onMouseMove={handleMouseMove}
|
onMouseMove={handleMouseMove}
|
||||||
@ -279,9 +298,8 @@ export function ThumbnailGrid({
|
|||||||
onBlur={() => setIsFocused(false)}
|
onBlur={() => setIsFocused(false)}
|
||||||
>
|
>
|
||||||
{taskObject.currentStage === 'video' && renderVideoThumbnails()}
|
{taskObject.currentStage === 'video' && renderVideoThumbnails()}
|
||||||
{taskObject.currentStage === 'scene' && renderSketchThumbnails(taskObject.scenes.data)}
|
{(taskObject.currentStage === 'scene' || taskObject.currentStage === 'character') && renderSketchThumbnails(getCurrentData())}
|
||||||
{taskObject.currentStage === 'shot_sketch' && renderSketchThumbnails(taskObject.shot_sketch.data)}
|
{taskObject.currentStage === 'shot_sketch' && renderSketchThumbnails(taskObject.shot_sketch.data)}
|
||||||
{taskObject.currentStage === 'character' && renderSketchThumbnails(taskObject.scenes.data)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -215,7 +215,8 @@ export function useWorkflowData() {
|
|||||||
characterList.push({
|
characterList.push({
|
||||||
name: character.character_name,
|
name: character.character_name,
|
||||||
url: character.image_path,
|
url: character.image_path,
|
||||||
status: character.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
|
status: character.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0),
|
||||||
|
type: 'role'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.roles.data = characterList;
|
taskCurrent.roles.data = characterList;
|
||||||
@ -242,7 +243,8 @@ export function useWorkflowData() {
|
|||||||
sketchList.push({
|
sketchList.push({
|
||||||
url: sketch.image_path,
|
url: sketch.image_path,
|
||||||
script: sketch.sketch_name,
|
script: sketch.sketch_name,
|
||||||
status: sketch.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
|
status: sketch.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0),
|
||||||
|
type: 'scene'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.scenes.data = sketchList;
|
taskCurrent.scenes.data = sketchList;
|
||||||
@ -269,7 +271,8 @@ export function useWorkflowData() {
|
|||||||
sketchList.push({
|
sketchList.push({
|
||||||
url: sketch.url,
|
url: sketch.url,
|
||||||
script: sketch.description,
|
script: sketch.description,
|
||||||
status: sketch.url ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
|
status: sketch.url ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0),
|
||||||
|
type: 'shot_sketch'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.shot_sketch.data = sketchList;
|
taskCurrent.shot_sketch.data = sketchList;
|
||||||
@ -302,6 +305,7 @@ export function useWorkflowData() {
|
|||||||
urls: video.urls,
|
urls: video.urls,
|
||||||
video_id: video.video_id,
|
video_id: video.video_id,
|
||||||
video_status: video_status, // 0 生成中 1 生成完成 2 生成失败
|
video_status: video_status, // 0 生成中 1 生成完成 2 生成失败
|
||||||
|
type: 'video'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.videos.data = videoList;
|
taskCurrent.videos.data = videoList;
|
||||||
@ -427,7 +431,8 @@ export function useWorkflowData() {
|
|||||||
characterList.push({
|
characterList.push({
|
||||||
name: character.character_name,
|
name: character.character_name,
|
||||||
url: character.image_path,
|
url: character.image_path,
|
||||||
status: character.image_path ? 1 : (data.character.task_status === 'COMPLETED' ? 2 : 0)
|
status: character.image_path ? 1 : (data.character.task_status === 'COMPLETED' ? 2 : 0),
|
||||||
|
type: 'role'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.roles.data = characterList;
|
taskCurrent.roles.data = characterList;
|
||||||
@ -446,7 +451,8 @@ export function useWorkflowData() {
|
|||||||
sketchList.push({
|
sketchList.push({
|
||||||
url: sketch.image_path,
|
url: sketch.image_path,
|
||||||
script: sketch.sketch_name,
|
script: sketch.sketch_name,
|
||||||
status: sketch.image_path ? 1 : (data.sketch.task_status === 'COMPLETED' ? 2 : 0)
|
status: sketch.image_path ? 1 : (data.sketch.task_status === 'COMPLETED' ? 2 : 0),
|
||||||
|
type: 'scene'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.scenes.data = sketchList;
|
taskCurrent.scenes.data = sketchList;
|
||||||
@ -466,7 +472,8 @@ export function useWorkflowData() {
|
|||||||
sketchList.push({
|
sketchList.push({
|
||||||
url: sketch.url,
|
url: sketch.url,
|
||||||
script: sketch.description,
|
script: sketch.description,
|
||||||
status: sketch.url ? 1 : (data.shot_sketch.task_status === 'COMPLETED' ? 2 : 0)
|
status: sketch.url ? 1 : (data.shot_sketch.task_status === 'COMPLETED' ? 2 : 0),
|
||||||
|
type: 'shot_sketch'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.shot_sketch.data = sketchList;
|
taskCurrent.shot_sketch.data = sketchList;
|
||||||
@ -492,6 +499,7 @@ export function useWorkflowData() {
|
|||||||
urls: video.urls,
|
urls: video.urls,
|
||||||
video_id: video.video_id,
|
video_id: video.video_id,
|
||||||
video_status: video_status, // 0 生成中 1 生成完成 2 生成失败
|
video_status: video_status, // 0 生成中 1 生成完成 2 生成失败
|
||||||
|
type: 'video'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
taskCurrent.videos.data = videoList;
|
taskCurrent.videos.data = videoList;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user