forked from 77media/video-flow
修复编译问题
This commit is contained in:
parent
94acd18075
commit
7603a1a26e
@ -2,7 +2,21 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { DragDropContext, DropResult } from 'react-beautiful-dnd';
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { ScriptMetaInfo } from '../script-overview/script-meta-info';
|
||||
import { SceneFilmstrip } from '../script-overview/scene-filmstrip';
|
||||
import { SceneCardList } from '../script-overview/scene-card-list';
|
||||
@ -30,6 +44,14 @@ export interface ScriptMeta {
|
||||
}
|
||||
|
||||
export default function ScriptOverview() {
|
||||
// Configure drag sensors
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
})
|
||||
);
|
||||
|
||||
// Example Data
|
||||
const [scriptMeta] = useState<ScriptMeta>({
|
||||
title: "Lost Stars",
|
||||
@ -164,14 +186,21 @@ export default function ScriptOverview() {
|
||||
const [selectedSceneId, setSelectedSceneId] = useState<string>();
|
||||
|
||||
// Handle scene drag and drop sorting
|
||||
const handleDragEnd = (result: DropResult) => {
|
||||
if (!result.destination) return;
|
||||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
|
||||
const items = Array.from(scenes);
|
||||
const [reorderedItem] = items.splice(result.source.index, 1);
|
||||
items.splice(result.destination.index, 0, reorderedItem);
|
||||
if (active.id === over?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
setScenes(items);
|
||||
const oldIndex = scenes.findIndex(scene => scene.id === active.id);
|
||||
const newIndex = scenes.findIndex(scene => scene.id === over?.id);
|
||||
|
||||
if (oldIndex === -1 || newIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
setScenes(arrayMove(scenes, oldIndex, newIndex));
|
||||
};
|
||||
|
||||
// Handle scene updates
|
||||
@ -215,7 +244,15 @@ export default function ScriptOverview() {
|
||||
<div className="flex-grow min-w-0 h-full overflow-hidden flex flex-col">
|
||||
{/* Scene Card List */}
|
||||
<div className="flex-grow overflow-y-auto px-8">
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={scenes.map(scene => scene.id)}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
<SceneCardList
|
||||
scenes={scenes}
|
||||
selectedSceneId={selectedSceneId}
|
||||
@ -223,7 +260,8 @@ export default function ScriptOverview() {
|
||||
onSceneDelete={handleSceneDelete}
|
||||
onSceneDuplicate={handleSceneDuplicate}
|
||||
/>
|
||||
</DragDropContext>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
|
||||
{/* Filmstrip Preview */}
|
||||
|
||||
@ -2,7 +2,21 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { DragDropContext, DropResult } from 'react-beautiful-dnd';
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { ScriptMetaInfo } from '../script-overview/script-meta-info';
|
||||
import { SceneFilmstrip } from '../script-overview/scene-filmstrip';
|
||||
import { StoryboardCardList } from '../storyboard/storyboard-card-list';
|
||||
@ -145,14 +159,21 @@ export default function StoryboardView() {
|
||||
const [selectedSceneId, setSelectedSceneId] = useState<string>();
|
||||
|
||||
// 处理场景拖拽排序
|
||||
const handleDragEnd = (result: DropResult) => {
|
||||
if (!result.destination) return;
|
||||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
|
||||
const items = Array.from(scenes);
|
||||
const [reorderedItem] = items.splice(result.source.index, 1);
|
||||
items.splice(result.destination.index, 0, reorderedItem);
|
||||
if (active.id === over?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
setScenes(items);
|
||||
const oldIndex = scenes.findIndex(scene => scene.id === active.id);
|
||||
const newIndex = scenes.findIndex(scene => scene.id === over?.id);
|
||||
|
||||
if (oldIndex === -1 || newIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
setScenes(arrayMove(scenes, oldIndex, newIndex));
|
||||
};
|
||||
|
||||
// 处理场景更新
|
||||
@ -209,7 +230,20 @@ export default function StoryboardView() {
|
||||
<div className="flex-grow min-w-0 h-full overflow-hidden flex flex-col">
|
||||
{/* Scene Card List */}
|
||||
<div className="flex-grow overflow-y-auto">
|
||||
<DragDropContext onDragEnd={handleDragEnd}>
|
||||
<DndContext
|
||||
sensors={useSensors(
|
||||
useSensor(PointerSensor),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
})
|
||||
)}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={scenes.map(scene => scene.id)}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
<StoryboardCardList
|
||||
scenes={scenes}
|
||||
selectedSceneId={selectedSceneId}
|
||||
@ -217,7 +251,8 @@ export default function StoryboardView() {
|
||||
onSceneDelete={handleSceneDelete}
|
||||
onSceneDuplicate={handleSceneDuplicate}
|
||||
/>
|
||||
</DragDropContext>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
|
||||
{/* Filmstrip Preview */}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import { Droppable } from 'react-beautiful-dnd';
|
||||
import { Scene } from '../pages/script-overview';
|
||||
import { SceneCard } from './scene-card';
|
||||
|
||||
@ -18,17 +17,7 @@ export function SceneCardList({
|
||||
onSceneDuplicate
|
||||
}: SceneCardListProps) {
|
||||
return (
|
||||
<Droppable droppableId="scenes" direction="horizontal">
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
className={`
|
||||
flex gap-6 overflow-x-auto hide-scrollbar h-full overflow-y-hidden
|
||||
${snapshot.isDraggingOver ? 'bg-white/5' : ''}
|
||||
transition-colors duration-300 rounded-xl p-2
|
||||
`}
|
||||
>
|
||||
<div className="flex gap-6 overflow-x-auto hide-scrollbar h-full overflow-y-hidden transition-colors duration-300 rounded-xl p-2">
|
||||
{scenes.map((scene, index) => (
|
||||
<SceneCard
|
||||
key={scene.id}
|
||||
@ -40,9 +29,6 @@ export function SceneCardList({
|
||||
onDuplicate={() => onSceneDuplicate(scene.id)}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
);
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { Trash2, Copy, RefreshCw, GripVertical } from 'lucide-react';
|
||||
import { Scene } from '../pages/script-overview';
|
||||
import Image from 'next/image';
|
||||
@ -29,6 +30,20 @@ export function SceneCard({
|
||||
const cardRef = useRef<HTMLDivElement>(null);
|
||||
const timeoutRef = useRef<NodeJS.Timeout>();
|
||||
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
isDragging,
|
||||
} = useSortable({ id: scene.id });
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
};
|
||||
|
||||
// 处理自动保存
|
||||
const handleContentChange = (
|
||||
field: keyof Scene,
|
||||
@ -67,12 +82,10 @@ export function SceneCard({
|
||||
}, [isSelected]);
|
||||
|
||||
return (
|
||||
<Draggable draggableId={scene.id} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
{...attributes}
|
||||
>
|
||||
<motion.div
|
||||
id={`scene-card-${scene.id}`}
|
||||
@ -80,9 +93,9 @@ export function SceneCard({
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
x: snapshot.isDragging ? 5 : 0,
|
||||
y: snapshot.isDragging ? 5 : 0,
|
||||
rotate: snapshot.isDragging ? 2 : 0
|
||||
x: isDragging ? 5 : 0,
|
||||
y: isDragging ? 5 : 0,
|
||||
rotate: isDragging ? 2 : 0
|
||||
}}
|
||||
transition={{
|
||||
type: "spring",
|
||||
@ -92,7 +105,7 @@ export function SceneCard({
|
||||
className={`
|
||||
relative flex-shrink-0 w-[400px] bg-white/5 backdrop-blur-sm rounded-xl overflow-hidden h-full
|
||||
flex flex-col group cursor-grab active:cursor-grabbing
|
||||
${snapshot.isDragging ? 'ring-2 ring-blue-500/50 shadow-lg z-50' : ''}
|
||||
${isDragging ? 'ring-2 ring-blue-500/50 shadow-lg z-50' : ''}
|
||||
${isEditing ? 'ring-2 ring-yellow-500/50' : ''}
|
||||
${isSelected ? 'ring-2 ring-purple-500/50' : ''}
|
||||
transition-all duration-300
|
||||
@ -103,6 +116,14 @@ export function SceneCard({
|
||||
setShowDeleteConfirm(false);
|
||||
}}
|
||||
>
|
||||
{/* Drag Handle */}
|
||||
<div
|
||||
{...listeners}
|
||||
className="absolute top-2 right-2 z-10 p-2 rounded-lg bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity cursor-grab active:cursor-grabbing"
|
||||
>
|
||||
<GripVertical className="w-4 h-4 text-white/60" />
|
||||
</div>
|
||||
|
||||
{/* Scene Image */}
|
||||
<div className="relative w-full h-[200px] flex-shrink-0">
|
||||
<Image
|
||||
@ -304,7 +325,5 @@ export function SceneCard({
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
@ -1,4 +1,3 @@
|
||||
import { Droppable } from 'react-beautiful-dnd';
|
||||
import { StoryboardScene } from '../pages/storyboard-view';
|
||||
import { StoryboardCard } from './storyboard-card';
|
||||
|
||||
@ -18,27 +17,18 @@ export function StoryboardCardList({
|
||||
onSceneDuplicate
|
||||
}: StoryboardCardListProps) {
|
||||
return (
|
||||
<Droppable droppableId="storyboard-scenes">
|
||||
{(provided) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
className="flex gap-6 overflow-x-auto hide-scrollbar h-full overflow-y-hidden p-8"
|
||||
>
|
||||
<div className="flex gap-6 overflow-x-auto hide-scrollbar h-full overflow-y-hidden transition-colors duration-300 rounded-xl p-2">
|
||||
{scenes.map((scene, index) => (
|
||||
<StoryboardCard
|
||||
key={scene.id}
|
||||
scene={scene}
|
||||
index={index}
|
||||
isSelected={selectedSceneId === scene.id}
|
||||
isSelected={scene.id === selectedSceneId}
|
||||
onUpdate={(updates) => onSceneUpdate(scene.id, updates)}
|
||||
onDelete={() => onSceneDelete(scene.id)}
|
||||
onDuplicate={() => onSceneDuplicate(scene.id)}
|
||||
/>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { Trash2, Copy, RefreshCw } from 'lucide-react';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { Trash2, Copy, RefreshCw, GripVertical } from 'lucide-react';
|
||||
import { StoryboardScene } from '../pages/storyboard-view';
|
||||
import Image from 'next/image';
|
||||
|
||||
@ -29,6 +30,20 @@ export function StoryboardCard({
|
||||
const cardRef = useRef<HTMLDivElement>(null);
|
||||
const timeoutRef = useRef<NodeJS.Timeout>();
|
||||
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
isDragging,
|
||||
} = useSortable({ id: scene.id });
|
||||
|
||||
const style = {
|
||||
transform: CSS.Transform.toString(transform),
|
||||
transition,
|
||||
};
|
||||
|
||||
// 处理自动保存
|
||||
const handleContentChange = (
|
||||
field: keyof StoryboardScene,
|
||||
@ -67,32 +82,13 @@ export function StoryboardCard({
|
||||
}, [isSelected]);
|
||||
|
||||
return (
|
||||
<Draggable draggableId={scene.id} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
<motion.div
|
||||
id={`scene-card-${scene.id}`}
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
x: snapshot.isDragging ? 5 : 0,
|
||||
y: snapshot.isDragging ? 5 : 0,
|
||||
rotate: snapshot.isDragging ? 2 : 0
|
||||
}}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 200,
|
||||
damping: 20
|
||||
}}
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
className={`
|
||||
relative flex-shrink-0 w-[400px] bg-white/5 backdrop-blur-sm rounded-xl overflow-hidden h-full
|
||||
flex flex-col group cursor-grab active:cursor-grabbing
|
||||
${snapshot.isDragging ? 'ring-2 ring-blue-500/50 shadow-lg z-50' : ''}
|
||||
${isDragging ? 'ring-2 ring-blue-500/50 shadow-lg z-50' : ''}
|
||||
${isEditing ? 'ring-2 ring-yellow-500/50' : ''}
|
||||
${isSelected ? 'ring-2 ring-purple-500/50' : ''}
|
||||
transition-all duration-300
|
||||
@ -103,6 +99,44 @@ export function StoryboardCard({
|
||||
setShowDeleteConfirm(false);
|
||||
}}
|
||||
>
|
||||
<motion.div
|
||||
id={`scene-card-${scene.id}`}
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
x: isDragging ? 5 : 0,
|
||||
y: isDragging ? 5 : 0,
|
||||
rotate: isDragging ? 2 : 0
|
||||
}}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 200,
|
||||
damping: 20
|
||||
}}
|
||||
className={`
|
||||
relative flex-shrink-0 w-[400px] bg-white/5 backdrop-blur-sm rounded-xl overflow-hidden h-full
|
||||
flex flex-col group cursor-grab active:cursor-grabbing
|
||||
${isDragging ? 'ring-2 ring-blue-500/50 shadow-lg z-50' : ''}
|
||||
${isEditing ? 'ring-2 ring-yellow-500/50' : ''}
|
||||
${isSelected ? 'ring-2 ring-purple-500/50' : ''}
|
||||
transition-all duration-300
|
||||
`}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => {
|
||||
setIsHovered(false);
|
||||
setShowDeleteConfirm(false);
|
||||
}}
|
||||
>
|
||||
{/* Drag Handle */}
|
||||
<div
|
||||
{...listeners}
|
||||
{...attributes}
|
||||
className="absolute top-2 right-2 z-10 p-2 rounded-lg bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity cursor-grab active:cursor-grabbing"
|
||||
>
|
||||
<GripVertical className="w-4 h-4 text-white/60" />
|
||||
</div>
|
||||
|
||||
{/* Scene Image */}
|
||||
<div className="relative w-full h-[200px] flex-shrink-0">
|
||||
<Image
|
||||
@ -304,7 +338,5 @@ export function StoryboardCard({
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
}
|
||||
@ -6,12 +6,28 @@ import {
|
||||
} from './constants';
|
||||
|
||||
// 当前选择的mock数据
|
||||
let selectedMockData = getRandomMockData();
|
||||
let selectedMockData: any = null;
|
||||
|
||||
// 加载mock数据的辅助函数
|
||||
const loadMockData = async () => {
|
||||
if (!selectedMockData) {
|
||||
try {
|
||||
selectedMockData = await getRandomMockData();
|
||||
} catch (error) {
|
||||
// 如果API失败,使用本地fallback数据
|
||||
const { MOCK_DATA } = await import('./constants');
|
||||
const randomIndex = Math.floor(Math.random() * MOCK_DATA.length);
|
||||
selectedMockData = MOCK_DATA[randomIndex];
|
||||
console.log('使用本地fallback数据:', selectedMockData);
|
||||
}
|
||||
}
|
||||
return selectedMockData;
|
||||
};
|
||||
|
||||
// 模拟接口请求 获取任务详情
|
||||
export const getTaskDetail = async (taskId: string): Promise<TaskObject> => {
|
||||
// 每次获取任务详情时重新随机选择数据
|
||||
selectedMockData = getRandomMockData();
|
||||
// 确保已经加载了数据
|
||||
await loadMockData();
|
||||
|
||||
const data: TaskObject = {
|
||||
projectId: selectedMockData.detail.projectId,
|
||||
@ -32,6 +48,9 @@ export const getTaskSketch = async (
|
||||
taskId: string,
|
||||
onProgress: (sketch: SketchItem, index: number) => void
|
||||
): Promise<void> => {
|
||||
// 确保已经加载了数据
|
||||
await loadMockData();
|
||||
|
||||
const sketchData = selectedMockData.sketch;
|
||||
const totalSketches = sketchData.length;
|
||||
|
||||
@ -71,6 +90,9 @@ export const getTaskVideo = async (
|
||||
sketchCount: number,
|
||||
onProgress: (video: VideoItem, index: number) => void
|
||||
): Promise<void> => {
|
||||
// 确保已经加载了数据
|
||||
await loadMockData();
|
||||
|
||||
const videoData = selectedMockData.video;
|
||||
const totalVideos = videoData.length;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user