42 lines
2.8 KiB
TypeScript
42 lines
2.8 KiB
TypeScript
import { eq } from "drizzle-orm";
|
||
import { notFound } from "next/navigation";
|
||
import { db } from "@/lib/db";
|
||
import { tvstarSession } from "@/lib/db/schema";
|
||
|
||
export const dynamic = "force-dynamic";
|
||
|
||
type SharedSnapshot = {
|
||
title: string;
|
||
goal: string;
|
||
createdAt: number;
|
||
messages: { role: "user" | "assistant"; content: string; createdAt: number }[];
|
||
plan: { summary: string; deliverables: string[] } | null;
|
||
shots: { shot: string; duration: string; sceneDescription: string }[];
|
||
};
|
||
|
||
export default async function TVstarSharedConversation({ params }: { params: Promise<{ token: string }> }) {
|
||
const { token } = await params;
|
||
if (!/^[A-Za-z0-9_-]{32}$/.test(token || "")) notFound();
|
||
const row = (await db.select({ snapshot: tvstarSession.sharedSnapshot }).from(tvstarSession)
|
||
.where(eq(tvstarSession.shareToken, token)).limit(1))[0];
|
||
if (!row?.snapshot) notFound();
|
||
const shared = row.snapshot as SharedSnapshot;
|
||
return <main className="min-h-screen bg-[#141414] px-4 py-12 text-white">
|
||
<article className="mx-auto max-w-2xl rounded-2xl border border-white/10 bg-[#1d1d1d] p-6 shadow-2xl">
|
||
<p className="text-xs tracking-widest text-cyan-300">TVstar · 只读分享</p>
|
||
<h1 className="mt-3 text-2xl font-semibold">{shared.title}</h1>
|
||
<p className="mt-2 text-sm text-white/50">{new Date(shared.createdAt).toLocaleString("zh-CN")}</p>
|
||
<p className="mt-6 whitespace-pre-wrap border-l-2 border-cyan-400 pl-4 text-sm text-white/70">{shared.goal}</p>
|
||
<section aria-label="分享的对话" className="mt-8 space-y-3">
|
||
{(shared.messages || []).map((message, index) => <div className={`rounded-xl p-4 text-sm leading-6 ${message.role === "user" ? "ml-8 bg-[#303846]" : "mr-8 bg-[#282828]"}`} key={`${message.createdAt}-${index}`}>
|
||
<p className="mb-1 text-xs text-white/40">{message.role === "user" ? "用户" : "TVstar"}</p>
|
||
<p className="whitespace-pre-wrap">{message.content}</p>
|
||
</div>)}
|
||
</section>
|
||
{shared.plan ? <section className="mt-8 border-t border-white/10 pt-5"><h2 className="text-lg">创作规划</h2><p className="mt-2 whitespace-pre-wrap text-sm text-white/70">{shared.plan.summary}</p></section> : null}
|
||
{shared.shots?.length ? <section className="mt-8 border-t border-white/10 pt-5"><h2 className="text-lg">分镜</h2><ol className="mt-3 space-y-3">{shared.shots.map((shot, index) => <li className="rounded-lg bg-white/5 p-3 text-sm" key={`${shot.shot}-${index}`}><strong>{shot.shot} · {shot.duration}</strong><p className="mt-1 whitespace-pre-wrap text-white/65">{shot.sceneDescription}</p></li>)}</ol></section> : null}
|
||
<p className="mt-8 border-t border-white/10 pt-5 text-xs text-white/40">此页面是分享时的对话快照,无法编辑画布;对话正文中的文字和链接会原样显示。</p>
|
||
</article>
|
||
</main>;
|
||
}
|