import React from 'react'; import { Avatar, Button, Empty, Input, Space, Spin, Timeline, Typography, } from 'antd'; import { CheckOutlined, CloseOutlined, EditOutlined, UserOutlined, } from '@ant-design/icons'; import tools from '../utils/tools'; import './TranscriptTimeline.css'; const { Text } = Typography; const TranscriptTimeline = ({ transcript = [], loading = false, visibleCount, currentHighlightIndex = -1, onJumpToTime, onScroll, transcriptRefs, getSpeakerColor, emptyDescription = '暂无对话数据', loadingTip = '正在加载转录内容...', showRenderHint = false, fillHeight = false, maxHeight = null, editable = false, isMeetingOwner = false, editing = {}, }) => { const { inlineSpeakerEdit = null, inlineSpeakerEditSegmentId = null, inlineSpeakerValue = '', setInlineSpeakerValue, startInlineSpeakerEdit, saveInlineSpeakerEdit, cancelInlineSpeakerEdit, inlineSegmentEditId = null, inlineSegmentValue = '', setInlineSegmentValue, startInlineSegmentEdit, saveInlineSegmentEdit, cancelInlineSegmentEdit, savingInlineEdit = false, } = editing; const renderCount = Math.min(visibleCount ?? transcript.length, transcript.length); if (loading) { return (
); } if (!transcript.length) { return (
); } return (
{ const isActive = currentHighlightIndex === index; const speakerColor = getSpeakerColor(item.speaker_id); const speakerEditKey = `speaker-${item.speaker_id}-${item.segment_id}`; return { label: ( {tools.formatDuration(item.start_time_ms / 1000)} ), dot: ( ), children: (
{ if (transcriptRefs?.current) { transcriptRefs.current[index] = el; } }} className={`transcript-entry${isActive ? ' is-active' : ''}`} onClick={() => onJumpToTime?.(item.start_time_ms)} >
} className="transcript-entry-avatar" style={{ backgroundColor: speakerColor }} /> {editable && inlineSpeakerEdit === item.speaker_id && inlineSpeakerEditSegmentId === speakerEditKey ? ( event.stopPropagation()}> setInlineSpeakerValue?.(event.target.value)} onPressEnter={saveInlineSpeakerEdit} style={{ width: 180 }} />
{editable && inlineSegmentEditId === item.segment_id ? (
event.stopPropagation()}> setInlineSegmentValue?.(event.target.value)} onPressEnter={(event) => { if (event.ctrlKey || event.metaKey) { saveInlineSegmentEdit?.(); } }} />
) : ( { event.stopPropagation(); startInlineSegmentEdit?.(item); } : undefined} > {item.text_content} )}
), }; })} /> {showRenderHint && renderCount < transcript.length ? (
已渲染 {renderCount} / {transcript.length} 条转录,继续向下滚动将自动加载更多
) : null}
); }; export default TranscriptTimeline;