Files
minimap1.1/frontend/app/page.tsx
2026-03-21 20:32:19 +08:00

215 lines
7.7 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.
"use client";
import { FormEvent, useState } from "react";
type GenerateResponse = {
message: string;
unique_id: string;
url: string;
query_url: string;
title?: string | null;
source?: string | null;
request_id?: string | null;
size_bytes: number;
created_at: string;
expires_at: string;
};
const apiBaseUrl =
process.env.NEXT_PUBLIC_API_BASE_URL?.replace(/\/$/, "") ||
"http://localhost:8000";
const initialHtml = `<section>
<h1>勾股定理</h1>
<p>在直角三角形中,两条直角边长度分别为 a、b斜边长度为 c则 a² + b² = c²。</p>
<ul>
<li>适用对象:直角三角形</li>
<li>核心关系:两直角边平方和等于斜边平方</li>
<li>常见用途:求边长、验证三角形是否为直角三角形</li>
</ul>
</section>`;
export default function Home() {
const [title, setTitle] = useState("知识点讲解");
const [source, setSource] = useState("tencent-agent");
const [requestId, setRequestId] = useState("");
const [htmlContent, setHtmlContent] = useState(initialHtml);
const [loading, setLoading] = useState(false);
const [result, setResult] = useState<GenerateResponse | null>(null);
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
setLoading(true);
setError(null);
setResult(null);
try {
const response = await fetch(`${apiBaseUrl}/api/html/generate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
title,
source,
request_id: requestId || undefined,
html_content: htmlContent,
}),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || data.message || "生成 HTML 失败");
}
setResult(data);
} catch (submissionError) {
setError(
submissionError instanceof Error
? submissionError.message
: "生成 HTML 失败,请稍后重试。"
);
} finally {
setLoading(false);
}
};
return (
<div className="mx-auto max-w-5xl space-y-8">
<section className="rounded-3xl border border-border bg-card p-8 shadow-sm">
<div className="max-w-3xl space-y-3">
<p className="text-sm uppercase tracking-[0.3em] text-muted-foreground">
HTML Explanation API
</p>
<h2 className="text-3xl font-bold text-foreground">
HTML
</h2>
<p className="text-muted-foreground">
HTML
</p>
</div>
</section>
<form
onSubmit={handleSubmit}
className="space-y-6 rounded-3xl border border-border bg-card p-8 shadow-sm"
>
<div className="grid gap-4 md:grid-cols-2">
<label className="space-y-2">
<span className="text-sm font-medium">title</span>
<input
value={title}
onChange={(event) => setTitle(event.target.value)}
className="w-full rounded-2xl border border-border bg-background px-4 py-3 outline-none ring-0 transition focus:border-primary"
placeholder="页面标题"
/>
</label>
<label className="space-y-2">
<span className="text-sm font-medium">source</span>
<input
value={source}
onChange={(event) => setSource(event.target.value)}
className="w-full rounded-2xl border border-border bg-background px-4 py-3 outline-none ring-0 transition focus:border-primary"
placeholder="来源,例如 tencent-agent"
/>
</label>
</div>
<label className="block space-y-2">
<span className="text-sm font-medium">request_id</span>
<input
value={requestId}
onChange={(event) => setRequestId(event.target.value)}
className="w-full rounded-2xl border border-border bg-background px-4 py-3 outline-none ring-0 transition focus:border-primary"
placeholder="可选的请求追踪 ID"
/>
</label>
<label className="block space-y-2">
<span className="text-sm font-medium">html_content</span>
<textarea
value={htmlContent}
onChange={(event) => setHtmlContent(event.target.value)}
rows={18}
className="w-full rounded-3xl border border-border bg-background px-4 py-4 font-mono text-sm outline-none ring-0 transition focus:border-primary"
placeholder="请输入完整 HTML 或 HTML 片段"
/>
</label>
<div className="flex flex-wrap items-center gap-4">
<button
type="submit"
disabled={loading || !htmlContent.trim()}
className="rounded-full bg-primary px-6 py-3 text-sm font-semibold text-primary-foreground transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
>
{loading ? "生成中..." : "生成 HTML 链接"}
</button>
<p className="text-sm text-muted-foreground">
{apiBaseUrl}/api/html/generate
</p>
</div>
</form>
{error ? (
<section className="rounded-3xl border border-destructive/20 bg-destructive/10 p-6 text-destructive">
{error}
</section>
) : null}
{result ? (
<section className="space-y-4 rounded-3xl border border-border bg-card p-8 shadow-sm">
<div>
<h3 className="text-xl font-semibold"></h3>
<p className="text-sm text-muted-foreground">{result.message}</p>
</div>
<div className="grid gap-4 md:grid-cols-2">
<div className="rounded-2xl bg-background p-4">
<p className="text-xs uppercase tracking-[0.2em] text-muted-foreground">
unique_id
</p>
<p className="mt-2 break-all font-mono text-sm">{result.unique_id}</p>
</div>
<div className="rounded-2xl bg-background p-4">
<p className="text-xs uppercase tracking-[0.2em] text-muted-foreground">
size_bytes
</p>
<p className="mt-2 font-mono text-sm">{result.size_bytes}</p>
</div>
</div>
<div className="space-y-3 rounded-2xl bg-background p-4">
<p className="text-xs uppercase tracking-[0.2em] text-muted-foreground">
url
</p>
<a
href={result.url}
target="_blank"
rel="noreferrer"
className="break-all text-sm text-primary underline-offset-4 hover:underline"
>
{result.url}
</a>
</div>
<div className="space-y-3 rounded-2xl bg-background p-4">
<p className="text-xs uppercase tracking-[0.2em] text-muted-foreground">
query_url
</p>
<a
href={result.query_url}
target="_blank"
rel="noreferrer"
className="break-all text-sm text-primary underline-offset-4 hover:underline"
>
{result.query_url}
</a>
</div>
<p className="text-sm text-muted-foreground">
{new Date(result.created_at).toLocaleString("zh-CN")}
{new Date(result.expires_at).toLocaleString("zh-CN")}
</p>
</section>
) : null}
</div>
);
}