@@ -34,6 +34,7 @@ import {
3434import { normalizeViewport } from "../../stores/flow/utils/viewportUtils" ;
3535import { splitPipelineAndConfig } from "./configSplitter" ;
3636import { isMpeField } from "../sorting" ;
37+ import { serializeNodePosition } from "../../stores/flow/utils/coordinateUtils" ;
3738
3839/**
3940 * 将Flow转换为Pipeline对象
@@ -85,6 +86,17 @@ export function flowToPipeline(datas?: FlowToOptions): PipelineObjType {
8586 const prefix = config . prefix ? config . prefix + "_" : "" ;
8687 const pipelineObj : PipelineObjType = { } ;
8788
89+ // 视觉副本:同 label 的 External / Anchor 主副本写入 entry(保持向后兼容),
90+ // 第二个起的副本位置追加到该 entry 的 $__mpe_code.extra_positions 数组中。
91+ const externalEntryByKey = new Map <
92+ string ,
93+ { mpeCode : Record < string , any > }
94+ > ( ) ;
95+ const anchorEntryByKey = new Map <
96+ string ,
97+ { mpeCode : Record < string , any > }
98+ > ( ) ;
99+
88100 sortedNodes . forEach ( ( node ) => {
89101 switch ( node . type ) {
90102 case NodeTypeEnum . Pipeline :
@@ -93,16 +105,53 @@ export function flowToPipeline(datas?: FlowToOptions): PipelineObjType {
93105 sortedNodes ,
94106 ) ;
95107 break ;
96- case NodeTypeEnum . External :
108+ case NodeTypeEnum . External : {
97109 if ( ! shouldExportConfig ) break ;
98- pipelineObj [ externalMarkPrefix + node . data . label + "_" + fileName ] =
99- parseExternalNodeForExport ( node as PipelineNodeType , sortedNodes ) ;
110+ const key = externalMarkPrefix + node . data . label + "_" + fileName ;
111+ const existing = externalEntryByKey . get ( key ) ;
112+ if ( existing ) {
113+ // 追加到 extra_positions
114+ const pos = serializeNodePosition ( node , sortedNodes ) ;
115+ existing . mpeCode . extra_positions ??= [ ] ;
116+ existing . mpeCode . extra_positions . push ( {
117+ x : Math . round ( pos . x ) ,
118+ y : Math . round ( pos . y ) ,
119+ } ) ;
120+ break ;
121+ }
122+ const entry = parseExternalNodeForExport (
123+ node as PipelineNodeType ,
124+ sortedNodes ,
125+ ) ;
126+ pipelineObj [ key ] = entry ;
127+ externalEntryByKey . set ( key , {
128+ mpeCode : entry [ configMark ] as Record < string , any > ,
129+ } ) ;
100130 break ;
101- case NodeTypeEnum . Anchor :
131+ }
132+ case NodeTypeEnum . Anchor : {
102133 if ( ! shouldExportConfig ) break ;
103- pipelineObj [ anchorMarkPrefix + node . data . label + "_" + fileName ] =
104- parseAnchorNodeForExport ( node as PipelineNodeType , sortedNodes ) ;
134+ const key = anchorMarkPrefix + node . data . label + "_" + fileName ;
135+ const existing = anchorEntryByKey . get ( key ) ;
136+ if ( existing ) {
137+ const pos = serializeNodePosition ( node , sortedNodes ) ;
138+ existing . mpeCode . extra_positions ??= [ ] ;
139+ existing . mpeCode . extra_positions . push ( {
140+ x : Math . round ( pos . x ) ,
141+ y : Math . round ( pos . y ) ,
142+ } ) ;
143+ break ;
144+ }
145+ const entry = parseAnchorNodeForExport (
146+ node as PipelineNodeType ,
147+ sortedNodes ,
148+ ) ;
149+ pipelineObj [ key ] = entry ;
150+ anchorEntryByKey . set ( key , {
151+ mpeCode : entry [ configMark ] as Record < string , any > ,
152+ } ) ;
105153 break ;
154+ }
106155 case NodeTypeEnum . Sticker :
107156 if ( ! shouldExportConfig ) break ;
108157 pipelineObj [ stickerMarkPrefix + node . data . label + "_" + fileName ] =
@@ -135,6 +184,9 @@ export function flowToPipeline(datas?: FlowToOptions): PipelineObjType {
135184 sortedEdges . push ( ...sorted ) ;
136185 } ) ;
137186
187+ // 多个副本指向同一 source 时会产生重复 ref,按 (source, linkType, targetLabel+attrs) 去重
188+ const linkSeen = new Set < string > ( ) ;
189+
138190 sortedEdges . forEach ( ( edge ) => {
139191 // 获取节点数据
140192 const sourceKey = findNodeLabelById ( nodes , edge . source ) ;
@@ -178,6 +230,9 @@ export function flowToPipeline(datas?: FlowToOptions): PipelineObjType {
178230
179231 // 添加链接
180232 const linkType = edge . sourceHandle as SourceHandleTypeEnum ;
233+ const dedupKey = `${ edge . source } |${ linkType } |${ nodeName } |${ isAnchor ? "a" : "" } ${ hasJumpBack ? "j" : "" } ` ;
234+ if ( linkSeen . has ( dedupKey ) ) return ;
235+ linkSeen . add ( dedupKey ) ;
181236 if ( ! ( linkType in pSourceNode ) ) pSourceNode [ linkType ] = [ ] ;
182237 pSourceNode [ linkType ] . push ( toPNodeRef ) ;
183238 } ) ;
0 commit comments