forked from 77media/video-flow
H5进度条
This commit is contained in:
parent
d92a8f285a
commit
444e8bc58e
@ -5,6 +5,7 @@ import "./style/work-flow.css";
|
||||
import { EditModal } from "@/components/ui/edit-modal";
|
||||
import { TaskInfo } from "./work-flow/task-info";
|
||||
import H5TaskInfo from "./work-flow/H5TaskInfo";
|
||||
import H5ProgressBar from "./work-flow/H5ProgressBar";
|
||||
import H5MediaViewer from "./work-flow/H5MediaViewer";
|
||||
import { MediaViewer } from "./work-flow/media-viewer";
|
||||
import { ThumbnailGrid } from "./work-flow/thumbnail-grid";
|
||||
@ -16,12 +17,8 @@ import { SaveEditUseCase } from "@/app/service/usecase/SaveEditUseCase";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import SmartChatBox from "@/components/SmartChatBox/SmartChatBox";
|
||||
import { Drawer, Tooltip, notification } from 'antd';
|
||||
import { showEditingNotification } from "@/components/pages/work-flow/editing-notification";
|
||||
// import { AIEditingIframeButton } from './work-flow/ai-editing-iframe';
|
||||
import { exportVideoWithRetry } from '@/utils/export-service';
|
||||
import { getFirstFrame } from '@/utils/tools';
|
||||
import { EditPoint as EditPointType } from './work-flow/video-edit/types';
|
||||
import { AIEditingIframeButton } from './work-flow/ai-editing-iframe';
|
||||
import { useDeviceType } from '@/hooks/useDeviceType';
|
||||
import { H5ProgressToastProvider, useH5ProgressToast } from '@/components/ui/h5-progress-toast';
|
||||
|
||||
@ -141,16 +138,16 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
const title = isMobile ? 'editing...' : 'Performing intelligent editing...';
|
||||
|
||||
// 显示进度提示并启动超时定时器
|
||||
emitToastShow({ title: title, progress: 0 });
|
||||
// emitToastShow({ title: title, progress: 0 });
|
||||
// 启动自动推进到 90% 的进度(8分钟)
|
||||
if (editingProgressIntervalRef.current) clearInterval(editingProgressIntervalRef.current);
|
||||
editingProgressStartRef.current = Date.now();
|
||||
const totalMs = 8 * 60 * 1000;
|
||||
editingProgressIntervalRef.current = setInterval(() => {
|
||||
const elapsed = Date.now() - editingProgressStartRef.current;
|
||||
const pct = Math.min(90, Math.max(0, Math.floor((elapsed / totalMs) * 90)));
|
||||
emitToastUpdate({ progress: pct });
|
||||
}, 250);
|
||||
// editingProgressIntervalRef.current = setInterval(() => {
|
||||
// const elapsed = Date.now() - editingProgressStartRef.current;
|
||||
// const pct = Math.min(90, Math.max(0, Math.floor((elapsed / totalMs) * 90)));
|
||||
// emitToastUpdate({ progress: pct });
|
||||
// }, 250);
|
||||
if (editingTimeoutRef.current) clearTimeout(editingTimeoutRef.current);
|
||||
editingTimeoutRef.current = setTimeout(() => {
|
||||
console.log('❌ Editing timeout - retrying...');
|
||||
@ -159,9 +156,9 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
clearInterval(editingProgressIntervalRef.current);
|
||||
editingProgressIntervalRef.current = null;
|
||||
}
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
setTimeout(() => {
|
||||
emitToastShow({ title: 'Retry intelligent editing...', progress: 0 });
|
||||
// emitToastShow({ title: 'Retry intelligent editing...', progress: 0 });
|
||||
// 重试阶段自动推进(5分钟到 90%)
|
||||
if (editingProgressIntervalRef.current) clearInterval(editingProgressIntervalRef.current);
|
||||
editingProgressStartRef.current = Date.now();
|
||||
@ -169,7 +166,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
editingProgressIntervalRef.current = setInterval(() => {
|
||||
const elapsed = Date.now() - editingProgressStartRef.current;
|
||||
const pct = Math.min(90, Math.max(0, Math.floor((elapsed / retryTotalMs) * 90)));
|
||||
emitToastUpdate({ progress: pct });
|
||||
// emitToastUpdate({ progress: pct });
|
||||
}, 250);
|
||||
if (editingTimeoutRef.current) clearTimeout(editingTimeoutRef.current);
|
||||
editingTimeoutRef.current = setTimeout(() => {
|
||||
@ -183,7 +180,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
clearInterval(editingProgressIntervalRef.current);
|
||||
editingProgressIntervalRef.current = null;
|
||||
}
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
}, 5000);
|
||||
}, 5 * 60 * 1000);
|
||||
}, 200);
|
||||
@ -204,7 +201,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
clearInterval(editingProgressIntervalRef.current);
|
||||
editingProgressIntervalRef.current = null;
|
||||
}
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
}, [emitToastHide]);
|
||||
|
||||
// 使用自定义 hooks 管理状态
|
||||
@ -272,15 +269,15 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
clearInterval(editingProgressIntervalRef.current);
|
||||
editingProgressIntervalRef.current = null;
|
||||
}
|
||||
emitToastUpdate({ title: 'Editing successful', progress: 100 });
|
||||
// emitToastUpdate({ title: 'Editing successful', progress: 100 });
|
||||
console.log('Editing successful');
|
||||
localStorage.setItem(`isLoaded_plan_${episodeId}`, 'true');
|
||||
setEditingStatus('success');
|
||||
setIsEditingInProgress(false);
|
||||
isEditingInProgressRef.current = false;
|
||||
setTimeout(() => {
|
||||
emitToastHide();
|
||||
}, 3000);
|
||||
// setTimeout(() => {
|
||||
// emitToastHide();
|
||||
// }, 3000);
|
||||
}
|
||||
}, [taskObject.final, isHandleEdit, episodeId, emitToastHide, emitToastUpdate]);
|
||||
|
||||
@ -422,13 +419,22 @@ Please process this video editing request.`;
|
||||
<div className="content-vPGYx8">
|
||||
<div className="info-UUGkPJ">
|
||||
{isMobile || isTablet ? (
|
||||
<H5TaskInfo
|
||||
title={taskObject.title}
|
||||
current={currentSketchIndex + 1}
|
||||
taskObject={taskObject}
|
||||
selectedView={selectedView}
|
||||
currentLoadingText={currentLoadingText}
|
||||
/>
|
||||
<>
|
||||
<H5TaskInfo
|
||||
title={taskObject.title}
|
||||
current={currentSketchIndex + 1}
|
||||
taskObject={taskObject}
|
||||
selectedView={selectedView}
|
||||
currentLoadingText={currentLoadingText}
|
||||
/>
|
||||
{taskObject.currentStage !== 'init' && (
|
||||
<H5ProgressBar
|
||||
taskObject={taskObject}
|
||||
scriptData={scriptData}
|
||||
currentLoadingText={currentLoadingText}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<TaskInfo
|
||||
taskObject={taskObject}
|
||||
|
||||
@ -102,14 +102,14 @@ export function H5MediaViewer({
|
||||
/** 视频轮播容器高度:按 aspectRatio 计算(基于视口宽度) */
|
||||
const videoWrapperHeight = useMemo(() => {
|
||||
const { w, h } = parseAspect(aspectRatio);
|
||||
return `min(calc(100vw * ${h} / ${w}), calc(100vh - 8.5rem))`;
|
||||
return `min(calc(100vw * ${h} / ${w}), calc(100vh - 10.5rem))`;
|
||||
}, [aspectRatio]);
|
||||
|
||||
/** 图片轮播容器高度:默认 16:9 */
|
||||
const imageWrapperHeight = useMemo(() => {
|
||||
// return 'calc(100vw * 9 / 16)';
|
||||
const { w, h } = parseAspect(aspectRatio);
|
||||
return `min(calc(100vw * ${h} / ${w}), calc(100vh - 8.5rem))`;
|
||||
return `min(calc(100vw * ${h} / ${w}), calc(100vh - 10.5rem))`;
|
||||
}, [aspectRatio]);
|
||||
|
||||
// 计算当前阶段类型
|
||||
@ -354,7 +354,7 @@ export function H5MediaViewer({
|
||||
<button
|
||||
type="button"
|
||||
data-alt="open-catalog-button"
|
||||
className="fixed bottom-[6rem] right-4 z-[60] w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-blue-600 text-white shadow-lg flex items-center justify-center active:scale-95"
|
||||
className="fixed bottom-[5rem] right-4 z-[60] w-12 h-12 rounded-full bg-gradient-to-br from-blue-500 to-blue-600 text-white shadow-lg flex items-center justify-center active:scale-95"
|
||||
aria-label="open-catalog"
|
||||
onClick={() => setIsCatalogOpen(true)}
|
||||
>
|
||||
|
||||
293
components/pages/work-flow/H5ProgressBar.tsx
Normal file
293
components/pages/work-flow/H5ProgressBar.tsx
Normal file
@ -0,0 +1,293 @@
|
||||
'use client'
|
||||
|
||||
import React, { useMemo, useEffect, useState } from 'react'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { Heart, Camera, Film, Scissors, type LucideIcon } from 'lucide-react'
|
||||
import { TaskObject } from '@/api/DTO/movieEdit'
|
||||
|
||||
interface H5ProgressBarProps {
|
||||
taskObject: TaskObject
|
||||
scriptData: any
|
||||
/** Loading text for stage detection */
|
||||
currentLoadingText: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
/** Stage configuration map */
|
||||
const stageIconMap: Record<number, { icon: LucideIcon; color: string; label: string }> = {
|
||||
0: { icon: Heart, color: '#6bf5f9', label: 'Script' },
|
||||
1: { icon: Camera, color: '#88bafb', label: 'Roles & Scenes' },
|
||||
2: { icon: Film, color: '#a285fd', label: 'Shots' },
|
||||
3: { icon: Scissors, color: '#c73dff', label: 'Final' }
|
||||
}
|
||||
|
||||
const H5ProgressBar: React.FC<H5ProgressBarProps> = ({
|
||||
taskObject,
|
||||
scriptData,
|
||||
currentLoadingText,
|
||||
className
|
||||
}) => {
|
||||
/** Calculate current stage based on taskObject state */
|
||||
const currentStage = useMemo(() => {
|
||||
/** Check if roles & scenes are completed */
|
||||
const rolesCompleted =
|
||||
taskObject.roles?.total_count > 0 &&
|
||||
taskObject.roles?.data?.filter(v => v.status !== 0).length === taskObject.roles?.total_count
|
||||
const scenesCompleted =
|
||||
taskObject.scenes?.total_count > 0 &&
|
||||
taskObject.scenes?.data?.filter(v => v.status !== 0).length === taskObject.scenes?.total_count
|
||||
const rolesAndScenesCompleted = rolesCompleted && scenesCompleted
|
||||
|
||||
/** Check if videos are completed or nearly completed */
|
||||
const videosCount = taskObject.videos?.data?.filter(v => v.video_status !== 0).length || 0
|
||||
const videosTotal = taskObject.videos?.total_count || 0
|
||||
const videosCompleted = videosTotal > 0 && videosCount === videosTotal
|
||||
const videosNearlyComplete = videosTotal > 0 && videosCount >= videosTotal * 0.9 /** 90% complete */
|
||||
|
||||
/** Check if final video exists */
|
||||
const finalVideoExists = !!taskObject.final?.url
|
||||
|
||||
/** Determine stage based on conditions */
|
||||
if (finalVideoExists) {
|
||||
return 4 /** Completed - all done */
|
||||
}
|
||||
|
||||
/** Enter final video stage when videos are completed or nearly complete, or stage is explicitly set */
|
||||
if (videosCompleted || videosNearlyComplete || taskObject.currentStage === 'final_video') {
|
||||
return 3 /** Final video stage */
|
||||
}
|
||||
|
||||
if (rolesAndScenesCompleted || taskObject.currentStage === 'video') {
|
||||
return 2 /** Shots/video stage */
|
||||
}
|
||||
|
||||
if (scriptData || taskObject.currentStage === 'character' || taskObject.currentStage === 'scene') {
|
||||
return 1 /** Roles & scenes stage */
|
||||
}
|
||||
|
||||
if (taskObject.currentStage === 'script') {
|
||||
return 0 /** Script stage */
|
||||
}
|
||||
|
||||
return 0 /** Default to script stage */
|
||||
}, [
|
||||
taskObject.currentStage,
|
||||
taskObject.roles?.data,
|
||||
taskObject.roles?.total_count,
|
||||
taskObject.scenes?.data,
|
||||
taskObject.scenes?.total_count,
|
||||
taskObject.videos?.data,
|
||||
taskObject.videos?.total_count,
|
||||
taskObject.final?.url,
|
||||
scriptData
|
||||
])
|
||||
|
||||
/** Generate progress segments */
|
||||
const segments = useMemo(() => {
|
||||
/** Calculate progress for each stage */
|
||||
const calculateStageProgress = (stage: number): number => {
|
||||
const isCompleted = stage < currentStage
|
||||
const isCurrent = stage === currentStage
|
||||
const isNext = stage === currentStage + 1
|
||||
|
||||
/** Completed stages are always 100% */
|
||||
if (isCompleted) {
|
||||
return 100
|
||||
}
|
||||
|
||||
/** Non-current and non-next stages are 0% */
|
||||
if (!isCurrent && !isNext) {
|
||||
return 0
|
||||
}
|
||||
|
||||
/** Calculate current stage progress */
|
||||
switch (stage) {
|
||||
case 0: /** Script stage */
|
||||
/** If scriptData exists or moved to next stage, show 100% */
|
||||
if (scriptData || currentStage > 0) {
|
||||
return 100
|
||||
}
|
||||
return 40
|
||||
|
||||
case 1: /** Roles & Scenes stage */
|
||||
const rolesCount = taskObject.roles?.data?.filter(v => v.status !== 0).length || 0
|
||||
const rolesTotal = taskObject.roles?.total_count || 0
|
||||
const scenesCount = taskObject.scenes?.data?.filter(v => v.status !== 0).length || 0
|
||||
const scenesTotal = taskObject.scenes?.total_count || 0
|
||||
const totalItems = rolesTotal + scenesTotal
|
||||
|
||||
if (totalItems === 0) {
|
||||
return 40
|
||||
}
|
||||
|
||||
const completedItems = rolesCount + scenesCount
|
||||
return Math.min(Math.round((completedItems / totalItems) * 100), 95)
|
||||
|
||||
case 2: /** Shots/Video stage */
|
||||
const videosCount = taskObject.videos?.data?.filter(v => v.video_status !== 0).length || 0
|
||||
const videosTotal = taskObject.videos?.total_count || 0
|
||||
|
||||
if (videosTotal === 0) {
|
||||
return 40
|
||||
}
|
||||
|
||||
return Math.min(Math.round((videosCount / videosTotal) * 100), 95)
|
||||
|
||||
case 3: /** Final video stage */
|
||||
/** If final.url exists, show 100% */
|
||||
if (taskObject.final?.url) {
|
||||
return 100
|
||||
}
|
||||
/** If this is the next stage (not current), show initial progress */
|
||||
if (isNext) {
|
||||
return 0
|
||||
}
|
||||
/** Current stage in progress */
|
||||
return 60
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
return [0, 1, 2, 3].map((stage) => {
|
||||
const config = stageIconMap[stage]
|
||||
const isCompleted = stage < currentStage
|
||||
const isCurrent = stage === currentStage
|
||||
const segmentProgress = calculateStageProgress(stage)
|
||||
|
||||
return {
|
||||
stage,
|
||||
config,
|
||||
isCompleted,
|
||||
isCurrent,
|
||||
segmentProgress
|
||||
}
|
||||
})
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
currentStage,
|
||||
scriptData,
|
||||
taskObject.roles?.data,
|
||||
taskObject.roles?.total_count,
|
||||
taskObject.scenes?.data,
|
||||
taskObject.scenes?.total_count,
|
||||
taskObject.videos?.data,
|
||||
taskObject.videos?.total_count,
|
||||
taskObject.final?.url
|
||||
])
|
||||
|
||||
return (
|
||||
<div
|
||||
data-alt="h5-progress-bar-container"
|
||||
className={`w-full py-2 ${className || ''}`}
|
||||
>
|
||||
<div data-alt="progress-segments" className="flex items-center gap-1 relative">
|
||||
{segments.map(({ stage, config, isCompleted, isCurrent, segmentProgress }) => {
|
||||
const Icon = config.icon
|
||||
|
||||
return (
|
||||
<div
|
||||
key={stage}
|
||||
data-alt={`progress-segment-${stage}`}
|
||||
className="flex-1 relative h-[0.35rem] bg-slate-700/50 rounded-full overflow-visible"
|
||||
>
|
||||
{/* Progress fill */}
|
||||
<motion.div
|
||||
data-alt="progress-fill"
|
||||
className="absolute inset-0 rounded-full z-0 backdrop-blur-md"
|
||||
style={{
|
||||
background: `${config.color}80`
|
||||
}}
|
||||
initial={{ width: '0%' }}
|
||||
animate={{ width: `${segmentProgress}%` }}
|
||||
transition={{
|
||||
duration: 0.6,
|
||||
ease: 'easeInOut'
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Animated icon for current stage only */}
|
||||
<AnimatePresence>
|
||||
{isCurrent && !currentLoadingText.includes('Task completed') && segmentProgress < 100 && (
|
||||
<motion.div
|
||||
data-alt="stage-icon-moving"
|
||||
className="absolute -top-1/2 -translate-y-1/2 z-20"
|
||||
initial={{ left: '0%', x: '-50%', opacity: 0, scale: 0.5 }}
|
||||
animate={{
|
||||
left: `${segmentProgress}%`,
|
||||
x: '-50%',
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
rotate: [0, 360],
|
||||
transition: {
|
||||
left: { duration: 0.6, ease: 'easeInOut' },
|
||||
x: { duration: 0 },
|
||||
opacity: { duration: 0.3 },
|
||||
scale: { duration: 0.3 },
|
||||
rotate: { duration: 2, repeat: Infinity, ease: 'linear' }
|
||||
}
|
||||
}}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
scale: 0.5,
|
||||
transition: { duration: 0.3 }
|
||||
}}
|
||||
>
|
||||
<div
|
||||
data-alt="icon-wrapper"
|
||||
className="w-3 h-3 rounded-full bg-white/90 backdrop-blur-sm flex items-center justify-center shadow-lg"
|
||||
style={{
|
||||
boxShadow: `0 0 8px ${config.color}80`,
|
||||
background: `${config.color}`
|
||||
}}
|
||||
>
|
||||
{/* <Icon className="w-2 h-2" style={{ color: config.color }} /> */}
|
||||
<Icon className="w-2 h-2" style={{ color: '#fff', fontWeight: 'bold' }} />
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Glow effect for current stage */}
|
||||
{isCurrent && segmentProgress < 100 && (
|
||||
<motion.div
|
||||
data-alt="glow-effect"
|
||||
className="absolute inset-0 rounded-full z-10"
|
||||
style={{
|
||||
background: `linear-gradient(to right, transparent, ${config.color}40, transparent)`
|
||||
}}
|
||||
animate={{
|
||||
x: ['-100%', '100%'],
|
||||
transition: {
|
||||
duration: 1.5,
|
||||
repeat: Infinity,
|
||||
ease: 'linear'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Stage labels (optional) */}
|
||||
{/* <div data-alt="stage-labels" className="flex items-center justify-between mt-1 px-1">
|
||||
{segments.map(({ stage, config, isCurrent }) => (
|
||||
<span
|
||||
key={stage}
|
||||
data-alt={`stage-label-${stage}`}
|
||||
className={`text-[10px] ${isCurrent ? 'text-white font-medium' : 'text-slate-400'}`}
|
||||
style={isCurrent ? { color: config.color } : {}}
|
||||
>
|
||||
{config.label}
|
||||
</span>
|
||||
))}
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default H5ProgressBar
|
||||
|
||||
@ -147,57 +147,6 @@ const H5TaskInfo: React.FC<H5TaskInfoProps> = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 右侧状态区域 */}
|
||||
<div data-alt="status-area" className="flex-shrink-0 bg-gradient-to-b from-slate-900/80 via-slate-900/40 to-transparent backdrop-blur-sm rounded-lg py-4 px-4 max-w-[200px]">
|
||||
<AnimatePresence mode="popLayout">
|
||||
{currentLoadingText && currentLoadingText !== 'Task completed' && (
|
||||
<motion.div
|
||||
key={currentLoadingText}
|
||||
data-alt="status-line"
|
||||
className="flex flex-col gap-2"
|
||||
initial={{ opacity: 0, x: 10 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: 10 }}
|
||||
transition={{ duration: 0.25 }}
|
||||
>
|
||||
<div className="flex items-center justify-center">
|
||||
{StageIcon}
|
||||
</div>
|
||||
<div className="relative text-center">
|
||||
{/* 背景流光 */}
|
||||
<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-[1px]"
|
||||
animate={{
|
||||
backgroundPosition: ['0% 50%', '100% 50%', '0% 50%'],
|
||||
transition: { duration: 2, repeat: Infinity, ease: 'linear' }
|
||||
}}
|
||||
style={{ backgroundSize: '200% 200%' }}
|
||||
>
|
||||
<span className="text-xs leading-tight break-words">{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.div>
|
||||
|
||||
{/* 底部装饰线 */}
|
||||
<motion.div
|
||||
className="absolute -bottom-0.5 left-1/2 transform -translate-x-1/2 h-0.5 w-8"
|
||||
style={{
|
||||
background: `linear-gradient(to right, ${stageColor}, rgb(34 211 238), rgb(168 85 247))`
|
||||
}}
|
||||
animate={{ width: ['0%', '100%', '0%'] }}
|
||||
transition={{ duration: 2, repeat: Infinity, ease: 'easeInOut' }}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -29,19 +29,19 @@ interface TaskInfoProps {
|
||||
const stageIconMap = {
|
||||
0: {
|
||||
icon: Heart,
|
||||
color: '#8b5cf6'
|
||||
color: '#6bf5f9'
|
||||
},
|
||||
1: {
|
||||
icon: Camera,
|
||||
color: '#06b6d4'
|
||||
color: '#88bafb'
|
||||
},
|
||||
2: {
|
||||
icon: Film,
|
||||
color: '#10b981'
|
||||
color: '#a285fd'
|
||||
},
|
||||
3: {
|
||||
icon: Scissors,
|
||||
color: '#f59e0b'
|
||||
color: '#c73dff'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
return () => {
|
||||
console.log("unmount-useWorkflowData");
|
||||
// 组件卸载时隐藏H5进度提示
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
};
|
||||
}, []);
|
||||
// 查看缓存中 是否已经 加载过 这个项目的 剪辑计划
|
||||
@ -161,7 +161,7 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
return;
|
||||
}
|
||||
// 显示生成剪辑计划进度提示
|
||||
emitToastShow({ title: isMobile ? 'Preparing for editing...' : `Generating intelligent editing plan... ${retryCount ? 'Retry Time: ' + retryCount : ''}`, progress: 0 });
|
||||
// !emitToastShow({ title: isMobile ? 'Preparing for editing...' : `Generating intelligent editing plan... ${retryCount ? 'Retry Time: ' + retryCount : ''}`, progress: 0 });
|
||||
// 平滑推进到 80%,后续阶段接管
|
||||
const start = Date.now();
|
||||
const duration = 3 * 60 * 1000; // 3分钟推进到 80%
|
||||
@ -170,7 +170,7 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
interval = setInterval(() => {
|
||||
const elapsed = Date.now() - start;
|
||||
const pct = Math.min(80, Math.floor((elapsed / duration) * 80));
|
||||
emitToastUpdate({ progress: pct });
|
||||
// emitToastUpdate({ progress: pct });
|
||||
if (pct >= 80) stop();
|
||||
}, 300);
|
||||
// 先停止轮询
|
||||
@ -200,10 +200,8 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
setNeedStreamData(true);
|
||||
setIsGenerateEditPlan(false);
|
||||
|
||||
// 显示失败提示,并在稍后隐藏
|
||||
// emitToastShow({ title: isMobile ? 'Editing plan generation failed. Retrying later.' : 'Editing plan generation failed. Retrying later.', progress: 0 });
|
||||
setTimeout(() => {
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
setIsLoadingGenerateEditPlan(false);
|
||||
}, 8000);
|
||||
stop();
|
||||
@ -234,14 +232,14 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
setCurrentLoadingText(LOADING_TEXT_MAP.toManyFailed);
|
||||
// 停止轮询
|
||||
setNeedStreamData(false);
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
}
|
||||
if (editingStatus === 'error') {
|
||||
window.msg.error('Editing failed, Please click the scissors button to go to the intelligent editing platform.', 8000);
|
||||
setCurrentLoadingText(LOADING_TEXT_MAP.editingError);
|
||||
// 停止轮询
|
||||
setNeedStreamData(false);
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
}
|
||||
}, [isShowError, editingStatus]);
|
||||
|
||||
@ -422,7 +420,7 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
if (analyze_video_total_count > 0 && !isAnalyzing && analyze_video_completed_count !== analyze_video_total_count) {
|
||||
setIsAnalyzing(true);
|
||||
// 显示准备剪辑计划的提示
|
||||
emitToastShow({ title: isMobile ? 'Preparing for editing...' : 'Preparing intelligent editing plan...', progress: 0 });
|
||||
// emitToastShow({ title: isMobile ? 'Preparing for editing...' : 'Preparing intelligent editing plan...', progress: 0 });
|
||||
}
|
||||
|
||||
if (analyze_video_total_count && analyze_video_completed_count === analyze_video_total_count) {
|
||||
@ -435,7 +433,7 @@ export function useWorkflowData({ onEditPlanGenerated, editingStatus, onExportFa
|
||||
} else {
|
||||
setIsShowError(true);
|
||||
setIsAnalyzing(false);
|
||||
emitToastHide();
|
||||
// emitToastHide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user