DirectToolGroupCard.tsx 2.4 KB

123456789101112131415161718192021222324252627
  1. import { useRef } from "react";
  2. import { ArrowRight, Database } from "lucide-react";
  3. import { Handle, Position, type NodeProps } from "@xyflow/react";
  4. import type { CanvasNodeData } from "@/lib/layout";
  5. import { SourceComparisonButton } from "@/components/flow/SourceComparisonButton";
  6. import { useRetrievalHoverPreview } from "@/components/flow/RetrievalHoverPreview";
  7. export function DirectToolGroupCard({ data }: NodeProps) {
  8. const node = data as unknown as CanvasNodeData;
  9. const item = node.item;
  10. if (!item || item.itemType !== "retrieval-direct") return null;
  11. return <DirectToolGroupCardContent node={node} item={item} />;
  12. }
  13. function DirectToolGroupCardContent({ node, item }: { node: CanvasNodeData; item: Extract<NonNullable<CanvasNodeData["item"]>, { itemType: "retrieval-direct" }> }) {
  14. const cardRef = useRef<HTMLElement>(null);
  15. const hoverPreview = useRetrievalHoverPreview({ anchorRef: cardRef, buildId: node.buildId, item, onOpenDetail: () => node.onOpen(item, "business") });
  16. const sourceText = item.group.sources.map((source) => source.businessLabel).join("、") || "相关信息";
  17. return <><article ref={cardRef} className="flowCard retrievalCard directToolCard" tabIndex={0} data-focus-return={`${item.id}:card`} {...hoverPreview.anchorProps} onKeyDown={(event) => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); node.onOpen(item, "business"); } }}>
  18. <Handle type="target" position={Position.Left} className="flowHandle" />
  19. <Handle type="source" position={Position.Right} className="flowHandle" />
  20. <header><span className="retrievalKind"><Database size={14} />工具取数</span><span className="retrievalOwner">实现 Agent 直接读取</span></header>
  21. <h3>{sourceText}</h3>
  22. <dl className="retrievalStats"><div><dt>读取</dt><dd>{item.group.callCount} 次</dd></div><div><dt>结果</dt><dd>{item.group.failureCount ? `${item.group.failureCount} 次失败` : item.group.interruptedCount ? `${item.group.interruptedCount} 次中断` : item.group.runningCount ? "进行中" : "已完成"}</dd></div></dl>
  23. <footer><button type="button" className="nodeAction nodrag nopan" data-focus-return={`${item.id}:business`} onClick={(event) => { event.stopPropagation(); node.onOpen(item, "business"); }}>查看读取内容<ArrowRight size={14} /></button><SourceComparisonButton item={item} onOpen={node.onOpen} /></footer>
  24. </article>{hoverPreview.preview}</>;
  25. }