forked from 77media/video-flow
优化细节
This commit is contained in:
parent
e0fbbb0f1e
commit
9dc168f22e
@ -151,7 +151,7 @@ export function HomePage2() {
|
||||
</div>
|
||||
|
||||
{/* Create Project Button */}
|
||||
<div className="fixed bottom-[5rem] left-[50%] -translate-x-1/2 z-50">
|
||||
<div className="fixed bottom-[3rem] left-[50%] -translate-x-1/2 z-50">
|
||||
<motion.div
|
||||
className="relative group"
|
||||
whileHover={!isCreating ? { scale: 1.05 } : {}}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.5rem;
|
||||
width: 190px;
|
||||
height: 128px;
|
||||
width: 8rem;
|
||||
height: 7rem;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
@ -49,9 +49,12 @@ export function MediaViewer({
|
||||
// 最终视频控制状态
|
||||
const [isFinalVideoPlaying, setIsFinalVideoPlaying] = useState(true);
|
||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||
const [finalVideoReady, setFinalVideoReady] = useState(false);
|
||||
const [userHasInteracted, setUserHasInteracted] = useState(false);
|
||||
|
||||
// 音量控制函数
|
||||
const toggleMute = () => {
|
||||
setUserHasInteracted(true);
|
||||
setIsMuted(!isMuted);
|
||||
if (mainVideoRef.current) {
|
||||
mainVideoRef.current.muted = !isMuted;
|
||||
@ -62,6 +65,7 @@ export function MediaViewer({
|
||||
};
|
||||
|
||||
const handleVolumeChange = (newVolume: number) => {
|
||||
setUserHasInteracted(true);
|
||||
setVolume(newVolume);
|
||||
if (mainVideoRef.current) {
|
||||
mainVideoRef.current.volume = newVolume;
|
||||
@ -79,20 +83,63 @@ export function MediaViewer({
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (finalVideoRef.current && finalVideoReady) {
|
||||
if (isFinalVideoPlaying) {
|
||||
finalVideoRef.current.play().catch(error => {
|
||||
console.log('最终视频自动播放被阻止:', error);
|
||||
// 如果自动播放被阻止,将状态设置为暂停
|
||||
setIsFinalVideoPlaying(false);
|
||||
});
|
||||
} else {
|
||||
finalVideoRef.current.pause();
|
||||
}
|
||||
}
|
||||
}, [isFinalVideoPlaying, finalVideoReady]);
|
||||
|
||||
// 最终视频播放控制
|
||||
const toggleFinalVideoPlay = () => {
|
||||
setUserHasInteracted(true);
|
||||
setIsFinalVideoPlaying(!isFinalVideoPlaying);
|
||||
};
|
||||
|
||||
// 处理最终视频加载完成
|
||||
const handleFinalVideoLoaded = () => {
|
||||
if (finalVideoRef.current) {
|
||||
setFinalVideoReady(true);
|
||||
applyVolumeSettings(finalVideoRef.current);
|
||||
|
||||
// 如果当前状态是应该播放的,尝试播放
|
||||
if (isFinalVideoPlaying) {
|
||||
finalVideoRef.current.pause();
|
||||
} else {
|
||||
finalVideoRef.current.play();
|
||||
finalVideoRef.current.play().catch(error => {
|
||||
console.log('最终视频自动播放被阻止:', error);
|
||||
setIsFinalVideoPlaying(false);
|
||||
});
|
||||
}
|
||||
setIsFinalVideoPlaying(!isFinalVideoPlaying);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理视频点击 - 首次交互时尝试播放
|
||||
const handleVideoClick = () => {
|
||||
if (!userHasInteracted && finalVideoRef.current && finalVideoReady) {
|
||||
setUserHasInteracted(true);
|
||||
if (isFinalVideoPlaying) {
|
||||
finalVideoRef.current.play().catch(error => {
|
||||
console.log('视频播放失败:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 包装编辑按钮点击事件
|
||||
const handleEditClick = (tab: string) => {
|
||||
setUserHasInteracted(true);
|
||||
onEditModalOpen(tab);
|
||||
};
|
||||
|
||||
// 全屏控制
|
||||
const toggleFullscreen = () => {
|
||||
setUserHasInteracted(true);
|
||||
if (!document.fullscreenElement) {
|
||||
// 进入全屏
|
||||
if (finalVideoRef.current) {
|
||||
@ -164,6 +211,17 @@ export function MediaViewer({
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 组件卸载时清理视频状态
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
// 清理最终视频状态
|
||||
setFinalVideoReady(false);
|
||||
if (finalVideoRef.current) {
|
||||
finalVideoRef.current.pause();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 渲染音量控制组件
|
||||
const renderVolumeControls = () => (
|
||||
<div className="flex items-center gap-2">
|
||||
@ -228,7 +286,6 @@ export function MediaViewer({
|
||||
<video
|
||||
className="w-full h-full rounded-lg object-cover object-center"
|
||||
src={taskVideos[currentSketchIndex]?.url}
|
||||
autoPlay
|
||||
loop
|
||||
playsInline
|
||||
muted
|
||||
@ -249,13 +306,13 @@ export function MediaViewer({
|
||||
ref={finalVideoRef}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
src={finalVideo.url}
|
||||
poster={taskSketch[currentSketchIndex]?.url}
|
||||
autoPlay={isFinalVideoPlaying}
|
||||
loop
|
||||
playsInline
|
||||
onLoadedData={() => applyVolumeSettings(finalVideoRef.current!)}
|
||||
onLoadedData={handleFinalVideoLoaded}
|
||||
onPlay={() => setIsFinalVideoPlaying(true)}
|
||||
onPause={() => setIsFinalVideoPlaying(false)}
|
||||
onClick={handleVideoClick}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
@ -272,7 +329,7 @@ export function MediaViewer({
|
||||
<GlassIconButton
|
||||
icon={Edit3}
|
||||
tooltip="Edit sketch"
|
||||
onClick={() => onEditModalOpen('4')}
|
||||
onClick={() => handleEditClick('4')}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
@ -506,7 +563,7 @@ export function MediaViewer({
|
||||
<GlassIconButton
|
||||
icon={Edit3}
|
||||
tooltip="Edit sketch"
|
||||
onClick={() => onEditModalOpen('3')}
|
||||
onClick={() => handleEditClick('3')}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
@ -692,7 +749,7 @@ export function MediaViewer({
|
||||
<GlassIconButton
|
||||
icon={Edit3}
|
||||
tooltip="Edit sketch"
|
||||
onClick={() => onEditModalOpen('1')}
|
||||
onClick={() => handleEditClick('1')}
|
||||
/>
|
||||
</motion.div>
|
||||
)}
|
||||
@ -737,20 +794,6 @@ export function MediaViewer({
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
{/* 播放进度指示器 */}
|
||||
<AnimatePresence>
|
||||
{isPlaying && (
|
||||
<motion.div
|
||||
className="absolute bottom-0 left-0 right-0 h-1 bg-blue-500/20"
|
||||
initial={{ scaleX: 0 }}
|
||||
animate={{ scaleX: 1 }}
|
||||
exit={{ scaleX: 0 }}
|
||||
transition={{ duration: 2, repeat: Infinity }}
|
||||
style={{ transformOrigin: "left" }}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,6 +3,16 @@
|
||||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import {
|
||||
Image,
|
||||
Video,
|
||||
CheckCircle,
|
||||
Music,
|
||||
Loader2,
|
||||
User,
|
||||
Scissors,
|
||||
Tv
|
||||
} from 'lucide-react';
|
||||
|
||||
interface TaskInfoProps {
|
||||
isLoading: boolean;
|
||||
@ -10,7 +20,32 @@ interface TaskInfoProps {
|
||||
currentLoadingText: string;
|
||||
}
|
||||
|
||||
// 根据加载文本返回对应的图标
|
||||
const getStageIcon = (loadingText: string) => {
|
||||
const text = loadingText.toLowerCase();
|
||||
|
||||
if (text.includes('sketch')) {
|
||||
return Image;
|
||||
} else if (text.includes('video')) {
|
||||
return Video;
|
||||
} else if (text.includes('character')) {
|
||||
return User;
|
||||
} else if (text.includes('audio')) {
|
||||
return Music;
|
||||
} else if (text.includes('post')) {
|
||||
return Scissors;
|
||||
} else if (text.includes('final')) {
|
||||
return Tv;
|
||||
} else if (text.includes('complete')) {
|
||||
return CheckCircle;
|
||||
} else {
|
||||
return Loader2;
|
||||
}
|
||||
};
|
||||
|
||||
export function TaskInfo({ isLoading, taskObject, currentLoadingText }: TaskInfoProps) {
|
||||
const StageIcon = getStageIcon(currentLoadingText);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<>
|
||||
@ -46,7 +81,7 @@ export function TaskInfo({ isLoading, taskObject, currentLoadingText }: TaskInfo
|
||||
}}
|
||||
/>
|
||||
<motion.div
|
||||
className="flex items-center gap-1.5"
|
||||
className="flex items-center gap-2"
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
@ -54,6 +89,16 @@ export function TaskInfo({ isLoading, taskObject, currentLoadingText }: TaskInfo
|
||||
visible: { opacity: 1 }
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
className="text-emerald-500"
|
||||
variants={{
|
||||
hidden: { opacity: 0, scale: 0.8 },
|
||||
visible: { opacity: 1, scale: 1 }
|
||||
}}
|
||||
transition={{ duration: 0.5 }}
|
||||
>
|
||||
<CheckCircle className="w-5 h-5" />
|
||||
</motion.div>
|
||||
<motion.span
|
||||
className="text-emerald-500 font-medium"
|
||||
variants={{
|
||||
@ -98,93 +143,117 @@ export function TaskInfo({ isLoading, taskObject, currentLoadingText }: TaskInfo
|
||||
repeatDelay: 0.2
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 阶段图标 */}
|
||||
<motion.div
|
||||
className="relative"
|
||||
className="flex items-center gap-2"
|
||||
key={currentLoadingText}
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: 10 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
{/* 背景发光效果 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-purple-400 blur-sm"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
className="text-blue-500"
|
||||
animate={{
|
||||
rotate: [0, 360],
|
||||
scale: [1, 1.1, 1]
|
||||
}}
|
||||
transition={{
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
transition={{
|
||||
scale: { duration: 1.5, repeat: Infinity, ease: "easeInOut" }
|
||||
}}
|
||||
>
|
||||
<span className="normalS400 subtitle-had8uE">{currentLoadingText}</span>
|
||||
<StageIcon className="w-5 h-5" />
|
||||
</motion.div>
|
||||
|
||||
{/* 主文字 - 颜色填充动画 */}
|
||||
|
||||
<motion.div
|
||||
className="relative z-10"
|
||||
animate={{
|
||||
scale: [1, 1.02, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.5,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
className="relative"
|
||||
initial={{ opacity: 0, x: -10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: 10 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<motion.span
|
||||
className="normalS400 subtitle-had8uE text-transparent bg-clip-text bg-gradient-to-r from-blue-600 via-cyan-500 to-purple-600"
|
||||
{/* 背景发光效果 */}
|
||||
<motion.div
|
||||
className="absolute inset-0 text-transparent bg-clip-text bg-gradient-to-r from-blue-400 via-cyan-400 to-purple-400 blur-sm"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 3,
|
||||
duration: 2,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "300% 300%",
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
>
|
||||
{currentLoadingText}
|
||||
</motion.span>
|
||||
<span className="normalS400 subtitle-had8uE">{currentLoadingText}</span>
|
||||
</motion.div>
|
||||
|
||||
{/* 主文字 - 颜色填充动画 */}
|
||||
<motion.div
|
||||
className="relative z-10"
|
||||
animate={{
|
||||
scale: [1, 1.02, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 1.5,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut"
|
||||
}}
|
||||
>
|
||||
<motion.span
|
||||
className="normalS400 subtitle-had8uE text-transparent bg-clip-text bg-gradient-to-r from-blue-600 via-cyan-500 to-purple-600"
|
||||
animate={{
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
duration: 3,
|
||||
repeat: Infinity,
|
||||
ease: "linear"
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "300% 300%",
|
||||
}}
|
||||
>
|
||||
{currentLoadingText}
|
||||
</motion.span>
|
||||
</motion.div>
|
||||
|
||||
{/* 动态光点效果 */}
|
||||
<motion.div
|
||||
className="absolute left-0 top-1/2 transform -translate-y-1/2 w-2 h-2 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full blur-sm"
|
||||
animate={{
|
||||
x: [0, 200, 0],
|
||||
opacity: [0, 1, 0],
|
||||
scale: [0.5, 1, 0.5],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2.5,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 文字底部装饰线 */}
|
||||
<motion.div
|
||||
className="absolute bottom-0 left-0 h-0.5 bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500"
|
||||
animate={{
|
||||
width: ["0%", "100%", "0%"],
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
width: { duration: 2, repeat: Infinity, ease: "easeInOut" },
|
||||
backgroundPosition: { duration: 1.5, repeat: Infinity, ease: "linear" }
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
{/* 动态光点效果 */}
|
||||
<motion.div
|
||||
className="absolute left-0 top-1/2 transform -translate-y-1/2 w-2 h-2 bg-gradient-to-r from-cyan-400 to-blue-500 rounded-full blur-sm"
|
||||
animate={{
|
||||
x: [0, 200, 0],
|
||||
opacity: [0, 1, 0],
|
||||
scale: [0.5, 1, 0.5],
|
||||
}}
|
||||
transition={{
|
||||
duration: 2.5,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 文字底部装饰线 */}
|
||||
<motion.div
|
||||
className="absolute bottom-0 left-0 h-0.5 bg-gradient-to-r from-blue-500 via-cyan-400 to-purple-500"
|
||||
animate={{
|
||||
width: ["0%", "100%", "0%"],
|
||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
||||
}}
|
||||
transition={{
|
||||
width: { duration: 2, repeat: Infinity, ease: "easeInOut" },
|
||||
backgroundPosition: { duration: 1.5, repeat: Infinity, ease: "linear" }
|
||||
}}
|
||||
style={{
|
||||
backgroundSize: "200% 200%",
|
||||
}}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="w-1.5 h-1.5 rounded-full bg-blue-500"
|
||||
animate={{
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { getRandomMockData, STEP_MESSAGES } from '@/components/work-flow/constants';
|
||||
import { getRandomMockData, STEP_MESSAGES, MOCK_DELAY_TIME } from '@/components/work-flow/constants';
|
||||
|
||||
// 当前选择的mock数据
|
||||
let selectedMockData = getRandomMockData();
|
||||
@ -9,6 +9,7 @@ let selectedMockData = getRandomMockData();
|
||||
export function useWorkflowData() {
|
||||
const [taskObject, setTaskObject] = useState<any>(null);
|
||||
const [taskSketch, setTaskSketch] = useState<any[]>([]);
|
||||
const [taskRoles, setTaskRoles] = useState<any[]>([]);
|
||||
const [taskVideos, setTaskVideos] = useState<any[]>([]);
|
||||
const [sketchCount, setSketchCount] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@ -49,7 +50,7 @@ export function useWorkflowData() {
|
||||
|
||||
// 模拟分批获取分镜草图
|
||||
for (let i = 0; i < totalSketches; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 5000)); // 10s
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.sketch)); // 10s
|
||||
|
||||
const newSketch = {
|
||||
id: `sketch-${i}`,
|
||||
@ -76,17 +77,37 @@ export function useWorkflowData() {
|
||||
|
||||
// 模拟接口请求 每次获取一个角色 轮询获取
|
||||
const getTaskRole = async (taskId: string) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 2000 * selectedMockData.roles.length)); // 延长到30秒
|
||||
setTaskRoles([]);
|
||||
const roleData = selectedMockData.roles;
|
||||
const totalRoles = roleData.length;
|
||||
|
||||
for (let i = 0; i < totalRoles; i++) {
|
||||
// 先更新loading文字显示当前正在生成的角色
|
||||
setCurrentLoadingText(STEP_MESSAGES.newCharacter(i, totalRoles));
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.character)); // 2s 一个角色
|
||||
|
||||
// 添加角色到列表
|
||||
setTaskRoles(prev => [...prev, roleData[i]]);
|
||||
|
||||
// 更新loading文字显示已完成的角色数量
|
||||
setCurrentLoadingText(STEP_MESSAGES.newCharacter(i + 1, totalRoles));
|
||||
|
||||
// 如果不是最后一个角色,稍微延迟一下让用户看到更新
|
||||
if (i < totalRoles - 1) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 模拟接口请求 获取背景音
|
||||
const getTaskBackgroundAudio = async (taskId: string) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 2000)); // 10s
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.audio)); // 10s
|
||||
};
|
||||
|
||||
// 模拟接口请求 获取最终成品
|
||||
const getTaskFinalProduct = async (taskId: string) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 10000)); // 50s
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.final)); // 50s
|
||||
};
|
||||
|
||||
// 模拟接口请求 每次获取一个分镜视频 轮询获取
|
||||
@ -99,7 +120,7 @@ export function useWorkflowData() {
|
||||
|
||||
// 模拟分批获取分镜视频
|
||||
for (let i = 0; i < totalVideos; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 6000)); // 60s
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.video)); // 60s
|
||||
|
||||
const newVideo = {
|
||||
id: `video-${i}`,
|
||||
@ -130,6 +151,8 @@ export function useWorkflowData() {
|
||||
}
|
||||
|
||||
const totalSketches = selectedMockData.sketch.length;
|
||||
const totalVideos = selectedMockData.video.length;
|
||||
const totalCharacters = selectedMockData.roles.length;
|
||||
|
||||
if (currentStep === '1') {
|
||||
if (isGeneratingSketch) {
|
||||
@ -138,10 +161,14 @@ export function useWorkflowData() {
|
||||
setCurrentLoadingText(STEP_MESSAGES.sketchComplete);
|
||||
}
|
||||
} else if (currentStep === '2') {
|
||||
setCurrentLoadingText(STEP_MESSAGES.character);
|
||||
// 在角色生成阶段,loading文字已经在 getTaskRole 函数中直接管理
|
||||
// 这里不需要额外设置,避免覆盖
|
||||
if (taskRoles.length === totalCharacters) {
|
||||
setCurrentLoadingText(STEP_MESSAGES.newCharacter(totalCharacters, totalCharacters));
|
||||
}
|
||||
} else if (currentStep === '3') {
|
||||
if (isGeneratingVideo) {
|
||||
setCurrentLoadingText(STEP_MESSAGES.video(taskVideos.length, totalSketches));
|
||||
setCurrentLoadingText(STEP_MESSAGES.video(taskVideos.length, totalVideos));
|
||||
} else {
|
||||
setCurrentLoadingText(STEP_MESSAGES.videoComplete);
|
||||
}
|
||||
@ -152,7 +179,7 @@ export function useWorkflowData() {
|
||||
} else {
|
||||
setCurrentLoadingText(STEP_MESSAGES.complete);
|
||||
}
|
||||
}, [isLoading, currentStep, isGeneratingSketch, sketchCount, isGeneratingVideo, taskVideos.length, taskSketch.length]);
|
||||
}, [isLoading, currentStep, isGeneratingSketch, sketchCount, isGeneratingVideo, taskVideos.length, taskSketch.length, taskRoles.length]);
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
@ -194,7 +221,15 @@ export function useWorkflowData() {
|
||||
|
||||
// 获取分镜视频后,开始获取背景音
|
||||
await getTaskBackgroundAudio(taskId);
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
// 后期制作:抽卡中 对口型中 配音中 一致性处理中
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Selecting optimal frames'));
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.postProduction));
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Aligning lip sync'));
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.postProduction));
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Adding background audio'));
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.postProduction));
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Consistency processing'));
|
||||
await new Promise(resolve => setTimeout(resolve, MOCK_DELAY_TIME.postProduction));
|
||||
|
||||
// 修改 taskObject 下的 taskStatus 为 '5'
|
||||
setTaskObject((prev: any) => ({
|
||||
@ -202,15 +237,7 @@ export function useWorkflowData() {
|
||||
taskStatus: '5'
|
||||
}));
|
||||
setCurrentStep('5');
|
||||
// 后期制作:抽卡中 对口型中 配音中 一致性处理中
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Selecting optimal frames'));
|
||||
await new Promise(resolve => setTimeout(resolve, 10000));
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Aligning lip sync'));
|
||||
await new Promise(resolve => setTimeout(resolve, 10000));
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Adding background audio'));
|
||||
await new Promise(resolve => setTimeout(resolve, 10000));
|
||||
setCurrentLoadingText(STEP_MESSAGES.postProduction('Consistency processing'));
|
||||
await new Promise(resolve => setTimeout(resolve, 10000));
|
||||
|
||||
// 获取背景音后,开始获取最终成品
|
||||
await getTaskFinalProduct(taskId);
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
@ -139,7 +139,7 @@ function VideoScreenLayoutComponent({ videos }: VideoScreenLayoutProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-[600px] overflow-hidden bg-[var(--background)]">
|
||||
<div className="relative w-full h-[360px] mt-[3rem] overflow-hidden bg-[var(--background)]">
|
||||
{/* 视频面板容器 */}
|
||||
<div
|
||||
ref={containerRef}
|
||||
|
||||
@ -247,10 +247,20 @@ export const STEP_MESSAGES = {
|
||||
sketch: (count: number, total: number) => `Generating sketch ${count + 1 > total ? total : count + 1}/${total}...`,
|
||||
sketchComplete: 'Sketch generation complete',
|
||||
character: 'Drawing characters...',
|
||||
newCharacter: (count: number, total: number) => `Drawing character ${count + 1 > total ? total : count + 1}/${total}...`,
|
||||
video: (count: number, total: number) => `Generating video ${count + 1 > total ? total : count + 1}/${total}...`,
|
||||
videoComplete: 'Video generation complete',
|
||||
audio: 'Generating background audio...',
|
||||
postProduction: (step: string) => `Post-production: ${step}...`,
|
||||
final: 'Generating final product...',
|
||||
complete: 'Task completed'
|
||||
};
|
||||
};
|
||||
|
||||
export const MOCK_DELAY_TIME = {
|
||||
sketch: 5000, // 5s 一个草图
|
||||
character: 2000, // 2s 一个角色
|
||||
video: 6000, // 6s 一个分镜视频
|
||||
audio: 2000, // 2s 一个音频
|
||||
postProduction: 2000, // 2s 一个后期制作
|
||||
final: 10000, // 10s 一个最终成品
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user