Просмотр исходного кода

refactor(FlowChart): 调整节点间距、连线样式并增加折叠提示

- 增加节点纵向间距以改善布局
- 缩小箭头标记尺寸使连线更精致
- 调整连线起点和终点位置,使其从节点底部连接至顶部
- 为折叠的连线添加可交互的徽章提示,显示折叠数量
- 将节点文本容器改为foreignObject以支持多行文本显示
- 注释掉TopBar中的状态筛选下拉框(临时移除)
max_liu 3 недель назад
Родитель
Сommit
8268728da6

+ 62 - 24
frontend/react-template/src/components/FlowChart/FlowChart.tsx

@@ -175,7 +175,7 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
     const nodes: LayoutNode[] = []; // 所有节点列表
     const nodes: LayoutNode[] = []; // 所有节点列表
     const edges: LayoutEdge[] = []; // 所有连接线列表
     const edges: LayoutEdge[] = []; // 所有连接线列表
 
 
-    const NODE_HEIGHT = 80; // 节点间距(纵向)
+    const NODE_HEIGHT = 110; // 节点间距(纵向)
     const centerX = dimensions.width / 2; // 主链节点的 X 坐标(居中)
     const centerX = dimensions.width / 2; // 主链节点的 X 坐标(居中)
     const HORIZONTAL_OFFSET = 0; // 子节点水平偏移量
     const HORIZONTAL_OFFSET = 0; // 子节点水平偏移量
 
 
@@ -452,7 +452,7 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
    * 并且调整后续节点的位置,填补折叠后的空白
    * 并且调整后续节点的位置,填补折叠后的空白
    */
    */
   const visibleData = useMemo(() => {
   const visibleData = useMemo(() => {
-    const NODE_HEIGHT = 80;
+    const NODE_HEIGHT = 110;
 
 
     // 1. 找出所有折叠的边
     // 1. 找出所有折叠的边
     const collapsedEdgesList = layoutData.edges.filter((e) => e.collapsed);
     const collapsedEdgesList = layoutData.edges.filter((e) => e.collapsed);
@@ -582,9 +582,9 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
    */
    */
   const getArcPath = (source: LayoutNode, target: LayoutNode, level: number) => {
   const getArcPath = (source: LayoutNode, target: LayoutNode, level: number) => {
     const sx = source.x;
     const sx = source.x;
-    const sy = source.y;
+    const sy = source.y + 25; // 从节点底部出发
     const tx = target.x;
     const tx = target.x;
-    const ty = target.y;
+    const ty = target.y - 25; // 到节点顶部结束
 
 
     // 弧线向右偏移,偏移量根据层级递减
     // 弧线向右偏移,偏移量根据层级递减
     // 外层弧线偏移量大,内层弧线偏移量小
     // 外层弧线偏移量大,内层弧线偏移量小
@@ -604,7 +604,7 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
    * @returns SVG 路径字符串
    * @returns SVG 路径字符串
    */
    */
   const getLinePath = (source: LayoutNode, target: LayoutNode) => {
   const getLinePath = (source: LayoutNode, target: LayoutNode) => {
-    return `M ${source.x},${source.y} L ${target.x},${target.y}`;
+    return `M ${source.x},${source.y + 25} L ${target.x},${target.y - 25}`;
   };
   };
 
 
   /**
   /**
@@ -745,16 +745,47 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
               }
               }
 
 
               return (
               return (
-                <path
-                  key={edge.id}
-                  d={path}
-                  fill="none"
-                  stroke={color}
-                  strokeWidth={strokeWidth}
-                  markerEnd="url(#arrow-default)" // 箭头
-                  style={{ cursor: edge.collapsible ? "pointer" : "default" }} // 可折叠的显示手型光标
-                  onClick={() => edge.collapsible && toggleCollapse(edge.id)} // 点击切换折叠状态
-                />
+                <g key={edge.id}>
+                  <path
+                    d={path}
+                    fill="none"
+                    stroke={color}
+                    strokeWidth={strokeWidth}
+                    markerEnd="url(#arrow-default)" // 箭头
+                    style={{ cursor: edge.collapsible ? "pointer" : "default" }} // 可折叠的显示手型光标
+                    onClick={() => edge.collapsible && toggleCollapse(edge.id)} // 点击切换折叠状态
+                  />
+                  {/* 折叠状态提示徽章 */}
+                  {edge.collapsed && (
+                    <g
+                      transform={`translate(${(edge.source.x + edge.target.x) / 2},${
+                        (edge.source.y + edge.target.y) / 2
+                      })`}
+                      onClick={(e) => {
+                        e.stopPropagation();
+                        toggleCollapse(edge.id);
+                      }}
+                      style={{ cursor: "pointer" }}
+                    >
+                      <circle
+                        r={10}
+                        fill="#FFFFFF"
+                        stroke={color}
+                        strokeWidth={1}
+                      />
+                      <text
+                        x={0}
+                        y={4}
+                        fontSize={10}
+                        fill={color}
+                        textAnchor="middle"
+                        fontWeight="bold"
+                      >
+                        {edge.children ? edge.children.length : "+"}
+                      </text>
+                    </g>
+                  )}
+                </g>
               );
               );
             })}
             })}
           </g>
           </g>
