unnamed-ui
折叠/步骤

Execution Result

Execution result block for displaying function call results with collapsible items

已执行完成,调用3个组件
调用Tool iconsearch_api
请求来自 xxx
请求内容内容内容
响应来自 xxx
响应内容内容内容
"use client";

import { ExecutionResult } from "@/components/composed/execution-result/execution-result";

export function ExecutionResultDemo() {
  return (
    <div className="space-y-4 w-full h-full max-w-2xl">
      <ExecutionResult
        defaultOpen
        title="已执行完成,调用3个组件"
        items={[
          {
            status: "success",
            title: "调用",
            toolName: "search_api",
            imageSrc: "https://picsum.photos/16/16",
            imageAlt: "Tool icon",
            sections: [
              {
                title: "请求来自 xxx",
                content: "请求内容内容内容",
                copyText: "请求内容内容内容",
              },
              {
                title: "响应来自 xxx",
                content: "响应内容内容内容",
                copyText: "响应内容内容内容",
              },
            ],
          },
          {
            status: "success",
            title: "调用",
            toolName: "search_api",
            imageSrc: "https://picsum.photos/16/16",
            imageAlt: "Tool icon",
            sections: [
              {
                title: "请求来自 xxx",
                content: "请求内容内容内容",
                copyText: "请求内容内容内容",
              },
              {
                title: "响应来自 xxx",
                content: "响应内容内容内容",
                copyText: "响应内容内容内容",
              },
            ],
          },
          {
            status: "success",
            title: "调用",
            toolName: "search_api",
            imageSrc: "https://picsum.photos/16/16",
            imageAlt: "Tool icon",
            defaultOpen: true,
            sections: [
              {
                title: "请求来自 xxx",
                content: "请求内容内容内容",
                copyText: "请求内容内容内容",
              },
              {
                title: "响应来自 xxx",
                content: "响应内容内容内容",
                copyText: "响应内容内容内容",
              },
            ],
          },
        ]}
      />
    </div>
  );
}

Execution Result 组件用于展示函数调用、API 请求等执行结果,支持成功、失败、执行中等多种状态,每个执行项可包含多个区块(如请求、响应)并支持一键复制。

概述

  • 多状态支持:success(成功)、error(失败)、loading(执行中)、idle(待执行)
  • 可折叠交互:整体和每个执行项都支持展开/收起
  • 区块展示:每个执行项可包含多个区块(请求、响应等)
  • 一键复制:支持复制区块内容到剪贴板
  • 工具信息:可显示工具名称和图标
  • 类型安全:完整的 TypeScript 类型定义
  • 轻量级:基于原语组件构建,无额外依赖

快速开始

import { ExecutionResult } from "@/registry/wuhan/composed/execution-result/execution-result";

export function Example() {
  return (
    <ExecutionResult
      title="已执行完成,调用2个组件"
      items={[
        {
          status: "success",
          title: "调用成功 search_api",
          sections: [
            {
              title: "请求",
              content: '{"query": "搜索关键词"}',
              copyText: '{"query": "搜索关键词"}'
            },
            {
              title: "响应",
              content: '{"results": ["结果1", "结果2"]}',
              copyText: '{"results": ["结果1", "结果2"]}'
            }
          ]
        }
      ]}
    />
  );
}

特性

  • 智能状态管理:根据 status 自动切换图标和颜色
  • 灵活控制:支持受控模式和非受控模式
  • 嵌套折叠:整体可折叠,每个执行项也可单独折叠
  • 复制功能:自动处理复制到剪贴板,支持自定义复制逻辑
  • 工具展示:支持显示工具图标和名称
  • 可访问性:支持 aria 属性,键盘导航友好

安装

pnpm dlx shadcn@latest add http://localhost:3000/r/wuhan/execution-result.json

代码演示

基本

基础的执行结果展示,包含不同状态(成功、失败、进行中)。

已执行完成,调用3个组件
调用成功 search_api
请求来自 user
{ "query": "搜索关键词", "limit": 10 }
响应来自 search_api
{ "results": [ "结果1", "结果2", "结果3" ] }
执行失败,调用2个组件
"use client";

import { ExecutionResult } from "@/components/composed/execution-result/execution-result";

