fix: refine evidence detail presentation
This commit is contained in:
@@ -280,14 +280,28 @@ function AnalysisBlockBody({ block }: { block: Exclude<AnalysisBlock, { kind: "m
|
||||
|
||||
function ArtifactProvenance({ artifact }: { artifact: AnalysisArtifact }) {
|
||||
return (
|
||||
<section className="mt-5 grid gap-3 pb-2 xl:grid-cols-2" aria-label="成果依据与限制">
|
||||
<div className="surface-well rounded-xl border px-4 py-3.5">
|
||||
<h3 className="flex items-center gap-2 text-xs font-semibold text-slate-800"><Database size={14} aria-hidden="true" />数据来源</h3>
|
||||
<ul className="mt-2 flex flex-wrap gap-2">{artifact.sources.map((source) => <li key={source} className="rounded-md bg-white px-2.5 py-1 text-xs text-slate-600 shadow-[0_1px_2px_rgba(15,23,42,0.08)]">{source}</li>)}</ul>
|
||||
<section className="surface-well mt-5 grid overflow-hidden rounded-xl border xl:grid-cols-2 xl:divide-x xl:divide-slate-300/70" aria-label="成果依据与限制">
|
||||
<div className="flex min-w-0 items-start gap-3 px-4 py-3">
|
||||
<h3 className="flex shrink-0 items-center gap-1.5 pt-1 text-xs font-semibold text-slate-700">
|
||||
<Database size={14} aria-hidden="true" />
|
||||
数据来源
|
||||
</h3>
|
||||
<ul className="flex min-w-0 flex-wrap gap-1.5">
|
||||
{artifact.sources.map((source) => (
|
||||
<li key={source} className="surface-reading rounded-md border px-2.5 py-1 text-xs text-slate-600">{source}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="material-tone-warning rounded-xl border px-4 py-3.5">
|
||||
<h3 className="flex items-center gap-2 text-xs font-semibold text-amber-900"><AlertTriangle size={14} aria-hidden="true" />分析限制</h3>
|
||||
<ul className="mt-2 space-y-1 text-xs leading-5 text-amber-900/75">{artifact.limitations.map((item) => <li key={item}>• {item}</li>)}</ul>
|
||||
<div className="flex min-w-0 items-start gap-3 border-t border-slate-300/70 px-4 py-3 xl:border-t-0">
|
||||
<h3 className="flex shrink-0 items-center gap-1.5 pt-0.5 text-xs font-semibold text-amber-800">
|
||||
<AlertTriangle size={14} aria-hidden="true" />
|
||||
分析限制
|
||||
</h3>
|
||||
<ul className="min-w-0 space-y-1 text-xs leading-5 text-slate-600">
|
||||
{artifact.limitations.map((item) => (
|
||||
<li key={item} className="before:mr-2 before:text-amber-600 before:content-['·']">{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
@@ -302,39 +316,165 @@ function ArtifactDetailDrawer({
|
||||
block: AnalysisBlock;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const blockFacts = getEvidenceBlockFacts(block);
|
||||
|
||||
return (
|
||||
<aside aria-label="证据详情" className="surface-reading absolute bottom-[57px] right-0 top-0 z-30 w-full max-w-[420px] overflow-y-auto overscroll-contain border-l shadow-[-12px_0_36px_rgba(15,23,42,0.18)]">
|
||||
<div className="sticky top-0 z-10 flex items-center justify-between bg-slate-950 px-4 py-3 text-slate-100">
|
||||
<div>
|
||||
<p className="text-[11px] font-semibold uppercase tracking-[0.14em] text-blue-300">Evidence detail</p>
|
||||
<h3 className="mt-1 text-sm font-semibold">{block.title}</h3>
|
||||
<aside
|
||||
aria-label="证据详情"
|
||||
className="surface-reading absolute bottom-[57px] right-0 top-0 z-30 w-full max-w-[440px] overflow-y-auto overscroll-contain border-l border-slate-300/80 shadow-[-18px_0_44px_rgba(15,23,42,0.14)]"
|
||||
>
|
||||
<div className="surface-control sticky top-0 z-10 flex items-start justify-between gap-4 border-b border-slate-300/70 px-5 py-4">
|
||||
<div className="flex min-w-0 items-start gap-3">
|
||||
<span className="surface-reading grid h-9 w-9 shrink-0 place-items-center rounded-lg border text-blue-700 shadow-[0_1px_3px_rgba(15,23,42,0.08)]">
|
||||
<FileSearch size={17} aria-hidden="true" />
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
<div className="flex flex-wrap items-center gap-2 text-[11px] font-semibold text-slate-500">
|
||||
<span className="uppercase tracking-[0.12em]">证据详情</span>
|
||||
<span className="h-1 w-1 rounded-full bg-slate-300" aria-hidden="true" />
|
||||
<span className="text-blue-700">{evidenceBlockKindLabel(block)}</span>
|
||||
</div>
|
||||
<button type="button" aria-label="关闭证据详情" onClick={onClose} className="grid h-10 w-10 place-items-center rounded-md text-slate-300 hover:bg-white/10 hover:text-white active:scale-95">
|
||||
<X size={18} aria-hidden="true" />
|
||||
<h3 className="mt-1 text-base font-semibold leading-6 text-slate-950">{block.title}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="关闭证据详情"
|
||||
onClick={onClose}
|
||||
className="grid h-9 w-9 shrink-0 place-items-center rounded-lg text-slate-500 hover:bg-slate-200/70 hover:text-slate-900 active:scale-95"
|
||||
>
|
||||
<X size={17} aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-5 p-5">
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-slate-500">成果结论</p>
|
||||
<p className="mt-2 text-sm leading-7 text-slate-700">{artifact.summary}</p>
|
||||
<div className="space-y-6 px-5 py-5">
|
||||
<section aria-labelledby="evidence-purpose-heading">
|
||||
<p id="evidence-purpose-heading" className="text-xs font-semibold text-slate-500">证据说明</p>
|
||||
<p className="mt-2 text-sm leading-6 text-slate-700">
|
||||
{"description" in block ? block.description : "该模块汇总了当前成果中的关键判断依据。"}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="material-tone-agent rounded-xl border px-4 py-3.5" aria-labelledby="evidence-relation-heading">
|
||||
<div className="flex items-center gap-2 text-xs font-semibold text-blue-900">
|
||||
<Sparkles size={14} aria-hidden="true" />
|
||||
<h4 id="evidence-relation-heading">Agent 关联判断</h4>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs font-semibold text-slate-500">证据说明</p>
|
||||
<p className="mt-2 text-sm leading-7 text-slate-700">{"description" in block ? block.description : "该模块汇总了当前成果中的关键判断依据。"}</p>
|
||||
<p className="mt-2 text-sm leading-6 text-slate-700">结合当前模块与其余证据,{artifact.summary}</p>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="evidence-data-heading">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<h4 id="evidence-data-heading" className="text-xs font-semibold text-slate-500">数据概览</h4>
|
||||
<span className="text-[11px] font-medium text-slate-400">Artifact R{artifact.revision}</span>
|
||||
</div>
|
||||
<div className="bg-slate-100 p-4">
|
||||
<p className="text-xs font-semibold text-slate-700">版本上下文</p>
|
||||
<dl className="mt-3 grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-xs">
|
||||
<dt className="text-slate-500">版本</dt><dd className="text-right font-medium text-slate-800">R{artifact.revision}</dd>
|
||||
<dt className="text-slate-500">范围</dt><dd className="text-right font-medium text-slate-800">{artifact.scope}</dd>
|
||||
<dt className="text-slate-500">置信度</dt><dd className="text-right font-medium text-slate-800">{artifact.confidence}</dd>
|
||||
<dl className="surface-well mt-2 grid grid-cols-2 gap-px overflow-hidden rounded-xl border bg-slate-300/70">
|
||||
{blockFacts.map((fact) => (
|
||||
<div key={fact.label} className="surface-reading min-w-0 px-3.5 py-3">
|
||||
<dt className="text-[11px] text-slate-500">{fact.label}</dt>
|
||||
<dd className="mt-1 truncate text-sm font-semibold text-slate-900 tabular-nums" title={fact.value}>{fact.value}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section className="border-t border-slate-200 pt-5" aria-labelledby="evidence-context-heading">
|
||||
<h4 id="evidence-context-heading" className="text-xs font-semibold text-slate-500">分析上下文</h4>
|
||||
<dl className="mt-3 grid grid-cols-[72px_minmax(0,1fr)] gap-x-4 gap-y-2.5 text-xs leading-5">
|
||||
<dt className="text-slate-500">分析时间</dt>
|
||||
<dd className="text-right font-medium text-slate-800">{formatAnalyticalTimeRange(artifact.analyticalTimeRange)}</dd>
|
||||
<dt className="text-slate-500">分析范围</dt>
|
||||
<dd className="text-right font-medium text-slate-800">{artifact.scope}</dd>
|
||||
<dt className="text-slate-500">综合置信度</dt>
|
||||
<dd className="text-right font-medium text-slate-800 tabular-nums">{artifact.confidence}</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section className="border-t border-slate-200 pt-5" aria-labelledby="evidence-source-heading">
|
||||
<div className="flex items-center gap-2">
|
||||
<Database size={14} className="text-slate-500" aria-hidden="true" />
|
||||
<h4 id="evidence-source-heading" className="text-xs font-semibold text-slate-700">本成果数据来源</h4>
|
||||
</div>
|
||||
<ul className="mt-3 flex flex-wrap gap-2">
|
||||
{artifact.sources.map((source) => (
|
||||
<li key={source} className="surface-control rounded-md border px-2.5 py-1.5 text-xs text-slate-600">{source}</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className="material-tone-warning rounded-xl border px-4 py-3.5" aria-labelledby="evidence-limit-heading">
|
||||
<div className="flex items-center gap-2 text-xs font-semibold text-amber-900">
|
||||
<AlertTriangle size={14} aria-hidden="true" />
|
||||
<h4 id="evidence-limit-heading">使用限制</h4>
|
||||
</div>
|
||||
<ul className="mt-2 space-y-1.5 text-xs leading-5 text-amber-950/75">
|
||||
{artifact.limitations.map((item) => <li key={item}>• {item}</li>)}
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
function evidenceBlockKindLabel(block: AnalysisBlock) {
|
||||
if (block.kind === "chart") return block.chartType === "line" ? "趋势图" : "对比图";
|
||||
if (block.kind === "process-flow") return "流程证据";
|
||||
if (block.kind === "data-table") return "明细数据";
|
||||
if (block.kind === "narrative") return "分析说明";
|
||||
return "指标摘要";
|
||||
}
|
||||
|
||||
function getEvidenceBlockFacts(block: AnalysisBlock): Array<{ label: string; value: string }> {
|
||||
if (block.kind === "chart") {
|
||||
return [
|
||||
{ label: "数据序列", value: `${block.series.length} 组` },
|
||||
{ label: "时间 / 类别点", value: `${block.categories.length} 个` },
|
||||
{ label: "计量单位", value: block.unit },
|
||||
{ label: "图表类型", value: block.chartType === "line" ? "趋势曲线" : "对比柱图" }
|
||||
];
|
||||
}
|
||||
if (block.kind === "data-table") {
|
||||
return [
|
||||
{ label: "证据记录", value: `${block.rows.length} 条` },
|
||||
{ label: "数据字段", value: `${block.columns.length} 个` },
|
||||
{ label: "展示方式", value: "明细表格" },
|
||||
{ label: "证据状态", value: "已纳入结论" }
|
||||
];
|
||||
}
|
||||
if (block.kind === "process-flow") {
|
||||
return [
|
||||
{ label: "流程步骤", value: `${block.nodes.length} 项` },
|
||||
{ label: "已完成", value: `${block.nodes.filter((node) => node.status === "complete").length} 项` },
|
||||
{ label: "当前进行", value: `${block.nodes.filter((node) => node.status === "active").length} 项` },
|
||||
{ label: "展示方式", value: "处置流程" }
|
||||
];
|
||||
}
|
||||
if (block.kind === "narrative") {
|
||||
return [
|
||||
{ label: "分析段落", value: `${block.paragraphs.length} 段` },
|
||||
{ label: "展示方式", value: "分析说明" },
|
||||
{ label: "证据状态", value: "已纳入结论" },
|
||||
{ label: "内容来源", value: "Agent 生成" }
|
||||
];
|
||||
}
|
||||
return [
|
||||
{ label: "关键指标", value: `${block.metrics.length} 项` },
|
||||
{ label: "展示方式", value: "指标摘要" },
|
||||
{ label: "证据状态", value: "已纳入结论" },
|
||||
{ label: "内容来源", value: "Agent 生成" }
|
||||
];
|
||||
}
|
||||
|
||||
function formatAnalyticalTimeRange(range: AnalysisArtifact["analyticalTimeRange"]) {
|
||||
const formatter = new Intl.DateTimeFormat("zh-CN", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false
|
||||
});
|
||||
return `${formatter.format(new Date(range.start))} 至 ${formatter.format(new Date(range.end))}`;
|
||||
}
|
||||
|
||||
function ArtifactActionBar({
|
||||
artifact,
|
||||
surfaceMode,
|
||||
|
||||
Reference in New Issue
Block a user