/* * @Author: ZhaoYing * @Date: 2026-03-24 16:31:24 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-04-24 17:49:58 */ import { forwardRef, useImperativeHandle, useState, useEffect } from 'react'; import { Flex, Button, Empty, Skeleton } from 'antd'; import { useTranslation } from 'react-i18next'; import type { LogDetailModalRef, LogItem } from '../types' import RbModal from '@/components/RbModal' import { getAppLogDetail } from '@/api/application' import ChatContent from '@/components/Chat/ChatContent' import { formatDateTime } from '@/utils/format' import type { ChatItem } from '@/components/Chat/types' import Runtime from '@/views/Workflow/components/Chat/Runtime' import { nodeLibrary } from '@/views/Workflow/constant' const nodeIconMap = Object.fromEntries( nodeLibrary.flatMap(c => c.nodes.map(n => [n.type, n.icon])) ) /** Log detail data with conversation messages */ type Data = LogItem & { messages: ChatItem[]; } /** Modal component for displaying conversation log details */ const LogDetailModal = forwardRef((_props, ref) => { const { t } = useTranslation(); const [visible, setVisible] = useState(false); const [loading, setLoading] = useState(false) const [vo, setVo] = useState(null) const [data, setData] = useState({} as Data) /** Close modal and reset form */ const handleClose = () => { setVisible(false); setLoading(false) setVo(null) setData({} as Data) }; /** Open modal */ const handleOpen = (item: LogItem) => { setVisible(true); setVo(item) }; /** Fetch detail when modal opens */ useEffect(() => { if (visible && vo) { getDetail() } }, [visible, vo]) /** Fetch conversation log detail from API */ const getDetail = () => { if (!vo) return setLoading(true) getAppLogDetail(vo.app_id, vo.id).then(res => { const { node_executions_map, messages, ...rest } = res as Data; let hasSubContentMessages = messages if (messages && messages.length > 0 && node_executions_map && Object.keys(node_executions_map).length > 0) { hasSubContentMessages = messages.map(item => { if (item.id && node_executions_map[item.id]) { item.subContent = node_executions_map[item.id]?.map(({ input, output, cycle_items = [], error, process, ...node }: any) => { const converted: any = { ...node, icon: nodeIconMap[node.node_type], content: { input, output, process, error } } if (node.node_type === 'loop' && Array.isArray(cycle_items) && cycle_items.length > 0) { converted.subContent = cycle_items.map(({ input: cInput, output: cOutput, error: cError, process: cProcess, ...cNode }: any) => ({ ...cNode, icon: nodeIconMap[cNode.node_type], content: { input: cInput, output: cOutput, process: cProcess, error: cError } })) } return converted }) } return { ...item } }) } setData({ ...rest, messages: hasSubContentMessages }) }) .finally(() => { setLoading(false) }) } /** Expose methods to parent component */ useImperativeHandle(ref, () => ({ handleOpen, handleClose })); console.log('data', data) return ( {data.title}
{formatDateTime(data.created_at, 'YYYY.MM')} - {formatDateTime(data.updated_at, 'YYYY.MM')}
} open={visible} onCancel={handleClose} footer={null} width={1000} > {t('workingDetail.conversationStream')}
{loading ? : data.messages?.length === 0 ? : ( formatDateTime(item.created_at)} renderRuntime={(item, index) => } /> ) }
); }); export default LogDetailModal;