107 lines
4.2 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 { useState } from "react";
import { 客户端 } from "../../接口/生成/客户端";
import { useMuse来源列表, useMuse版本原文 } from "./数据";
import { Ui反馈状态 } from "../../界面/反馈状态";
import { useMuse作者会话 } from "../../应用/作者会话";
export function Ui资料页() {
const 会话 = useMuse作者会话();
const scope = 会话.data ? "session" : null;
const 来源 = useMuse来源列表(scope);
const [当前, set当前] = useState<{ id: string; revision: number } | null>(null);
const 版本 = useMuse版本原文(scope, 当前?.id ?? null, 当前?.revision ?? null);
const [消息, set消息] = useState("");
async function 生成并应用(sourceId: string, revision: number) {
try {
const { data, error } = await 客户端.POST(
"/api/v1/sources/{source_id}/versions/{revision}/clean-candidates",
{ params: { path: { source_id: sourceId, revision } } },
);
if (!data) throw new Error((error as { message?: string })?.message ?? "生成失败");
const apply = await 客户端.POST(
"/api/v1/clean-candidates/{candidate_id}/apply",
{ params: { path: { candidate_id: (data as { candidate_id: string }).candidate_id } } },
);
set消息(
apply.data
? "清理已应用为对照版本;原文保持不变。"
: "清理候选已生成,但应用失败,可重试。",
);
set当前({ id: sourceId, revision });
} catch (e) {
set消息(e instanceof Error ? e.message : "清理流程失败,可重试。");
}
}
return (
<main className="content">
<p className="eyebrow">工作台</p>
<h1>资料研究</h1>
<p className="muted">
来源与原文对照;清理只生成对照结果,原文版本不可改写。榜单与拆书在
<a className="text-button" href="/research">研究工作区</a>与<a className="text-button" href="/rankings">榜单与选题</a>。
</p>
<section className="paper-panel" aria-label="来源清单">
<div className="panel-heading">
<h2>来源清单</h2>
<span className="muted">{来源.data?.length ?? 0} 个来源</span>
</div>
{来源.isPending ? (
<Ui反馈状态 message="正在读取来源…" />
) : (来源.data?.length ?? 0) === 0 ? (
<p className="muted">还没有导入来源;经 CLI 或主会话导入后这里可见。</p>
) : (
<ul className="event-list">
{来源.data!.map((源) => (
<li key={源.source_id}>
<button
className="text-button"
onClick={() => set当前({ id: 源.source_id, revision: 源.最新版本 })}
>
{源.title}({源.kind})r{源.最新版本}
</button>
<span className="mono muted">{源.origin}</span>
</li>
))}
</ul>
)}
{来源.error && <Ui反馈状态 message={来源.error.message} error />}
</section>
{当前 && (
<section className="paper-panel" aria-label="原文与清理对照">
<div className="panel-heading">
<h2>原文与清理对照</h2>
<span className="muted">
r{当前.revision}
</span>
</div>
{版本.isPending ? (
<Ui反馈状态 message="正在读取原文…" />
) : 版本.error ? (
<Ui反馈状态 message="该版本读取失败。" error />
) : (
<>
<pre className="mono draft-stream" aria-label="版本原文">
{版本.data?.content}
</pre>
<button
className="primary"
onClick={() => void 生成并应用(当前.id, 当前.revision)}
>
生成并应用清理对照
</button>
{消息 && (
<p role="status">{消息}</p>
)}
</>
)}
</section>
)}
</main>
);
}