forked from 77media/video-flow
289 lines
10 KiB
TypeScript
289 lines
10 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useRef, useEffect } from "react";
|
||
import { Table, AlignHorizontalSpaceAround, Loader2, Clapperboard, CreditCard } from "lucide-react";
|
||
import "./style/home-page2.css";
|
||
import { useRouter, useSearchParams } from "next/navigation";
|
||
import { VideoCarouselLayout } from '@/components/video-carousel-layout';
|
||
import { VideoGridLayout } from '@/components/video-grid-layout';
|
||
import { motion, AnimatePresence } from "framer-motion";
|
||
import { LiquidButton } from "@/components/ui/liquid-glass-button";
|
||
import {
|
||
getResourcesList,
|
||
Resource
|
||
} from '@/api/resources';
|
||
import {
|
||
getCheckoutSessionStatus,
|
||
PaymentStatusResponse
|
||
} from "@/lib/stripe";
|
||
|
||
export function HomePage2() {
|
||
const router = useRouter();
|
||
const searchParams = useSearchParams();
|
||
const [activeTool, setActiveTool] = useState("stretch");
|
||
const [dropPosition, setDropPosition] = useState<"left" | "right">("left");
|
||
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 [showPaymentSuccess, setShowPaymentSuccess] = useState(false);
|
||
const [paymentData, setPaymentData] = useState<any>(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 });
|
||
console.log(response);
|
||
if (response.code === 0) {
|
||
setResources(response.data);
|
||
} else {
|
||
console.error('获取资源列表失败:', response.message);
|
||
}
|
||
} catch (error) {
|
||
console.error('获取资源列表出错:', error);
|
||
} finally {
|
||
setIsLoadingResources(false);
|
||
}
|
||
};
|
||
|
||
// 检测支付成功
|
||
useEffect(() => {
|
||
const sessionId = searchParams.get('session_id');
|
||
const payment = searchParams.get('payment');
|
||
|
||
if (sessionId && payment === 'success') {
|
||
// 显示支付成功提示
|
||
setShowPaymentSuccess(true);
|
||
|
||
// 获取支付详情
|
||
fetchPaymentDetails(sessionId);
|
||
|
||
// 清除URL参数,避免刷新页面时重复显示
|
||
const newUrl = new URL(window.location.href);
|
||
newUrl.searchParams.delete('session_id');
|
||
newUrl.searchParams.delete('payment');
|
||
window.history.replaceState({}, '', newUrl.pathname);
|
||
}
|
||
}, [searchParams]);
|
||
|
||
// 获取支付详情
|
||
const fetchPaymentDetails = async (sessionId: string) => {
|
||
try {
|
||
const User = JSON.parse(localStorage.getItem("currentUser") || "{}");
|
||
const result: PaymentStatusResponse = await getCheckoutSessionStatus(sessionId, User.id);
|
||
|
||
if (result.successful && result.data) {
|
||
setPaymentData(result.data);
|
||
}
|
||
} catch (error) {
|
||
console.error('获取支付详情失败:', error);
|
||
}
|
||
};
|
||
|
||
// 组件挂载时获取资源
|
||
useEffect(() => {
|
||
fetchResources();
|
||
}, []);
|
||
|
||
// 处理编辑视频
|
||
const handleEdit = (id: string) => {
|
||
// TODO: 实现编辑功能
|
||
};
|
||
|
||
// 处理删除视频
|
||
const handleDelete = (id: string) => {
|
||
// TODO: 实现删除功能
|
||
};
|
||
|
||
// 处理创建项目
|
||
const handleCreateProject = async () => {
|
||
// console.log('isCreating', isCreating);
|
||
router.push(`/create`);
|
||
// if (isCreating) return;
|
||
|
||
// try {
|
||
// setIsCreating(true);
|
||
// router.push(`/create`);
|
||
// return;
|
||
|
||
// // 使用默认值
|
||
// const projectType = ProjectTypeEnum.SCRIPT_TO_VIDEO;
|
||
|
||
// // 构建项目数据并调用API
|
||
// const projectData: CreateScriptProjectRequest = {
|
||
// title: "script default", // 默认剧本名称
|
||
// project_type: projectType,
|
||
// mode: ModeEnum.MANUAL === 'manual' ? 1 : 2, // 1 表示手动模式,2 表示自动模式
|
||
// resolution: 1080 // 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);
|
||
// }
|
||
};
|
||
|
||
// 处理工具切换
|
||
const handleToolChange = (position: "left" | "right") => {
|
||
setDropPosition(position);
|
||
setActiveTool(position === "left" ? "stretch" : "table");
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen bg-[var(--background)]" ref={containerRef}>
|
||
{/* 支付成功提示 */}
|
||
{showPaymentSuccess && paymentData && (
|
||
<div className="fixed top-4 left-1/2 transform -translate-x-1/2 z-50 bg-green-50 border border-green-200 rounded-lg p-4 shadow-lg max-w-md">
|
||
<div className="flex items-center">
|
||
<div className="flex-shrink-0">
|
||
<svg className="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
|
||
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
||
</svg>
|
||
</div>
|
||
<div className="ml-3">
|
||
<h3 className="text-sm font-medium text-green-800">支付成功!</h3>
|
||
<p className="text-sm text-green-700 mt-1">
|
||
您的订阅已激活,订单号: {paymentData.biz_order_no}
|
||
</p>
|
||
</div>
|
||
<div className="ml-auto pl-3">
|
||
<button
|
||
onClick={() => setShowPaymentSuccess(false)}
|
||
className="text-green-400 hover:text-green-600"
|
||
>
|
||
<svg className="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
||
<path fillRule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clipRule="evenodd" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="flex relative" style={{height: '100vh'}}>
|
||
{/* 工具栏-列表形式切换 */}
|
||
<div className="absolute top-[8rem] z-[49] right-6 w-[128px] flex justify-end">
|
||
<LiquidButton className="w-[128px] h-[3rem] text-sm"
|
||
onClick={(e: React.MouseEvent) => {
|
||
e.stopPropagation();
|
||
handleToolChange(activeTool === "stretch" ? "right" : "left");
|
||
}}
|
||
>
|
||
<div className="relative flex items-center justify-around gap-4 w-[128px] h-[3rem] p-2">
|
||
<div
|
||
className={`cursor-pointer relative z-10 transition-opacity duration-300 ${activeTool === "stretch" ? "opacity-100" : "opacity-50"}`}>
|
||
<AlignHorizontalSpaceAround className="w-4 h-4 text-white" />
|
||
</div>
|
||
<div
|
||
className={`cursor-pointer relative z-10 transition-opacity duration-300 ${activeTool === "table" ? "opacity-100" : "opacity-50"}`}>
|
||
<Table className="w-4 h-4 text-white" />
|
||
</div>
|
||
{/* 水滴动画 */}
|
||
<AnimatePresence>
|
||
<motion.div
|
||
className="absolute w-[40px] h-8 bg-[rgba(255,255,255,0.35)] rounded-full backdrop-blur-[2px] z-[1]"
|
||
initial={{ x: dropPosition === "left" ? -32 : 32 }}
|
||
animate={{
|
||
x: dropPosition === "left" ? -32 : 32,
|
||
scale: [1, 1.2, 1],
|
||
}}
|
||
transition={{
|
||
type: "spring",
|
||
stiffness: 300,
|
||
damping: 30,
|
||
scale: {
|
||
duration: 0.2,
|
||
}
|
||
}}
|
||
/>
|
||
</AnimatePresence>
|
||
</div>
|
||
</LiquidButton>
|
||
</div>
|
||
|
||
{/* 屏风式视频布局 */}
|
||
<div
|
||
className={`absolute w-full h-[calc(100vh - 4rem)] transition-all duration-500
|
||
${activeTool === "stretch" ? "opacity-100 translate-x-0" : "opacity-0 translate-x-[-100%] pointer-events-none"}
|
||
`}
|
||
style={{
|
||
height: '100%',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
marginTop: '4rem'
|
||
}}
|
||
>
|
||
<VideoCarouselLayout videos={videos} />
|
||
</div>
|
||
|
||
{/* 网格式视频布局 */}
|
||
<div
|
||
className={`absolute top-[8rem] 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>
|
||
|
||
{/* Pricing 入口 */}
|
||
<div className="fixed bottom-[3rem] right-[3rem] z-50">
|
||
<LiquidButton className="w-[120px] h-[48px] text-sm">
|
||
<div className="flex items-center justify-center gap-2"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
router.push('/pricing');
|
||
}}>
|
||
<CreditCard className="w-5 h-5 text-white" />
|
||
Pricing
|
||
</div>
|
||
</LiquidButton>
|
||
</div>
|
||
|
||
<div className="w-[128px] h-[128px] rounded-[50%] overflow-hidden fixed bottom-[3rem] left-[50%] -translate-x-1/2 z-50">
|
||
<LiquidButton className="w-[128px] h-[128px] text-lg">
|
||
<div className="flex items-center justify-center gap-2"
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
handleCreateProject();
|
||
}}>
|
||
{isCreating ? (
|
||
<Loader2 className="w-6 h-6 text-white animate-spin" />
|
||
) : (
|
||
<Clapperboard className="w-6 h-6 text-white" />
|
||
)}
|
||
{isCreating ? "Action..." : "Action"}
|
||
</div>
|
||
</LiquidButton>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|