整理 主界面 loading 展示,改为大阶段 展示 8s 后 关闭。

This commit is contained in:
北枳 2025-08-21 22:34:44 +08:00
parent 0ef11c4e89
commit 5471457a4c
6 changed files with 97 additions and 341 deletions

View File

@ -642,6 +642,24 @@ export interface ShotVideo {
video_status: number;
}
// 执行loading文字映射
export const LOADING_TEXT_MAP = {
initializing: 'initializing...',
script: 'Generating script...',
getSketchStatus: 'Getting sketch status...',
sketch: (count: number, total: number) => `Generating sketch ${count}/${total}...`,
character: 'Getting character status...',
newCharacter: (count: number, total: number) => `Drawing character ${count}/${total}...`,
getShotSketchStatus: 'Getting shot sketch status...',
shotSketch: (count: number, total: number) => `Generating shot sketch ${count}/${total}...`,
getVideoStatus: 'Getting video status...',
video: (count: number, total: number) => `Generating video ${count}/${total}...`,
audio: 'Generating background audio...',
postProduction: (step: string) => `Post-production: ${step}...`,
final: 'Generating final product...',
complete: 'Task completed'
} as const;
export type Status = 'IN_PROGRESS' | 'COMPLETED' | 'FAILED';
export type Stage = 'script' | 'character' | 'scene' | 'shot_sketch' | 'video' | 'final_video';
// 添加 TaskObject 接口

View File

