mxivideo/src/pages/ProjectDetailPage.tsx

175 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { ArrowLeft, User, Video } from 'lucide-react'
import { Project, ProjectService } from '../services/projectService'
import { VideoSegment, MediaService } from '../services/mediaService'
import { Model, ModelService } from '../services/modelService'
import ProjectMaterialsCenter from '../components/ProjectMaterialsCenter'
import AGUIChat from '../components/AGUIChat'
const ProjectDetailPage: React.FC = () => {
const { projectId } = useParams<{ projectId: string }>()
const navigate = useNavigate()
const [project, setProject] = useState<Project | null>(null)
const [loading, setLoading] = useState(true)
// 数据状态
const [projectModels, setProjectModels] = useState<Model[]>([])
const [projectMaterials, setProjectMaterials] = useState<VideoSegment[]>([])
useEffect(() => {
if (projectId) {
loadProjectDetail()
}
}, [projectId])
const loadProjectDetail = async () => {
if (!projectId) return
try {
setLoading(true)
// 加载项目基本信息
const projectResponse = await ProjectService.getProjectById(projectId)
if (projectResponse.status && projectResponse.data) {
setProject(projectResponse.data)
// 加载项目相关数据
await Promise.all([
loadProjectModels(),
loadProjectMaterials(projectResponse.data)
])
} else {
console.error('Failed to load project:', projectResponse.msg)
navigate('/projects')
}
} catch (error) {
console.error('Failed to load project detail:', error)
navigate('/projects')
} finally {
setLoading(false)
}
}
const loadProjectModels = async () => {
try {
// 获取所有模特,后续可以添加项目关联逻辑
const response = await ModelService.getAllModels()
if (response.status && response.data) {
setProjectModels(response.data)
}
} catch (error) {
console.error('Failed to load project models:', error)
}
}
const loadProjectMaterials = async (project: Project) => {
try {
// 获取与项目商品名相关的素材
const response = await MediaService.getAllSegments()
if (response.status && response.data) {
// 过滤包含商品名标签且未使用的素材
const filteredMaterials = response.data.filter(segment =>
segment.tags.includes(project.product_name) && segment.use_count === 0
)
setProjectMaterials(filteredMaterials)
}
} catch (error) {
console.error('Failed to load project materials:', error)
}
}
if (loading) {
return (
<div className="p-6">
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded w-1/4 mb-6"></div>
<div className="h-32 bg-gray-200 rounded mb-6"></div>
<div className="h-64 bg-gray-200 rounded"></div>
</div>
</div>
)
}
if (!project) {
return (
<div className="p-6">
<div className="text-center py-12">
<h2 className="text-xl font-semibold text-gray-900 mb-2"></h2>
<p className="text-gray-600 mb-4"></p>
<button
onClick={() => navigate('/projects')}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
</button>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gray-50">
{/* 顶部导航栏 */}
<div className="bg-white border-b border-gray-200 px-6 py-4">
<div className="flex items-center justify-between">
<div className="flex items-center">
<button
onClick={() => navigate('/projects')}
className="mr-4 p-2 text-gray-400 hover:text-gray-600 transition-colors"
>
<ArrowLeft size={24} />
</button>
<div>
<h1 className="text-xl font-bold text-gray-900">{project.name}</h1>
<p className="text-sm text-gray-600">{project.product_name}</p>
</div>
</div>
{/* 项目信息概览 */}
<div className="flex items-center space-x-6 text-sm text-gray-600">
<div className="flex items-center">
<Video size={16} className="mr-1" />
<span>{projectMaterials.length} </span>
</div>
<div className="flex items-center">
<User size={16} className="mr-1" />
<span>{projectModels.length} </span>
</div>
<div className="text-xs">
{new Date(project.created_at).toLocaleDateString()}
</div>
</div>
</div>
</div>
{/* 主要内容区域 - 三栏布局 */}
<div className="flex h-[calc(100vh-120px)]">
{/* 左侧 AI 聊天面板 */}
<div className="w-80 bg-white flex flex-col">
<AGUIChat
project={project}
models={projectModels}
onMaterialCreated={() => loadProjectMaterials(project)}
/>
</div>
{/* 右侧主要区域 - 项目素材管理 */}
<div className="flex-1 px-4 py-3 overflow-hidden">
<ProjectMaterialsCenter
project={project}
materials={projectMaterials}
models={projectModels}
onMaterialsChange={setProjectMaterials}
/>
</div>
</div>
</div>
)
}
export default ProjectDetailPage