Files
vf_react/src/components/ChatBot/StepResultCard.js
2025-11-21 14:47:47 +08:00

187 lines
5.9 KiB
JavaScript

// src/components/ChatBot/StepResultCard.js
// 步骤结果展示卡片(可折叠)
import React, { useState } from 'react';
import {
Box,
VStack,
HStack,
Text,
Badge,
Collapse,
Icon,
IconButton,
Code,
useColorModeValue,
Divider,
} from '@chakra-ui/react';
import { FiChevronDown, FiChevronUp, FiCheckCircle, FiXCircle, FiClock, FiDatabase } from 'react-icons/fi';
/**
* 步骤结果卡片组件
*/
export const StepResultCard = ({ stepResult }) => {
const [isExpanded, setIsExpanded] = useState(false);
const cardBg = useColorModeValue('white', 'rgba(40, 45, 50, 0.8)');
const borderColor = useColorModeValue('gray.200', 'rgba(255, 215, 0, 0.2)');
const successColor = useColorModeValue('green.500', 'green.300');
const errorColor = useColorModeValue('red.500', 'red.300');
const getStatusIcon = () => {
switch (stepResult.status) {
case 'success':
return FiCheckCircle;
case 'failed':
return FiXCircle;
default:
return FiClock;
}
};
const getStatusColor = () => {
switch (stepResult.status) {
case 'success':
return 'green';
case 'failed':
return 'red';
default:
return 'gray';
}
};
const StatusIcon = getStatusIcon();
const statusColorScheme = getStatusColor();
// 格式化数据以便展示
const formatResult = (data) => {
if (typeof data === 'string') return data;
if (Array.isArray(data)) {
return `找到 ${data.length} 条记录`;
}
if (typeof data === 'object') {
return JSON.stringify(data, null, 2);
}
return String(data);
};
return (
<Box
bg={cardBg}
borderRadius="md"
borderWidth="1px"
borderColor={borderColor}
overflow="hidden"
boxShadow="sm"
>
{/* 头部 - 始终可见 */}
<HStack
p={3}
justify="space-between"
cursor="pointer"
onClick={() => setIsExpanded(!isExpanded)}
_hover={{ bg: useColorModeValue('gray.50', 'rgba(50, 55, 60, 0.7)') }}
>
<HStack flex={1}>
<Icon as={StatusIcon} color={`${statusColorScheme}.500`} boxSize={5} />
<VStack align="stretch" spacing={0} flex={1}>
<HStack>
<Text fontSize="sm" fontWeight="bold">
步骤 {stepResult.step_index + 1}: {stepResult.tool}
</Text>
<Badge colorScheme={statusColorScheme} fontSize="xs">
{stepResult.status === 'success' ? '成功' :
stepResult.status === 'failed' ? '失败' : '执行中'}
</Badge>
</HStack>
<Text fontSize="xs" color={useColorModeValue('gray.500', '#9BA1A6')}>
耗时: {stepResult.execution_time?.toFixed(2)}s
</Text>
</VStack>
</HStack>
<IconButton
icon={<Icon as={isExpanded ? FiChevronUp : FiChevronDown} />}
size="sm"
variant="ghost"
aria-label={isExpanded ? "收起" : "展开"}
/>
</HStack>
{/* 内容 - 可折叠 */}
<Collapse in={isExpanded} animateOpacity>
<Box p={3} pt={0}>
<Divider mb={3} />
{/* 参数 */}
{stepResult.arguments && Object.keys(stepResult.arguments).length > 0 && (
<VStack align="stretch" spacing={2} mb={3}>
<HStack>
<Icon as={FiDatabase} color="blue.500" boxSize={4} />
<Text fontSize="xs" fontWeight="bold">请求参数:</Text>
</HStack>
<Code
p={2}
borderRadius="md"
fontSize="xs"
whiteSpace="pre-wrap"
wordBreak="break-word"
>
{JSON.stringify(stepResult.arguments, null, 2)}
</Code>
</VStack>
)}
{/* 结果或错误 */}
{stepResult.status === 'success' && stepResult.result && (
<VStack align="stretch" spacing={2}>
<Text fontSize="xs" fontWeight="bold">执行结果:</Text>
<Box
maxH="300px"
overflowY="auto"
p={2}
bg={useColorModeValue('gray.50', 'rgba(25, 28, 32, 0.6)')}
borderRadius="md"
fontSize="xs"
>
{typeof stepResult.result === 'string' ? (
<Text whiteSpace="pre-wrap">{stepResult.result}</Text>
) : Array.isArray(stepResult.result) ? (
<VStack align="stretch" spacing={2}>
<Text fontWeight="bold">找到 {stepResult.result.length} 条记录:</Text>
{stepResult.result.slice(0, 3).map((item, idx) => (
<Code key={idx} p={2} borderRadius="md" fontSize="xs">
{JSON.stringify(item, null, 2)}
</Code>
))}
{stepResult.result.length > 3 && (
<Text fontSize="xs" color={useColorModeValue('gray.500', '#9BA1A6')}>
...还有 {stepResult.result.length - 3} 条记录
</Text>
)}
</VStack>
) : (
<Code whiteSpace="pre-wrap" wordBreak="break-word">
{JSON.stringify(stepResult.result, null, 2)}
</Code>
)}
</Box>
</VStack>
)}
{stepResult.status === 'failed' && stepResult.error && (
<VStack align="stretch" spacing={2}>
<Text fontSize="xs" fontWeight="bold" color="red.500">错误信息:</Text>
<Text fontSize="xs" color={useColorModeValue('red.600', 'red.300')} p={2} bg={useColorModeValue('red.50', 'rgba(220, 38, 38, 0.15)')} borderRadius="md">
{stepResult.error}
</Text>
</VStack>
)}
</Box>
</Collapse>
</Box>
);
};
export default StepResultCard;