This commit is contained in:
root 2025-07-10 23:48:08 +08:00
parent 562e49f028
commit 538f223217
2 changed files with 78 additions and 9 deletions

View File

@ -27,6 +27,7 @@ interface TrackTimelineProps {
currentTime: number
onSegmentClick?: (segment: TrackSegment) => void
onSegmentHover?: (segment: TrackSegment | null) => void
onSegmentNameChange?: (segmentId: string, newName: string) => void
}
export const TrackTimeline: React.FC<TrackTimelineProps> = ({
@ -34,8 +35,11 @@ export const TrackTimeline: React.FC<TrackTimelineProps> = ({
totalDuration,
currentTime,
onSegmentClick,
onSegmentHover
onSegmentHover,
onSegmentNameChange
}) => {
const [editingSegmentId, setEditingSegmentId] = React.useState<string | null>(null)
const [editingName, setEditingName] = React.useState('')
const getSegmentColor = (type: string) => {
switch (type) {
case 'video': return 'bg-blue-500 hover:bg-blue-600'
@ -73,6 +77,38 @@ export const TrackTimeline: React.FC<TrackTimelineProps> = ({
return `${minutes}:${secs.padStart(5, '0')}`
}
const handleSegmentDoubleClick = (segment: TrackSegment) => {
setEditingSegmentId(segment.id)
setEditingName(segment.name)
}
const handleSegmentRightClick = (e: React.MouseEvent, segment: TrackSegment) => {
e.preventDefault()
setEditingSegmentId(segment.id)
setEditingName(segment.name)
}
const handleNameSubmit = (segmentId: string) => {
if (onSegmentNameChange && editingName.trim()) {
onSegmentNameChange(segmentId, editingName.trim())
}
setEditingSegmentId(null)
setEditingName('')
}
const handleNameCancel = () => {
setEditingSegmentId(null)
setEditingName('')
}
const handleKeyDown = (e: React.KeyboardEvent, segmentId: string) => {
if (e.key === 'Enter') {
handleNameSubmit(segmentId)
} else if (e.key === 'Escape') {
handleNameCancel()
}
}
return (
<div className="border border-gray-200 rounded-lg overflow-hidden">
{/* Track Header */}
@ -122,16 +158,28 @@ export const TrackTimeline: React.FC<TrackTimelineProps> = ({
minWidth: '80px'
}}
onClick={() => onSegmentClick?.(segment)}
onDoubleClick={() => handleSegmentDoubleClick(segment)}
onContextMenu={(e) => handleSegmentRightClick(e, segment)}
onMouseEnter={() => onSegmentHover?.(segment)}
onMouseLeave={() => onSegmentHover?.(null)}
title={`${segment.name}\n类型: ${segment.type}\n开始: ${formatTime(segment.start_time)}\n结束: ${formatTime(segment.end_time)}\n时长: ${formatTime(segment.duration)}${segment.resource_path ? `\n资源: ${segment.resource_path}` : ''}`}
>
<div className="truncate flex-1">
{segment.name}
</div>
<div className="text-xs opacity-75 ml-2">
{formatTime(segment.duration)}
</div>
{editingSegmentId === segment.id ? (
<input
type="text"
value={editingName}
onChange={(e) => setEditingName(e.target.value)}
onBlur={() => handleNameSubmit(segment.id)}
onKeyDown={(e) => handleKeyDown(e, segment.id)}
className="w-full bg-transparent text-inherit border-none outline-none"
autoFocus
onClick={(e) => e.stopPropagation()}
/>
) : (
<div className="truncate flex-1">
{segment.name}
</div>
)}
</div>
)
})}

View File

@ -108,6 +108,26 @@ const TemplateDetailPage: React.FC = () => {
}
}
const handleSegmentNameChange = (segmentId: string, newName: string) => {
if (!templateDetail) return
// Update the segment name in the local state
const updatedDetail = {
...templateDetail,
tracks: templateDetail.tracks.map(track => ({
...track,
segments: track.segments.map(segment =>
segment.id === segmentId ? { ...segment, name: newName } : segment
)
}))
}
setTemplateDetail(updatedDetail)
// TODO: Save to backend
console.log(`Segment ${segmentId} renamed to: ${newName}`)
}
if (loading) {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
@ -266,6 +286,7 @@ const TemplateDetailPage: React.FC = () => {
// Could show segment details in a tooltip
console.log('Hovering segment:', segment?.name)
}}
onSegmentNameChange={handleSegmentNameChange}
/>
))}
</div>