存--替换视频进度

This commit is contained in:
北枳 2025-08-14 12:58:53 +08:00
parent 06840ab17a
commit 19ef2792f6

View File

@ -1,6 +1,6 @@
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, Check, ReplaceAll, X, TriangleAlert, Loader2 } from 'lucide-react'; import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, CircleX, ReplaceAll, X, TriangleAlert, Loader2 } from 'lucide-react';
import { cn } from '@/public/lib/utils'; import { cn } from '@/public/lib/utils';
import { CharacterEditor } from './character-editor'; import { CharacterEditor } from './character-editor';
import ImageBlurTransition from './ImageBlurTransition'; import ImageBlurTransition from './ImageBlurTransition';
@ -34,23 +34,31 @@ interface Role {
} }
// Mock 数据 // Mock 数据
const mockRole: Role = { const mockReplaceVideoData = {
name: "青春女学生", count: 10,
url: "/assets/3dr_chihiro.png", completed: 2, // 已完成个数
sound: "", data: [
soundDescription: "", {
roleDescription: "一位充满活力和梦想的高中女生,蓝色长发随风飘扬,眼神中透露着对未来的憧憬。她身着整洁的校服,举止优雅而不失活力。", id: '1',
age: 16, name: '替换视频1',
gender: 'female', videoUrl: ['https://video-base-imf.oss-ap-southeast-7.aliyuncs.com/uploads/FJ1_76a6cd5d-e4dd-4bed-8d5f-65306f146caf-20250812112433.mp4'],
ethnicity: '亚洲人', status: 1
appearance: { }, {
hairStyle: "鲜艳蓝色长发", id: '2',
skinTone: "白皙", name: '替换视频1',
facialFeatures: "大眼睛,清秀五官", videoUrl: [],
bodyType: "苗条" status: 2
}, },
tags: ['高中生', '校服', '蓝色长发', '大眼睛', '清秀五官', '苗条'] { id: '3', name: '替换视频1', videoUrl: [], status: 0 },
}; { id: '4', name: '替换视频1', videoUrl: [], status: 0 },
{ id: '5', name: '替换视频1', videoUrl: [], status: 0 },
{ id: '6', name: '替换视频1', videoUrl: [], status: 0 },
{ id: '7', name: '替换视频1', videoUrl: [], status: 0 },
{ id: '8', name: '替换视频1', videoUrl: [], status: 0 },
{ id: '9', name: '替换视频1', videoUrl: [], status: 0 },
{ id: '10', name: '替换视频1', videoUrl: [], status: 0 },
]
}
interface CharacterTabContentProps { interface CharacterTabContentProps {
taskSketch: any[]; taskSketch: any[];
@ -63,7 +71,7 @@ export function CharacterTabContent({
taskSketch, taskSketch,
currentRoleIndex, currentRoleIndex,
onSketchSelect, onSketchSelect,
roles = [mockRole] roles = []
}: CharacterTabContentProps) { }: CharacterTabContentProps) {
const [isReplacePanelOpen, setIsReplacePanelOpen] = useState(false); const [isReplacePanelOpen, setIsReplacePanelOpen] = useState(false);
const [replacePanelKey, setReplacePanelKey] = useState(0); const [replacePanelKey, setReplacePanelKey] = useState(0);
@ -394,6 +402,56 @@ export function CharacterTabContent({
</motion.div> </motion.div>
{/* 替换视频进度 预览区域 */}
<motion.div
className="grid grid-cols-1 gap-6"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
>
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<span className="text-sm text-gray-500"></span>
<span className="text-sm text-blue-500">
{mockReplaceVideoData.completed}/{mockReplaceVideoData.count}
</span>
</div>
<HorizontalScroller
itemWidth={128}
gap={0}
selectedIndex={-1}
onItemClick={() => {}}
>
{mockReplaceVideoData.data.map((shot) => (
<div key={shot.id} className="flex items-center w-[128px] h-full rounded-sm overflow-hidden">
{shot.status === 0 && (
<div className="w-full h-full flex items-center justify-center bg-black/10">
<Loader2 className="w-4 h-4 animate-spin text-blue-500" />
</div>
)}
{shot.status === 1 && (
<video
src={shot.videoUrl[0]}
className="w-full h-full object-cover"
muted
loop
playsInline
onMouseEnter={(e) => e.currentTarget.play()}
onMouseLeave={(e) => e.currentTarget.pause()}
/>
)}
{/* 任务失败 */}
{shot.status === 2 && (
<div className="w-full h-full flex items-center justify-center bg-red-500/10">
<CircleX className="w-4 h-4 text-red-500" />
</div>
)}
</div>
))}
</HorizontalScroller>
</div>
</motion.div>
<FloatingGlassPanel <FloatingGlassPanel
open={isReplacePanelOpen} open={isReplacePanelOpen}