/** * 编辑描述显示组件 * 显示已提交的编辑描述内容,带有优雅的连接线 */ import React, { useMemo } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { EditPoint as EditPointType, EditPointStatus } from './types'; import { CONNECTION_STYLE, calculateArrowGeometry, calculateCurvePath, getConnectionAnimationConfig } from './connection-config'; interface EditDescriptionProps { /** 编辑点数据 */ editPoint: EditPointType; /** 容器尺寸 */ containerSize: { width: number; height: number }; /** 描述框位置 */ position: { x: number; y: number }; /** 连接线终点 */ connectionEnd: { x: number; y: number }; /** 点击事件处理 */ onClick?: (editPoint: EditPointType) => void; /** 编辑事件处理 */ onEdit?: (id: string) => void; /** 删除事件处理 */ onDelete?: (id: string) => void; } /** * 编辑描述组件 */ export const EditDescription: React.FC = ({ editPoint, containerSize, position, connectionEnd, onClick, onEdit, onDelete }) => { // 计算编辑点的屏幕坐标 const editPointPosition = useMemo(() => ({ x: (editPoint.position.x / 100) * containerSize.width, y: (editPoint.position.y / 100) * containerSize.height }), [editPoint.position, containerSize]); // 使用统一的连接线几何计算 const connectionGeometry = useMemo(() => { const startPoint = { x: editPointPosition.x, y: editPointPosition.y }; const endPoint = { x: connectionEnd.x, y: connectionEnd.y }; // 使用统一的箭头几何计算 const arrowGeometry = calculateArrowGeometry(startPoint, endPoint); // 使用统一的路径计算 const path = calculateCurvePath(startPoint, arrowGeometry.center, containerSize); return { path, arrowPoints: arrowGeometry.points, arrowTip: arrowGeometry.tip, arrowBase: arrowGeometry.base, arrowCenter: arrowGeometry.center }; }, [editPointPosition, connectionEnd, containerSize]); // 获取统一的动画配置 const animationConfig = useMemo(() => getConnectionAnimationConfig(true), // EditDescription总是使用动画 [] ); // 获取状态颜色 const getStatusColor = () => { switch (editPoint.status) { case EditPointStatus.EDITED: return '#10b981'; // 绿色 case EditPointStatus.PROCESSING: return '#3b82f6'; // 蓝色 case EditPointStatus.COMPLETED: return '#059669'; // 深绿色 case EditPointStatus.FAILED: return '#ef4444'; // 红色 default: return '#6b7280'; // 灰色 } }; // 获取状态文本 const getStatusText = () => { switch (editPoint.status) { case EditPointStatus.EDITED: return '已编辑'; case EditPointStatus.PROCESSING: return '处理中'; case EditPointStatus.COMPLETED: return '已完成'; case EditPointStatus.FAILED: return '失败'; default: return ''; } }; const statusColor = getStatusColor(); const statusText = getStatusText(); return ( {editPoint.description && editPoint.status !== EditPointStatus.PENDING && ( <> {/* 统一的虚线连接线 - 与EditConnection完全一致 */} {/* 统一的虚线连接线 - 与EditConnection完全一致 */} {/* 几何精确的箭头 - 与连接线完美对齐 */} `${p.x},${p.y}`).join(' ')} fill={CONNECTION_STYLE.color} initial={animationConfig.arrow?.initial} animate={animationConfig.arrow?.animate} exit={animationConfig.arrow?.initial} transition={animationConfig.arrow?.transition} style={{ filter: CONNECTION_STYLE.dropShadow }} /> {/* Consistent white text display matching EditInput component */} onClick?.(editPoint)} > {/* White text display with exact same styling as EditInput */}
{editPoint.description}
{/* Interactive edit/delete buttons on hover */}
{onEdit && ( { e.stopPropagation(); onEdit(editPoint.id); }} className="w-6 h-6 rounded-full bg-white/20 hover:bg-white/30 backdrop-blur-sm flex items-center justify-center text-white text-xs transition-colors" whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} title="Edit description" > ✏️ )} {onDelete && ( { e.stopPropagation(); onDelete(editPoint.id); }} className="w-6 h-6 rounded-full bg-red-500/20 hover:bg-red-500/30 backdrop-blur-sm flex items-center justify-center text-white text-xs transition-colors" whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }} title="Delete edit point" > 🗑️ )}
{/* Status indicator for processing states */} {editPoint.status === EditPointStatus.PROCESSING && (
Processing...
)} {editPoint.status === EditPointStatus.FAILED && (
Failed - Click to retry
)}
)}
); };