export function ExecutionResultDefault() {
  return (
    <div className="space-y-4 w-full h-full max-w-2xl">
      {/* 成功状态 */}
      <ExecutionResult
        defaultOpen
        title="已执行完成,调用3个组件"
        items={[
          {
            status: "success",
            title: "思考完成",
            sections: [
              {
                showCopyIcon: false,
                content:
                  "用户想要了解AI发展的趋势,这是一个比较开放的问题,需要从多个维度来概括当前的主要方向。考虑到用户可能不是专业人士,应该用清晰的结构和易懂的语言来组织信息。",
              },
            ],
          },
          {
            status: "success",
            title: "调用成功 search_api",
            defaultOpen: true,
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify(
                  { query: "搜索关键词", limit: 10 },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  { query: "搜索关键词", limit: 10 },
                  null,
                  2,
                ),
              },
              {
                title: "响应来自 search_api",
                content: JSON.stringify(
                  { results: ["结果1", "结果2", "结果3"] },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  { results: ["结果1", "结果2", "结果3"] },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "调用成功 image_generator",
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify(
                  { prompt: "生成一张图片", style: "realistic" },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  { prompt: "生成一张图片", style: "realistic" },
                  null,
                  2,
                ),
              },
              {
                title: "响应来自 image_generator",
                content: JSON.stringify(
                  { image_url: "https://example.com/image.png" },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  { image_url: "https://example.com/image.png" },
                  null,
                  2,
                ),
              },
            ],
          },
        ]}
      />

      {/* 失败状态 */}
      <ExecutionResult
        defaultOpen
        title="执行失败,调用2个组件"
        items={[
          {
            status: "error",
            title: "调用失败 api_error",
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify({ action: "fetch_data" }, null, 2),
                copyText: JSON.stringify({ action: "fetch_data" }, null, 2),
              },
              {
                title: "错误信息",
                content: JSON.stringify(
                  { error: "Internal Server Error", code: 500 },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  { error: "Internal Server Error", code: 500 },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "loading",
            title: "正在重试调用 retry_api",
            sections: [
              {
                title: "请求来自 system",
                content: JSON.stringify(
                  { action: "retry_request", retryCount: 2 },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  { action: "retry_request", retryCount: 2 },
                  null,
                  2,
                ),
              },
            ],
          },
        ]}
      />
    </div>
  );
}

受控模式

受控模式的执行结果组件,可通过外部状态控制展开和动态添加执行项。

已执行完成,调用1个组件
"use client";

import {
  ExecutionResult,
  type ExecutionResultItem,
} from "@/components/composed/execution-result/execution-result";
import { Button } from "@/components/ui/button";
import { useState } from "react";

export function ExecutionResultControlled() {
  const [isOpen, setIsOpen] = useState(true);
  const [items, setItems] = useState<ExecutionResultItem[]>([
    {
      status: "success",
      title: "调用成功 search_api",
      sections: [
        {
          title: "请求",
          content: JSON.stringify({ query: "搜索内容" }, null, 2),
          copyText: JSON.stringify({ query: "搜索内容" }, null, 2),
        },
      ],
    },
  ]);

  const addLoadingItem = () => {
    setItems([
      ...items,
      {
        status: "loading",
        title: "正在调用 data_api",
        sections: [
          {
            title: "请求中...",
            content: "等待服务器响应",
            showCopyIcon: false,
          },
        ],
      },
    ]);

    // 模拟3秒后完成
    setTimeout(() => {
      setItems((prev) =>
        prev.map((item, idx) =>
          idx === prev.length - 1
            ? {
                ...item,
                status: "success" as const,
                title: "调用成功 data_api",
                sections: [
                  {
                    title: "请求",
                    content: JSON.stringify({ action: "fetch" }, null, 2),
                    copyText: JSON.stringify({ action: "fetch" }, null, 2),
                  },
                  {
                    title: "响应",
                    content: JSON.stringify({ data: [1, 2, 3] }, null, 2),
                    copyText: JSON.stringify({ data: [1, 2, 3] }, null, 2),
                  },
                ],
              }
            : item,
        ),
      );
    }, 3000);
  };

  return (
    <div className="space-y-4 w-full h-full max-w-2xl">
      <div className="flex gap-2">
        <Button size="sm" variant="outline" onClick={() => setIsOpen(!isOpen)}>
          {isOpen ? "折叠全部" : "展开全部"}
        </Button>
        <Button size="sm" variant="outline" onClick={addLoadingItem}>
          添加新执行项
        </Button>
      </div>

      <ExecutionResult
        title={`已执行完成,调用${items.length}个组件`}
        items={items}
        open={isOpen}
        onOpenChange={setIsOpen}
      />
    </div>
  );
}