@@ -784,7 +815,7 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
                   <rect
                   <rect
                     x={-70}
                     x={-70}
                     y={-25}
                     y={-25}
-                    width={140}
+                    width={150}
                     height={50}
                     height={50}
                     rx={8}
                     rx={8}
                     fill={isGoal ? "#E3F2FD" : "#F5F5F5"} // 目标节点浅蓝色,消息节点灰色
                     fill={isGoal ? "#E3F2FD" : "#F5F5F5"} // 目标节点浅蓝色,消息节点灰色
@@ -793,15 +824,22 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
                   />
                   />
                   {/* 节点文本(带 Tooltip) */}
                   {/* 节点文本(带 Tooltip) */}
                   <Tooltip content={text}>
                   <Tooltip content={text}>
-                    <text
-                      x={0}
-                      y={5}
-                      fontSize={12}
-                      fill={textColor}
-                      textAnchor="middle"
+                    <foreignObject
+                      x={-70}
+                      y={-25}
+                      width={150}
+                      height={50}
                     >
                     >
-                      {text.length > 10 ? text.slice(0, 10) + "..." : text}
-                    </text>
+                      <div
+                        className="w-full h-full flex items-center justify-center text-xs text-center leading-[1.2] px-1 box-border line-clamp-3"
+                        style={{
+                          color: textColor,
+                          WebkitBoxPack: "center", // 垂直居中
+                        }}
+                      >
+                        {text}
+                      </div>
+                    </foreignObject>
                   </Tooltip>
                   </Tooltip>
                 </g>
                 </g>
               );
               );

+ 10 - 10
frontend/react-template/src/components/FlowChart/components/ArrowMarkers.tsx

@@ -8,8 +8,8 @@ export const ArrowMarkers: FC = () => (
       viewBox="0 0 10 10"
       viewBox="0 0 10 10"
       refX="10"
       refX="10"
       refY="5"
       refY="5"
-      markerWidth="7"
-      markerHeight="7"
+      markerWidth="3"
+      markerHeight="3"
       orient="auto"
       orient="auto"
     >
     >
       <path
       <path
@@ -22,8 +22,8 @@ export const ArrowMarkers: FC = () => (
       viewBox="0 0 10 10"
       viewBox="0 0 10 10"
       refX="10"
       refX="10"
       refY="5"
       refY="5"
-      markerWidth="7"
-      markerHeight="7"
+      markerWidth="3"
+      markerHeight="3"
       orient="auto"
       orient="auto"
     >
     >
       <path
       <path
@@ -36,8 +36,8 @@ export const ArrowMarkers: FC = () => (
       viewBox="0 0 10 10"
       viewBox="0 0 10 10"
       refX="10"
       refX="10"
       refY="5"
       refY="5"
-      markerWidth="7"
-      markerHeight="7"
+      markerWidth="3"
+      markerHeight="3"
       orient="auto"
       orient="auto"
     >
     >
       <path
       <path
@@ -50,8 +50,8 @@ export const ArrowMarkers: FC = () => (
       viewBox="0 0 10 10"
       viewBox="0 0 10 10"
       refX="10"
       refX="10"
       refY="5"
       refY="5"
-      markerWidth="7"
-      markerHeight="7"
+      markerWidth="3"
+      markerHeight="3"
       orient="auto"
       orient="auto"
     >
     >
       <path
       <path
@@ -64,8 +64,8 @@ export const ArrowMarkers: FC = () => (
       viewBox="0 0 10 10"
       viewBox="0 0 10 10"
       refX="10"
       refX="10"
       refY="5"
       refY="5"
-      markerWidth="7"
-      markerHeight="7"
+      markerWidth="3"
+      markerHeight="3"
       orient="auto"
       orient="auto"
     >
     >
       <path
       <path

+ 2 - 2
frontend/react-template/src/components/TopBar/TopBar.tsx

@@ -55,7 +55,7 @@ export const TopBar: FC<TopBarProps> = ({ onTraceSelect }) => {
         <h1>{title}</h1>
         <h1>{title}</h1>
       </div>
       </div>
       <div className={styles.filters}>
       <div className={styles.filters}>
-        <select
+        {/* <select
           value={statusFilter}
           value={statusFilter}
           onChange={(e: ChangeEvent<HTMLSelectElement>) => handleStatusChange(e.target.value)}
           onChange={(e: ChangeEvent<HTMLSelectElement>) => handleStatusChange(e.target.value)}
           className={styles.select}
           className={styles.select}
@@ -65,7 +65,7 @@ export const TopBar: FC<TopBarProps> = ({ onTraceSelect }) => {
           <option value="running">运行中</option>
           <option value="running">运行中</option>
           <option value="completed">已完成</option>
           <option value="completed">已完成</option>
           <option value="failed">失败</option>
           <option value="failed">失败</option>
-        </select>
+        </select> */}
         {/* <button
         {/* <button
           onClick={() => loadTraces(statusFilter)}
           onClick={() => loadTraces(statusFilter)}
           className={styles.button}
           className={styles.button}