forked from 77media/video-flow
311 lines
8.4 KiB
TypeScript
311 lines
8.4 KiB
TypeScript
import { useState, useEffect, useRef, useCallback } from 'react';
|
||
import { TaskObject, SketchItem, VideoItem, STEP_MESSAGES } from '@/components/work-flow/constants';
|
||
import {
|
||
getTaskDetail,
|
||
getTaskSketch,
|
||
getTaskRole,
|
||
getTaskBackgroundAudio,
|
||
getTaskFinalProduct,
|
||
getTaskVideo
|
||
} from '@/components/work-flow/api';
|
||
|
||
export const useWorkFlow = () => {
|
||
// 基础状态
|
||
const [taskObject, setTaskObject] = useState<TaskObject | null>(null);
|
||
const [taskSketch, setTaskSketch] = useState<SketchItem[]>([]);
|
||
const [taskVideos, setTaskVideos] = useState<VideoItem[]>([]);
|
||
const [isLoading, setIsLoading] = useState(true);
|
||
const [currentStep, setCurrentStep] = useState('0');
|
||
const [currentSketchIndex, setCurrentSketchIndex] = useState(0);
|
||
const [currentLoadingText, setCurrentLoadingText] = useState('Loading task information...');
|
||
const [totalSketchCount, setTotalSketchCount] = useState(0);
|
||
|
||
// 生成状态
|
||
const [isGeneratingSketch, setIsGeneratingSketch] = useState(false);
|
||
const [isGeneratingVideo, setIsGeneratingVideo] = useState(false);
|
||
const [sketchCount, setSketchCount] = useState(0);
|
||
|
||
// 播放状态
|
||
const [isPlaying, setIsPlaying] = useState(false);
|
||
const [isVideoPlaying, setIsVideoPlaying] = useState(true);
|
||
const playTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||
const videoPlayTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||
const mainVideoRef = useRef<HTMLVideoElement>(null);
|
||
|
||
// 拖拽状态
|
||
const [isDragging, setIsDragging] = useState(false);
|
||
const [startX, setStartX] = useState(0);
|
||
const [scrollLeft, setScrollLeft] = useState(0);
|
||
|
||
// 界面状态
|
||
const [showControls, setShowControls] = useState(false);
|
||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||
const [activeEditTab, setActiveEditTab] = useState('1');
|
||
|
||
// 初始化工作流
|
||
useEffect(() => {
|
||
const initWorkFlow = async () => {
|
||
const taskId = localStorage.getItem("taskId") || "taskId-123";
|
||
|
||
try {
|
||
// 获取任务详情
|
||
const data = await getTaskDetail(taskId);
|
||
setTaskObject(data);
|
||
setIsLoading(false);
|
||
setCurrentStep('1');
|
||
|
||
// 获取分镜草图
|
||
await handleGetTaskSketch(taskId);
|
||
await delay(2000);
|
||
updateTaskStatus('2');
|
||
setCurrentStep('2');
|
||
|
||
// 绘制角色
|
||
await getTaskRole(taskId);
|
||
await delay(2000);
|
||
updateTaskStatus('3');
|
||
setCurrentStep('3');
|
||
|
||
// 获取分镜视频
|
||
await handleGetTaskVideo(taskId);
|
||
await delay(2000);
|
||
updateTaskStatus('4');
|
||
setCurrentStep('4');
|
||
|
||
// 获取背景音
|
||
await getTaskBackgroundAudio(taskId);
|
||
await delay(2000);
|
||
updateTaskStatus('5');
|
||
setCurrentStep('5');
|
||
|
||
// 获取最终成品
|
||
await getTaskFinalProduct(taskId);
|
||
await delay(2000);
|
||
updateTaskStatus('6');
|
||
setCurrentStep('6');
|
||
} catch (error) {
|
||
console.error('工作流初始化失败:', error);
|
||
}
|
||
};
|
||
|
||
initWorkFlow();
|
||
}, []);
|
||
|
||
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||
|
||
const updateTaskStatus = (status: string) => {
|
||
setTaskObject(prev => prev ? { ...prev, taskStatus: status } : null);
|
||
};
|
||
|
||
const handleGetTaskSketch = async (taskId: string) => {
|
||
if (isGeneratingSketch || taskSketch.length > 0) return;
|
||
|
||
setIsGeneratingSketch(true);
|
||
setTaskSketch([]);
|
||
|
||
await getTaskSketch(taskId, (newSketch, index) => {
|
||
setTaskSketch(prev => {
|
||
if (prev.find(sketch => sketch.id === newSketch.id)) {
|
||
return prev;
|
||
}
|
||
const newSketchList = [...prev, newSketch];
|
||
if (index === 0) {
|
||
// 这里我们需要从API获取总数,暂时使用当前逻辑
|
||
}
|
||
return newSketchList;
|
||
});
|
||
setCurrentSketchIndex(index);
|
||
setSketchCount(index + 1);
|
||
});
|
||
|
||
setIsGeneratingSketch(false);
|
||
setTotalSketchCount(taskSketch.length);
|
||
};
|
||
|
||
const handleGetTaskVideo = async (taskId: string) => {
|
||
setIsGeneratingVideo(true);
|
||
setTaskVideos([]);
|
||
|
||
await getTaskVideo(taskId, taskSketch.length, (newVideo, index) => {
|
||
setTaskVideos(prev => {
|
||
if (prev.find(video => video.id === newVideo.id)) {
|
||
return prev;
|
||
}
|
||
return [...prev, newVideo];
|
||
});
|
||
setCurrentSketchIndex(index);
|
||
});
|
||
|
||
setIsGeneratingVideo(false);
|
||
};
|
||
|
||
// 自动播放逻辑
|
||
useEffect(() => {
|
||
if (isPlaying && taskSketch.length > 0) {
|
||
playTimerRef.current = setInterval(() => {
|
||
setCurrentSketchIndex(prev => (prev + 1) % taskSketch.length);
|
||
}, 2000);
|
||
} else if (playTimerRef.current) {
|
||
clearInterval(playTimerRef.current);
|
||
}
|
||
|
||
return () => {
|
||
if (playTimerRef.current) {
|
||
clearInterval(playTimerRef.current);
|
||
}
|
||
};
|
||
}, [isPlaying, taskSketch.length]);
|
||
|
||
// 视频播放逻辑
|
||
useEffect(() => {
|
||
if (isVideoPlaying && taskVideos.length > 0) {
|
||
if (mainVideoRef.current) {
|
||
mainVideoRef.current.play().catch(error => {
|
||
console.log('视频播放失败:', error);
|
||
setIsVideoPlaying(false);
|
||
});
|
||
}
|
||
} else {
|
||
if (mainVideoRef.current) {
|
||
mainVideoRef.current.pause();
|
||
}
|
||
if (videoPlayTimerRef.current) {
|
||
clearInterval(videoPlayTimerRef.current);
|
||
}
|
||
}
|
||
|
||
return () => {
|
||
if (videoPlayTimerRef.current) {
|
||
clearInterval(videoPlayTimerRef.current);
|
||
}
|
||
};
|
||
}, [isVideoPlaying, taskVideos.length]);
|
||
|
||
// 当切换视频时重置播放
|
||
useEffect(() => {
|
||
if (mainVideoRef.current) {
|
||
mainVideoRef.current.currentTime = 0;
|
||
if (isVideoPlaying) {
|
||
mainVideoRef.current.play().catch(error => {
|
||
console.log('视频播放失败:', error);
|
||
setIsVideoPlaying(false);
|
||
});
|
||
}
|
||
}
|
||
}, [currentSketchIndex]);
|
||
|
||
// 更新加载文字
|
||
useEffect(() => {
|
||
if (isLoading) {
|
||
setCurrentLoadingText(STEP_MESSAGES.loading);
|
||
return;
|
||
}
|
||
|
||
switch (currentStep) {
|
||
case '1':
|
||
setCurrentLoadingText(
|
||
isGeneratingSketch
|
||
? STEP_MESSAGES.sketch(sketchCount, Math.max(totalSketchCount, sketchCount + 1))
|
||
: STEP_MESSAGES.sketchComplete
|
||
);
|
||
break;
|
||
case '2':
|
||
setCurrentLoadingText(STEP_MESSAGES.character);
|
||
break;
|
||
case '3':
|
||
setCurrentLoadingText(
|
||
isGeneratingVideo
|
||
? STEP_MESSAGES.video(taskVideos.length, taskSketch.length)
|
||
: STEP_MESSAGES.videoComplete
|
||
);
|
||
break;
|
||
case '4':
|
||
setCurrentLoadingText(STEP_MESSAGES.audio);
|
||
break;
|
||
case '5':
|
||
setCurrentLoadingText(STEP_MESSAGES.final);
|
||
break;
|
||
default:
|
||
setCurrentLoadingText(STEP_MESSAGES.complete);
|
||
}
|
||
}, [isLoading, currentStep, isGeneratingSketch, sketchCount, isGeneratingVideo, taskVideos.length, taskSketch.length, totalSketchCount]);
|
||
|
||
// 控制函数
|
||
const togglePlay = useCallback(() => {
|
||
setIsPlaying(prev => !prev);
|
||
}, []);
|
||
|
||
const toggleVideoPlay = useCallback(() => {
|
||
if (mainVideoRef.current) {
|
||
if (isVideoPlaying) {
|
||
mainVideoRef.current.pause();
|
||
} else {
|
||
mainVideoRef.current.play();
|
||
}
|
||
}
|
||
setIsVideoPlaying(prev => !prev);
|
||
}, [isVideoPlaying]);
|
||
|
||
const handleEditModalOpen = (tab: string) => {
|
||
setIsPlaying(false);
|
||
setIsVideoPlaying(false);
|
||
setActiveEditTab(tab);
|
||
setIsEditModalOpen(true);
|
||
};
|
||
|
||
// 当切换到视频模式时,停止播放
|
||
useEffect(() => {
|
||
if (currentStep === '3') {
|
||
setIsPlaying(false);
|
||
}
|
||
}, [currentStep]);
|
||
|
||
// 当切换到分镜草图模式时,停止视频播放
|
||
useEffect(() => {
|
||
if (currentStep !== '3') {
|
||
setIsVideoPlaying(false);
|
||
}
|
||
}, [currentStep]);
|
||
|
||
return {
|
||
// 数据状态
|
||
taskObject,
|
||
taskSketch,
|
||
taskVideos,
|
||
isLoading,
|
||
currentStep,
|
||
currentSketchIndex,
|
||
setCurrentSketchIndex,
|
||
currentLoadingText,
|
||
|
||
// 生成状态
|
||
isGeneratingSketch,
|
||
isGeneratingVideo,
|
||
sketchCount,
|
||
|
||
// 播放状态
|
||
isPlaying,
|
||
isVideoPlaying,
|
||
mainVideoRef,
|
||
|
||
// 拖拽状态
|
||
isDragging,
|
||
setIsDragging,
|
||
startX,
|
||
setStartX,
|
||
scrollLeft,
|
||
setScrollLeft,
|
||
|
||
// 界面状态
|
||
showControls,
|
||
setShowControls,
|
||
isEditModalOpen,
|
||
setIsEditModalOpen,
|
||
activeEditTab,
|
||
|
||
// 控制函数
|
||
togglePlay,
|
||
toggleVideoPlay,
|
||
handleEditModalOpen,
|
||
};
|
||
};
|