@ -33,17 +33,9 @@ const WorkFlow = React.memo(function WorkFlow() {
const {
taskObject,
scriptData,
taskSketch,
taskVideos,
sketchCount,
isLoading,
currentStep,
currentSketchIndex,
isGeneratingSketch,
isGeneratingVideo,
currentLoadingText,
totalSketchCount,
final,
dataLoadError,
setCurrentSketchIndex,
retryLoadData,
@ -58,9 +50,8 @@ const WorkFlow = React.memo(function WorkFlow() {
const {
isVideoPlaying,
togglePlay,
toggleVideoPlay,
} = usePlaybackControls(taskSketch, taskVideos, currentStep);
} = usePlaybackControls(taskObject.videos.data, taskObject.currentStage);
useEffect(() => {
console.log('changedIndex_work-flow', currentSketchIndex, taskObject);
@ -97,10 +88,8 @@ const WorkFlow = React.memo(function WorkFlow() {
<div className="info-UUGkPJ">
<ErrorBoundary>
<TaskInfo
isLoading={isLoading}
taskObject={taskObject}
currentLoadingText={currentLoadingText}
dataLoadError={dataLoadError}
roles={taskObject.roles.data}
isPauseWorkFlow={isPauseWorkFlow}
/>
@ -170,14 +159,7 @@ const WorkFlow = React.memo(function WorkFlow() {
<ThumbnailGrid
isDisabledFocus={isEditModalOpen || isPauseWorkFlow}
taskObject={taskObject}
isLoading={isLoading}
currentSketchIndex={currentSketchIndex}
taskSketch={taskSketch}
taskVideos={taskVideos}
isGeneratingSketch={isGeneratingSketch}
isGeneratingVideo={isGeneratingVideo}
sketchCount={sketchCount}
totalSketchCount={totalSketchCount}
onSketchSelect={setCurrentSketchIndex}
/>
</div>

View File

@ -10,12 +10,11 @@ import {
Film,
Scissors
} from 'lucide-react';
import { TaskObject } from '@/api/DTO/movieEdit';
interface TaskInfoProps {
isLoading: boolean;
taskObject: any;
taskObject: TaskObject;
currentLoadingText: string;
dataLoadError?: string | null;
roles: any[];
isPauseWorkFlow: boolean;
}
@ -120,17 +119,14 @@ const StageIcons = ({ currentStage, isExpanded, isPauseWorkFlow }: { currentStag
);
};
export function TaskInfo({
isLoading,
taskObject,
export function TaskInfo({
taskObject,
currentLoadingText,
dataLoadError,
roles,
isPauseWorkFlow
}: TaskInfoProps) {
const [isScriptModalOpen, setIsScriptModalOpen] = useState(false);
const [currentStage, setCurrentStage] = useState(0);
const [isShowScriptIcon, setIsShowScriptIcon] = useState(true);
const [isStageIconsExpanded, setIsStageIconsExpanded] = useState(false);
const timerRef = useRef<NodeJS.Timeout | null>(null);
@ -146,72 +142,39 @@ export function TaskInfo({
timerRef.current = null;
}
// 统一更新currentStage
if (currentLoadingText.includes('initializing') || currentLoadingText.includes('script') || currentLoadingText.includes('character')) {
setCurrentStage(0);
} else if (currentLoadingText.includes('sketch') && !currentLoadingText.includes('shot sketch')) {
setCurrentStage(1);
} else if (!currentLoadingText.includes('Post-production') && (currentLoadingText.includes('shot sketch') || currentLoadingText.includes('video'))) {
setCurrentStage(2);
} else if (currentLoadingText.includes('Post-production')) {
setCurrentStage(3);
}
if (currentLoadingText.includes('Task completed')) {
console.log('Closing modal at completion');
setIsScriptModalOpen(false);
setIsShowScriptIcon(false);
}
if (currentLoadingText.includes('Post-production')) {
if (isScriptModalOpen) {
setIsScriptModalOpen(false);
}
setCurrentStage(3);
if (currentLoadingText.includes('Post-production') || currentLoadingText.includes('status')) {
console.log('isScriptModalOpen-Post-production', currentLoadingText, isScriptModalOpen);
timerRef.current = setTimeout(() => {
setIsScriptModalOpen(true);
}, 8000);
}
if (currentLoadingText.includes('Generating video')) {
console.log('isScriptModalOpen-video', currentLoadingText, isScriptModalOpen);
if (isScriptModalOpen) {
setIsScriptModalOpen(false);
setCurrentStage(2);
// 延迟8s 再次打开
timerRef.current = setTimeout(() => {
setIsScriptModalOpen(true);
}, 8000);
} else {
setIsScriptModalOpen(true);
setCurrentStage(2);
}
}
if (currentLoadingText.includes('video status')) {
if (isScriptModalOpen) {
setIsScriptModalOpen(false);
}
setCurrentStage(2);
}
if (currentLoadingText.includes('Generating sketch') || currentLoadingText.includes('Generating shot sketch')) {
console.log('isScriptModalOpen-sketch', currentLoadingText, isScriptModalOpen);
if (isScriptModalOpen) {
setIsScriptModalOpen(false);
setCurrentStage(1);
// 延迟8s 再次打开
timerRef.current = setTimeout(() => {
setIsScriptModalOpen(true);
setIsScriptModalOpen(false);
}, 8000);
} else {
setIsScriptModalOpen(true);
setCurrentStage(1);
}
}
if (currentLoadingText.includes('sketch status')) {
if (isScriptModalOpen) {
setIsScriptModalOpen(false);
}
setCurrentStage(1);
}
if (currentLoadingText.includes('script')) {
console.log('isScriptModalOpen-script', currentLoadingText, isScriptModalOpen);
setIsScriptModalOpen(true);
setCurrentStage(0);
}
if (currentLoadingText.includes('initializing')) {
console.log('isScriptModalOpen-initializing', currentLoadingText, isScriptModalOpen);
setIsScriptModalOpen(true);
setCurrentStage(0);
}
return () => {
if (timerRef.current) {

View File

@ -10,28 +10,14 @@ import { TaskObject } from '@/api/DTO/movieEdit';
interface ThumbnailGridProps {
isDisabledFocus: boolean;
taskObject: TaskObject;
isLoading: boolean;
currentSketchIndex: number;
taskSketch: any[];
taskVideos: any[];
isGeneratingSketch: boolean;
isGeneratingVideo: boolean;
sketchCount: number;
totalSketchCount: number;
onSketchSelect: (index: number) => void;
}
export function ThumbnailGrid({
isDisabledFocus,
taskObject,
isLoading,
currentSketchIndex,
taskSketch,
taskVideos,
isGeneratingSketch,
isGeneratingVideo,
sketchCount,
totalSketchCount,
onSketchSelect
}: ThumbnailGridProps) {
const thumbnailsRef = useRef<HTMLDivElement>(null);
@ -166,89 +152,11 @@ export function ThumbnailGrid({
console.log('taskObject.currentStage_thumbnail-grid', taskObject.currentStage);
}, [taskObject.currentStage]);
// 渲染加载状态
if (isLoading) {
return (
<>
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
</>
);
}
// 粗剪/精剪最终成片阶段不显示缩略图
if (taskObject.currentStage === 'final_video') {
return null;
}
// 渲染生成中的缩略图
const renderGeneratingThumbnail = () => {
const currentSketch = taskSketch[currentSketchIndex];
const defaultBgColors = ['RGB(45, 50, 70)', 'RGB(75, 80, 100)', 'RGB(105, 110, 130)'];
const bgColors = currentSketch?.bg_rgb || defaultBgColors;
return (
<motion.div
className="relative aspect-video rounded-lg overflow-hidden"
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.3 }}
>
{/* 动态渐变背景 */}
<motion.div
className={`absolute inset-0 bg-gradient-to-r from-[${bgColors[0]}] via-[${bgColors[1]}] to-[${bgColors[2]}]`}
animate={{
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
}}
transition={{
duration: 5,
repeat: Infinity,
ease: "linear"
}}
style={{
backgroundSize: "200% 200%",
}}
/>
{/* 动态光效 */}
<motion.div
className="absolute inset-0 opacity-50"
style={{
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
}}
animate={{
scale: [1, 1.2, 1],
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
<div className="absolute inset-0 flex items-center justify-center">
<div className="relative">
<motion.div
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
animate={{
scale: [1, 1.2, 1],
rotate: [0, 180, 360],
}}
transition={{
duration: 4,
repeat: Infinity,
ease: "linear"
}}
/>
</div>
</div>
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
<span className="text-xs text-white/90">Scene {sketchCount + 1}</span>
</div>
</motion.div>
);
};
// 渲染视频阶段的缩略图
const renderVideoThumbnails = () => (
taskObject.videos.data.map((video, index) => {
@ -354,7 +262,6 @@ export function ThumbnailGrid({
</div>
);
})}
{isGeneratingSketch && sketchCount < totalSketchCount && renderGeneratingThumbnail()}
</>
);

View File

@ -2,7 +2,7 @@
import { useState, useRef, useEffect, useCallback } from 'react';
export function usePlaybackControls(taskSketch: any[], taskVideos: any[], currentStep: string) {
export function usePlaybackControls(taskVideos: any[], currentStage: string) {
const [isPlaying, setIsPlaying] = useState(false);
const [isVideoPlaying, setIsVideoPlaying] = useState(true);
const [showControls, setShowControls] = useState(false);
@ -19,24 +19,6 @@ export function usePlaybackControls(taskSketch: any[], taskVideos: any[], curren
setIsVideoPlaying(prev => !prev);
}, []);
// 自动播放逻辑 - 分镜草图(移除重复的定时器逻辑,由主组件处理)
// useEffect(() => {
// if (isPlaying && taskSketch.length > 0) {
// playTimerRef.current = setInterval(() => {
// // 这里的切换逻辑需要在父组件中处理
// // 因为需要访问 setCurrentSketchIndex
// }, 1000);
// } else if (playTimerRef.current) {
// clearInterval(playTimerRef.current);
// }
// return () => {
// if (playTimerRef.current) {
// clearInterval(playTimerRef.current);
// }
// };
// }, [isPlaying, taskSketch.length]);
// 视频自动播放逻辑
useEffect(() => {
if (isVideoPlaying && taskVideos.length > 0) {
@ -55,20 +37,12 @@ export function usePlaybackControls(taskSketch: any[], taskVideos: any[], curren
};
}, [isVideoPlaying, taskVideos.length]);
// 当切换到视频模式时,停止分镜草图播放(注释掉,让用户手动控制)
// useEffect(() => {
// if (Number(currentStep) >= 3) {
// console.log('切换到步骤3+,停止分镜草图播放');
// setIsPlaying(false);
// }
// }, [currentStep]);
// 当切换到分镜草图模式时,停止视频播放
useEffect(() => {
if (currentStep !== '3') {
if (currentStage !== 'video') {
setIsVideoPlaying(false);
}
}, [currentStep]);
}, [currentStage]);
return {
isPlaying,

View File

@ -3,43 +3,9 @@
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useSearchParams } from 'next/navigation';
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, pauseMovieProjectPlan, resumeMovieProjectPlan } from '@/api/video_flow';
import { useAppDispatch, useAppSelector } from '@/lib/store/hooks';
import { setSketchCount, setVideoCount } from '@/lib/store/workflowSlice';
import { useScriptService } from "@/app/service/Interaction/ScriptService";
import { useUpdateEffect } from '@/app/hooks/useUpdateEffect';
import { TaskObject, Status, Stage } from '@/api/DTO/movieEdit';
// 步骤映射
const STEP_MAP = {
'initializing': '0',
'sketch': '1',
'character': '2',
'video': '3',
'music': '4',
'final_video': '6'
} as const;
// 执行loading文字映射
const LOADING_TEXT_MAP = {
initializing: 'initializing...',
script: 'Generating script...',
getSketchStatus: 'Getting sketch status...',
sketch: (count: number, total: number) => `Generating sketch ${count}/${total}...`,
sketchComplete: 'Sketch generation complete',
character: 'Drawing characters...',
newCharacter: (count: number, total: number) => `Drawing character ${count}/${total}...`,
getShotSketchStatus: 'Getting shot sketch status...',
shotSketch: (count: number, total: number) => `Generating shot sketch ${count}/${total}...`,
getVideoStatus: 'Getting video status...',
video: (count: number, total: number) => `Generating video ${count}/${total}...`,
videoComplete: 'Video generation complete',
audio: 'Generating background audio...',
postProduction: (step: string) => `Post-production: ${step}...`,
final: 'Generating final product...',
complete: 'Task completed'
} as const;
type ApiStep = keyof typeof STEP_MAP;
import { LOADING_TEXT_MAP, TaskObject, Status, Stage } from '@/api/DTO/movieEdit';
export function useWorkflowData() {
useEffect(() => {
@ -53,7 +19,7 @@ export function useWorkflowData() {
let tempTaskObject = useRef<TaskObject>({
title: '',
tags: [],
currentStage: 'script',
currentStage: 'script' as Stage,
status: 'IN_PROGRESS' as Status,
roles: {
data: [],
@ -81,19 +47,8 @@ export function useWorkflowData() {
// 更新 taskObject 的类型
const [taskObject, setTaskObject] = useState<TaskObject>(tempTaskObject.current);
const [taskSketch, setTaskSketch] = useState<any[]>([]);
const [taskScenes, setTaskScenes] = useState<any[]>([]);
const [taskShotSketch, setTaskShotSketch] = useState<any[]>([]);
const [taskVideos, setTaskVideos] = useState<any[]>([]);
const [currentStep, setCurrentStep] = useState('0');
const [currentSketchIndex, setCurrentSketchIndex] = useState(0);
const [isGeneratingSketch, setIsGeneratingSketch] = useState(false);
const [isGeneratingVideo, setIsGeneratingVideo] = useState(false);
const [currentLoadingText, setCurrentLoadingText] = useState('loading project info...');
const [totalSketchCount, setTotalSketchCount] = useState(0);
const [roles, setRoles] = useState<any[]>([]);
const [music, setMusic] = useState<any[]>([]);
const [final, setFinal] = useState<any>(null);
const [dataLoadError, setDataLoadError] = useState<string | null>(null);
const [needStreamData, setNeedStreamData] = useState(false);
const [isPauseWorkFlow, setIsPauseWorkFlow] = useState(false);
@ -103,10 +58,6 @@ export function useWorkflowData() {
isLoading: true
});
const dispatch = useAppDispatch();
const { sketchCount, videoCount } = useAppSelector((state) => state.workflow);
const {
scriptBlocksMemo, // 渲染剧本数据
initializeFromProject,
@ -170,24 +121,24 @@ export function useWorkflowData() {
console.log('应用剧本');
// 自动模式下 应用剧本;手动模式 需要点击 下一步 触发
// 确保仅自动触发一次
state.mode.includes('auto') && loadingText.current !== LOADING_TEXT_MAP.getSketchStatus && applyScript();
loadingText.current = LOADING_TEXT_MAP.getSketchStatus;
state.mode.includes('auto') && loadingText.current !== LOADING_TEXT_MAP.character && applyScript();
loadingText.current = LOADING_TEXT_MAP.character;
} else {
loadingText.current = LOADING_TEXT_MAP.script;
}
}
if (taskObject.currentStage === 'scene') {
const realSketchResultData = taskObject.scenes.data.filter((item: any) => item.status !== 0);
if (taskObject.scenes.total_count > realSketchResultData.length) {
loadingText.current = LOADING_TEXT_MAP.sketch(realSketchResultData.length, taskObject.scenes.total_count);
} else {
loadingText.current = LOADING_TEXT_MAP.character;
}
}
if (taskObject.currentStage === 'character') {
const realCharacterResultData = taskObject.roles.data.filter((item: any) => item.status !== 0);
if (taskObject.roles.total_count > realCharacterResultData.length) {
loadingText.current = LOADING_TEXT_MAP.newCharacter(realCharacterResultData.length, taskObject.roles.total_count);
} else {
loadingText.current = LOADING_TEXT_MAP.getSketchStatus;
}
}
if (taskObject.currentStage === 'scene') {
const realSketchResultData = taskObject.scenes.data.filter((item: any) => item.status !== 0);
if (taskObject.scenes.total_count > realSketchResultData.length) {
loadingText.current = LOADING_TEXT_MAP.sketch(realSketchResultData.length, taskObject.scenes.total_count);
} else {
loadingText.current = LOADING_TEXT_MAP.getShotSketchStatus;
}
@ -217,16 +168,6 @@ export function useWorkflowData() {
setCurrentLoadingText(loadingText.current);
}, [scriptBlocksMemo, taskObject.currentStage, taskObject.scenes.data, taskObject.roles.data, taskObject.shot_sketch.data, taskObject.videos.data, taskObject.status], {mode: 'none'});
// 更新 setSketchCount
const updateSketchCount = useCallback((count: number) => {
dispatch(setSketchCount(count));
}, [dispatch]);
// 更新 setVideoCount
const updateVideoCount = useCallback((count: number) => {
dispatch(setVideoCount(count));
}, [dispatch]);
// 将 sketchCount 和 videoCount 放到 redux 中 每一次变化也要更新
// 添加手动播放控制
@ -249,13 +190,7 @@ export function useWorkflowData() {
throw new Error(response.message);
}
let sketchCount = 0;
const all_task_data = response.data;
// all_task_data 下标0 和 下标1 换位置
const temp = all_task_data[0];
all_task_data[0] = all_task_data[1];
all_task_data[1] = temp;
const { current: taskCurrent } = tempTaskObject;
console.log('---look-all_task_data', all_task_data);
@ -266,32 +201,6 @@ export function useWorkflowData() {
for (const task of all_task_data) {
// 如果有已完成的数据,同步到状态
if (task.task_name === 'generate_sketch' && task.task_result && task.task_result.data) {
let realSketchResultData = task.task_result.data.filter((item: any) => item.image_path);
if (task.task_status === 'COMPLETED') {
realSketchResultData = taskCurrent.scenes.data.filter((item: any) => item.status !== 0);
}
console.log('---look-realSketchResultData', realSketchResultData);
taskCurrent.scenes.total_count = task.task_result.total_count;
if (task.task_status !== 'COMPLETED' || taskCurrent.scenes.total_count !== realSketchResultData.length) {
taskCurrent.currentStage = 'scene';
// 正在生成草图中 替换 sketch 数据
const sketchList = [];
for (const sketch of task.task_result.data) {
sketchList.push({
url: sketch.image_path,
script: sketch.sketch_name,
status: sketch.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
});
}
taskCurrent.scenes.data = sketchList;
if (task.task_status === 'COMPLETED') {
// 草图生成完成
}
break;
}
}
if (task.task_name === 'generate_character' && task.task_result && task.task_result.data) {
let realCharacterResultData = task.task_result.data.filter((item: any) => item.image_path);
if (task.task_status === 'COMPLETED') {
@ -317,6 +226,32 @@ export function useWorkflowData() {
}
}
if (task.task_name === 'generate_sketch' && task.task_result && task.task_result.data) {
let realSketchResultData = task.task_result.data.filter((item: any) => item.image_path);
if (task.task_status === 'COMPLETED') {
realSketchResultData = taskCurrent.scenes.data.filter((item: any) => item.status !== 0);
}
console.log('---look-realSketchResultData', realSketchResultData);
taskCurrent.scenes.total_count = task.task_result.total_count;
if (task.task_status !== 'COMPLETED' || taskCurrent.scenes.total_count !== realSketchResultData.length) {
taskCurrent.currentStage = 'scene';
// 正在生成草图中 替换 sketch 数据
const sketchList = [];
for (const sketch of task.task_result.data) {
sketchList.push({
url: sketch.image_path,
script: sketch.sketch_name,
status: sketch.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
});
}
taskCurrent.scenes.data = sketchList;
if (task.task_status === 'COMPLETED') {
// 草图生成完成
}
break;
}
}
// debugger;
if (task.task_name === 'generate_shot_sketch' && task.task_result && task.task_result.data) {
@ -485,27 +420,6 @@ export function useWorkflowData() {
// 如果有已完成的数据,同步到状态
if (data) {
if (data.sketch && data.sketch.data) {
taskCurrent.currentStage = 'scene';
const realSketchResultData = data.sketch.data.filter((item: any) => item.image_path);
const sketchList = [];
for (const sketch of data.sketch.data) {
sketchList.push({
url: sketch.image_path,
script: sketch.sketch_name,
status: sketch.image_path ? 1 : (data.sketch.task_status === 'COMPLETED' ? 2 : 0)
});
}
taskCurrent.scenes.data = sketchList;
taskCurrent.scenes.total_count = data.sketch.total_count;
// 设置为最后一个草图
if (data.sketch.total_count > realSketchResultData.length) {
// 场景生成中
setIsGeneratingSketch(true);
} else {
// 场景生成完成
}
}
if (data.character && data.character.data && data.character.data.length > 0) {
taskCurrent.currentStage = 'character';
const characterList = [];
@ -524,6 +438,26 @@ export function useWorkflowData() {
// 角色生成完成
}
}
if (data.sketch && data.sketch.data) {
taskCurrent.currentStage = 'scene';
const realSketchResultData = data.sketch.data.filter((item: any) => item.image_path);
const sketchList = [];
for (const sketch of data.sketch.data) {
sketchList.push({
url: sketch.image_path,
script: sketch.sketch_name,
status: sketch.image_path ? 1 : (data.sketch.task_status === 'COMPLETED' ? 2 : 0)
});
}
taskCurrent.scenes.data = sketchList;
taskCurrent.scenes.total_count = data.sketch.total_count;
// 设置为最后一个草图
if (data.sketch.total_count > realSketchResultData.length) {
// 场景生成中
} else {
// 场景生成完成
}
}
if (data.shot_sketch && data.shot_sketch.data) {
taskCurrent.currentStage = 'shot_sketch';
const realShotResultData = data.shot_sketch.data.filter((item: any) => item.url);
@ -629,17 +563,7 @@ export function useWorkflowData() {
// 重试加载数据
const retryLoadData = () => {
setDataLoadError(null);
// 重置所有状态
setTaskSketch([]);
setTaskScenes([]);
setTaskVideos([]);
updateSketchCount(0);
updateVideoCount(0);
setRoles([]);
setMusic([]);
setFinal(null);
setCurrentSketchIndex(0);
setCurrentStep('0');
// 重新初始化
initializeWorkflow();
};
@ -652,21 +576,9 @@ export function useWorkflowData() {
return {
taskObject,
scriptData,
taskSketch,
taskScenes,
taskShotSketch,
taskVideos,
sketchCount,
isLoading: state.isLoading,
currentStep,
currentSketchIndex,
isGeneratingSketch,
isGeneratingVideo,
currentLoadingText,
totalSketchCount,
roles,
music,
final,
dataLoadError,
setCurrentSketchIndex,
retryLoadData,