142 lines
4.4 KiB
TypeScript
142 lines
4.4 KiB
TypeScript
"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
|
|
);
|
|
}
|