This commit is contained in:
root 2025-07-11 01:45:19 +08:00
parent c0fa5c503c
commit 61782a77b3
1 changed files with 141 additions and 18 deletions

View File

@ -1,13 +1,101 @@
import React from 'react'
import React, { useState, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { Plus, FolderOpen, Video, Music, Zap, Sparkles, Database } from 'lucide-react'
import { invoke } from '@tauri-apps/api/core'
import { ProjectService, Project } from '../services/projectService'
const HomePage: React.FC = () => {
const recentProjects = [
{ id: 1, name: '旅行视频剪辑', lastModified: '2 小时前', thumbnail: '/placeholder-video.jpg' },
{ id: 2, name: '产品宣传片', lastModified: '1 天前', thumbnail: '/placeholder-video.jpg' },
{ id: 3, name: '音乐MV制作', lastModified: '3 天前', thumbnail: '/placeholder-video.jpg' },
]
const [recentProjects, setRecentProjects] = useState<Project[]>([])
const [loading, setLoading] = useState(true)
// 加载最近的项目
useEffect(() => {
const loadRecentProjects = async () => {
try {
const response = await ProjectService.getAllProjects()
if (response.status && response.data) {
// 按更新时间排序取最近的3个项目
const sortedProjects = response.data
.sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime())
.slice(0, 3)
setRecentProjects(sortedProjects)
}
} catch (error) {
console.error('Failed to load recent projects:', error)
} finally {
setLoading(false)
}
}
loadRecentProjects()
}, [])
// 简化的图片组件
const ProjectImage: React.FC<{ imagePath: string; alt: string; className: string }> = ({
imagePath, alt, className
}) => {
const [imageSrc, setImageSrc] = useState<string>('')
const [imageLoading, setImageLoading] = useState(true)
useEffect(() => {
const loadImage = async () => {
if (!imagePath) {
setImageLoading(false)
return
}
if (imagePath.startsWith('http') || imagePath.startsWith('data:')) {
setImageSrc(imagePath)
setImageLoading(false)
return
}
try {
const dataUrl = await invoke<string>('read_image_as_data_url', { filePath: imagePath })
setImageSrc(dataUrl)
} catch (error) {
console.error('Failed to read image:', error)
} finally {
setImageLoading(false)
}
}
loadImage()
}, [imagePath])
if (imageLoading) {
return <div className={`${className} bg-secondary-200 animate-pulse`}></div>
}
if (!imageSrc) {
return (
<div className={`${className} bg-secondary-200 flex items-center justify-center`}>
<Video className="text-secondary-400" size={48} />
</div>
)
}
return <img src={imageSrc} alt={alt} className={className} />
}
// 格式化时间显示
const formatTimeAgo = (dateString: string): string => {
const now = new Date()
const date = new Date(dateString)
const diffInMs = now.getTime() - date.getTime()
const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60))
const diffInDays = Math.floor(diffInHours / 24)
if (diffInHours < 1) {
return '刚刚'
} else if (diffInHours < 24) {
return `${diffInHours} 小时前`
} else if (diffInDays < 7) {
return `${diffInDays} 天前`
} else {
return date.toLocaleDateString('zh-CN')
}
}
const quickActions = [
{ icon: Sparkles, label: 'AI 视频生成', description: '使用 AI 将图片转换为动态视频', path: '/ai-video' },
@ -73,20 +161,55 @@ const HomePage: React.FC = () => {
</Link>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{recentProjects.map((project) => (
<div
key={project.id}
className="card overflow-hidden hover:shadow-md transition-shadow cursor-pointer"
>
<div className="aspect-video bg-secondary-200 flex items-center justify-center">
<Video className="text-secondary-400" size={48} />
</div>
<div className="p-4">
<h3 className="font-medium text-secondary-900 mb-1">{project.name}</h3>
<p className="text-sm text-secondary-600">{project.lastModified}</p>
{loading ? (
// 加载状态
Array.from({ length: 3 }).map((_, index) => (
<div key={index} className="card overflow-hidden">
<div className="aspect-video bg-secondary-200 animate-pulse"></div>
<div className="p-4">
<div className="h-4 bg-secondary-200 rounded animate-pulse mb-2"></div>
<div className="h-3 bg-secondary-200 rounded animate-pulse w-2/3"></div>
</div>
</div>
))
) : recentProjects.length > 0 ? (
// 显示真实项目
recentProjects.map((project) => (
<Link
key={project.id}
to={`/projects/${project.id}`}
className="card overflow-hidden hover:shadow-md transition-shadow cursor-pointer"
>
<div className="aspect-video overflow-hidden">
<ProjectImage
imagePath={project.product_image}
alt={project.name}
className="w-full h-full object-cover"
/>
</div>
<div className="p-4">
<h3 className="font-medium text-secondary-900 mb-1">{project.name}</h3>
<p className="text-sm text-secondary-600">{formatTimeAgo(project.updated_at)}</p>
{project.product_name && (
<p className="text-xs text-secondary-500 mt-1">{project.product_name}</p>
)}
</div>
</Link>
))
) : (
// 空状态
<div className="col-span-full text-center py-8">
<Video className="mx-auto text-secondary-400 mb-4" size={48} />
<p className="text-secondary-600 mb-4"></p>
<Link
to="/projects"
className="btn-primary inline-flex items-center"
>
<Plus size={16} className="mr-2" />
</Link>
</div>
))}
)}
</div>
</div>