# 代码材料(后30页) 软件名称:StudioAgent AI视频制片平台软件 版本号:V0.1.0 ## 第 55 页 ```text // Get or create conversation const convs = await apiFetch<{ id: string }[]>( `/projects/${projectId}/conversations`, ); if (convs.length > 0) { setConversationId(convs[0].id); } else { const newConv = await apiFetch<{ id: string }>( `/projects/${projectId}/conversations`, { method: "POST" }, ); setConversationId(newConv.id); } } catch (err) { console.error("Bootstrap error:", err); router.push("/projects"); } } bootstrap(); }, [projectId, token, router]); return (
{/* Header */}
StudioAgent | {projectTitle}
{/* Main workspace: Chat + Assets */}
{/* Agent chat panel (55%) */}
{conversationId ? ( ) : (
初始化中...
)}
{/* Asset panel (45%) */}
{/* Footer status bar */}
); } // File: frontend/src/app/projects/[id]/settings/page.tsx export default function ProjectSettingsPage() { return (

项目设置

{/* TODO: Project settings form */}
); } // File: frontend/src/app/projects/page.tsx "use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import { apiFetch } from "@/lib/api"; import { useUserStore } from "@/stores/user"; interface Project { id: string; title: string; description: string | null; status: string; style: string; created_at: string; } export default function ProjectsPage() { const router = useRouter(); const token = useUserStore((s) => s.token); const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(true); const [showCreate, setShowCreate] = useState(false); const [newTitle, setNewTitle] = useState(""); const [newDesc, setNewDesc] = useState(""); const [creating, setCreating] = useState(false); useEffect(() => { if (!token) { router.push("/login"); return; } loadProjects(); }, [token, router]); async function loadProjects() { try { const data = await apiFetch("/projects"); setProjects(data); } catch { // token expired router.push("/login"); ``` ## 第 57 页 ```text } finally { setLoading(false); } } async function handleCreate(e: React.FormEvent) { e.preventDefault(); if (!newTitle.trim()) return; setCreating(true); try { const project = await apiFetch("/projects", { method: "POST", body: JSON.stringify({ title: newTitle, description: newDesc || undefined }), }); router.push(`/projects/${project.id}`); } catch (err: any) { alert(err.message || "创建失败"); } finally { setCreating(false); } } if (loading) { return (
加载中...
); } return (

我的项目

{/* Create project dialog */} {showCreate && (

新建项目

setNewTitle(e.target.value)} required className="w-full rounded-lg border px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700" placeholder="给你的项目起个名字" autoFocus ``` ## 第 58 页 ```text />