新增案例库列表和详情页
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
"use client";
|
||||
|
||||
import type {
|
||||
HumanCopyCaseInputPayload,
|
||||
HumanCopyResultVersionPayload,
|
||||
OptimizationResultVersion,
|
||||
} from "../../lib/cases/types";
|
||||
|
||||
interface HumanCopyCaseDetailProps {
|
||||
input: unknown;
|
||||
version: OptimizationResultVersion | null;
|
||||
}
|
||||
|
||||
const intensityLabels: Record<string, string> = {
|
||||
light: "轻微整理",
|
||||
medium: "适度润色",
|
||||
conversational: "更口语自然",
|
||||
};
|
||||
|
||||
export function HumanCopyCaseDetail({
|
||||
input,
|
||||
version,
|
||||
}: HumanCopyCaseDetailProps) {
|
||||
const payload = isHumanCopyInput(input) ? input : null;
|
||||
const result = isHumanCopyResult(version?.payload) ? version.payload : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="panel stack">
|
||||
<div className="panel-heading">原始文案</div>
|
||||
{payload ? (
|
||||
<>
|
||||
<pre className="copy-result">{payload.source_text}</pre>
|
||||
<div className="case-meta-grid">
|
||||
<MetaItem label="优化目标" value={payload.goal} />
|
||||
<MetaItem
|
||||
label="修改强度"
|
||||
value={intensityLabels[payload.intensity] ?? payload.intensity}
|
||||
/>
|
||||
<MetaItem
|
||||
label="发布目标"
|
||||
value={payload.publish_target || "未指定"}
|
||||
/>
|
||||
<MetaItem
|
||||
label="补充要求"
|
||||
value={payload.user_instructions || "无"}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<p className="empty-panel">没有保存输入。</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="panel stack">
|
||||
<div className="panel-heading">优化后文案</div>
|
||||
{result ? (
|
||||
<>
|
||||
<pre className="copy-result">{result.optimized_text}</pre>
|
||||
<section className="stack">
|
||||
<h3>改动说明</h3>
|
||||
{result.change_notes.length > 0 ? (
|
||||
<ul className="qa-list">
|
||||
{result.change_notes.map((note, index) => (
|
||||
<li className="qa-item" key={`${note.original}-${index}`}>
|
||||
<p>{note.reason}</p>
|
||||
<small>原句:{note.original}</small>
|
||||
<small>改后:{note.revised}</small>
|
||||
{note.revertible ? <em>这处可还原。</em> : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="empty-panel">没有改动说明。</p>
|
||||
)}
|
||||
</section>
|
||||
<section className="stack">
|
||||
<h3>AI 味检查</h3>
|
||||
{result.ai_taste_checks.length > 0 ? (
|
||||
<ul className="qa-list">
|
||||
{result.ai_taste_checks.map((check) => (
|
||||
<li className="qa-item" key={check.rule_id}>
|
||||
<div className="qa-title-row">
|
||||
<strong>{check.rule_id}</strong>
|
||||
<span className={`status-pill ${check.status}`}>
|
||||
{check.status}
|
||||
</span>
|
||||
</div>
|
||||
<small>{check.evidence}</small>
|
||||
{check.suggestion ? <small>{check.suggestion}</small> : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p className="empty-panel">没有 AI 味检查记录。</p>
|
||||
)}
|
||||
</section>
|
||||
{result.warnings.length > 0 ? (
|
||||
<ul className="calibration-observations">
|
||||
{result.warnings.map((warning) => (
|
||||
<li key={warning}>{warning}</li>
|
||||
))}
|
||||
</ul>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<p className="empty-panel">
|
||||
{version?.error_summary ?? "当前版本没有优化结果。"}
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function MetaItem({ label, value }: { label: string; value: string }) {
|
||||
return (
|
||||
<div>
|
||||
<span>{label}</span>
|
||||
<strong>{value}</strong>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function isHumanCopyInput(value: unknown): value is HumanCopyCaseInputPayload {
|
||||
return (
|
||||
value !== null &&
|
||||
typeof value === "object" &&
|
||||
"source_text" in value &&
|
||||
"goal" in value
|
||||
);
|
||||
}
|
||||
|
||||
function isHumanCopyResult(value: unknown): value is HumanCopyResultVersionPayload {
|
||||
return (
|
||||
value !== null &&
|
||||
typeof value === "object" &&
|
||||
"optimized_text" in value &&
|
||||
"change_notes" in value
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user