forked from 77media/video-flow
188 lines
6.5 KiB
TypeScript
188 lines
6.5 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useRef, useEffect } from "react";
|
|
import { Plus, Table, AlignHorizontalSpaceAround, Loader2 } from "lucide-react";
|
|
import "./style/home-page2.css";
|
|
import { useRouter } from "next/navigation";
|
|
import { VideoScreenLayout } from '@/components/video-screen-layout';
|
|
import { VideoGridLayout } from '@/components/video-grid-layout';
|
|
import { motion } from "framer-motion";
|
|
import {
|
|
createScriptProject,
|
|
CreateScriptProjectRequest
|
|
} from '@/api/script_project';
|
|
import {
|
|
ProjectTypeEnum,
|
|
ModeEnum,
|
|
ResolutionEnum
|
|
} from '@/api/enums';
|
|
import {
|
|
getResourcesList,
|
|
Resource
|
|
} from '@/api/resources';
|
|
|
|
export function HomePage2() {
|
|
const router = useRouter();
|
|
const [activeTool, setActiveTool] = useState("stretch");
|
|
const [isCreating, setIsCreating] = useState(false);
|
|
const [createdProjectId, setCreatedProjectId] = useState<number | null>(null);
|
|
const [resources, setResources] = useState<Resource[]>([]);
|
|
const [isLoadingResources, setIsLoadingResources] = useState(false);
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
// 将资源数据转换为视频格式
|
|
const videos = resources.map(resource => ({
|
|
id: resource.id.toString(),
|
|
url: resource.url,
|
|
title: resource.title
|
|
}));
|
|
|
|
// 获取资源列表
|
|
const fetchResources = async () => {
|
|
try {
|
|
setIsLoadingResources(true);
|
|
const response = await getResourcesList({ published: 1 });
|
|
if (response.code === 0 && response.successful) {
|
|
setResources(response.data);
|
|
} else {
|
|
console.error('获取资源列表失败:', response.message);
|
|
}
|
|
} catch (error) {
|
|
console.error('获取资源列表出错:', error);
|
|
} finally {
|
|
setIsLoadingResources(false);
|
|
}
|
|
};
|
|
|
|
// 组件挂载时获取资源
|
|
useEffect(() => {
|
|
fetchResources();
|
|
}, []);
|
|
|
|
// 处理编辑视频
|
|
const handleEdit = (id: string) => {
|
|
// TODO: 实现编辑功能
|
|
};
|
|
|
|
// 处理删除视频
|
|
const handleDelete = (id: string) => {
|
|
// TODO: 实现删除功能
|
|
};
|
|
|
|
// 处理创建项目
|
|
const handleCreateProject = async () => {
|
|
if (isCreating) return;
|
|
|
|
try {
|
|
setIsCreating(true);
|
|
|
|
// 使用默认值
|
|
const projectType = ProjectTypeEnum.SCRIPT_TO_VIDEO;
|
|
|
|
// 构建项目数据并调用API
|
|
const projectData: CreateScriptProjectRequest = {
|
|
title: "script default", // 默认剧本名称
|
|
project_type: projectType,
|
|
mode: ModeEnum.MANUAL,
|
|
resolution: ResolutionEnum.FULL_HD_1080P
|
|
};
|
|
|
|
const projectResponse = await createScriptProject(projectData);
|
|
|
|
if (projectResponse.code === 0 && projectResponse.data.id) {
|
|
const projectId = projectResponse.data.id;
|
|
setCreatedProjectId(projectId);
|
|
// projectId 作为参数传递给 create 页面
|
|
router.push(`/create?projectId=${projectId}`);
|
|
} else {
|
|
alert(`创建项目失败: ${projectResponse.message}`);
|
|
}
|
|
} catch (error) {
|
|
alert("创建项目时发生错误,请稍后重试");
|
|
} finally {
|
|
setIsCreating(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-[var(--background)]" ref={containerRef}>
|
|
<div className="min-h-[100%] flex relative">
|
|
{/* 工具栏-列表形式切换 */}
|
|
<div className="absolute top-[1rem] right-6 w-[8rem] flex justify-end">
|
|
<div role="group" className="flex p-1 bg-white/20 backdrop-blur-[15px] w-full rounded-[3rem]">
|
|
<button
|
|
className={`flex items-center justify-center h-10 transition-all duration-300 w-1/2 rounded-[3rem]
|
|
${activeTool === "stretch" ? "bg-white/20 text-white" : "hover:bg-white/10 text-white/30"}`}
|
|
onClick={() => setActiveTool("stretch")}
|
|
>
|
|
<AlignHorizontalSpaceAround className="w-5 h-5" />
|
|
</button>
|
|
<button
|
|
className={`flex items-center justify-center h-10 transition-all duration-300 w-1/2 rounded-[3rem]
|
|
${activeTool === "table" ? "bg-white/20 text-white" : "hover:bg-white/10 text-white/30"}`}
|
|
onClick={() => setActiveTool("table")}
|
|
>
|
|
<Table className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 屏风式视频布局 */}
|
|
<div
|
|
className={`absolute top-[4rem] w-full transition-all duration-500
|
|
${activeTool === "stretch" ? "opacity-100 translate-x-0" : "opacity-0 translate-x-[-100%] pointer-events-none"}
|
|
`}
|
|
>
|
|
<VideoScreenLayout videos={videos} />
|
|
</div>
|
|
|
|
{/* 网格式视频布局 */}
|
|
<div
|
|
className={`absolute top-[4rem] w-full transition-all duration-500 max-h-[calc(100vh-8rem)] overflow-y-auto hide-scrollbar
|
|
${activeTool === "table" ? "opacity-100 translate-x-0" : "opacity-0 translate-x-[100%] pointer-events-none"}
|
|
`}
|
|
>
|
|
<VideoGridLayout
|
|
videos={videos}
|
|
onEdit={handleEdit}
|
|
onDelete={handleDelete}
|
|
/>
|
|
</div>
|
|
|
|
{/* Create Project Button */}
|
|
<div className="fixed bottom-[5rem] left-[50%] -translate-x-1/2 z-50">
|
|
<motion.div
|
|
className="relative group"
|
|
whileHover={!isCreating ? { scale: 1.05 } : {}}
|
|
whileTap={!isCreating ? { scale: 0.95 } : {}}
|
|
onClick={handleCreateProject}
|
|
>
|
|
|
|
{/* 玻璃按钮 */}
|
|
<motion.div
|
|
className={`add-project-btn relative flex items-center gap-3 px-6 py-4 rounded-2xl
|
|
bg-white/20 backdrop-blur-md cursor-pointer
|
|
shadow-[0_8px_32px_rgba(0,0,0,0.2)] group-hover:shadow-[0_8px_32px_rgba(0,0,0,0.4)]
|
|
transition-all duration-300 ${isCreating ? 'opacity-70 cursor-not-allowed' : ''}`}
|
|
initial={false}
|
|
whileHover={!isCreating ? {
|
|
backgroundColor: "rgba(255, 255, 255, 0.15)"
|
|
} : {}}
|
|
>
|
|
{isCreating ? (
|
|
<Loader2 className="w-6 h-6 text-white animate-spin" />
|
|
) : (
|
|
<Plus className="w-6 h-6 text-white" />
|
|
)}
|
|
<div className="btn-text text-lg font-medium bg-gradient-to-r text-white
|
|
bg-clip-text text-transparent">
|
|
{isCreating ? "Creating..." : "Create"}
|
|
</div>
|
|
</motion.div>
|
|
</motion.div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
} |