工具图标

带工具图标的执行结果展示,显示不同工具的调用情况。

已执行完成,调用4个工具
调用Calculator iconcalculator
请求来自 user
{ "expression": "(123 + 456) * 2", "precision": 2 }
响应来自 calculator
{ "result": 1158, "formula": "(123 + 456) * 2 = 1158" }
"use client";

import { ExecutionResult } from "@/components/composed/execution-result/execution-result";

export function ExecutionResultWithTools() {
  return (
    <div className="space-y-4 w-full h-full max-w-2xl">
      <ExecutionResult
        defaultOpen
        title="已执行完成,调用4个工具"
        items={[
          {
            status: "success",
            title: "调用",
            toolName: "search_engine",
            imageSrc: "https://picsum.photos/seed/search/16/16",
            imageAlt: "Search engine icon",
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify(
                  {
                    query: "人工智能发展趋势",
                    language: "zh-CN",
                    maxResults: 10,
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    query: "人工智能发展趋势",
                    language: "zh-CN",
                    maxResults: 10,
                  },
                  null,
                  2,
                ),
              },
              {
                title: "响应来自 search_engine",
                content: JSON.stringify(
                  {
                    results: [
                      "AI在医疗领域的应用",
                      "大语言模型的最新进展",
                      "AI与自动驾驶技术",
                    ],
                    totalCount: 125,
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    results: [
                      "AI在医疗领域的应用",
                      "大语言模型的最新进展",
                      "AI与自动驾驶技术",
                    ],
                    totalCount: 125,
                  },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "调用",
            toolName: "calculator",
            imageSrc: "https://picsum.photos/seed/calc/16/16",
            imageAlt: "Calculator icon",
            defaultOpen: true,
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify(
                  {
                    expression: "(123 + 456) * 2",
                    precision: 2,
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    expression: "(123 + 456) * 2",
                    precision: 2,
                  },
                  null,
                  2,
                ),
              },
              {
                title: "响应来自 calculator",
                content: JSON.stringify(
                  {
                    result: 1158,
                    formula: "(123 + 456) * 2 = 1158",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    result: 1158,
                    formula: "(123 + 456) * 2 = 1158",
                  },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "调用",
            toolName: "weather_api",
            imageSrc: "https://picsum.photos/seed/weather/16/16",
            imageAlt: "Weather API icon",
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify(
                  {
                    city: "北京",
                    days: 7,
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    city: "北京",
                    days: 7,
                  },
                  null,
                  2,
                ),
              },
              {
                title: "响应来自 weather_api",
                content: JSON.stringify(
                  {
                    city: "北京",
                    temperature: 15,
                    condition: "晴",
                    forecast: ["晴", "多云", "雨"],
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    city: "北京",
                    temperature: 15,
                    condition: "晴",
                    forecast: ["晴", "多云", "雨"],
                  },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "调用",
            toolName: "database_query",
            imageSrc: "https://picsum.photos/seed/db/16/16",
            imageAlt: "Database icon",
            sections: [
              {
                title: "请求来自 system",
                content: JSON.stringify(
                  {
                    table: "users",
                    filter: { status: "active" },
                    limit: 100,
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    table: "users",
                    filter: { status: "active" },
                    limit: 100,
                  },
                  null,
                  2,
                ),
              },
              {
                title: "响应来自 database_query",
                content: JSON.stringify(
                  {
                    count: 87,
                    rows: ["user1", "user2", "user3"],
                    executionTime: "12ms",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    count: 87,
                    rows: ["user1", "user2", "user3"],
                    executionTime: "12ms",
                  },
                  null,
                  2,
                ),
              },
            ],
          },
        ]}
      />
    </div>
  );
}

工作流

工作流执行结果展示,适用于多步骤流程和批处理任务。

数据处理工作流 - 已完成
步骤2: 数据清洗
清洗规则
{ "removeNulls": true, "removeDuplicates": true, "normalizeFields": [ "email", "phone" ] }
清洗结果
{ "inputRecords": 9856, "outputRecords": 9234, "removedNulls": 234, "removedDuplicates": 388, "duration": "1.8s" }
API 批量调用 - 部分失败
批次2: 订单数据同步 (45/100)
错误详情
{ "error": "Rate limit exceeded", "code": 429, "retryAfter": 60, "failedRequests": 55 }
建议
请等待60秒后重试失败的请求,或考虑降低请求频率
"use client";

import { ExecutionResult } from "@/components/composed/execution-result/execution-result";

export function ExecutionResultWorkflow() {
  return (
    <div className="space-y-4 w-full h-full max-w-2xl">
      {/* 工作流执行结果 */}
      <ExecutionResult
        defaultOpen
        title="数据处理工作流 - 已完成"
        items={[
          {
            status: "success",
            title: "步骤1: 数据采集",
            sections: [
              {
                title: "数据源",
                content: JSON.stringify(
                  {
                    source: "MySQL Database",
                    table: "raw_data",
                    timestamp: "2024-02-02 10:00:00",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    source: "MySQL Database",
                    table: "raw_data",
                    timestamp: "2024-02-02 10:00:00",
                  },
                  null,
                  2,
                ),
              },
              {
                title: "采集结果",
                content: JSON.stringify(
                  {
                    totalRecords: 10000,
                    validRecords: 9856,
                    invalidRecords: 144,
                    duration: "2.3s",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    totalRecords: 10000,
                    validRecords: 9856,
                    invalidRecords: 144,
                    duration: "2.3s",
                  },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "步骤2: 数据清洗",
            defaultOpen: true,
            sections: [
              {
                title: "清洗规则",
                content: JSON.stringify(
                  {
                    removeNulls: true,
                    removeDuplicates: true,
                    normalizeFields: ["email", "phone"],
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    removeNulls: true,
                    removeDuplicates: true,
                    normalizeFields: ["email", "phone"],
                  },
                  null,
                  2,
                ),
              },
              {
                title: "清洗结果",
                content: JSON.stringify(
                  {
                    inputRecords: 9856,
                    outputRecords: 9234,
                    removedNulls: 234,
                    removedDuplicates: 388,
                    duration: "1.8s",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    inputRecords: 9856,
                    outputRecords: 9234,
                    removedNulls: 234,
                    removedDuplicates: 388,
                    duration: "1.8s",
                  },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "步骤3: 数据转换",
            sections: [
              {
                title: "转换配置",
                content: JSON.stringify(
                  {
                    format: "JSON",
                    encoding: "UTF-8",
                    compression: "gzip",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    format: "JSON",
                    encoding: "UTF-8",
                    compression: "gzip",
                  },
                  null,
                  2,
                ),
              },
              {
                title: "转换结果",
                content: JSON.stringify(
                  {
                    records: 9234,
                    outputSize: "1.2 MB",
                    compressionRatio: "75%",
                    duration: "0.9s",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    records: 9234,
                    outputSize: "1.2 MB",
                    compressionRatio: "75%",
                    duration: "0.9s",
                  },
                  null,
                  2,
                ),
              },
            ],
          },
          {
            status: "success",
            title: "步骤4: 数据存储",
            sections: [
              {
                title: "存储目标",
                content: JSON.stringify(
                  {
                    destination: "AWS S3",
                    bucket: "processed-data",
                    path: "/2024/02/02/data.json.gz",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    destination: "AWS S3",
                    bucket: "processed-data",
                    path: "/2024/02/02/data.json.gz",
                  },
                  null,
                  2,
                ),
              },
              {
                title: "存储结果",
                content: JSON.stringify(
                  {
                    status: "success",
                    fileUrl: "s3://processed-data/2024/02/02/data.json.gz",
                    uploadDuration: "1.5s",
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    status: "success",
                    fileUrl: "s3://processed-data/2024/02/02/data.json.gz",
                    uploadDuration: "1.5s",
                  },
                  null,
                  2,
                ),
              },
            ],
          },
        ]}
      />

      {/* 部分失败的工作流 */}
      <ExecutionResult
        defaultOpen
        title="API 批量调用 - 部分失败"
        items={[
          {
            status: "success",
            title: "批次1: 用户信息获取 (100/100)",
            sections: [
              {
                title: "执行摘要",
                content: "成功获取100个用户的详细信息",
                showCopyIcon: false,
              },
            ],
          },
          {
            status: "error",
            title: "批次2: 订单数据同步 (45/100)",
            defaultOpen: true,
            sections: [
              {
                title: "错误详情",
                content: JSON.stringify(
                  {
                    error: "Rate limit exceeded",
                    code: 429,
                    retryAfter: 60,
                    failedRequests: 55,
                  },
                  null,
                  2,
                ),
                copyText: JSON.stringify(
                  {
                    error: "Rate limit exceeded",
                    code: 429,
                    retryAfter: 60,
                    failedRequests: 55,
                  },
                  null,
                  2,
                ),
              },
              {
                title: "建议",
                content: "请等待60秒后重试失败的请求,或考虑降低请求频率",
                showCopyIcon: false,
              },
            ],
          },
          {
            status: "idle",
            title: "批次3: 库存更新 (等待中)",
            sections: [
              {
                title: "状态",
                content: "等待批次2完成后执行",
                showCopyIcon: false,
              },
            ],
          },
        ]}
      />
    </div>
  );
}

API

ExecutionResult (Composed Component)

执行结果主组件,支持多种状态和完全自定义。

Props

PropTypeDefaultDescription
titleReact.ReactNode-整体标题(如"已执行完成,调用3个组件")
itemsExecutionResultItem[][]执行结果列表项
defaultOpenbooleanfalse非受控模式下的默认展开状态
openboolean-受控模式下的展开状态
onOpenChange(open: boolean) => void-展开状态变化回调函数
arrowIconReact.ReactNode-自定义展开/收起箭头图标

Example

import { ExecutionResult } from "@/registry/wuhan/composed/execution-result/execution-result";
import { useState } from "react";

function APIResults() {
  const [isOpen, setIsOpen] = useState(true);
  
  return (
    <div className="flex flex-col gap-4">
      {/* 非受控模式 */}
      <ExecutionResult
        defaultOpen
        title="已执行完成,调用2个组件"
        items={[
          {
            status: "success",
            title: "调用成功 search_api",
            toolName: "search_api",
            imageSrc: "/icons/search.png",
            sections: [
              {
                title: "请求来自 user",
                content: JSON.stringify({ query: "AI trends" }, null, 2),
                copyText: JSON.stringify({ query: "AI trends" }, null, 2)
              },
              {
                title: "响应来自 search_api",
                content: JSON.stringify({ results: [...] }, null, 2),
                copyText: JSON.stringify({ results: [...] }, null, 2)
              }
            ]
          },
          {
            status: "error",
            title: "调用失败 database_api",
            sections: [
              {
                title: "错误信息",
                content: "Connection timeout",
                showCopyIcon: false
              }
            ]
          }
        ]}
      />
      
      {/* 受控模式 */}
      <ExecutionResult
        title="执行结果"
        items={items}
        open={isOpen}
        onOpenChange={setIsOpen}
      />
      
      {/* 自定义复制逻辑 */}
      <ExecutionResult
        items={[
          {
            status: "success",
            title: "数据处理完成",
            sections: [
              {
                title: "结果",
                content: "Processing completed",
                onCopy: () => {
                  console.log("Custom copy logic");
                  navigator.clipboard.writeText("Custom text");
                }
              }
            ]
          }
        ]}
      />
    </div>
  );
}

ExecutionResultItem

执行结果列表项配置接口。

interface ExecutionResultItem {
  /** 列表项唯一标识 */
  key?: React.Key;
  /** 执行状态:success | error | loading | idle */
  status?: ExecutionResultStatus;
  /** 列表项标题 */
  title?: React.ReactNode;
  /** 工具/函数名称 */
  toolName?: React.ReactNode;
  /** 工具图标图片地址 */
  imageSrc?: string;
  /** 工具图标图片 alt 文本 */
  imageAlt?: string;
  /** 是否默认展开详情 */
  defaultOpen?: boolean;
  /** 区块列表(请求、响应等) */
  sections?: ExecutionResultSection[];
}

ExecutionResultSection

执行结果区块配置接口。

interface ExecutionResultSection {
  /** 区块标题(如"请求来自 xxx"、"响应来自 xxx") */
  title?: React.ReactNode;
  /** 区块内容 */
  content?: React.ReactNode;
  /** 复制按钮要复制的文本内容 */
  copyText?: string;
  /** 是否显示复制图标 */
  showCopyIcon?: boolean;
  /** 自定义复制回调函数 */
  onCopy?: () => void;
}

ExecutionResultStatus

状态类型定义。

type ExecutionResultStatus = 
  | "success"   // 成功
  | "error"     // 失败
  | "loading"   // 执行中
  | "idle";     // 待执行

状态默认配置

StatusIconColor
successCheckCircle2text-success (绿色)
errorXCircletext-error (红色)
loadingLoader2 (旋转动画)text-brand (蓝色)
idleCircletext-tertiary (灰色)

使用场景

  • AI Agent 执行:展示 AI Agent 调用的工具/函数列表及其结果
  • API 请求追踪:显示 API 请求和响应详情
  • 函数调用日志:记录函数调用的输入参数和返回结果
  • 工作流执行:展示工作流各步骤的执行状态和结果
  • 批处理结果:显示批量任务的执行状态和详细信息
  • 调试信息:开发调试时查看执行过程和结果

最佳实践

  1. 状态管理:根据执行结果及时更新状态(loading → success/error)
  2. JSON 格式化:请求/响应内容使用 JSON.stringify(data, null, 2) 格式化
  3. 复制文本:为每个区块提供 copyText,方便用户复制
  4. 默认展开:最新的执行项建议设置 defaultOpen={true}
  5. 工具图标:为不同工具提供独特的图标,提升识别度
  6. 错误处理:失败状态应在 sections 中提供详细错误信息
  7. 加载状态:执行中的项使用 loading 状态并禁用展开

注意事项

  • 整体容器和每个执行项都可以独立折叠
  • copyTextonCopy 只需提供其一,优先使用 onCopy
  • 设置 showCopyIcon={false} 可以隐藏复制按钮
  • status 默认为 "success",不提供时显示成功图标
  • imageSrctoolName 可以同时使用
  • 使用受控模式时必须同时提供 openonOpenChange

原语组件

Execution Result 基于以下原语组件构建:

  • ExecutionResultContainerPrimitive - 容器,基于 Collapsible
  • ExecutionResultTitlePrimitive - 整体标题
  • ExecutionResultContentPrimitive - 列表项容器
  • ExecutionResultItemPrimitive - 单个执行项
  • ExecutionResultItemHeaderPrimitive - 执行项头部
  • ExecutionResultItemIconPrimitive - 状态图标容器
  • ExecutionResultItemTitlePrimitive - 执行项标题
  • ExecutionResultItemImagePrimitive - 工具图标
  • ExecutionResultItemToolNamePrimitive - 工具名称
  • ExecutionResultItemContentPrimitive - 执行项内容
  • ExecutionResultSectionPrimitive - 区块(请求/响应)
  • ExecutionResultCopyIconPrimitive - 复制按钮
  • ExecutionResultArrowPrimitive - 箭头图标

这些原语可以在 registry/wuhan/blocks/execution-result/execution-result-01.tsx 中找到。

样式定制

组件使用 Tailwind CSS 和 CSS 变量,可以通过以下方式定制:

// 使用原语组件完全自定义
import {
  ExecutionResultContainerPrimitive,
  ExecutionResultItemPrimitive,
} from "@/registry/wuhan/blocks/execution-result/execution-result-01";

<ExecutionResultContainerPrimitive>
  <ExecutionResultItemPrimitive className="bg-blue-50 border-blue-200">
    {/* 自定义样式 */}
  </ExecutionResultItemPrimitive>
</ExecutionResultContainerPrimitive>

扩展示例

实时更新执行状态

import { ExecutionResult } from "@/registry/wuhan/composed/execution-result/execution-result";
import { useState, useEffect } from "react";

function LiveExecutionResult() {
  const [items, setItems] = useState([
    { status: "loading", title: "正在调用 API...", sections: [] }
  ]);
  
  useEffect(() => {
    // 模拟 API 调用
    setTimeout(() => {
      setItems([
        {
          status: "success",
          title: "调用成功 search_api",
          sections: [
            {
              title: "请求",
              content: JSON.stringify({ query: "test" }, null, 2),
              copyText: JSON.stringify({ query: "test" }, null, 2)
            },
            {
              title: "响应",
              content: JSON.stringify({ data: [...] }, null, 2),
              copyText: JSON.stringify({ data: [...] }, null, 2)
            }
          ]
        }
      ]);
    }, 2000);
  }, []);
  
  return (
    <ExecutionResult
      title="执行结果"
      items={items}
      defaultOpen
    />
  );
}

带工具图标的执行结果

import { ExecutionResult } from "@/registry/wuhan/composed/execution-result/execution-result";

function ToolExecutionResult() {
  return (
    <ExecutionResult
      title="已执行完成,调用3个工具"
      items={[
        {
          status: "success",
          title: "调用",
          toolName: "search",
          imageSrc: "/icons/search.png",
          imageAlt: "Search tool",
          sections: [
            { title: "查询", content: "AI trends 2024" }
          ]
        },
        {
          status: "success",
          title: "调用",
          toolName: "calculator",
          imageSrc: "/icons/calc.png",
          imageAlt: "Calculator tool",
          sections: [
            { title: "计算", content: "1 + 1 = 2" }
          ]
        }
      ]}
    />
  );
}

多层次展示

import { ExecutionResult } from "@/registry/wuhan/composed/execution-result/execution-result";
import { useState } from "react";

function NestedExecutionResult() {
  const [open, setOpen] = useState(true);
  
  return (
    <ExecutionResult
      title="工作流执行结果"
      open={open}
      onOpenChange={setOpen}
      items={[
        {
          status: "success",
          title: "步骤1: 数据获取",
          defaultOpen: false,
          sections: [
            { title: "数据源", content: "database_api" },
            { title: "记录数", content: "1,234 条" }
          ]
        },
        {
          status: "success",
          title: "步骤2: 数据处理",
          defaultOpen: false,
          sections: [
            { title: "处理方式", content: "filter + transform" },
            { title: "输出", content: "890 条有效记录" }
          ]
        },
        {
          status: "success",
          title: "步骤3: 结果保存",
          defaultOpen: true,
          sections: [
            { title: "保存位置", content: "/output/result.json" },
            { title: "文件大小", content: "125 KB" }
          ]
        }
      ]}
    />
  );
}

原语组件 API

以下是原语组件的 API 文档,用于需要完全自定义的场景。

ExecutionResultContainerPrimitive

执行结果容器组件,用于包裹整个执行结果列表。

参数类型说明
childrenReactNode子元素
classNamestring自定义样式类名

ExecutionResultTitlePrimitive

执行结果标题组件,用于显示总体执行状态。

参数类型说明
childrenReactNode标题内容
classNamestring自定义样式类名

ExecutionResultItemPrimitive

执行结果列表项容器组件,支持展开/收起。

参数类型说明
childrenReactNode子元素
defaultOpenboolean是否默认展开
openboolean控制展开状态
onOpenChange(open: boolean) => void展开状态变化回调
classNamestring自定义样式类名

ExecutionResultItemHeaderPrimitive

执行结果列表项头部组件。

参数类型说明
childrenReactNode左侧内容(通常是图标和标题)
arrowReactNode右侧内容(通常是箭头图标)
classNamestring自定义样式类名

ExecutionResultItemIconPrimitive

执行结果列表项图标容器组件。

参数类型说明
childrenReactNode图标内容
classNamestring自定义样式类名

ExecutionResultItemTitlePrimitive

执行结果列表项标题组件。

参数类型说明
childrenReactNode标题内容
classNamestring自定义样式类名

ExecutionResultItemContentPrimitive

执行结果列表项内容容器组件。

参数类型说明
childrenReactNode内容
classNamestring自定义样式类名

ExecutionResultSectionPrimitive

执行结果区块组件(请求/响应部分)。

参数类型默认值说明
titlestring-区块标题
showCopyIconbooleantrue是否显示复制图标
onCopy() => void-复制回调
childrenReactNode-内容
classNamestring-自定义样式类名

ExecutionResultCopyIconPrimitive

执行结果复制图标组件。

参数类型说明
onCopy() => void复制回调
classNamestring自定义样式类名

ExecutionResultArrowPrimitive

执行结果箭头图标组件。

参数类型默认值说明
childrenReactNode">"箭头内容
classNamestring-自定义样式类名