ai-chatbot/components/canvas/DetailUiValidationPanel.tsx
Your Name 10e1096c83
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: add detail surface protocol workflow
2026-03-21 20:55:04 +08:00

145 lines
5.9 KiB
TypeScript
Raw Permalink 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 { AlertCircle, CheckCircle2 } from "lucide-react";
import { cn } from "@/lib/utils";
type DetailUiValidationSnapshot = {
passed?: boolean;
issues?: string[];
};
type DetailUiReviewSnapshot = {
screenIndex: number;
action?: "pass" | "protocol_patch" | "regenerate_image";
passed?: boolean;
issues?: string[];
};
export function DetailUiValidationPanel(params: {
generationMode: "classic" | "agent_layout";
planValidation?: DetailUiValidationSnapshot | null;
latestScreenValidation?: DetailUiReviewSnapshot | null;
surfaceId?: string | null;
}) {
const planIssues = Array.isArray(params.planValidation?.issues)
? params.planValidation?.issues.filter(Boolean)
: [];
const latestIssues = Array.isArray(params.latestScreenValidation?.issues)
? params.latestScreenValidation.issues.filter(Boolean)
: [];
if (!params.planValidation && !params.latestScreenValidation) {
return null;
}
const title =
params.generationMode === "agent_layout" ? "协议排版质检" : "排版与复审状态";
const hasPlanValidation = Boolean(params.planValidation);
const latestActionLabel =
params.latestScreenValidation?.action === "protocol_patch"
? "已走协议修正"
: params.latestScreenValidation?.action === "regenerate_image"
? "已要求重生图"
: "通过";
return (
<div className="mt-3 rounded-xl border border-border/50 bg-zinc-50/40 p-3 dark:bg-zinc-900/40">
<div className="mb-2 flex items-center justify-between gap-3">
<div className="flex items-center gap-2">
{params.planValidation?.passed === false || latestIssues.length > 0 ? (
<AlertCircle className="h-4 w-4 text-amber-500" />
) : (
<CheckCircle2 className="h-4 w-4 text-emerald-500" />
)}
<p className="text-[11px] font-medium text-foreground">{title}</p>
</div>
<span className="text-[10px] text-muted-foreground">
{params.surfaceId
? params.generationMode === "agent_layout"
? "结构化 surface 已建立"
: "当前结果可继续复审"
: params.generationMode === "agent_layout"
? "文字层可直接修正"
: "问题会触发二次修图"}
</span>
</div>
<div className="space-y-2">
<div className="flex items-start justify-between gap-3 rounded-lg border border-border/40 bg-background/80 px-3 py-2 dark:bg-zinc-950/40">
<div>
<div className="text-[11px] font-medium text-foreground">规划阶段</div>
<div className="mt-0.5 text-[10px] text-muted-foreground">
{params.planValidation?.passed === false
? `发现 ${planIssues.length} 条协议/排版提示`
: hasPlanValidation
? "协议结构已通过基础校验"
: "等待本轮规划结果"}
</div>
</div>
<span
className={cn(
"rounded-full px-2 py-0.5 text-[10px] font-medium",
!hasPlanValidation
? "bg-zinc-100 text-zinc-600 ring-1 ring-inset ring-zinc-500/10 dark:bg-zinc-800 dark:text-zinc-300"
: params.planValidation?.passed === false
? "bg-amber-50 text-amber-700 ring-1 ring-inset ring-amber-500/20 dark:bg-amber-500/10 dark:text-amber-300"
: "bg-emerald-50 text-emerald-700 ring-1 ring-inset ring-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300",
)}
>
{!hasPlanValidation
? "待开始"
: params.planValidation?.passed === false
? "待优化"
: "通过"}
</span>
</div>
{params.latestScreenValidation ? (
<div className="flex items-start justify-between gap-3 rounded-lg border border-border/40 bg-background/80 px-3 py-2 dark:bg-zinc-950/40">
<div>
<div className="text-[11px] font-medium text-foreground">
最近一屏:第 {params.latestScreenValidation.screenIndex} 屏
</div>
<div className="mt-0.5 text-[10px] text-muted-foreground">
{params.latestScreenValidation.passed === false
? latestIssues[0] || "存在可优化项"
: "最近一屏已通过当前质检"}
</div>
</div>
<span
className={cn(
"rounded-full px-2 py-0.5 text-[10px] font-medium",
params.latestScreenValidation.action === "regenerate_image"
? "bg-red-50 text-red-700 ring-1 ring-inset ring-red-500/20 dark:bg-red-500/10 dark:text-red-300"
: params.latestScreenValidation.action === "protocol_patch"
? "bg-blue-50 text-blue-700 ring-1 ring-inset ring-blue-500/20 dark:bg-blue-500/10 dark:text-blue-300"
: "bg-emerald-50 text-emerald-700 ring-1 ring-inset ring-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300",
)}
>
{latestActionLabel}
</span>
</div>
) : null}
{(planIssues.length > 0 || latestIssues.length > 0) && (
<div className="rounded-lg border border-dashed border-border/40 bg-background/60 px-3 py-2 dark:bg-zinc-950/30">
<div className="text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
当前关注点
</div>
<div className="mt-1 space-y-1">
{[...planIssues, ...latestIssues]
.filter((item, index, array) => array.indexOf(item) === index)
.slice(0, 3)
.map((issue) => (
<div key={issue} className="text-[11px] leading-5 text-foreground/85">
· {issue}
</div>
))}
</div>
</div>
)}
</div>
</div>
);
}