|
|
@@ -213,17 +213,7 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
|
|
|
let lastNode = currentNode; // 记录最后一个节点,用于连接到下一个主链节点
|
|
|
globalY += NODE_HEIGHT; // 更新全局 Y 坐标
|
|
|
|
|
|
- // 递归展开 sub_goals
|
|
|
- if (goal.sub_goals && goal.sub_goals.length > 0) {
|
|
|
- goal.sub_goals.forEach((subGoal) => {
|
|
|
- const subX = x + HORIZONTAL_OFFSET; // 子节点向右偏移
|
|
|
- const result = expandNode(subGoal, subX, level + 1, nodeId);
|
|
|
- localNodes.push(...result.nodes);
|
|
|
- lastNode = result.lastNode; // 更新最后一个节点
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- // 展开 msgGroup(消息组)
|
|
|
+ // 1. 先展开 msgGroup(消息组)- 按照用户需求,消息显示在 sub_goals 之前
|
|
|
const messages = msgGroups[nodeId];
|
|
|
if (messages && messages.length > 0) {
|
|
|
messages.forEach((msg) => {
|
|
|
@@ -242,6 +232,16 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ // 2. 再递归展开 sub_goals
|
|
|
+ if (goal.sub_goals && goal.sub_goals.length > 0) {
|
|
|
+ goal.sub_goals.forEach((subGoal) => {
|
|
|
+ const subX = x + HORIZONTAL_OFFSET; // 子节点向右偏移
|
|
|
+ const result = expandNode(subGoal, subX, level + 1, nodeId);
|
|
|
+ localNodes.push(...result.nodes);
|
|
|
+ lastNode = result.lastNode; // 更新最后一个节点
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
return { nodes: localNodes, firstNode: currentNode, lastNode };
|
|
|
};
|
|
|
|
|
|
@@ -308,6 +308,26 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
|
|
|
const childNodes = current.allNodes.slice(1);
|
|
|
const directChildren = childNodes.filter((n) => n.parentId === current.firstNode.id);
|
|
|
|
|
|
+ // Logic A: Messages Group Arc (A -> s1)
|
|
|
+ // 检查是否有消息节点且后面跟着子目标节点
|
|
|
+ // 如果有,绘制一条蓝色弧线从主节点到第一个子目标节点,包裹所有消息节点
|
|
|
+ const firstSubgoalIndex = directChildren.findIndex((n) => n.type === "goal");
|
|
|
+ if (firstSubgoalIndex > 0) {
|
|
|
+ const target = directChildren[firstSubgoalIndex];
|
|
|
+ const messages = directChildren.slice(0, firstSubgoalIndex);
|
|
|
+ const arcId = `arc-msg-${current.firstNode.id}-${target.id}`;
|
|
|
+ edges.push({
|
|
|
+ id: arcId,
|
|
|
+ source: current.firstNode,
|
|
|
+ target: target,
|
|
|
+ type: "arc",
|
|
|
+ level: 1,
|
|
|
+ collapsible: true,
|
|
|
+ collapsed: collapsedEdges.has(arcId),
|
|
|
+ children: messages,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
// 连接第一个节点到第一个子节点
|
|
|
if (directChildren.length > 0) {
|
|
|
edges.push({
|
|
|
@@ -407,6 +427,50 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
|
|
|
collapsible: false,
|
|
|
collapsed: false,
|
|
|
});
|
|
|
+
|
|
|
+ // Logic C: Last Child Arc (s2 -> B)
|
|
|
+ // 如果最后一个直接子节点是 sub_goal 且有子节点,绘制弧线连接到下一个主节点
|
|
|
+ const lastChild = directChildren[directChildren.length - 1];
|
|
|
+ const lastChildChildren = nodes.filter((n) => n.parentId === lastChild.id);
|
|
|
+
|
|
|
+ if (lastChild.type === "goal" && lastChildChildren.length > 0) {
|
|
|
+ const arcId = `arc-${lastChild.id}-${next.firstNode.id}`;
|
|
|
+ edges.push({
|
|
|
+ id: arcId,
|
|
|
+ source: lastChild,
|
|
|
+ target: next.firstNode,
|
|
|
+ type: "arc",
|
|
|
+ level: 1,
|
|
|
+ collapsible: true,
|
|
|
+ collapsed: collapsedEdges.has(arcId),
|
|
|
+ children: lastChildChildren,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 补充绘制最后一个子节点的内部连线(直线)
|
|
|
+ // 1. 连接 lastChild 到第一个孙节点
|
|
|
+ edges.push({
|
|
|
+ id: `line-${lastChild.id}-${lastChildChildren[0].id}`,
|
|
|
+ source: lastChild,
|
|
|
+ target: lastChildChildren[0],
|
|
|
+ type: "line",
|
|
|
+ level: lastChild.level + 1,
|
|
|
+ collapsible: false,
|
|
|
+ collapsed: false,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 2. 连接孙节点之间
|
|
|
+ for (let k = 0; k < lastChildChildren.length - 1; k++) {
|
|
|
+ edges.push({
|
|
|
+ id: `line-${lastChildChildren[k].id}-${lastChildChildren[k + 1].id}`,
|
|
|
+ source: lastChildChildren[k],
|
|
|
+ target: lastChildChildren[k + 1],
|
|
|
+ type: "line",
|
|
|
+ level: lastChild.level + 1,
|
|
|
+ collapsible: false,
|
|
|
+ collapsed: false,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
} else {
|
|
|
// 情况 4:没有子节点,直接绘制直线
|
|
|
@@ -455,7 +519,17 @@ export const FlowChart: FC<FlowChartProps> = ({ goals, msgGroups = {}, onNodeCli
|
|
|
const NODE_HEIGHT = 110;
|
|
|
|
|
|
// 1. 找出所有折叠的边
|
|
|
- const collapsedEdgesList = layoutData.edges.filter((e) => e.collapsed);
|
|
|
+ const allCollapsedEdges = layoutData.edges.filter((e) => e.collapsed);
|
|
|
+
|
|
|
+ // 筛选出“有效”的折叠边:如果一个折叠边被另一个更大的折叠边包含(即其节点被隐藏),则忽略它
|
|
|
+ // 避免重复计算 shiftY
|
|
|
+ const collapsedEdgesList = allCollapsedEdges.filter((edge) => {
|
|
|
+ return !allCollapsedEdges.some((other) => {
|
|
|
+ if (edge === other) return false;
|
|
|
+ // 如果当前边的源节点或目标节点在另一个折叠边的子节点列表中,说明当前边是被包裹在内部的
|
|
|
+ return other.children?.some((child) => child.id === edge.source.id || child.id === edge.target.id);
|
|
|
+ });
|
|
|
+ });
|
|
|
|
|
|
// 2. 过滤节点:隐藏被折叠的节点
|
|
|
const visibleNodesRaw = layoutData.nodes.filter((node) => {
|