forked from 77media/video-flow
159 lines
6.3 KiB
TypeScript
159 lines
6.3 KiB
TypeScript
'use client'
|
||
|
||
import React, { useMemo } from 'react'
|
||
import { TaskObject } from '@/api/DTO/movieEdit'
|
||
import { GlassIconButton } from '@/components/ui/glass-icon-button'
|
||
import { Pencil, RotateCcw, Download, ArrowDownWideNarrow, Scissors, Maximize, Minimize, MessageCircleMore } from 'lucide-react'
|
||
|
||
interface H5TaskInfoProps {
|
||
/** 标题文案 */
|
||
title: string
|
||
/** 当前分镜序号(从1开始) */
|
||
current: number
|
||
/** 任务对象(用于读取总数等信息) */
|
||
taskObject: TaskObject
|
||
/** video:聊天编辑 */
|
||
onEditWithChat?: () => void
|
||
/** 下载:全部分镜 */
|
||
onDownloadAll?: () => void
|
||
/** 下载:最终成片 */
|
||
onDownloadFinal?: () => void
|
||
/** 下载:当前分镜视频 */
|
||
onDownloadCurrent?: () => void
|
||
/** video:失败时显示重试 */
|
||
showRetry?: boolean
|
||
onRetry?: () => void
|
||
className?: string
|
||
}
|
||
|
||
const H5TaskInfo: React.FC<H5TaskInfoProps> = ({
|
||
title,
|
||
current,
|
||
taskObject,
|
||
onEditWithChat,
|
||
onDownloadAll,
|
||
onDownloadFinal,
|
||
onDownloadCurrent,
|
||
showRetry,
|
||
onRetry,
|
||
className
|
||
}) => {
|
||
const total = useMemo(() => {
|
||
if (taskObject.currentStage === 'video' || taskObject.currentStage === 'final_video') {
|
||
return taskObject.videos?.total_count || taskObject.videos?.data?.length || 0
|
||
}
|
||
if (taskObject.currentStage === 'scene' || taskObject.currentStage === 'character') {
|
||
const rolesTotal = taskObject.roles?.total_count || taskObject.roles?.data?.length || 0
|
||
const scenesTotal = taskObject.scenes?.total_count || taskObject.scenes?.data?.length || 0
|
||
return rolesTotal + scenesTotal
|
||
}
|
||
return 0
|
||
}, [taskObject])
|
||
|
||
const shouldShowCount = taskObject.currentStage !== 'script'
|
||
|
||
const displayCurrent = useMemo(() => {
|
||
if (taskObject.currentStage === 'video' || taskObject.currentStage === 'final_video') {
|
||
return Math.max(current, 1)
|
||
}
|
||
if (taskObject.currentStage === 'scene' || taskObject.currentStage === 'character') {
|
||
const bounded = Math.min(Math.max(current, 1), Math.max(total, 1))
|
||
return bounded
|
||
}
|
||
return 0
|
||
}, [taskObject, current, total])
|
||
|
||
return (
|
||
<div
|
||
data-alt="h5-header"
|
||
className={`absolute top-0 left-0 right-0 z-[50] pr-2 ${className || ''}`}
|
||
>
|
||
<div
|
||
data-alt="h5-header-bar"
|
||
className="flex items-start justify-between"
|
||
>
|
||
<div data-alt="title-area" className="flex flex-col min-w-0 bg-gradient-to-b from-slate-900/80 via-slate-900/40 to-transparent backdrop-blur-sm rounded-lg p-4">
|
||
<h1
|
||
data-alt="title"
|
||
className="text-white text-lg font-bold"
|
||
title={title}
|
||
>
|
||
{title || '...'}
|
||
</h1>
|
||
{shouldShowCount && (
|
||
<span data-alt="shot-count" className="flex items-center gap-4 text-sm text-slate-300">
|
||
分镜 {displayCurrent}/{Math.max(total, 1)}
|
||
</span>
|
||
)}
|
||
</div>
|
||
|
||
<div data-alt="actions" className="flex flex-col items-center gap-2">
|
||
{taskObject.currentStage === 'final_video' && (
|
||
<div data-alt="final-video-actions" className="flex flex-col items-center gap-2">
|
||
<GlassIconButton
|
||
data-alt="download-all-button"
|
||
className="w-10 h-10 bg-gradient-to-br from-purple-500/80 to-purple-600/80 backdrop-blur-xl border border-purple-400/30 rounded-full flex items-center justify-center hover:from-purple-400/80 hover:to-purple-500/80 transition-all"
|
||
icon={ArrowDownWideNarrow}
|
||
size="sm"
|
||
aria-label="download-all"
|
||
onClick={onDownloadAll}
|
||
/>
|
||
<GlassIconButton
|
||
data-alt="download-final-button"
|
||
className="w-10 h-10 bg-gradient-to-br from-amber-500/80 to-yellow-600/80 backdrop-blur-xl border border-amber-400/30 rounded-full flex items-center justify-center hover:from-amber-400/80 hover:to-yellow-500/80 transition-all"
|
||
icon={Download}
|
||
size="sm"
|
||
aria-label="download-final"
|
||
onClick={onDownloadFinal}
|
||
/>
|
||
</div>
|
||
)}
|
||
|
||
{taskObject.currentStage === 'video' && (
|
||
<div data-alt="video-actions" className="flex flex-col items-center gap-2">
|
||
<GlassIconButton
|
||
data-alt="edit-with-chat-button"
|
||
className="w-10 h-10 bg-gradient-to-br from-blue-500/80 to-blue-600/80 backdrop-blur-xl border border-blue-400/30 rounded-full flex items-center justify-center hover:from-blue-400/80 hover:to-blue-500/80 transition-all"
|
||
icon={MessageCircleMore}
|
||
size="sm"
|
||
aria-label="edit-with-chat"
|
||
onClick={onEditWithChat}
|
||
/>
|
||
<GlassIconButton
|
||
data-alt="download-all-button"
|
||
className="w-10 h-10 bg-gradient-to-br from-purple-500/80 to-purple-600/80 backdrop-blur-xl border border-purple-400/30 rounded-full flex items-center justify-center hover:from-purple-400/80 hover:to-purple-500/80 transition-all"
|
||
icon={ArrowDownWideNarrow}
|
||
size="sm"
|
||
aria-label="download-all"
|
||
onClick={onDownloadAll}
|
||
/>
|
||
<GlassIconButton
|
||
data-alt="download-current-button"
|
||
className="w-10 h-10 bg-gradient-to-br from-amber-500/80 to-yellow-600/80 backdrop-blur-xl border border-amber-400/30 rounded-full flex items-center justify-center hover:from-amber-400/80 hover:to-yellow-500/80 transition-all"
|
||
icon={Download}
|
||
size="sm"
|
||
aria-label="download-current"
|
||
onClick={onDownloadCurrent}
|
||
/>
|
||
{showRetry && (
|
||
<GlassIconButton
|
||
data-alt="retry-button"
|
||
className="w-10 h-10 bg-gradient-to-br from-purple-500/80 to-purple-600/80 backdrop-blur-xl border border-purple-400/30 rounded-full flex items-center justify-center hover:from-purple-400/80 hover:to-purple-500/80 transition-all"
|
||
icon={RotateCcw}
|
||
size="sm"
|
||
aria-label="retry"
|
||
onClick={onRetry}
|
||
/>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default H5TaskInfo
|
||
|
||
|