"use client"; import { useMemo, useState } from "react"; import { Activity, Calculator, Database, FileText, History, ScrollText } from "lucide-react"; import type { InspectorComparisonRow, InspectorModule, SourceBinding, SourceRecord, SourceSelector } from "@/lib/types"; import { BindingBadge, selectorDescription } from "@/components/inspector/BindingBadge"; import { BusinessValueRenderer } from "@/components/inspector/BusinessValueRenderer"; import { LongValueDisclosure } from "@/components/inspector/LongValueDisclosure"; interface RowProps { row: InspectorComparisonRow; module: InspectorModule; businessProjection: unknown; sources: Record; markers: Map; activeBindingId?: string; onActivate: (bindingId: string, toggle?: boolean) => void; } export function ComparisonRowCells(props: RowProps) { const bindings = props.row.bindingIds .map((id) => props.module.bindings.find((binding) => binding.id === id)) .filter((binding): binding is SourceBinding => Boolean(binding)); const businessResult = pointerValue(props.businessProjection, props.row.businessSelector); const active = bindings.some((binding) => binding.id === props.activeBindingId); return
{props.row.label ?

{props.row.label}

: null} {businessResult.found ? :

业务详情中的这一项无法定位。

}
{bindings.length ? bindings.map((binding) => ) :

没有返回来源绑定。

}
{bindings.length ? bindings.map((binding) => ) :

没有可展示的原始记录。

}
; } function EvidenceSummary({ binding, source, marker, active, onActivate }: { binding: SourceBinding; source?: SourceRecord; marker: string; active: boolean; onActivate: RowProps["onActivate"] }) { return
{source?.label || (binding.selector.kind === "unresolved" ? "无法定位来源" : binding.sourceId)} {roleLabel(binding.role)} · {transformLabel(binding)}
定位详情 {selectorDescription(binding)} {confidenceLabel(binding.evidence.confidence)}{binding.resolution !== "resolved" ? ` · ${resolutionLabel(binding.resolution)}` : ""}
; } function SourceExcerpt({ binding, source, sources, marker }: { binding: SourceBinding; source?: SourceRecord; sources: Record; marker: string }) { const [rawOpen, setRawOpen] = useState(false); const excerpt = useMemo(() => resolveExcerpt(binding.selector, source, sources), [binding.selector, source, sources]); const Icon = sourceIcon(source?.kind); return
{source ? : null} {source?.resultState === "empty" ?
查询完成,返回 0 条这不是记录缺失。
: null} {excerpt.kind === "span" ? : excerpt.kind === "members" ?
{excerpt.items.map((item, index) =>
{item.label}
)}
: excerpt.kind === "missing" ?

{excerpt.reason}

: } {source?.rawRecord !== undefined && source?.rawRecord !== null ?
setRawOpen(event.currentTarget.open)}> 完整原始记录{source.truncated ? `已省略 ${source.omittedCharacters || 0} 字符` : "按需展开"} {rawOpen ?
: null}
: null}
; } type Excerpt = | { kind: "value"; value: unknown } | { kind: "span"; before: string; exact: string; after: string } | { kind: "members"; items: Array<{ label: string; value: unknown }> } | { kind: "missing"; reason: string }; function resolveExcerpt(selector: SourceSelector, source: SourceRecord | undefined, sources: Record): Excerpt { if (selector.kind === "unresolved") return { kind: "missing", reason: selector.reason }; if (!source) return { kind: "missing", reason: "来源记录没有随接口响应返回。" }; if (selector.kind === "whole-record") return { kind: "value", value: source.rawRecord }; if (selector.kind === "json-pointer") { const selected = pointerValue(source.rawRecord, selector.path); return selected.found ? { kind: "value", value: selected.value } : { kind: "missing", reason: `原始记录中不存在字段 ${selector.path}` }; } if (selector.kind === "text-span") { const selected = pointerValue(source.rawRecord, selector.path); if (!selected.found || typeof selected.value !== "string") return { kind: "missing", reason: `原始记录中不存在文本字段 ${selector.path}` }; const characters = Array.from(selected.value); const start = selector.startCodePoint; const end = selector.endCodePoint; return { kind: "span", before: characters.slice(Math.max(0, start - 80), start).join(""), exact: characters.slice(start, end).join("") || selector.exactText, after: characters.slice(end, end + 80).join(""), }; } const items = selector.members.map((member, index) => { const memberSource = sources[member.sourceId]; const resolved = resolveExcerpt(member.selector, memberSource, sources); return { label: memberSource?.label || `参与记录 ${index + 1}`, value: resolved.kind === "value" ? resolved.value : resolved.kind === "span" ? `${resolved.before}${resolved.exact}${resolved.after}` : resolved.kind === "missing" ? resolved.reason : resolved.items.map((item) => item.value), }; }); return { kind: "members", items }; } function TextSpanExcerpt({ before, exact, after }: { before: string; exact: string; after: string }) { return

{before ? {before} : null}{exact}{after ? {after} : null}

; } function pointerValue(value: unknown, pointer: string): { found: boolean; value: unknown } { if (!pointer) return { found: true, value }; let current = value; for (const rawPart of pointer.replace(/^\//, "").split("/")) { const part = rawPart.replaceAll("~1", "/").replaceAll("~0", "~"); if (Array.isArray(current)) { const index = Number(part); if (!Number.isInteger(index) || index < 0 || index >= current.length) return { found: false, value: undefined }; current = current[index]; } else if (current && typeof current === "object" && Object.prototype.hasOwnProperty.call(current, part)) { current = (current as Record)[part]; } else return { found: false, value: undefined }; } return { found: true, value: current }; } function SourceMeta({ source }: { source: SourceRecord }) { const locator = typeof source.locator === "string" ? undefined : source.locator; const fields = locator ? Object.entries(locator).filter(([, value]) => value !== undefined && value !== null && value !== "") : []; return fields.length || source.status || typeof source.durationMs === "number" ?
{fields.map(([key, value]) =>
{locatorLabel(key)}
{printMeta(value)}
)} {source.status ?
状态
{source.status}
: null} {typeof source.durationMs === "number" ?
耗时
{source.durationMs >= 1000 ? `${(source.durationMs / 1000).toFixed(1)} 秒` : `${source.durationMs} ms`}
: null}
: null; } function sourceIcon(kind?: string) { if (kind === "database") return Database; if (kind === "runtime-event") return Activity; if (kind === "artifact") return FileText; if (kind === "log-anchor") return ScrollText; if (kind === "calculation") return Calculator; return History; } function sourceKindLabel(kind?: string) { return ({ database: "数据库记录", "runtime-event": "运行事件 / Event Body", artifact: "脚本或候选产物", "log-anchor": "日志锚点", calculation: "可视化确定性计算", "historical-fallback": "历史回退", missing: "原始记录缺失" } as Record)[kind || "missing"] || kind || "原始记录缺失"; } function roleLabel(role: SourceBinding["role"]) { return ({ input: "输入", basis: "判断依据", constraint: "约束", process: "运行过程", output: "产出", status: "状态" } as const)[role]; } function transformLabel(binding: SourceBinding) { const value = binding.transform; return value.kind === "direct" ? "直接展示" : value.kind === "parsed" ? "确定性解析" : value.kind === "combined" ? "多来源组合" : value.kind === "calculated" ? "确定性计算" : "历史回退"; } function confidenceLabel(value: SourceBinding["evidence"]["confidence"]) { return ({ exact: "精确对应", "safe-association": "可安全关联", deterministic: "确定性生成", unconfirmed: "关联未确认" } as const)[value]; } function resolutionLabel(value: SourceBinding["resolution"]) { return ({ partial: "部分定位", missing: "记录缺失", unsafe: "无法安全关联", resolved: "已定位" } as const)[value]; } function locatorLabel(key: string) { return ({ table: "数据库表", recordId: "记录 ID", eventId: "Event ID", eventName: "Event 名称", eventType: "Event 类型", artifactRef: "产物", logAnchor: "日志锚点", fieldPath: "字段路径", filters: "查询条件", resultCount: "结果数量", reason: "缺失原因" } as Record)[key] || key; } function printMeta(value: unknown) { if (typeof value === "string") return value; try { return JSON.stringify(value); } catch { return String(value); } }