/* * @Description: 滚动列表 * @Version: 0.0.1 * @Author: yujiangping * @Date: 2025-11-18 16:19:58 * @LastEditors: yujiangping * @LastEditTime: 2025-11-29 19:08:40 */ import { FileOutlined, FieldTimeOutlined, EditOutlined } from '@ant-design/icons'; import { Skeleton } from 'antd'; import { useTranslation } from 'react-i18next'; import type { RecallTestData } from '../types'; import { NoData } from './noData'; import { formatDateTime } from '@/utils/format'; import InfiniteScroll from 'react-infinite-scroll-component'; import RbMarkdown from '@/components/Markdown'; interface RecallTestResultProps { data: RecallTestData[]; showEmpty?: boolean; hasMore?: boolean; loadMore?: () => void; loading?: boolean; scrollableTarget?: string; editable?: boolean; // 是否可编辑 onItemClick?: (item: RecallTestData, index: number) => void; // 点击项的回调 } const RecallTestResult = ({ data, showEmpty = true, hasMore = false, loadMore, loading = false, scrollableTarget, editable = false, onItemClick, }: RecallTestResultProps) => { const { t } = useTranslation(); const handleItemClick = (e: React.MouseEvent, item: RecallTestData, index: number) => { // 检查点击的是否是图片或图片相关元素 const target = e.target as HTMLElement; // 检查是否点击了图片本身、图片的容器、预览层、关闭按钮或 SVG 图标 if ( target.tagName === 'IMG' || target.tagName === 'SVG' || // SVG 图标 target.tagName === 'PATH' || // SVG 路径 target.closest('.ant-image') || target.closest('.ant-image-preview') || target.closest('.ant-image-preview-wrap') || target.closest('.ant-image-preview-operations') || target.closest('.anticon') || // Ant Design 图标 target.classList.contains('ant-image-img') || target.classList.contains('ant-image-mask') || target.classList.contains('ant-image-preview-close') || target.classList.contains('anticon') ) { return; } if (editable && onItemClick) { onItemClick(item, index); } }; // 根据分数获取颜色类名 const getScoreColorClass = (score: number): string => { const percentage = score * 100; if (percentage >= 90) { return 'rb:text-[#155EEF]'; } else if (percentage >= 80) { return 'rb:text-[#369F21]'; } else { return 'rb:text-[#FF5D34]'; } }; if (data.length === 0 && showEmpty) { return ( ); } if (data.length === 0) { return null; } const renderContent = () => (
{data.map((item, index) => { const score = item.metadata?.score ?? 1; const scorePercentage = score * 100; const colorClass = getScoreColorClass(score); const showScore = item.metadata?.score !== null && item.metadata?.score !== undefined; return (
handleItemClick(e, item, index)} > {editable && (
)}
{showScore && ( {scorePercentage.toFixed(1)}% {t('knowledgeBase.similarity')} )}
{item.metadata?.file_name || '-'} chunk_{item.metadata?.sort_id || index}
{item.metadata?.file_created_at && (
{formatDateTime(item.metadata.file_created_at)}
)}
); })} {loading && (
)}
); // 如果提供了 loadMore 和 hasMore,使用 InfiniteScroll if (loadMore && hasMore !== undefined) { return (
{t('knowledgeBase.recallResult')} ({data.length} results)
} scrollableTarget={scrollableTarget} > {renderContent()}
); } // 否则使用普通渲染 return (
{t('knowledgeBase.recallResult')} ({data.length} results)
{renderContent()}
); }; export default RecallTestResult;